23 #include "clang/AST/Decl.h"
24 #include "clang/AST/DeclCXX.h"
25 #include "clang/AST/Type.h"
26 #include "clang/Sema/CodeCompleteConsumer.h"
27 #include "llvm/Support/Casting.h"
28 #include "gmock/gmock.h"
29 #include "gtest/gtest.h"
41 TEST(QualityTests, SymbolQualitySignalExtraction) {
46 int _f() { return _X; }
48 #define DECL_NAME(x, y) x##_##y##_Decl
49 #define DECL(x, y) class DECL_NAME(x, y) {};
50 DECL(X, Y); // X_Y_Decl
53 auto Symbols = Header.headerSymbols();
54 auto AST = Header.
build();
58 EXPECT_FALSE(
Quality.Deprecated);
59 EXPECT_FALSE(
Quality.ImplementationDetail);
60 EXPECT_TRUE(
Quality.ReservedName);
65 EXPECT_TRUE(
Quality.ImplementationDetail);
71 EXPECT_TRUE(
Quality.Deprecated);
72 EXPECT_FALSE(
Quality.ReservedName);
73 EXPECT_EQ(
Quality.References, 24u);
78 EXPECT_TRUE(
Quality.Deprecated);
79 EXPECT_FALSE(
Quality.ReservedName);
84 Quality.merge(CodeCompletionResult(
"if"));
88 TEST(QualityTests, SymbolRelevanceSignalExtraction) {
94 namespace hdr { class Bar {}; } // namespace hdr
96 #define DEFINE_FLAG(X) \
106 using flags::FLAGS_FOO;
108 int ::header_main() {}
112 int deprecated() { return 0; }
114 namespace { struct X { void y() { int z; } }; }
117 auto AST = Test.
build();
120 Relevance.
merge(CodeCompletionResult(&
findDecl(AST,
"deprecated"),
128 Relevance.
merge(CodeCompletionResult(&
findDecl(AST,
"main"), 42));
130 <<
"Decl in current file";
132 Relevance.
merge(CodeCompletionResult(&
findDecl(AST,
"header"), 42));
135 Relevance.
merge(CodeCompletionResult(&
findDecl(AST,
"header_main"), 42));
137 <<
"Current file and header";
139 auto constructShadowDeclCompletionResult = [&](
const std::string DeclName) {
141 *dyn_cast<UsingDecl>(&
findDecl(AST, [&](
const NamedDecl &ND) {
142 if (
const UsingDecl *Using = dyn_cast<UsingDecl>(&ND))
143 if (Using->shadow_size() &&
144 Using->getQualifiedNameAsString() == DeclName)
148 CodeCompletionResult Result(Shadow->getTargetDecl(), 42);
149 Result.ShadowDecl = Shadow;
154 Relevance.
merge(constructShadowDeclCompletionResult(
"Bar"));
156 <<
"Using declaration in main file";
157 Relevance.
merge(constructShadowDeclCompletionResult(
"FLAGS_FOO"));
159 <<
"Using declaration in main file";
172 Relevance.
merge(CodeCompletionResult(&
findDecl(AST,
"S::S"), 42));
178 BaseMember.InBaseClass =
true;
179 Relevance.
merge(BaseMember);
186 bool Matched =
false;
193 EXPECT_TRUE(Matched);
197 TEST(QualityTests, SymbolQualitySignalsSanity) {
203 EXPECT_LT(Deprecated.evaluate(), Default.
evaluate());
207 EXPECT_LT(ReservedName.evaluate(), Default.
evaluate());
211 EXPECT_LT(ImplementationDetail.evaluate(), Default.
evaluate());
215 ManyReferences.References = 1000;
216 EXPECT_GT(WithReferences.evaluate(), Default.
evaluate());
217 EXPECT_GT(ManyReferences.evaluate(), WithReferences.evaluate());
234 EXPECT_LT(Destructor.evaluate(),
Constructor.evaluate());
237 TEST(QualityTests, SymbolRelevanceSignalsSanity) {
243 EXPECT_LT(Forbidden.evaluate(), Default.
evaluate());
247 EXPECT_LT(PoorNameMatch.evaluate(), Default.
evaluate());
251 EXPECT_GT(WithSemaFileProximity.evaluate(), Default.
evaluate());
257 WithSemaScopeProximity.SemaSaysInScope =
true;
258 EXPECT_GT(WithSemaScopeProximity.evaluate(), Default.
evaluate());
262 WithIndexScopeProximity.SymbolScope =
"x::";
263 EXPECT_GT(WithSemaScopeProximity.evaluate(), Default.
evaluate());
266 IndexProximate.
SymbolURI =
"unittest:/foo/bar.h";
267 llvm::StringMap<SourceParams> ProxSources;
268 ProxSources.try_emplace(
testPath(
"foo/baz.h"));
270 IndexProximate.FileProximityMatch = &Distance;
271 EXPECT_GT(IndexProximate.evaluate(), Default.
evaluate());
273 IndexDistant.
SymbolURI =
"unittest:/elsewhere/path.h";
274 EXPECT_GT(IndexProximate.evaluate(), IndexDistant.evaluate())
275 << IndexProximate << IndexDistant;
276 EXPECT_GT(IndexDistant.evaluate(), Default.
evaluate());
280 EXPECT_LT(Scoped.evaluate(), Default.
evaluate());
282 EXPECT_GT(Scoped.evaluate(), Default.
evaluate());
286 EXPECT_EQ(Instance.evaluate(), Default.
evaluate());
287 Instance.Context = CodeCompletionContext::CCC_DotMemberAccess;
288 EXPECT_LT(Instance.evaluate(), Default.
evaluate());
289 Instance.IsInstanceMember =
true;
290 EXPECT_EQ(Instance.evaluate(), Default.
evaluate());
294 EXPECT_LT(InBaseClass.evaluate(), Default.
evaluate());
296 llvm::StringSet<> Words = {
"one",
"two",
"three"};
299 WithoutMatchingWord.
Name =
"four";
303 WithMatchingWord.Name =
"TheTwoTowers";
304 EXPECT_GT(WithMatchingWord.evaluate(), Default.
evaluate());
307 TEST(QualityTests, ScopeProximity) {
309 ScopeDistance ScopeProximity({
"x::y::z::",
"x::",
"llvm::",
""});
313 float NotMatched = Relevance.
evaluate();
316 float Global = Relevance.
evaluate();
317 EXPECT_GT(Global, NotMatched);
320 float NonParent = Relevance.
evaluate();
321 EXPECT_GT(NonParent, Global);
324 float GrandParent = Relevance.
evaluate();
325 EXPECT_GT(GrandParent, Global);
329 EXPECT_GT(
Parent, GrandParent);
332 float Enclosing = Relevance.
evaluate();
333 EXPECT_GT(Enclosing,
Parent);
336 TEST(QualityTests, SortText) {
337 EXPECT_LT(
sortText(std::numeric_limits<float>::infinity()),
343 EXPECT_LT(
sortText(-10),
sortText(-std::numeric_limits<float>::infinity()));
349 TEST(QualityTests, NoBoostForClassConstructor) {
356 auto Symbols = Header.headerSymbols();
357 auto AST = Header.
build();
359 const NamedDecl *Foo = &
findDecl(AST,
"Foo");
361 Cls.
merge(CodeCompletionResult(Foo, 0));
363 const NamedDecl *CtorDecl = &
findDecl(AST, [](
const NamedDecl &ND) {
364 return (ND.getQualifiedNameAsString() ==
"Foo::Foo") &&
365 isa<CXXConstructorDecl>(&ND);
368 Ctor.
merge(CodeCompletionResult(CtorDecl, 0));
374 TEST(QualityTests, IsInstanceMember) {
380 template <typename T> void tpl(T *t) {}
385 auto Symbols = Header.headerSymbols();
400 auto AST = Header.
build();
401 const NamedDecl *Foo = &
findDecl(AST,
"Foo::foo");
402 const NamedDecl *Bar = &
findDecl(AST,
"Foo::bar");
403 const NamedDecl *Tpl = &
findDecl(AST,
"Foo::tpl");
406 Rel.
merge(CodeCompletionResult(Foo, 0));
408 Rel.
merge(CodeCompletionResult(Bar, 0));
411 Rel.
merge(CodeCompletionResult(Tpl, 0));
415 TEST(QualityTests, ConstructorDestructor) {
423 auto Symbols = Header.headerSymbols();
424 auto AST = Header.
build();
426 const NamedDecl *CtorDecl = &
findDecl(AST, [](
const NamedDecl &ND) {
427 return (ND.getQualifiedNameAsString() ==
"Foo::Foo") &&
428 isa<CXXConstructorDecl>(&ND);
430 const NamedDecl *DtorDecl = &
findDecl(AST, [](
const NamedDecl &ND) {
431 return (ND.getQualifiedNameAsString() ==
"Foo::~Foo") &&
432 isa<CXXDestructorDecl>(&ND);
436 CtorQ.
merge(CodeCompletionResult(CtorDecl, 0));
441 CtorQ.merge(CtorSym);
445 DtorQ.
merge(CodeCompletionResult(DtorDecl, 0));
453 bool operator<(const Foo& f1);
456 auto AST = Header.
build();
459 if (
const auto *OD = dyn_cast<FunctionDecl>(&ND))
460 if (OD->isOverloadedOperator())
469 TEST(QualityTests, ItemWithFixItsRankedDown) {
476 auto AST = Header.
build();
479 RelevanceWithFixIt.
merge(CodeCompletionResult(&
findDecl(AST,
"x"), 0,
nullptr,
480 false,
true, {FixItHint{}}));
484 RelevanceWithoutFixIt.
merge(
485 CodeCompletionResult(&
findDecl(AST,
"x"), 0,
nullptr,
false,
true, {}));