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();
77 Quality.
merge(CodeCompletionResult(
"if"));
91TEST(QualityTests, SymbolRelevanceSignalExtraction) {
97 namespace hdr { class Bar {}; } // namespace hdr
99 #define DEFINE_FLAG(X) \
109 using flags::FLAGS_FOO;
111 int ::header_main() { return 0; }
115 int deprecated() { return 0; }
117 namespace { struct X { void y() { int z; } }; }
135 <<
"Decl in current file";
142 <<
"Current file and header";
144 auto ConstructShadowDeclCompletionResult = [&](
const std::string DeclName) {
146 *dyn_cast<UsingDecl>(&
findDecl(
AST, [&](
const NamedDecl &ND) {
147 if (
const UsingDecl *Using = dyn_cast<UsingDecl>(&ND))
148 if (Using->shadow_size() &&
149 Using->getQualifiedNameAsString() == DeclName)
153 CodeCompletionResult Result(Shadow->getTargetDecl(), 42);
154 Result.ShadowDecl = Shadow;
159 Relevance.
merge(ConstructShadowDeclCompletionResult(
"Bar"));
161 <<
"Using declaration in main file";
162 Relevance.
merge(ConstructShadowDeclCompletionResult(
"FLAGS_FOO"));
164 <<
"Using declaration in main file";
183 BaseMember.InBaseClass =
true;
184 Relevance.
merge(BaseMember);
187 auto Index = Test.
index();
191 bool Matched =
false;
192 Index->fuzzyFind(Req, [&](
const Symbol &S) {
198 EXPECT_TRUE(Matched);
202TEST(QualityTests, SymbolQualitySignalsSanity) {
204 EXPECT_EQ(Default.evaluateHeuristics(), 1);
208 EXPECT_LT(
Deprecated.evaluateHeuristics(), Default.evaluateHeuristics());
217 Default.evaluateHeuristics());
236 EXPECT_GT(
Variable.evaluateHeuristics(), Default.evaluateHeuristics());
237 EXPECT_GT(
Keyword.evaluateHeuristics(),
Variable.evaluateHeuristics());
238 EXPECT_LT(
Macro.evaluateHeuristics(), Default.evaluateHeuristics());
239 EXPECT_LT(
Operator.evaluateHeuristics(), Default.evaluateHeuristics());
244TEST(QualityTests, SymbolRelevanceSignalsSanity) {
246 EXPECT_EQ(Default.evaluateHeuristics(), 1);
259 Default.evaluateHeuristics());
265 WithSemaScopeProximity.SemaSaysInScope =
true;
266 EXPECT_GT(WithSemaScopeProximity.evaluateHeuristics(),
267 Default.evaluateHeuristics());
272 EXPECT_GT(WithSemaScopeProximity.evaluateHeuristics(),
273 Default.evaluateHeuristics());
276 IndexProximate.
SymbolURI =
"unittest:/foo/bar.h";
277 llvm::StringMap<SourceParams> ProxSources;
278 ProxSources.try_emplace(
testPath(
"foo/baz.h"));
283 IndexDistant.
SymbolURI =
"unittest:/elsewhere/path.h";
286 << IndexProximate << IndexDistant;
298 Instance.
Context = CodeCompletionContext::CCC_DotMemberAccess;
307 llvm::StringSet<> Words = {
"one",
"two",
"three"};
310 WithoutMatchingWord.
Name =
"four";
312 Default.evaluateHeuristics());
315 WithMatchingWord.
Name =
"TheTwoTowers";
317 Default.evaluateHeuristics());
320TEST(QualityTests, ScopeProximity) {
322 ScopeDistance ScopeProximity({
"x::y::z::",
"x::",
"llvm::",
""});
330 EXPECT_GT(Global, NotMatched);
334 EXPECT_GT(NonParent, Global);
338 EXPECT_GT(GrandParent, Global);
342 EXPECT_GT(Parent, GrandParent);
346 EXPECT_GT(Enclosing, Parent);
349TEST(QualityTests, SortText) {
350 EXPECT_LT(
sortText(std::numeric_limits<float>::infinity()),
356 EXPECT_LT(
sortText(-10),
sortText(-std::numeric_limits<float>::infinity()));
362TEST(QualityTests, NoBoostForClassConstructor) {
369 auto Symbols = Header.headerSymbols();
370 auto AST = Header.build();
374 Cls.
merge(CodeCompletionResult(Foo, 0));
376 const NamedDecl *CtorDecl = &
findDecl(
AST, [](
const NamedDecl &ND) {
377 return (ND.getQualifiedNameAsString() ==
"Foo::Foo") &&
378 isa<CXXConstructorDecl>(&ND);
381 Ctor.
merge(CodeCompletionResult(CtorDecl, 0));
387TEST(QualityTests, IsInstanceMember) {
393 template <typename T> void tpl(T *t) {}
398 auto Symbols = Header.headerSymbols();
413 auto AST = Header.build();
419 Rel.
merge(CodeCompletionResult(Foo, 0));
421 Rel.
merge(CodeCompletionResult(
Bar, 0));
424 Rel.
merge(CodeCompletionResult(Tpl, 0));
428TEST(QualityTests, ConstructorDestructor) {
436 auto Symbols = Header.headerSymbols();
437 auto AST = Header.build();
439 const NamedDecl *CtorDecl = &
findDecl(
AST, [](
const NamedDecl &ND) {
440 return (ND.getQualifiedNameAsString() ==
"Foo::Foo") &&
441 isa<CXXConstructorDecl>(&ND);
443 const NamedDecl *DtorDecl = &
findDecl(
AST, [](
const NamedDecl &ND) {
444 return (ND.getQualifiedNameAsString() ==
"Foo::~Foo") &&
445 isa<CXXDestructorDecl>(&ND);
449 CtorQ.
merge(CodeCompletionResult(CtorDecl, 0));
454 CtorQ.merge(CtorSym);
458 DtorQ.
merge(CodeCompletionResult(DtorDecl, 0));
466 bool operator<(const Foo& f1);
469 auto AST = Header.build();
472 if (
const auto *OD = dyn_cast<FunctionDecl>(&ND))
473 if (OD->isOverloadedOperator())
482TEST(QualityTests, ItemWithFixItsRankedDown) {
484 Opts.IncludeFixIts =
true;
489 auto AST = Header.build();
492 RelevanceWithFixIt.
merge(CodeCompletionResult(
494 false,
true, {FixItHint{}}));
498 RelevanceWithoutFixIt.
merge(CodeCompletionResult(
Support lookups like FileDistance, but the lookup keys are symbol scopes.
An immutable symbol container that stores a set of symbols.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
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++ -*-===//
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.
unsigned References
The number of translation units that reference this symbol from their main file.
static TestTU withHeaderCode(llvm::StringRef HeaderCode)
static TestTU withCode(llvm::StringRef Code)
std::unique_ptr< SymbolIndex > index() const