24#include "clang/AST/Decl.h"
25#include "clang/AST/DeclCXX.h"
26#include "clang/Sema/CodeCompleteConsumer.h"
27#include "llvm/Support/Casting.h"
28#include "gmock/gmock.h"
29#include "gtest/gtest.h"
41TEST(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_TRUE(
Quality.ImplementationDetail);
64 EXPECT_TRUE(
Quality.Deprecated);
65 EXPECT_FALSE(
Quality.ReservedName);
66 EXPECT_EQ(
Quality.References, 24u);
71 EXPECT_TRUE(
Quality.Deprecated);
72 EXPECT_FALSE(
Quality.ReservedName);
77 Quality.merge(CodeCompletionResult(
"if"));
86 EXPECT_FALSE(
Quality.Deprecated);
87 EXPECT_FALSE(
Quality.ImplementationDetail);
88 EXPECT_TRUE(
Quality.ReservedName);
91TEST(QualityTests, SymbolRelevanceSignalExtraction) {
97 namespace hdr { class Bar {}; } // namespace hdr
99 #define DEFINE_FLAG(X) \
109 using flags::FLAGS_FOO;
111 int ::header_main() {}
115 int deprecated() { return 0; }
117 namespace { struct X { void y() { int z; } }; }
133 <<
"Decl in current file";
140 <<
"Current file and header";
142 auto ConstructShadowDeclCompletionResult = [&](
const std::string DeclName) {
144 *dyn_cast<UsingDecl>(&
findDecl(
AST, [&](
const NamedDecl &ND) {
145 if (
const UsingDecl *Using = dyn_cast<UsingDecl>(&ND))
146 if (Using->shadow_size() &&
147 Using->getQualifiedNameAsString() == DeclName)
151 CodeCompletionResult Result(Shadow->getTargetDecl(), 42);
152 Result.ShadowDecl = Shadow;
157 Relevance.
merge(ConstructShadowDeclCompletionResult(
"Bar"));
159 <<
"Using declaration in main file";
160 Relevance.
merge(ConstructShadowDeclCompletionResult(
"FLAGS_FOO"));
162 <<
"Using declaration in main file";
181 BaseMember.InBaseClass =
true;
182 Relevance.
merge(BaseMember);
185 auto Index = Test.
index();
189 bool Matched =
false;
190 Index->fuzzyFind(Req, [&](
const Symbol &S) {
196 EXPECT_TRUE(Matched);
200TEST(QualityTests, SymbolQualitySignalsSanity) {
202 EXPECT_EQ(Default.evaluateHeuristics(), 1);
206 EXPECT_LT(
Deprecated.evaluateHeuristics(), Default.evaluateHeuristics());
215 Default.evaluateHeuristics());
234 EXPECT_GT(
Variable.evaluateHeuristics(), Default.evaluateHeuristics());
235 EXPECT_GT(
Keyword.evaluateHeuristics(),
Variable.evaluateHeuristics());
236 EXPECT_LT(
Macro.evaluateHeuristics(), Default.evaluateHeuristics());
237 EXPECT_LT(
Operator.evaluateHeuristics(), Default.evaluateHeuristics());
242TEST(QualityTests, SymbolRelevanceSignalsSanity) {
244 EXPECT_EQ(Default.evaluateHeuristics(), 1);
257 Default.evaluateHeuristics());
263 WithSemaScopeProximity.SemaSaysInScope =
true;
264 EXPECT_GT(WithSemaScopeProximity.evaluateHeuristics(),
265 Default.evaluateHeuristics());
270 EXPECT_GT(WithSemaScopeProximity.evaluateHeuristics(),
271 Default.evaluateHeuristics());
274 IndexProximate.
SymbolURI =
"unittest:/foo/bar.h";
275 llvm::StringMap<SourceParams> ProxSources;
276 ProxSources.try_emplace(
testPath(
"foo/baz.h"));
281 IndexDistant.
SymbolURI =
"unittest:/elsewhere/path.h";
284 << IndexProximate << IndexDistant;
296 Instance.
Context = CodeCompletionContext::CCC_DotMemberAccess;
305 llvm::StringSet<> Words = {
"one",
"two",
"three"};
308 WithoutMatchingWord.
Name =
"four";
310 Default.evaluateHeuristics());
313 WithMatchingWord.
Name =
"TheTwoTowers";
315 Default.evaluateHeuristics());
318TEST(QualityTests, ScopeProximity) {
320 ScopeDistance ScopeProximity({
"x::y::z::",
"x::",
"llvm::",
""});
328 EXPECT_GT(Global, NotMatched);
332 EXPECT_GT(NonParent, Global);
336 EXPECT_GT(GrandParent, Global);
340 EXPECT_GT(
Parent, GrandParent);
344 EXPECT_GT(Enclosing,
Parent);
347TEST(QualityTests, SortText) {
348 EXPECT_LT(
sortText(std::numeric_limits<float>::infinity()),
354 EXPECT_LT(
sortText(-10),
sortText(-std::numeric_limits<float>::infinity()));
360TEST(QualityTests, NoBoostForClassConstructor) {
367 auto Symbols = Header.headerSymbols();
368 auto AST = Header.build();
372 Cls.
merge(CodeCompletionResult(Foo, 0));
374 const NamedDecl *CtorDecl = &
findDecl(
AST, [](
const NamedDecl &ND) {
375 return (ND.getQualifiedNameAsString() ==
"Foo::Foo") &&
376 isa<CXXConstructorDecl>(&ND);
379 Ctor.
merge(CodeCompletionResult(CtorDecl, 0));
385TEST(QualityTests, IsInstanceMember) {
391 template <typename T> void tpl(T *t) {}
396 auto Symbols = Header.headerSymbols();
411 auto AST = Header.build();
417 Rel.
merge(CodeCompletionResult(Foo, 0));
419 Rel.
merge(CodeCompletionResult(
Bar, 0));
422 Rel.
merge(CodeCompletionResult(Tpl, 0));
426TEST(QualityTests, ConstructorDestructor) {
434 auto Symbols = Header.headerSymbols();
435 auto AST = Header.build();
437 const NamedDecl *CtorDecl = &
findDecl(
AST, [](
const NamedDecl &ND) {
438 return (ND.getQualifiedNameAsString() ==
"Foo::Foo") &&
439 isa<CXXConstructorDecl>(&ND);
441 const NamedDecl *DtorDecl = &
findDecl(
AST, [](
const NamedDecl &ND) {
442 return (ND.getQualifiedNameAsString() ==
"Foo::~Foo") &&
443 isa<CXXDestructorDecl>(&ND);
447 CtorQ.
merge(CodeCompletionResult(CtorDecl, 0));
452 CtorQ.merge(CtorSym);
456 DtorQ.
merge(CodeCompletionResult(DtorDecl, 0));
464 bool operator<(const Foo& f1);
467 auto AST = Header.build();
470 if (
const auto *OD = dyn_cast<FunctionDecl>(&ND))
471 if (OD->isOverloadedOperator())
480TEST(QualityTests, ItemWithFixItsRankedDown) {
487 auto AST = Header.build();
490 RelevanceWithFixIt.
merge(CodeCompletionResult(&
findDecl(
AST,
"x"), 0,
nullptr,
491 false,
true, {FixItHint{}}));
495 RelevanceWithoutFixIt.
merge(
496 CodeCompletionResult(&
findDecl(
AST,
"x"), 0,
nullptr,
false,
true, {}));
SignatureQualitySignals Quality
Support lookups like FileDistance, but the lookup keys are symbol scopes.
An immutable symbol container that stores a set of symbols.
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
std::string sortText(float Score, llvm::StringRef Name)
Returns a string that sorts in the same order as (-Score, Tiebreak), for LSP.
SlabTuple indexMainDecls(ParsedAST &AST)
Retrieves symbols and refs of local top level decls in AST (i.e.
std::string testPath(PathRef File, llvm::sys::path::Style Style)
TEST(BackgroundQueueTest, Priority)
const NamedDecl & findUnqualifiedDecl(ParsedAST &AST, llvm::StringRef Name)
const Symbol & findSymbol(const SymbolSlab &Slab, llvm::StringRef QName)
@ Deprecated
Deprecated or obsolete code.
volatile int UnittestSchemeAnchorSource
static int LLVM_ATTRIBUTE_UNUSED UnittestSchemeAnchorDest
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
bool IncludeFixIts
Include completions that require small corrections, e.g.
std::string Query
A query string for the fuzzy find.
bool AnyScope
If set to true, allow symbols from any scope.
Attributes of a symbol that affect how much we like it.
float evaluateHeuristics() const
enum clang::clangd::SymbolQualitySignals::SymbolCategory Category
void merge(const CodeCompletionResult &SemaCCResult)
bool ImplementationDetail
Attributes of a symbol-query pair that affect how much we like it.
float NameMatch
0-1+ fuzzy-match score for unqualified name. Must be explicitly assigned.
bool NeedsFixIts
Whether fixits needs to be applied for that completion or not.
ScopeDistance * ScopeProximityMatch
llvm::StringRef Name
The name of the symbol (for ContextWords). Must be explicitly assigned.
llvm::StringRef SymbolURI
These are used to calculate proximity between the index symbol and the query.
llvm::StringSet * ContextWords
Lowercase words relevant to the context (e.g. near the completion point).
URIDistance * FileProximityMatch
void merge(const CodeCompletionResult &SemaResult)
CodeCompletionContext::Kind Context
float SemaFileProximityScore
FIXME: unify with index proximity score - signals should be source-independent.
enum clang::clangd::SymbolRelevanceSignals::QueryType Query
enum clang::clangd::SymbolRelevanceSignals::AccessibleScope Scope
float evaluateHeuristics() const
std::optional< llvm::StringRef > SymbolScope
The class presents a C++ symbol, e.g.
static TestTU withHeaderCode(llvm::StringRef HeaderCode)
static TestTU withCode(llvm::StringRef Code)
std::unique_ptr< SymbolIndex > index() const