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/SourceManager.h"
21#include "clang/Sema/CodeCompleteConsumer.h"
22#include "llvm/ADT/StringRef.h"
23#include "llvm/Support/Casting.h"
24#include "llvm/Support/FormatVariadic.h"
25#include "llvm/Support/MathExtras.h"
26#include "llvm/Support/raw_ostream.h"
35 auto &SourceMgr = D.getASTContext().getSourceManager();
36 for (
auto *Redecl : D.redecls()) {
44 const auto &
Context = R.Declaration->getASTContext();
45 const auto &SourceMgr =
Context.getSourceManager();
54 if (
const auto *FD = dyn_cast<FunctionDecl>(&ND)) {
55 if (FD->isOverloadedOperator())
59 :
public ConstDeclVisitor<Switch, SymbolQualitySignals::SymbolCategory> {
61#define MAP(DeclType, Category) \
62 SymbolQualitySignals::SymbolCategory Visit##DeclType(const DeclType *) { \
63 return SymbolQualitySignals::Category; \
68 MAP(TypeAliasTemplateDecl,
Type);
71 MAP(CXXDestructorDecl, Destructor);
79 return Switch().Visit(&ND);
86 if (R.Kind == CodeCompletionResult::RK_Macro)
90 switch (R.CursorKind) {
91 case CXCursor_CXXMethod:
93 case CXCursor_ModuleImportDecl:
95 case CXCursor_MacroDefinition:
97 case CXCursor_TypeRef:
99 case CXCursor_MemberRef:
101 case CXCursor_Constructor:
111 case index::SymbolKind::Namespace:
112 case index::SymbolKind::NamespaceAlias:
114 case index::SymbolKind::Macro:
116 case index::SymbolKind::Enum:
117 case index::SymbolKind::Struct:
118 case index::SymbolKind::Class:
119 case index::SymbolKind::Protocol:
120 case index::SymbolKind::Extension:
121 case index::SymbolKind::Union:
122 case index::SymbolKind::TypeAlias:
123 case index::SymbolKind::TemplateTypeParm:
124 case index::SymbolKind::TemplateTemplateParm:
125 case index::SymbolKind::Concept:
127 case index::SymbolKind::Function:
128 case index::SymbolKind::ClassMethod:
129 case index::SymbolKind::InstanceMethod:
130 case index::SymbolKind::StaticMethod:
131 case index::SymbolKind::InstanceProperty:
132 case index::SymbolKind::ClassProperty:
133 case index::SymbolKind::StaticProperty:
134 case index::SymbolKind::ConversionFunction:
136 case index::SymbolKind::Destructor:
138 case index::SymbolKind::Constructor:
140 case index::SymbolKind::Variable:
141 case index::SymbolKind::Field:
142 case index::SymbolKind::EnumConstant:
143 case index::SymbolKind::Parameter:
144 case index::SymbolKind::NonTypeTemplateParm:
148 case index::SymbolKind::IncludeDirective:
149 case index::SymbolKind::Using:
150 case index::SymbolKind::Module:
151 case index::SymbolKind::Unknown:
154 llvm_unreachable(
"Unknown index::SymbolKind");
160 if (
const auto *TP = dyn_cast<FunctionTemplateDecl>(ND))
161 ND = TP->TemplateDecl::getTemplatedDecl();
162 if (
const auto *CM = dyn_cast<CXXMethodDecl>(ND))
163 return !CM->isStatic();
164 return isa<FieldDecl>(ND);
169 case index::SymbolKind::InstanceMethod:
170 case index::SymbolKind::InstanceProperty:
171 case index::SymbolKind::Field:
179 Deprecated |= (SemaCCResult.Availability == CXAvailability_Deprecated);
182 if (SemaCCResult.Declaration) {
184 if (
auto *ID = SemaCCResult.Declaration->getIdentifier())
186 }
else if (SemaCCResult.Kind == CodeCompletionResult::RK_Macro)
214 Score *= 6.0 * (1 - S) / (1 + S) + 0.59;
252 OS << llvm::formatv(
"\tReferences: {0}\n", S.
References);
253 OS << llvm::formatv(
"\tDeprecated: {0}\n", S.
Deprecated);
254 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<CXXRecordDecl>(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();
281 llvm::to_underlying(Linkage::External))
304 const CodeCompletionResult &SemaResult) {
307 if ((SemaResult.Kind != CodeCompletionResult::RK_Declaration) &&
308 (SemaResult.Kind != CodeCompletionResult::RK_Pattern))
310 if (
const NamedDecl *ND = SemaResult.getDeclaration()) {
318 if (
const auto *NSD = dyn_cast<NamespaceDecl>(ND->getDeclContext())) {
319 if (NSD->isAnonymousNamespace())
330 if (SemaCCResult.Availability == CXAvailability_NotAvailable ||
331 SemaCCResult.Availability == CXAvailability_NotAccessible)
334 if (SemaCCResult.Declaration) {
350 if (SemaCCResult.Declaration)
372 return std::max(0.65, 2.0 * std::pow(0.6,
ScopeDistance / 2.0));
375static std::optional<llvm::StringRef>
376wordMatching(llvm::StringRef Name,
const llvm::StringSet<> *ContextWords) {
378 for (
const auto &Word : ContextWords->keys())
379 if (Name.contains_insensitive(Word))
384SymbolRelevanceSignals::DerivedSignals
463 (
Context == CodeCompletionContext::CCC_DotMemberAccess ||
464 Context == CodeCompletionContext::CCC_ArrowMemberAccess)) {
482 Score *= 11.0 * (1 - S) / (1 + S) + 0.7;
487 Score *= 10.0 * (1 - S) / (1 + S) + 0.7;
496 OS << llvm::formatv(
"\tName: {0}\n", S.
Name);
497 OS << llvm::formatv(
"\tName match: {0}\n", S.
NameMatch);
500 "\tMatching context word: {0}\n",
502 OS << llvm::formatv(
"\tForbidden: {0}\n", S.
Forbidden);
503 OS << llvm::formatv(
"\tNeedsFixIts: {0}\n", S.
NeedsFixIts);
505 OS << llvm::formatv(
"\tInBaseClass: {0}\n", S.
InBaseClass);
506 OS << llvm::formatv(
"\tContext: {0}\n", getCompletionKindString(S.
Context));
507 OS << llvm::formatv(
"\tQuery type: {0}\n",
static_cast<int>(S.
Query));
508 OS << llvm::formatv(
"\tScope: {0}\n",
static_cast<int>(S.
Scope));
510 OS << llvm::formatv(
"\tSymbol URI: {0}\n", S.
SymbolURI);
511 OS << llvm::formatv(
"\tSymbol scope: {0}\n",
517 OS << llvm::formatv(
"\tIndex URI proximity: {0} (distance={1})\n", Score,
524 OS << llvm::formatv(
"\tIndex scope boost: {0}\n",
528 "\tType matched preferred: {0} (Context type: {1}, Symbol type: {2}\n",
535 return SymbolQuality * SymbolRelevance;
541 static_assert(std::numeric_limits<float>::is_iec559);
542 constexpr uint32_t TopBit = ~(~uint32_t{0} >> 1);
545 uint32_t U = llvm::bit_cast<uint32_t>(F);
552std::string
sortText(
float Score, llvm::StringRef Name) {
556 llvm::raw_string_ostream OS(S);
557 llvm::write_hex(OS,
encodeFloat(-Score), llvm::HexPrintStyle::Lower,
565 OS << llvm::formatv(
"=== Signature Quality:\n");
567 OS << llvm::formatv(
"\tNumber of optional parameters: {0}\n",
569 OS << llvm::formatv(
"\tKind: {0}\n", S.
Kind);
#define MAP(DeclType, Category)
A context is an immutable container for per-request data that must be propagated through layers that ...
static constexpr unsigned Unreachable
Support lookups like FileDistance, but the lookup keys are symbol scopes.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
static bool hasUsingDeclInMainFile(const CodeCompletionResult &R)
SymbolID getSymbolID(const Decl *D)
Gets the symbol ID for a declaration. Returned SymbolID might be null.
static float fileProximityScore(unsigned FileDistance)
static bool isInstanceMember(const NamedDecl *ND)
std::string sortText(float Score, llvm::StringRef Name)
Returns a string that sorts in the same order as (-Score, Tiebreak), for LSP.
static std::optional< llvm::StringRef > wordMatching(llvm::StringRef Name, const llvm::StringSet<> *ContextWords)
bool isReservedName(llvm::StringRef Name)
Returns true if Name is reserved, like _Foo or __Vector_base.
static float scopeProximityScore(unsigned ScopeDistance)
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
static SymbolRelevanceSignals::AccessibleScope computeScope(const NamedDecl *D)
static SymbolQualitySignals::SymbolCategory categorize(const NamedDecl &ND)
bool hasUnstableLinkage(const Decl *D)
Whether we must avoid computing linkage for D during code completion.
static uint32_t encodeFloat(float F)
static bool hasDeclInMainFile(const Decl &D)
@ Type
An inlay hint that for a type annotation.
bool isImplementationDetail(const Decl *D)
Returns true if the declaration is considered implementation detail based on heuristics.
float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance)
Combine symbol quality and relevance into a single score.
std::string printNamespaceScope(const DeclContext &DC)
Returns the first enclosing namespace scope starting from DC.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
uint32_t NumberOfParameters
uint32_t NumberOfOptionalParameters
CodeCompleteConsumer::OverloadCandidate::CandidateKind Kind
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
Set of derived signals computed by calculateDerivedSignals().
bool NameMatchesContext
Whether Name contains some word from context.
unsigned FileProximityDistance
Min distance between SymbolURI and all the headers included by the TU.
unsigned ScopeProximityDistance
Min distance between SymbolScope and all the available scopes.
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.
DerivedSignals calculateDerivedSignals() const
ScopeDistance * ScopeProximityMatch
unsigned MainFileRefs
Number of references to the candidate in the main file.
llvm::StringRef Name
The name of the symbol (for ContextWords). Must be explicitly assigned.
void computeASTSignals(const CodeCompletionResult &SemaResult)
llvm::StringRef SymbolURI
These are used to calculate proximity between the index symbol and the query.
unsigned ScopeRefsInFile
Number of unique symbols in the main file which belongs to candidate's namespace.
const ASTSignals * MainFileSignals
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
bool TypeMatchesPreferred
float evaluateHeuristics() const
std::optional< llvm::StringRef > SymbolScope
The class presents a C++ symbol, e.g.
@ Deprecated
Indicates if the symbol is deprecated.
@ ImplementationDetail
Symbol is an implementation detail.
@ VisibleOutsideFile
Symbol is visible to other files (not e.g. a static helper function).
index::SymbolInfo SymInfo
The symbol information, like symbol kind.
llvm::StringRef Name
The unqualified name of the symbol, e.g. "bar" (for ns::bar).
llvm::StringRef Scope
The containing namespace. e.g. "" (global), "ns::" (top-level namespace).
unsigned References
The number of translation units that reference this symbol from their main file.
SymbolLocation CanonicalDeclaration
The location of the preferred declaration of the symbol.
SymbolID ID
The ID of the symbol.