14 #include "clang/AST/ASTContext.h" 15 #include "clang/AST/Decl.h" 16 #include "clang/AST/DeclCXX.h" 17 #include "clang/AST/DeclTemplate.h" 18 #include "clang/AST/DeclVisitor.h" 19 #include "clang/Basic/CharInfo.h" 20 #include "clang/Basic/SourceManager.h" 21 #include "clang/Sema/CodeCompleteConsumer.h" 22 #include "llvm/ADT/ArrayRef.h" 23 #include "llvm/ADT/SmallString.h" 24 #include "llvm/ADT/SmallVector.h" 25 #include "llvm/ADT/StringExtras.h" 26 #include "llvm/ADT/StringRef.h" 27 #include "llvm/Support/Casting.h" 28 #include "llvm/Support/FormatVariadic.h" 29 #include "llvm/Support/MathExtras.h" 30 #include "llvm/Support/raw_ostream.h" 38 return Name.size() >= 2 && Name[0] ==
'_' &&
39 (isUppercase(Name[1]) || Name[1] ==
'_');
43 auto &SourceMgr = D.getASTContext().getSourceManager();
44 for (
auto *Redecl : D.redecls()) {
45 auto Loc = SourceMgr.getSpellingLoc(Redecl->getLocation());
46 if (SourceMgr.isWrittenInMainFile(
Loc))
53 const auto &
Context = R.Declaration->getASTContext();
54 const auto &SourceMgr =
Context.getSourceManager();
56 const auto Loc = SourceMgr.getExpansionLoc(R.ShadowDecl->getLocation());
57 if (SourceMgr.isWrittenInMainFile(
Loc))
64 if (
const auto *FD = dyn_cast<FunctionDecl>(&ND)) {
65 if (FD->isOverloadedOperator())
69 :
public ConstDeclVisitor<Switch, SymbolQualitySignals::SymbolCategory> {
71 #define MAP(DeclType, Category) \ 72 SymbolQualitySignals::SymbolCategory Visit##DeclType(const DeclType *) { \ 73 return SymbolQualitySignals::Category; \ 78 MAP(TypeAliasTemplateDecl, Type);
79 MAP(ClassTemplateDecl, Type);
81 MAP(CXXDestructorDecl, Destructor);
89 return Switch().Visit(&ND);
96 if (R.Kind == CodeCompletionResult::RK_Macro)
100 switch (R.CursorKind) {
101 case CXCursor_CXXMethod:
103 case CXCursor_ModuleImportDecl:
105 case CXCursor_MacroDefinition:
107 case CXCursor_TypeRef:
109 case CXCursor_MemberRef:
111 case CXCursor_Constructor:
121 case index::SymbolKind::Namespace:
122 case index::SymbolKind::NamespaceAlias:
124 case index::SymbolKind::Macro:
126 case index::SymbolKind::Enum:
127 case index::SymbolKind::Struct:
128 case index::SymbolKind::Class:
129 case index::SymbolKind::Protocol:
130 case index::SymbolKind::Extension:
131 case index::SymbolKind::Union:
132 case index::SymbolKind::TypeAlias:
134 case index::SymbolKind::Function:
135 case index::SymbolKind::ClassMethod:
136 case index::SymbolKind::InstanceMethod:
137 case index::SymbolKind::StaticMethod:
138 case index::SymbolKind::InstanceProperty:
139 case index::SymbolKind::ClassProperty:
140 case index::SymbolKind::StaticProperty:
141 case index::SymbolKind::ConversionFunction:
143 case index::SymbolKind::Destructor:
145 case index::SymbolKind::Constructor:
147 case index::SymbolKind::Variable:
148 case index::SymbolKind::Field:
149 case index::SymbolKind::EnumConstant:
150 case index::SymbolKind::Parameter:
152 case index::SymbolKind::Using:
153 case index::SymbolKind::Module:
157 llvm_unreachable(
"Unknown index::SymbolKind");
163 if (
const auto *TP = dyn_cast<FunctionTemplateDecl>(ND))
164 ND = TP->TemplateDecl::getTemplatedDecl();
165 if (
const auto *CM = dyn_cast<CXXMethodDecl>(ND))
166 return !CM->isStatic();
167 return isa<FieldDecl>(ND);
172 case index::SymbolKind::InstanceMethod:
173 case index::SymbolKind::InstanceProperty:
174 case index::SymbolKind::Field:
182 Deprecated |= (SemaCCResult.Availability == CXAvailability_Deprecated);
185 if (SemaCCResult.Declaration) {
187 if (
auto *ID = SemaCCResult.Declaration->getIdentifier())
188 ReservedName = ReservedName ||
isReserved(ID->getName());
189 }
else if (SemaCCResult.Kind == CodeCompletionResult::RK_Macro)
190 ReservedName = ReservedName ||
isReserved(SemaCCResult.Macro->getName());
196 References = std::max(IndexResult.
References, References);
206 if (References >= 10) {
215 float S = std::pow(References, -0.06);
216 Score *= 6.0 * (1 - S) / (1 + S) + 0.59;
223 if (ImplementationDetail)
253 OS << llvm::formatv(
"=== Symbol quality: {0}\n", S.
evaluate());
254 OS << llvm::formatv(
"\tReferences: {0}\n", S.
References);
255 OS << llvm::formatv(
"\tDeprecated: {0}\n", S.
Deprecated);
256 OS << llvm::formatv(
"\tReserved name: {0}\n", S.
ReservedName);
257 OS << llvm::formatv(
"\tCategory: {0}\n", static_cast<int>(S.
Category));
264 const DeclContext *DC = D->getDeclContext();
265 if (
auto *R = dyn_cast_or_null<RecordDecl>(D))
266 if (R->isInjectedClassName())
267 DC = DC->getParent();
269 if (isa<CXXConstructorDecl>(D))
270 DC = DC->getParent();
271 bool InClass =
false;
272 for (; !DC->isFileContext(); DC = DC->getParent()) {
273 if (DC->isFunctionOrMethod())
275 InClass = InClass || DC->isRecord();
280 if (D->getLinkageInternal() < ExternalLinkage)
290 SymbolScope = IndexResult.
Scope;
295 if (SemaCCResult.Availability == CXAvailability_NotAvailable ||
296 SemaCCResult.Availability == CXAvailability_NotAccessible)
299 if (SemaCCResult.Declaration) {
300 SemaSaysInScope =
true;
308 SemaFileProximityScore = std::max(DeclProximity, SemaFileProximityScore);
310 InBaseClass |= SemaCCResult.InBaseClass;
314 if (SemaCCResult.Declaration)
315 Scope = std::min(Scope,
computeScope(SemaCCResult.Declaration));
317 NeedsFixIts = !SemaCCResult.FixIts.empty();
320 static std::pair<float, unsigned>
uriProximity(llvm::StringRef SymbolURI,
322 if (!D || SymbolURI.empty())
324 unsigned Distance = D->
distance(SymbolURI);
330 llvm::Optional<llvm::StringRef> SymbolScope) {
333 auto D = Distance.
distance(*SymbolScope);
336 return std::max(0.65, 2.0 * std::pow(0.6,
D / 2.0));
349 Score *= 1 + 2 * std::max(
uriProximity(SymbolURI, FileProximityMatch).first,
350 SemaFileProximityScore);
352 if (ScopeProximityMatch)
358 SemaSaysInScope ? 2.0 :
scopeBoost(*ScopeProximityMatch, SymbolScope);
362 if (Query == CodeComplete) {
380 if (TypeMatchesPreferred)
384 if (!IsInstanceMember &&
385 (
Context == CodeCompletionContext::CCC_DotMemberAccess ||
386 Context == CodeCompletionContext::CCC_ArrowMemberAccess)) {
402 OS << llvm::formatv(
"=== Symbol relevance: {0}\n", S.
evaluate());
403 OS << llvm::formatv(
"\tName match: {0}\n", S.
NameMatch);
404 OS << llvm::formatv(
"\tForbidden: {0}\n", S.
Forbidden);
405 OS << llvm::formatv(
"\tNeedsFixIts: {0}\n", S.
NeedsFixIts);
407 OS << llvm::formatv(
"\tContext: {0}\n", getCompletionKindString(S.
Context));
408 OS << llvm::formatv(
"\tQuery type: {0}\n", static_cast<int>(S.
Query));
409 OS << llvm::formatv(
"\tScope: {0}\n", static_cast<int>(S.
Scope));
411 OS << llvm::formatv(
"\tSymbol URI: {0}\n", S.
SymbolURI);
412 OS << llvm::formatv(
"\tSymbol scope: {0}\n",
417 OS << llvm::formatv(
"\tIndex URI proximity: {0} (distance={1})\n",
418 Score.first, Score.second);
424 OS << llvm::formatv(
"\tIndex scope boost: {0}\n",
428 "\tType matched preferred: {0} (Context type: {1}, Symbol type: {2}\n",
435 return SymbolQuality * SymbolRelevance;
441 static_assert(std::numeric_limits<float>::is_iec559,
"");
442 constexpr uint32_t TopBit = ~(~uint32_t{0} >> 1);
445 uint32_t U = llvm::FloatToBits(F);
456 llvm::raw_string_ostream OS(S);
466 OS << llvm::formatv(
"=== Signature Quality:\n");
468 OS << llvm::formatv(
"\tNumber of optional parameters: {0}\n",
470 OS << llvm::formatv(
"\tContains active parameter: {0}\n",
472 OS << llvm::formatv(
"\tKind: {0}\n", S.
Kind);
SourceLocation Loc
'#' location in the include directive
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
bool ContainsActiveParameter
void merge(const CodeCompletionResult &SemaResult)
std::string sortText(float Score, llvm::StringRef Name)
Returns a string that sorts in the same order as (-Score, Tiebreak), for LSP.
static constexpr unsigned Unreachable
static bool isReserved(llvm::StringRef Name)
CodeCompletionContext::Kind Context
Attributes of a symbol that affect how much we like it.
enum clang::clangd::SymbolRelevanceSignals::AccessibleScope Scope
CodeCompleteConsumer::OverloadCandidate::CandidateKind Kind
index::SymbolInfo SymInfo
bool TypeMatchesPreferred
bool NeedsFixIts
Whether fixits needs to be applied for that completion or not.
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
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.
float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance)
Combine symbol quality and relevance into a single score.
static bool isInstanceMember(const NamedDecl *ND)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Support lookups like FileDistance, but the lookup keys are symbol scopes.
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)