15 #include "clang/AST/ASTContext.h" 16 #include "clang/AST/Decl.h" 17 #include "clang/AST/DeclCXX.h" 18 #include "clang/AST/DeclTemplate.h" 19 #include "clang/AST/DeclVisitor.h" 20 #include "clang/Basic/CharInfo.h" 21 #include "clang/Basic/SourceManager.h" 22 #include "clang/Sema/CodeCompleteConsumer.h" 23 #include "llvm/ADT/ArrayRef.h" 24 #include "llvm/ADT/SmallString.h" 25 #include "llvm/ADT/SmallVector.h" 26 #include "llvm/ADT/StringExtras.h" 27 #include "llvm/ADT/StringRef.h" 28 #include "llvm/Support/Casting.h" 29 #include "llvm/Support/FormatVariadic.h" 30 #include "llvm/Support/MathExtras.h" 31 #include "llvm/Support/raw_ostream.h" 39 return Name.size() >= 2 && Name[0] ==
'_' &&
40 (isUppercase(Name[1]) || Name[1] ==
'_');
44 auto &SourceMgr = D.getASTContext().getSourceManager();
45 for (
auto *Redecl : D.redecls()) {
53 const auto &
Context = R.Declaration->getASTContext();
54 const auto &SourceMgr =
Context.getSourceManager();
63 if (
const auto *FD = dyn_cast<FunctionDecl>(&ND)) {
64 if (FD->isOverloadedOperator())
68 :
public ConstDeclVisitor<Switch, SymbolQualitySignals::SymbolCategory> {
70 #define MAP(DeclType, Category) \ 71 SymbolQualitySignals::SymbolCategory Visit##DeclType(const DeclType *) { \ 72 return SymbolQualitySignals::Category; \ 77 MAP(TypeAliasTemplateDecl,
Type);
80 MAP(CXXDestructorDecl, Destructor);
88 return Switch().Visit(&ND);
95 if (R.Kind == CodeCompletionResult::RK_Macro)
99 switch (R.CursorKind) {
100 case CXCursor_CXXMethod:
102 case CXCursor_ModuleImportDecl:
104 case CXCursor_MacroDefinition:
106 case CXCursor_TypeRef:
108 case CXCursor_MemberRef:
110 case CXCursor_Constructor:
120 case index::SymbolKind::Namespace:
121 case index::SymbolKind::NamespaceAlias:
123 case index::SymbolKind::Macro:
125 case index::SymbolKind::Enum:
126 case index::SymbolKind::Struct:
127 case index::SymbolKind::Class:
128 case index::SymbolKind::Protocol:
129 case index::SymbolKind::Extension:
130 case index::SymbolKind::Union:
131 case index::SymbolKind::TypeAlias:
133 case index::SymbolKind::Function:
134 case index::SymbolKind::ClassMethod:
135 case index::SymbolKind::InstanceMethod:
136 case index::SymbolKind::StaticMethod:
137 case index::SymbolKind::InstanceProperty:
138 case index::SymbolKind::ClassProperty:
139 case index::SymbolKind::StaticProperty:
140 case index::SymbolKind::ConversionFunction:
142 case index::SymbolKind::Destructor:
144 case index::SymbolKind::Constructor:
146 case index::SymbolKind::Variable:
147 case index::SymbolKind::Field:
148 case index::SymbolKind::EnumConstant:
149 case index::SymbolKind::Parameter:
151 case index::SymbolKind::Using:
152 case index::SymbolKind::Module:
156 llvm_unreachable(
"Unknown index::SymbolKind");
162 if (
const auto *TP = dyn_cast<FunctionTemplateDecl>(ND))
163 ND = TP->TemplateDecl::getTemplatedDecl();
164 if (
const auto *
CM = dyn_cast<CXXMethodDecl>(ND))
165 return !
CM->isStatic();
166 return isa<FieldDecl>(ND);
171 case index::SymbolKind::InstanceMethod:
172 case index::SymbolKind::InstanceProperty:
173 case index::SymbolKind::Field:
181 Deprecated |= (SemaCCResult.Availability == CXAvailability_Deprecated);
184 if (SemaCCResult.Declaration) {
186 if (
auto *ID = SemaCCResult.Declaration->getIdentifier())
187 ReservedName = ReservedName ||
isReserved(ID->getName());
188 }
else if (SemaCCResult.Kind == CodeCompletionResult::RK_Macro)
189 ReservedName = ReservedName ||
isReserved(SemaCCResult.Macro->getName());
215 Score *= 6.0 * (1 - S) / (1 + S) + 0.59;
222 if (ImplementationDetail)
252 OS << llvm::formatv(
"=== Symbol quality: {0}\n", S.
evaluate());
253 OS << llvm::formatv(
"\tReferences: {0}\n", S.
References);
254 OS << llvm::formatv(
"\tDeprecated: {0}\n", S.
Deprecated);
255 OS << llvm::formatv(
"\tReserved name: {0}\n", S.
ReservedName);
256 OS << llvm::formatv(
"\tCategory: {0}\n", static_cast<int>(S.
Category));
263 const DeclContext *DC = D->getDeclContext();
264 if (
auto *R = dyn_cast_or_null<RecordDecl>(D))
265 if (R->isInjectedClassName())
266 DC = DC->getParent();
268 if (isa<CXXConstructorDecl>(D))
269 DC = DC->getParent();
270 bool InClass =
false;
271 for (; !DC->isFileContext(); DC = DC->getParent()) {
272 if (DC->isFunctionOrMethod())
274 InClass = InClass || DC->isRecord();
279 if (D->getLinkageInternal() < ExternalLinkage)
286 SymbolScope = IndexResult.
Scope;
289 Scope = AccessibleScope::FileScope;
294 if (SemaCCResult.Availability == CXAvailability_NotAvailable ||
295 SemaCCResult.Availability == CXAvailability_NotAccessible)
298 if (SemaCCResult.Declaration) {
299 SemaSaysInScope =
true;
307 SemaFileProximityScore = std::max(DeclProximity, SemaFileProximityScore);
309 InBaseClass |= SemaCCResult.InBaseClass;
313 if (SemaCCResult.Declaration)
314 Scope = std::min(Scope,
computeScope(SemaCCResult.Declaration));
316 NeedsFixIts = !SemaCCResult.FixIts.empty();
319 static std::pair<float, unsigned>
uriProximity(llvm::StringRef SymbolURI,
321 if (!D || SymbolURI.empty())
323 unsigned Distance = D->
distance(SymbolURI);
329 llvm::Optional<llvm::StringRef> SymbolScope) {
332 auto D = Distance.
distance(*SymbolScope);
335 return std::max(0.65, 2.0 * std::pow(0.6, D / 2.0));
338 static llvm::Optional<llvm::StringRef>
341 for (
const auto&
Word : ContextWords->keys())
342 if (Name.contains_lower(
Word))
357 Score *= 1 + 2 * std::max(
uriProximity(SymbolURI, FileProximityMatch).first,
358 SemaFileProximityScore);
360 if (ScopeProximityMatch)
366 SemaSaysInScope ? 2.0 :
scopeBoost(*ScopeProximityMatch, SymbolScope);
373 if (Query == CodeComplete) {
404 if (TypeMatchesPreferred)
408 if (!IsInstanceMember &&
409 (
Context == CodeCompletionContext::CCC_DotMemberAccess ||
410 Context == CodeCompletionContext::CCC_ArrowMemberAccess)) {
426 OS << llvm::formatv(
"=== Symbol relevance: {0}\n", S.
evaluate());
427 OS << llvm::formatv(
"\tName: {0}\n", S.
Name);
428 OS << llvm::formatv(
"\tName match: {0}\n", S.
NameMatch);
431 "\tMatching context word: {0}\n",
433 OS << llvm::formatv(
"\tForbidden: {0}\n", S.
Forbidden);
434 OS << llvm::formatv(
"\tNeedsFixIts: {0}\n", S.
NeedsFixIts);
436 OS << llvm::formatv(
"\tContext: {0}\n", getCompletionKindString(S.
Context));
437 OS << llvm::formatv(
"\tQuery type: {0}\n", static_cast<int>(S.
Query));
438 OS << llvm::formatv(
"\tScope: {0}\n", static_cast<int>(S.
Scope));
440 OS << llvm::formatv(
"\tSymbol URI: {0}\n", S.
SymbolURI);
441 OS << llvm::formatv(
"\tSymbol scope: {0}\n",
446 OS << llvm::formatv(
"\tIndex URI proximity: {0} (distance={1})\n",
453 OS << llvm::formatv(
"\tIndex scope boost: {0}\n",
457 "\tType matched preferred: {0} (Context type: {1}, Symbol type: {2}\n",
464 return SymbolQuality * SymbolRelevance;
470 static_assert(std::numeric_limits<float>::is_iec559,
"");
471 constexpr uint32_t TopBit = ~(~uint32_t{0} >> 1);
474 uint32_t U = llvm::FloatToBits(F);
485 llvm::raw_string_ostream OS(S);
495 OS << llvm::formatv(
"=== Signature Quality:\n");
497 OS << llvm::formatv(
"\tNumber of optional parameters: {0}\n",
499 OS << llvm::formatv(
"\tKind: {0}\n", S.
Kind);
const FunctionDecl * Decl
static SymbolQualitySignals::SymbolCategory categorize(const NamedDecl &ND)
void merge(const CodeCompletionResult &SemaCCResult)
static float scopeBoost(ScopeDistance &Distance, llvm::Optional< llvm::StringRef > SymbolScope)
unsigned distance(llvm::StringRef SymbolScope)
llvm::Optional< llvm::StringRef > SymbolScope
static uint32_t encodeFloat(float F)
enum clang::clangd::SymbolQualitySignals::SymbolCategory Category
void merge(const CodeCompletionResult &SemaResult)
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
std::string sortText(float Score, llvm::StringRef Name)
Returns a string that sorts in the same order as (-Score, Tiebreak), for LSP.
Symbol is visible to other files (not e.g. a static helper function).
static constexpr unsigned Unreachable
static bool isReserved(llvm::StringRef Name)
CodeCompletionContext::Kind Context
llvm::StringRef Scope
The containing namespace. e.g. "" (global), "ns::" (top-level namespace).
Documents should not be synced at all.
Attributes of a symbol that affect how much we like it.
llvm::StringRef Name
The name of the symbol (for ContextWords). Must be explicitly assigned.
enum clang::clangd::SymbolRelevanceSignals::AccessibleScope Scope
CodeCompleteConsumer::OverloadCandidate::CandidateKind Kind
unsigned References
The number of translation units that reference this symbol from their main file.
index::SymbolInfo SymInfo
The symbol information, like symbol kind.
bool TypeMatchesPreferred
llvm::Optional< float > Score
Symbol is an implementation detail.
bool NeedsFixIts
Whether fixits needs to be applied for that completion or not.
llvm::StringSet * ContextWords
Lowercase words relevant to the context (e.g. near the completion point).
URIDistance * FileProximityMatch
enum clang::clangd::SymbolRelevanceSignals::QueryType Query
clang::find_all_symbols::SymbolInfo SymbolInfo
#define MAP(DeclType, Category)
*that are placed right before the argument **code *void f(bool foo)
Checks that argument comments match parameter names.
static constexpr llvm::StringLiteral Name
SymbolLocation CanonicalDeclaration
The location of the preferred declaration of the symbol.
const Symbol * IndexResult
ScopeDistance * ScopeProximityMatch
A context is an immutable container for per-request data that must be propagated through layers that ...
static bool hasDeclInMainFile(const Decl &D)
unsigned distance(llvm::StringRef URI)
llvm::StringRef SymbolURI
These are used to calculate proximity between the index symbol and the query.
static llvm::Optional< llvm::StringRef > wordMatching(llvm::StringRef Name, const llvm::StringSet<> *ContextWords)
float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance)
Combine symbol quality and relevance into a single score.
static bool isInstanceMember(const NamedDecl *ND)
The class presents a C++ symbol, e.g.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Support lookups like FileDistance, but the lookup keys are symbol scopes.
llvm::StringRef Name
The unqualified name of the symbol, e.g. "bar" (for ns::bar).
float SemaFileProximityScore
FIXME: unify with index proximity score - signals should be source-independent.
static SymbolRelevanceSignals::AccessibleScope computeScope(const NamedDecl *D)
static std::pair< float, unsigned > uriProximity(llvm::StringRef SymbolURI, URIDistance *D)
bool isImplementationDetail(const Decl *D)
Returns true if the declaration is considered implementation detail based on heuristics.
float NameMatch
0-1+ fuzzy-match score for unqualified name. Must be explicitly assigned.
uint32_t NumberOfParameters
Indicates if the symbol is deprecated.
uint32_t NumberOfOptionalParameters
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
Attributes of a symbol-query pair that affect how much we like it.
static bool hasUsingDeclInMainFile(const CodeCompletionResult &R)