19#include "clang-include-cleaner/Analysis.h"
20#include "clang-include-cleaner/Types.h"
29#include "clang/AST/ASTContext.h"
30#include "clang/AST/ASTTypeTraits.h"
31#include "clang/AST/Attr.h"
32#include "clang/AST/Attrs.inc"
33#include "clang/AST/Decl.h"
34#include "clang/AST/DeclCXX.h"
35#include "clang/AST/DeclObjC.h"
36#include "clang/AST/DeclTemplate.h"
37#include "clang/AST/DeclVisitor.h"
38#include "clang/AST/ExprCXX.h"
39#include "clang/AST/RecursiveASTVisitor.h"
40#include "clang/AST/Stmt.h"
41#include "clang/AST/StmtCXX.h"
42#include "clang/AST/StmtVisitor.h"
43#include "clang/AST/Type.h"
44#include "clang/Basic/LLVM.h"
45#include "clang/Basic/Module.h"
46#include "clang/Basic/SourceLocation.h"
47#include "clang/Basic/SourceManager.h"
48#include "clang/Basic/TokenKinds.h"
49#include "clang/Index/IndexDataConsumer.h"
50#include "clang/Index/IndexSymbol.h"
51#include "clang/Index/IndexingAction.h"
52#include "clang/Index/IndexingOptions.h"
53#include "clang/Lex/Lexer.h"
54#include "clang/Sema/HeuristicResolver.h"
55#include "clang/Tooling/Syntax/Tokens.h"
56#include "clang/UnifiedSymbolResolution/USRGeneration.h"
57#include "llvm/ADT/ArrayRef.h"
58#include "llvm/ADT/DenseMap.h"
59#include "llvm/ADT/DenseSet.h"
60#include "llvm/ADT/STLExtras.h"
61#include "llvm/ADT/ScopeExit.h"
62#include "llvm/ADT/SmallVector.h"
63#include "llvm/ADT/StringRef.h"
64#include "llvm/Support/Casting.h"
65#include "llvm/Support/Error.h"
66#include "llvm/Support/ErrorHandling.h"
67#include "llvm/Support/Path.h"
68#include "llvm/Support/raw_ostream.h"
84const NamedDecl *getDefinition(
const NamedDecl *D) {
87 if (
const auto *TD = dyn_cast<TagDecl>(D))
88 return TD->getDefinition();
89 if (
const auto *VD = dyn_cast<VarDecl>(D))
90 return VD->getDefinition();
91 if (
const auto *FD = dyn_cast<FunctionDecl>(D))
92 return FD->getDefinition();
93 if (
const auto *CTD = dyn_cast<ClassTemplateDecl>(D))
94 if (
const auto *RD = CTD->getTemplatedDecl())
95 return RD->getDefinition();
96 if (
const auto *
MD = dyn_cast<ObjCMethodDecl>(D)) {
97 if (
MD->isThisDeclarationADefinition())
100 auto *DeclCtx = cast<Decl>(
MD->getDeclContext());
101 if (DeclCtx->isInvalidDecl())
104 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(DeclCtx))
106 return Impl->getMethod(
MD->getSelector(),
MD->isInstanceMethod());
108 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(D))
111 if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
112 isa<TemplateTemplateParmDecl>(D))
119 if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
120 log(
"Possible overflow in symbol location: {0}", Loc);
126 llvm::StringRef TUPath) {
131 elog(
"{0}", LSPLoc.takeError());
140 URIStorage = Loc.uri.uri();
141 SymLoc.FileURI = URIStorage.c_str();
142 SymLoc.Start.setLine(Loc.range.start.line);
143 SymLoc.Start.setColumn(Loc.range.start.character);
144 SymLoc.End.setLine(Loc.range.end.line);
145 SymLoc.End.setColumn(Loc.range.end.character);
152 std::string &Scratch) {
156 ASTSym.ID = IdxSym.ID =
SymbolID(
"mock_symbol_id");
157 ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
158 IdxSym.CanonicalDeclaration = IdxLoc;
160 return Merged.CanonicalDeclaration;
163std::vector<std::pair<const NamedDecl *, DeclRelationSet>>
164getDeclAtPositionWithRelations(
ParsedAST &
AST, SourceLocation Pos,
166 ASTNodeKind *NodeKind =
nullptr) {
167 unsigned Offset =
AST.getSourceManager().getDecomposedSpellingLoc(Pos).second;
168 std::vector<std::pair<const NamedDecl *, DeclRelationSet>> Result;
172 *NodeKind = N->ASTNode.getNodeKind();
177 if (N->ASTNode.get<Attr>() && N->Parent)
180 std::back_inserter(Result),
181 [&](
auto &Entry) { return !(Entry.second & ~Relations); });
183 return !Result.empty();
186 Offset, ResultFromTree);
190std::vector<const NamedDecl *>
192 ASTNodeKind *NodeKind =
nullptr) {
193 std::vector<const NamedDecl *> Result;
195 getDeclAtPositionWithRelations(
AST, Pos, Relations, NodeKind))
196 Result.push_back(Entry.first);
203const CallExpr *findEnclosingCallAt(
ParsedAST &
AST, SourceLocation Loc) {
204 unsigned Offset =
AST.getSourceManager().getDecomposedSpellingLoc(Loc).second;
205 const CallExpr *Found =
nullptr;
208 if (const SelectionTree::Node *N =
210 Found = N->ASTNode.get<CallExpr>();
218std::optional<Location> makeLocation(
const ASTContext &
AST, SourceLocation Loc,
219 llvm::StringRef TUPath) {
220 const auto &SM =
AST.getSourceManager();
221 const auto F = SM.getFileEntryRefForID(SM.getFileID(Loc));
226 log(
"failed to get path!");
233 auto TokLen = Lexer::MeasureTokenLength(Loc, SM,
AST.getLangOpts());
235 SM, CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(TokLen)));
239std::optional<LocatedSymbol>
240locateModuleReferent(
const syntax::Token &TouchedIdentifier,
ParsedAST &
AST,
241 llvm::StringRef MainFilePath) {
242 const SourceManager &SM =
AST.getSourceManager();
243 const ASTContext &
Context =
AST.getASTContext();
245 const Module *ResultModule =
nullptr;
247 for (
const ImportDecl *Import :
Context.local_imports()) {
248 const Module *Imported = Import->getImportedModule();
249 ArrayRef<SourceLocation> IdentifierLocs = Import->getIdentifierLocs();
250 if (!Imported || !Imported->isNamedModule() || IdentifierLocs.empty())
253 const SourceLocation NameBegin = SM.getSpellingLoc(IdentifierLocs.front());
255 if (SM.isBeforeInTranslationUnit(TouchedIdentifier.location(), NameBegin))
258 const std::string FullName = Imported->getFullModuleName();
259 const SourceLocation NameEnd =
260 NameBegin.getLocWithOffset(FullName.size() - 1);
262 if (SM.isPointWithin(TouchedIdentifier.location(), NameBegin, NameEnd)) {
263 ResultModule = Imported;
271 const SourceLocation DefinitionLoc =
272 SM.getSpellingLoc(ResultModule->DefinitionLoc);
279 Result.
Name = ResultModule->getFullModuleName();
286std::optional<LocatedSymbol> locateFileReferent(
const Position &Pos,
288 llvm::StringRef MainFilePath) {
289 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
290 if (!Inc.Resolved.empty() && Inc.HashLine == Pos.line) {
292 File.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
293 File.PreferredDeclaration = {
295 File.Definition =
File.PreferredDeclaration;
305std::optional<LocatedSymbol>
306locateMacroReferent(
const syntax::Token &TouchedIdentifier,
ParsedAST &
AST,
307 llvm::StringRef MainFilePath) {
310 makeLocation(
AST.getASTContext(), M->NameLoc, MainFilePath)) {
312 Macro.Name = std::string(M->Name);
313 Macro.PreferredDeclaration = *Loc;
314 Macro.Definition = std::move(Loc);
335const NamedDecl *getPreferredDecl(
const NamedDecl *D) {
340 D = llvm::cast<NamedDecl>(
D->getCanonicalDecl());
343 if (
const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
344 if (
const auto *DefinitionID = ID->getDefinition())
346 if (
const auto *PD = dyn_cast<ObjCProtocolDecl>(D))
347 if (
const auto *DefinitionID = PD->getDefinition())
353std::vector<LocatedSymbol> findImplementors(llvm::DenseSet<SymbolID> IDs,
356 llvm::StringRef MainFilePath) {
357 if (IDs.empty() || !Index)
363 FindImplementorsMetric.record(1,
"find-base");
366 FindImplementorsMetric.record(1,
"find-override");
372 llvm::DenseSet<SymbolID> SeenIDs;
373 llvm::DenseSet<SymbolID> Queue = std::move(IDs);
374 std::vector<LocatedSymbol> Results;
375 while (!Queue.empty()) {
376 Req.Subjects = std::move(Queue);
379 if (!SeenIDs.insert(
Object.ID).second)
385 elog(
"Find overrides: {0}", DeclLoc.takeError());
388 Results.emplace_back();
389 Results.back().Name =
Object.Name.str();
390 Results.back().PreferredDeclaration = *DeclLoc;
393 elog(
"Failed to convert location: {0}", DefLoc.takeError());
396 Results.back().Definition = *DefLoc;
404void enhanceLocatedSymbolsFromIndex(llvm::MutableArrayRef<LocatedSymbol> Result,
406 llvm::StringRef MainFilePath) {
408 llvm::DenseMap<SymbolID, unsigned> ResultIndex;
409 for (
unsigned I = 0; I < Result.size(); ++I) {
410 if (
auto ID = Result[I].ID) {
411 ResultIndex.try_emplace(ID, I);
412 QueryRequest.IDs.insert(ID);
415 if (!Index || QueryRequest.IDs.empty())
418 Index->lookup(QueryRequest, [&](
const Symbol &Sym) {
419 auto &R = Result[ResultIndex.lookup(Sym.ID)];
424 if (
auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
425 R.PreferredDeclaration = *Loc;
429 if (
auto Loc = toLSPLocation(
430 getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
434 R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
437 if (
auto Loc = toLSPLocation(
438 getPreferredLocation(R.PreferredDeclaration,
439 Sym.CanonicalDeclaration, Scratch),
441 R.PreferredDeclaration = *Loc;
446bool objcMethodIsTouched(
const SourceManager &SM,
const ObjCMethodDecl *OMD,
447 SourceLocation Loc) {
448 unsigned NumSels = OMD->getNumSelectorLocs();
449 for (
unsigned I = 0; I < NumSels; ++I)
450 if (SM.getSpellingLoc(OMD->getSelectorLoc(I)) == Loc)
459std::vector<LocatedSymbol>
460locateASTReferent(SourceLocation CurLoc,
const syntax::Token *TouchedIdentifier,
463 const SourceManager &SM =
AST.getSourceManager();
465 std::vector<LocatedSymbol> Result;
469 auto AddResultDecl = [&](
const NamedDecl *
D) {
470 D = getPreferredDecl(D);
476 Result.emplace_back();
477 Result.back().Name =
printName(
AST.getASTContext(), *D);
478 Result.back().PreferredDeclaration = *Loc;
480 if (
const NamedDecl *Def = getDefinition(D))
481 Result.back().Definition = makeLocation(
494 if (
const auto *CE = findEnclosingCallAt(
AST, CurLoc)) {
495 if (
const auto *Callee = CE->getDirectCallee()) {
496 llvm::SmallPtrSet<const CXXConstructorDecl *, 1> Seen;
497 for (
const auto *Ctor :
499 if (Seen.insert(Ctor).second) {
500 LocateASTReferentMetric.record(1,
"forwarded-constructor");
505 if (!Result.empty()) {
506 enhanceLocatedSymbolsFromIndex(Result, Index, MainFilePath);
514 getDeclAtPositionWithRelations(
AST, CurLoc, Relations, &NodeKind);
515 llvm::DenseSet<SymbolID> VirtualMethods;
516 for (
const auto &E : Candidates) {
517 const NamedDecl *
D = E.first;
518 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
522 if (CMD->isPureVirtual()) {
523 if (TouchedIdentifier && SM.getSpellingLoc(CMD->getLocation()) ==
524 TouchedIdentifier->location()) {
526 LocateASTReferentMetric.record(1,
"method-to-override");
530 if (NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverrideAttr>()) ||
531 NodeKind.isSame(ASTNodeKind::getFromNodeKind<FinalAttr>())) {
533 for (
const NamedDecl *ND : CMD->overridden_methods())
544 if (
const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(D)) {
545 if (OMD->isThisDeclarationADefinition() && TouchedIdentifier &&
546 objcMethodIsTouched(SM, OMD, TouchedIdentifier->location())) {
547 llvm::SmallVector<const ObjCMethodDecl *, 4>
Overrides;
551 AddResultDecl(Override);
552 LocateASTReferentMetric.record(1,
"objc-overriden-method");
566 SM.isPointWithin(TouchedIdentifier ? TouchedIdentifier->location()
568 D->getBeginLoc(),
D->getEndLoc()))
573 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
574 if (TouchedIdentifier &&
575 D->getLocation() == TouchedIdentifier->location()) {
576 LocateASTReferentMetric.record(1,
"template-specialization-to-primary");
577 AddResultDecl(CTSD->getSpecializedTemplate());
588 if (
const auto *CD = dyn_cast<ObjCCategoryDecl>(D))
589 if (
const auto *ID = CD->getClassInterface())
590 if (TouchedIdentifier &&
591 (CD->getLocation() == TouchedIdentifier->location() ||
592 ID->getName() == TouchedIdentifier->text(SM))) {
593 LocateASTReferentMetric.record(1,
"objc-category-to-class");
597 LocateASTReferentMetric.record(1,
"regular");
601 enhanceLocatedSymbolsFromIndex(Result, Index, MainFilePath);
604 Index, MainFilePath);
609std::vector<LocatedSymbol> locateSymbolForType(
const ParsedAST &
AST,
610 const QualType &
Type,
612 const auto &SM =
AST.getSourceManager();
613 auto MainFilePath =
AST.tuPath();
617 auto Decls =
targetDecl(DynTypedNode::create(
Type.getNonReferenceType()),
619 AST.getHeuristicResolver());
623 std::vector<LocatedSymbol> Results;
624 const auto &ASTContext =
AST.getASTContext();
626 for (
const NamedDecl *D : Decls) {
627 D = getPreferredDecl(D);
629 auto Loc = makeLocation(ASTContext,
nameLocation(*D, SM), MainFilePath);
633 Results.emplace_back();
634 Results.back().Name =
printName(ASTContext, *D);
635 Results.back().PreferredDeclaration = *Loc;
637 if (
const NamedDecl *Def = getDefinition(D))
638 Results.back().Definition =
639 makeLocation(ASTContext,
nameLocation(*Def, SM), MainFilePath);
641 enhanceLocatedSymbolsFromIndex(Results, Index, MainFilePath);
646bool tokenSpelledAt(SourceLocation SpellingLoc,
const syntax::TokenBuffer &TB) {
647 auto ExpandedTokens = TB.expandedTokens(
648 TB.sourceManager().getMacroArgExpandedLocation(SpellingLoc));
649 return !ExpandedTokens.empty();
652llvm::StringRef sourcePrefix(SourceLocation Loc,
const SourceManager &SM) {
653 auto D = SM.getDecomposedLoc(Loc);
654 bool Invalid =
false;
655 llvm::StringRef Buf = SM.getBufferData(
D.first, &Invalid);
656 if (Invalid ||
D.second > Buf.size())
658 return Buf.substr(0,
D.second);
661bool isDependentName(ASTNodeKind NodeKind) {
662 return NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverloadExpr>()) ||
664 ASTNodeKind::getFromNodeKind<CXXDependentScopeMemberExpr>()) ||
666 ASTNodeKind::getFromNodeKind<DependentScopeDeclRefExpr>());
674 llvm::StringRef MainFilePath,
675 ASTNodeKind NodeKind) {
689 const auto &SM =
AST.getSourceManager();
703 bool TooMany =
false;
704 using ScoredLocatedSymbol = std::pair<float, LocatedSymbol>;
705 std::vector<ScoredLocatedSymbol> ScoredResults;
716 if (Sym.
SymInfo.Kind == index::SymbolKind::Constructor)
722 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
732 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
739 if (ScoredResults.size() >= 5) {
752 Relevance.
merge(Sym);
755 dlog(
"locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym.
Scope,
756 Sym.
Name, Score, Quality, Relevance);
758 ScoredResults.push_back({Score, std::move(Located)});
762 vlog(
"Heuristic index lookup for {0} returned too many candidates, ignored",
767 llvm::sort(ScoredResults,
768 [](
const ScoredLocatedSymbol &A,
const ScoredLocatedSymbol &B) {
769 return A.first > B.first;
771 std::vector<LocatedSymbol> Results;
772 for (
auto &Res : std::move(ScoredResults))
773 Results.push_back(std::move(Res.second));
775 vlog(
"No heuristic index definition for {0}", Word.
Text);
777 log(
"Found definition heuristically in index for {0}", Word.
Text);
782 const syntax::TokenBuffer &TB) {
793 const SourceManager &SM = TB.sourceManager();
797 unsigned WordLine = SM.getSpellingLineNumber(Word.
Location);
798 auto Cost = [&](SourceLocation Loc) ->
unsigned {
799 assert(SM.getFileID(Loc) ==
File &&
"spelled token in wrong file?");
800 unsigned Line = SM.getSpellingLineNumber(Loc);
801 return Line >= WordLine ? Line - WordLine : 2 * (WordLine - Line);
803 const syntax::Token *BestTok =
nullptr;
804 unsigned BestCost = -1;
808 unsigned MaxDistance =
809 1U << std::min<unsigned>(Word.
Text.size(),
810 std::numeric_limits<unsigned>::digits - 1);
817 WordLine + 1 <= MaxDistance / 2 ? 1 : WordLine + 1 - MaxDistance / 2;
818 unsigned LineMax = WordLine + 1 + MaxDistance;
819 SourceLocation LocMin = SM.translateLineCol(
File, LineMin, 1);
820 assert(LocMin.isValid());
821 SourceLocation LocMax = SM.translateLineCol(
File, LineMax, 1);
822 assert(LocMax.isValid());
826 auto Consider = [&](
const syntax::Token &Tok) {
827 if (Tok.location() < LocMin || Tok.location() > LocMax)
829 if (!(Tok.kind() == tok::identifier && Tok.text(SM) == Word.
Text))
832 if (Tok.location() == Word.
Location)
835 unsigned TokCost = Cost(Tok.location());
836 if (TokCost >= BestCost)
840 if (!(tokenSpelledAt(Tok.location(), TB) || TB.expansionStartingAt(&Tok)))
847 auto SpelledTokens = TB.spelledTokens(
File);
849 auto *I = llvm::partition_point(SpelledTokens, [&](
const syntax::Token &T) {
850 assert(SM.getFileID(T.location()) == SM.getFileID(Word.
Location));
851 return T.location() < Word.
Location;
854 for (
const syntax::Token &Tok : llvm::ArrayRef(I, SpelledTokens.end()))
858 for (
const syntax::Token &Tok :
859 llvm::reverse(llvm::ArrayRef(SpelledTokens.begin(), I)))
865 "Word {0} under cursor {1} isn't a token (after PP), trying nearby {2}",
867 BestTok->location().printToString(SM));
874 const auto &SM =
AST.getSourceManager();
875 auto MainFilePath =
AST.tuPath();
877 if (
auto File = locateFileReferent(Pos,
AST, MainFilePath))
878 return {std::move(*
File)};
882 elog(
"locateSymbolAt failed to convert position to source location: {0}",
887 const syntax::Token *TouchedIdentifier =
nullptr;
888 auto TokensTouchingCursor =
889 syntax::spelledTokensTouching(*CurLoc,
AST.getTokens());
890 for (
const syntax::Token &Tok : TokensTouchingCursor) {
891 if (Tok.kind() == tok::identifier) {
892 if (
auto Macro = locateMacroReferent(Tok,
AST, MainFilePath))
896 return {*std::move(
Macro)};
898 TouchedIdentifier = &Tok;
902 if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
908 auto LocSym = locateSymbolForType(
AST, *
Deduced, Index);
915 if (TouchedIdentifier)
917 locateModuleReferent(*TouchedIdentifier,
AST, MainFilePath))
918 return {*std::move(
Module)};
920 ASTNodeKind NodeKind;
921 auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier,
AST,
922 MainFilePath, Index, NodeKind);
923 if (!ASTResults.empty())
931 if (
const syntax::Token *NearbyIdent =
933 if (
auto Macro = locateMacroReferent(*NearbyIdent,
AST, MainFilePath)) {
934 log(
"Found macro definition heuristically using nearby identifier {0}",
936 return {*std::move(
Macro)};
938 ASTResults = locateASTReferent(NearbyIdent->location(), NearbyIdent,
AST,
939 MainFilePath, Index, NodeKind);
940 if (!ASTResults.empty()) {
941 log(
"Found definition heuristically using nearby identifier {0}",
942 NearbyIdent->text(SM));
945 vlog(
"No definition found using nearby identifier {0} at {1}", Word->Text,
946 Word->Location.printToString(SM));
949 auto TextualResults =
951 if (!TextualResults.empty())
952 return TextualResults;
959 const auto &SM =
AST.getSourceManager();
961 std::vector<DocumentLink> Result;
962 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
963 if (Inc.Resolved.empty())
967 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
971 const auto *HashTok =
AST.getTokens().spelledTokenContaining(HashLoc);
972 assert(HashTok &&
"got inclusion at wrong offset");
973 const auto *IncludeTok = std::next(HashTok);
974 const auto *FileTok = std::next(IncludeTok);
982 CharSourceRange FileRange;
984 if (FileTok->kind() == tok::TokenKind::less) {
988 syntax::FileRange(SM, FileTok->location(), Inc.Written.length())
990 }
else if (FileTok->kind() == tok::TokenKind::string_literal) {
993 FileRange = FileTok->range(SM).toCharRange(SM);
1004 FileRange = FileTok->range(SM).toCharRange(SM);
1018class ReferenceFinder :
public index::IndexDataConsumer {
1021 syntax::Token SpelledTok;
1022 index::SymbolRoleSet Role;
1023 const Decl *Container;
1025 Range range(
const SourceManager &SM)
const {
1030 ReferenceFinder(ParsedAST &AST,
1031 const llvm::ArrayRef<const NamedDecl *> Targets,
1033 : PerToken(PerToken), AST(AST) {
1034 for (
const NamedDecl *ND : Targets) {
1035 TargetDecls.insert(ND->getCanonicalDecl());
1036 if (
auto *
Constructor = llvm::dyn_cast<clang::CXXConstructorDecl>(ND))
1041 std::vector<Reference> take() && {
1042 llvm::sort(References, [](
const Reference &L,
const Reference &R) {
1043 auto LTok = L.SpelledTok.location();
1044 auto RTok = R.SpelledTok.location();
1045 return std::tie(LTok, L.Role) < std::tie(RTok, R.Role);
1048 References.erase(llvm::unique(References,
1049 [](
const Reference &L,
const Reference &R) {
1050 auto LTok = L.SpelledTok.location();
1051 auto RTok = R.SpelledTok.location();
1052 return std::tie(LTok, L.Role) ==
1053 std::tie(RTok, R.Role);
1056 return std::move(References);
1059 bool forwardsToConstructor(
const Decl *D) {
1060 if (TargetConstructors.empty())
1062 const auto *FD = llvm::dyn_cast<clang::FunctionDecl>(D);
1065 for (
const auto *Ctor :
1067 if (TargetConstructors.contains(Ctor))
1073 handleDeclOccurrence(
const Decl *D, index::SymbolRoleSet Roles,
1074 llvm::ArrayRef<index::SymbolRelation>
Relations,
1076 index::IndexDataConsumer::ASTNodeInfo ASTNode)
override {
1077 if (!TargetDecls.contains(
D->getCanonicalDecl()) &&
1078 !forwardsToConstructor(ASTNode.OrigD))
1080 const SourceManager &SM = AST.getSourceManager();
1083 const auto &TB = AST.getTokens();
1085 llvm::SmallVector<SourceLocation, 1> Locs;
1089 if (
auto *OME = llvm::dyn_cast_or_null<ObjCMessageExpr>(ASTNode.OrigE)) {
1090 OME->getSelectorLocs(Locs);
1091 }
else if (
auto *OMD =
1092 llvm::dyn_cast_or_null<ObjCMethodDecl>(ASTNode.OrigD)) {
1093 OMD->getSelectorLocs(Locs);
1097 if (!Locs.empty() && Locs.front() != Loc)
1101 Locs.push_back(Loc);
1103 SymbolCollector::Options CollectorOpts;
1104 CollectorOpts.CollectMainFileSymbols =
true;
1105 for (SourceLocation L : Locs) {
1106 L = SM.getFileLoc(L);
1107 if (
const auto *Tok = TB.spelledTokenContaining(L))
1108 References.push_back(
1117 std::vector<Reference> References;
1119 llvm::DenseSet<const Decl *> TargetDecls;
1121 llvm::DenseSet<const CXXConstructorDecl *> TargetConstructors;
1124std::vector<ReferenceFinder::Reference>
1125findRefs(
const llvm::ArrayRef<const NamedDecl *> TargetDecls,
ParsedAST &
AST,
1127 ReferenceFinder RefFinder(
AST, TargetDecls, PerToken);
1128 index::IndexingOptions IndexOpts;
1129 IndexOpts.SystemSymbolFilter =
1130 index::IndexingOptions::SystemSymbolFilterKind::All;
1131 IndexOpts.IndexFunctionLocals =
true;
1132 IndexOpts.IndexParametersInDeclarations =
true;
1133 IndexOpts.IndexTemplateParameters =
true;
1134 indexTopLevelDecls(
AST.getASTContext(),
AST.getPreprocessor(),
1135 AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
1136 return std::move(RefFinder).take();
1139const Stmt *getFunctionBody(DynTypedNode N) {
1140 if (
const auto *FD = N.get<FunctionDecl>())
1141 return FD->getBody();
1142 if (
const auto *FD = N.get<BlockDecl>())
1143 return FD->getBody();
1144 if (
const auto *FD = N.get<LambdaExpr>())
1145 return FD->getBody();
1146 if (
const auto *FD = N.get<ObjCMethodDecl>())
1147 return FD->getBody();
1151const Stmt *getLoopBody(DynTypedNode N) {
1152 if (
const auto *LS = N.get<ForStmt>())
1153 return LS->getBody();
1154 if (
const auto *LS = N.get<CXXForRangeStmt>())
1155 return LS->getBody();
1156 if (
const auto *LS = N.get<WhileStmt>())
1157 return LS->getBody();
1158 if (
const auto *LS = N.get<DoStmt>())
1159 return LS->getBody();
1166class FindControlFlow :
public RecursiveASTVisitor<FindControlFlow> {
1175 All = Break | Continue | Return | Case | Throw | Goto,
1179 std::vector<SourceLocation> &Result;
1180 const SourceManager &SM;
1184 template <
typename Func>
1185 bool filterAndTraverse(DynTypedNode D,
const Func &Delegate) {
1186 llvm::scope_exit RestoreIgnore(
1187 [OldIgnore(Ignore),
this] { Ignore = OldIgnore; });
1188 if (getFunctionBody(D))
1190 else if (getLoopBody(D))
1191 Ignore |= Continue | Break;
1192 else if (
D.get<SwitchStmt>())
1193 Ignore |= Break | Case;
1195 return (Ignore == All) ? true : Delegate();
1198 void found(Target T, SourceLocation Loc) {
1201 if (SM.isBeforeInTranslationUnit(Loc, Bounds.getBegin()) ||
1202 SM.isBeforeInTranslationUnit(Bounds.getEnd(), Loc))
1204 Result.push_back(Loc);
1208 FindControlFlow(SourceRange Bounds, std::vector<SourceLocation> &Result,
1209 const SourceManager &SM)
1210 : Bounds(Bounds), Result(Result), SM(SM) {}
1214 bool TraverseDecl(Decl *D) {
1215 return !
D || filterAndTraverse(DynTypedNode::create(*D), [&] {
1216 return RecursiveASTVisitor::TraverseDecl(D);
1219 bool TraverseStmt(Stmt *S) {
1220 return !S || filterAndTraverse(DynTypedNode::create(*S), [&] {
1221 return RecursiveASTVisitor::TraverseStmt(S);
1226 bool VisitReturnStmt(ReturnStmt *R) {
1227 found(Return, R->getReturnLoc());
1230 bool VisitBreakStmt(BreakStmt *B) {
1231 found(Break,
B->getKwLoc());
1234 bool VisitContinueStmt(ContinueStmt *C) {
1235 found(Continue,
C->getKwLoc());
1238 bool VisitSwitchCase(SwitchCase *C) {
1239 found(Case,
C->getKeywordLoc());
1242 bool VisitCXXThrowExpr(CXXThrowExpr *T) {
1243 found(Throw,
T->getThrowLoc());
1246 bool VisitGotoStmt(GotoStmt *G) {
1248 if (
const auto *LD = G->getLabel()) {
1249 if (SM.isBeforeInTranslationUnit(LD->getLocation(), Bounds.getBegin()) ||
1250 SM.isBeforeInTranslationUnit(Bounds.getEnd(), LD->getLocation()))
1251 found(Goto, G->getGotoLoc());
1260SourceRange findCaseBounds(
const SwitchStmt &Switch, SourceLocation Loc,
1261 const SourceManager &SM) {
1264 std::vector<const SwitchCase *> Cases;
1265 for (
const SwitchCase *Case = Switch.getSwitchCaseList(); Case;
1266 Case = Case->getNextSwitchCase())
1267 Cases.push_back(Case);
1268 llvm::sort(Cases, [&](
const SwitchCase *L,
const SwitchCase *R) {
1269 return SM.isBeforeInTranslationUnit(L->getKeywordLoc(), R->getKeywordLoc());
1273 auto CaseAfter = llvm::partition_point(Cases, [&](
const SwitchCase *C) {
1274 return !SM.isBeforeInTranslationUnit(Loc,
C->getKeywordLoc());
1276 SourceLocation End = CaseAfter == Cases.end() ? Switch.getEndLoc()
1277 : (*CaseAfter)->getKeywordLoc();
1280 if (CaseAfter == Cases.begin())
1281 return SourceRange(Switch.getBeginLoc(), End);
1283 auto CaseBefore = std::prev(CaseAfter);
1285 while (CaseBefore != Cases.begin() &&
1286 (*std::prev(CaseBefore))->getSubStmt() == *CaseBefore)
1288 return SourceRange((*CaseBefore)->getKeywordLoc(), End);
1299 const SourceManager &SM =
1300 N.getDeclContext().getParentASTContext().getSourceManager();
1301 std::vector<SourceLocation> Result;
1304 enum class Cur {
None, Break, Continue, Return, Case, Throw } Cursor;
1305 if (N.ASTNode.get<BreakStmt>()) {
1306 Cursor = Cur::Break;
1307 }
else if (N.ASTNode.get<ContinueStmt>()) {
1308 Cursor = Cur::Continue;
1309 }
else if (N.ASTNode.get<ReturnStmt>()) {
1310 Cursor = Cur::Return;
1311 }
else if (N.ASTNode.get<CXXThrowExpr>()) {
1312 Cursor = Cur::Throw;
1313 }
else if (N.ASTNode.get<SwitchCase>()) {
1315 }
else if (
const GotoStmt *GS = N.ASTNode.get<GotoStmt>()) {
1317 Result.push_back(GS->getGotoLoc());
1318 if (
const auto *LD = GS->getLabel())
1319 Result.push_back(LD->getLocation());
1325 const Stmt *Root =
nullptr;
1328 for (
const auto *P = &N;
P;
P =
P->Parent) {
1330 if (
const Stmt *FunctionBody = getFunctionBody(
P->ASTNode)) {
1331 if (Cursor == Cur::Return || Cursor == Cur::Throw) {
1332 Root = FunctionBody;
1337 if (
const Stmt *LoopBody = getLoopBody(
P->ASTNode)) {
1338 if (Cursor == Cur::None || Cursor == Cur::Break ||
1339 Cursor == Cur::Continue) {
1343 Result.push_back(
P->ASTNode.getSourceRange().getBegin());
1350 if (
const auto *SS =
P->ASTNode.get<SwitchStmt>()) {
1351 if (Cursor == Cur::Break || Cursor == Cur::Case) {
1352 Result.push_back(SS->getSwitchLoc());
1353 Root = SS->getBody();
1355 Bounds = findCaseBounds(*SS, N.ASTNode.getSourceRange().getBegin(), SM);
1360 if (Cursor == Cur::None)
1364 if (!Bounds.isValid())
1365 Bounds = Root->getSourceRange();
1366 FindControlFlow(Bounds, Result, SM).TraverseStmt(
const_cast<Stmt *
>(Root));
1372 const SourceManager &SM) {
1375 if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
1377 else if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
1384std::optional<DocumentHighlight> toHighlight(SourceLocation Loc,
1385 const syntax::TokenBuffer &TB) {
1386 Loc = TB.sourceManager().getFileLoc(Loc);
1387 if (
const auto *Tok = TB.spelledTokenContaining(Loc)) {
1391 CharSourceRange::getCharRange(Tok->location(), Tok->endLocation()));
1394 return std::nullopt;
1401 const SourceManager &SM =
AST.getSourceManager();
1405 llvm::consumeError(CurLoc.takeError());
1408 std::vector<DocumentHighlight> Result;
1414 targetDecl(N->ASTNode, Relations,
AST.getHeuristicResolver());
1415 if (!TargetDecls.empty()) {
1418 for (
const auto &
Ref : findRefs(TargetDecls,
AST,
true))
1419 Result.push_back(toHighlight(
Ref, SM));
1422 auto ControlFlow = relatedControlFlow(*N);
1423 if (!ControlFlow.empty()) {
1424 for (SourceLocation Loc : ControlFlow)
1425 if (
auto Highlight = toHighlight(Loc,
AST.getTokens()))
1426 Result.push_back(std::move(*Highlight));
1434 AST.getSourceManager().getDecomposedSpellingLoc(*CurLoc).second;
1447 const SourceManager &SM =
AST.getSourceManager();
1450 elog(
"Failed to convert position to source location: {0}",
1451 CurLoc.takeError());
1456 llvm::DenseSet<SymbolID> IDs;
1458 for (
const NamedDecl *ND : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1459 if (
const auto *CXXMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1460 if (CXXMD->isVirtual()) {
1464 }
else if (
const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
1467 }
else if (
const auto *OMD = dyn_cast<ObjCMethodDecl>(ND)) {
1470 }
else if (
const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) {
1475 return findImplementors(std::move(IDs), QueryKind, Index,
AST.tuPath());
1481void getOverriddenMethods(
const CXXMethodDecl *CMD,
1482 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1485 for (
const CXXMethodDecl *Base : CMD->overridden_methods()) {
1487 OverriddenMethods.insert(ID);
1488 getOverriddenMethods(Base, OverriddenMethods);
1494void getOverriddenMethods(
const ObjCMethodDecl *OMD,
1495 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1498 llvm::SmallVector<const ObjCMethodDecl *, 4>
Overrides;
1500 for (
const ObjCMethodDecl *Base :
Overrides) {
1502 OverriddenMethods.insert(ID);
1503 getOverriddenMethods(Base, OverriddenMethods);
1507std::optional<std::string>
1508stringifyContainerForMainFileRef(
const Decl *Container) {
1511 if (
auto *ND = llvm::dyn_cast_if_present<NamedDecl>(Container))
1516std::optional<ReferencesResult>
1519 const auto &Includes =
AST.getIncludeStructure().MainFileIncludes;
1520 auto IncludeOnLine = llvm::find_if(Includes, [&Pos](
const Inclusion &Inc) {
1521 return Inc.HashLine == Pos.line;
1523 if (IncludeOnLine == Includes.end())
1524 return std::nullopt;
1526 const SourceManager &SM =
AST.getSourceManager();
1529 include_cleaner::walkUsed(
1531 &
AST.getPragmaIncludes(),
AST.getPreprocessor(),
1532 [&](
const include_cleaner::SymbolReference &
Ref,
1533 llvm::ArrayRef<include_cleaner::Header> Providers) {
1534 if (Ref.RT != include_cleaner::RefType::Explicit ||
1535 !isPreferredProvider(*IncludeOnLine, Converted, Providers))
1538 auto Loc = SM.getFileLoc(Ref.RefLocation);
1541 while (SM.getFileID(Loc) != SM.getMainFileID())
1542 Loc = SM.getIncludeLoc(SM.getFileID(Loc));
1544 ReferencesResult::Reference Result;
1545 const auto *Token = AST.getTokens().spelledTokenContaining(Loc);
1546 assert(Token &&
"references expected token here");
1547 Result.Loc.range = Range{sourceLocToPosition(SM, Token->location()),
1548 sourceLocToPosition(SM, Token->endLocation())};
1549 Result.Loc.uri = URIMainFile;
1550 Results.References.push_back(std::move(Result));
1552 if (Results.References.empty())
1553 return std::nullopt;
1558 IncludeOnLine->HashOffset);
1559 Result.Loc.uri = std::move(URIMainFile);
1560 Results.References.push_back(std::move(Result));
1568 const SourceManager &SM =
AST.getSourceManager();
1569 auto MainFilePath =
AST.tuPath();
1573 llvm::consumeError(CurLoc.takeError());
1577 const auto IncludeReferences =
1578 maybeFindIncludeReferences(
AST, Pos, URIMainFile);
1579 if (IncludeReferences)
1580 return *IncludeReferences;
1582 llvm::DenseSet<SymbolID> IDsToQuery, OverriddenMethods;
1584 const auto *IdentifierAtCursor =
1585 syntax::spelledIdentifierTouching(*CurLoc,
AST.getTokens());
1586 std::optional<DefinedMacro>
Macro;
1587 if (IdentifierAtCursor)
1593 const auto &IDToRefs =
AST.getMacros().MacroRefs;
1594 auto Refs = IDToRefs.find(MacroSID);
1595 if (Refs != IDToRefs.end()) {
1596 for (
const auto &
Ref : Refs->second) {
1599 Result.
Loc.
uri = URIMainFile;
1600 if (
Ref.IsDefinition) {
1604 Results.
References.push_back(std::move(Result));
1607 IDsToQuery.insert(MacroSID);
1614 std::vector<const NamedDecl *> Decls =
1615 getDeclAtPosition(
AST, *CurLoc, Relations);
1616 llvm::SmallVector<const NamedDecl *> TargetsInMainFile;
1617 for (
const NamedDecl *D : Decls) {
1621 TargetsInMainFile.push_back(D);
1625 if (D->getParentFunctionOrMethod())
1627 IDsToQuery.insert(ID);
1633 for (
const NamedDecl *ND : Decls) {
1636 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1637 if (CMD->isVirtual()) {
1640 getOverriddenMethods(CMD, OverriddenMethods);
1645 if (
const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(ND)) {
1647 getOverriddenMethods(OMD, OverriddenMethods);
1653 auto MainFileRefs = findRefs(TargetsInMainFile,
AST,
false);
1657 MainFileRefs.erase(llvm::unique(MainFileRefs,
1658 [](
const ReferenceFinder::Reference &L,
1659 const ReferenceFinder::Reference &R) {
1660 return L.SpelledTok.location() ==
1661 R.SpelledTok.location();
1663 MainFileRefs.end());
1664 for (
const auto &
Ref : MainFileRefs) {
1667 Result.
Loc.
uri = URIMainFile;
1671 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Declaration))
1674 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Definition))
1677 Results.
References.push_back(std::move(Result));
1685 llvm::DenseMap<SymbolID, size_t> RefIndexForContainer;
1688 if (Limit && Results.
References.size() >= Limit) {
1692 const auto LSPLocDecl =
1693 toLSPLocation(
Object.CanonicalDeclaration, MainFilePath);
1694 const auto LSPLocDef = toLSPLocation(
Object.Definition, MainFilePath);
1695 if (LSPLocDecl && LSPLocDecl != LSPLocDef) {
1697 Result.
Loc = {std::move(*LSPLocDecl), std::nullopt};
1702 Results.
References.push_back(std::move(Result));
1706 Result.
Loc = {std::move(*LSPLocDef), std::nullopt};
1712 Results.
References.push_back(std::move(Result));
1716 if (!ContainerLookup.
IDs.empty() && AddContext)
1717 Index->
lookup(ContainerLookup, [&](
const Symbol &Container) {
1718 auto Ref = RefIndexForContainer.find(Container.ID);
1719 assert(
Ref != RefIndexForContainer.end());
1721 Container.Scope.str() + Container.Name.str();
1726 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs,
bool AllowAttributes,
1727 bool AllowMainFileSymbols) {
1728 if (IDs.empty() || !Index || Results.
HasMore)
1731 Req.
IDs = std::move(IDs);
1743 llvm::DenseMap<SymbolID, std::vector<size_t>> RefIndicesForContainer;
1745 auto LSPLoc = toLSPLocation(R.
Location, MainFilePath);
1748 (!AllowMainFileSymbols && LSPLoc->uri.file() == MainFilePath))
1751 Result.
Loc = {std::move(*LSPLoc), std::nullopt};
1752 if (AllowAttributes) {
1762 ContainerLookup.
IDs.insert(Container);
1763 RefIndicesForContainer[Container].push_back(Results.
References.size());
1765 Results.
References.push_back(std::move(Result));
1768 if (!ContainerLookup.
IDs.empty() && AddContext)
1769 Index->
lookup(ContainerLookup, [&](
const Symbol &Container) {
1770 auto Ref = RefIndicesForContainer.find(Container.ID);
1771 assert(
Ref != RefIndicesForContainer.end());
1772 auto ContainerName = Container.Scope.str() + Container.Name.str();
1773 for (
auto I :
Ref->getSecond()) {
1774 Results.
References[I].Loc.containerName = ContainerName;
1778 QueryIndex(std::move(IDsToQuery),
true,
1783 QueryIndex(std::move(OverriddenMethods),
false,
1789 const SourceManager &SM =
AST.getSourceManager();
1792 llvm::consumeError(CurLoc.takeError());
1795 auto MainFilePath =
AST.tuPath();
1796 std::vector<SymbolDetails> Results;
1802 for (
const NamedDecl *D : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1803 D = getPreferredDecl(D);
1809 NewSymbol.
name = std::string(SplitQName.second);
1812 if (
const auto *ParentND =
1813 dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
1816 llvm::SmallString<32> USR;
1817 if (!index::generateUSRForDecl(D, USR)) {
1818 NewSymbol.
USR = std::string(USR);
1821 if (
const NamedDecl *Def = getDefinition(D))
1825 makeLocation(
AST.getASTContext(),
nameLocation(*D, SM), MainFilePath);
1827 Results.push_back(std::move(NewSymbol));
1830 const auto *IdentifierAtCursor =
1831 syntax::spelledIdentifierTouching(*CurLoc,
AST.getTokens());
1832 if (!IdentifierAtCursor)
1837 NewMacro.
name = std::string(M->Name);
1838 llvm::SmallString<32> USR;
1839 if (!index::generateUSRForMacro(NewMacro.
name, M->Info->getDefinitionLoc(),
1841 NewMacro.
USR = std::string(USR);
1844 Results.push_back(std::move(NewMacro));
1865 OS <<
" [override]";
1869template <
typename HierarchyItem>
1870static std::optional<HierarchyItem>
1872 ASTContext &Ctx = ND.getASTContext();
1873 auto &SM = Ctx.getSourceManager();
1874 SourceLocation NameLoc =
nameLocation(ND, Ctx.getSourceManager());
1875 SourceLocation BeginLoc = SM.getFileLoc(ND.getBeginLoc());
1876 SourceLocation EndLoc = SM.getFileLoc(ND.getEndLoc());
1877 const auto DeclRange =
1880 return std::nullopt;
1881 const auto FE = SM.getFileEntryRefForID(SM.getFileID(NameLoc));
1883 return std::nullopt;
1886 return std::nullopt;
1890 SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
1892 index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
1904 HI.selectionRange =
Range{NameBegin, NameEnd};
1905 if (!HI.range.contains(HI.selectionRange)) {
1908 HI.range = HI.selectionRange;
1916static std::optional<TypeHierarchyItem>
1920 Result->deprecated = ND.isDeprecated();
1930static std::optional<CallHierarchyItem>
1935 if (ND.isDeprecated())
1938 Result->data = ID.str();
1942template <
typename HierarchyItem>
1947 elog(
"Failed to convert symbol to hierarchy item: {0}", Loc.takeError());
1948 return std::nullopt;
1951 HI.name = std::string(S.
Name);
1952 HI.detail = S.
Scope.empty() ? std::string()
1953 : S.
Scope.drop_back(2).str();
1956 HI.selectionRange = Loc->range;
1959 HI.range = HI.selectionRange;
1965static std::optional<TypeHierarchyItem>
1970 Result->data.symbolID = S.
ID;
1975static std::optional<CallHierarchyItem>
1980 Result->data = S.
ID.
str();
1985 std::vector<TypeHierarchyItem> &SubTypes,
1991 if (std::optional<TypeHierarchyItem> ChildSym =
1994 ChildSym->children.emplace();
1997 SubTypes.emplace_back(std::move(*ChildSym));
2015 auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD :
nullptr;
2017 if (!RPSet.insert(Pattern).second) {
2022 for (
const CXXRecordDecl *ParentDecl :
typeParents(&CXXRD)) {
2023 if (std::optional<TypeHierarchyItem> ParentSym =
2027 Item.
parents->emplace_back(std::move(*ParentSym));
2032 RPSet.erase(Pattern);
2039 std::vector<const CXXRecordDecl *> Records;
2048 AST.getHeuristicResolver());
2049 for (
const NamedDecl *D : Decls) {
2051 if (
const VarDecl *VD = dyn_cast<VarDecl>(D)) {
2053 if (
const auto *RD = VD->getType().getTypePtr()->getAsCXXRecordDecl())
2054 Records.push_back(RD);
2058 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(D)) {
2060 Records.push_back(
Method->getParent());
2068 if (
auto *RD = dyn_cast<CXXRecordDecl>(D))
2069 Records.push_back(RD);
2074 const SourceManager &SM =
AST.getSourceManager();
2075 std::vector<const CXXRecordDecl *> Result;
2078 llvm::consumeError(Offset.takeError());
2083 Result = RecordFromNode(ST.commonAncestor());
2084 return !Result.empty();
2091static QualType
typeForNode(
const ASTContext &Ctx,
const HeuristicResolver *H,
2095 while (N && N->
ASTNode.get<NestedNameSpecifierLoc>())
2101 if (
const TypeLoc *TL = N->
ASTNode.get<TypeLoc>()) {
2102 if (llvm::isa<DeducedType>(TL->getTypePtr()))
2104 N->
getDeclContext().getParentASTContext(), H, TL->getBeginLoc()))
2107 if (llvm::isa<TypedefType>(TL->getTypePtr()))
2108 return TL->getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
2109 return TL->getType();
2113 if (
const auto *CCI = N->
ASTNode.get<CXXCtorInitializer>()) {
2114 if (
const FieldDecl *FD = CCI->getAnyMember())
2115 return FD->getType();
2116 if (
const Type *Base = CCI->getBaseClass())
2117 return QualType(Base, 0);
2121 if (
const auto *CBS = N->
ASTNode.get<CXXBaseSpecifier>())
2122 return CBS->getType();
2124 if (
const Decl *D = N->
ASTNode.get<Decl>()) {
2125 struct Visitor : ConstDeclVisitor<Visitor, QualType> {
2126 const ASTContext &Ctx;
2127 Visitor(
const ASTContext &Ctx) : Ctx(Ctx) {}
2129 QualType VisitValueDecl(
const ValueDecl *D) {
return D->getType(); }
2131 QualType VisitTypeDecl(
const TypeDecl *D) {
2132 return Ctx.getTypeDeclType(D);
2135 QualType VisitTypedefNameDecl(
const TypedefNameDecl *D) {
2136 return D->getUnderlyingType();
2139 QualType VisitTemplateDecl(
const TemplateDecl *D) {
2140 if (
const auto *TD = D->getTemplatedDecl())
2149 if (
const Stmt *S = N->
ASTNode.get<Stmt>()) {
2150 struct Visitor : ConstStmtVisitor<Visitor, QualType> {
2152 QualType type(
const Stmt *S) {
return S ? Visit(S) : QualType(); }
2155 QualType VisitExpr(
const Expr *S) {
2156 return S->IgnoreImplicitAsWritten()->getType();
2158 QualType VisitMemberExpr(
const MemberExpr *S) {
2160 if (S->getType()->isSpecificBuiltinType(BuiltinType::BoundMember))
2161 return Expr::findBoundMemberType(S);
2162 return VisitExpr(S);
2165 QualType VisitCXXDeleteExpr(
const CXXDeleteExpr *S) {
2166 return S->getDestroyedType();
2168 QualType VisitCXXPseudoDestructorExpr(
const CXXPseudoDestructorExpr *S) {
2169 return S->getDestroyedType();
2171 QualType VisitCXXThrowExpr(
const CXXThrowExpr *S) {
2172 return S->getSubExpr()->getType();
2174 QualType VisitCoyieldExpr(
const CoyieldExpr *S) {
2175 return type(S->getOperand());
2178 QualType VisitDesignatedInitExpr(
const DesignatedInitExpr *S) {
2180 for (
auto &D : llvm::reverse(S->designators()))
2181 if (D.isFieldDesignator())
2182 if (
const auto *FD = D.getFieldDecl())
2183 return FD->getType();
2188 QualType VisitSwitchStmt(
const SwitchStmt *S) {
2189 return type(S->getCond());
2191 QualType VisitWhileStmt(
const WhileStmt *S) {
return type(S->getCond()); }
2192 QualType VisitDoStmt(
const DoStmt *S) {
return type(S->getCond()); }
2193 QualType VisitIfStmt(
const IfStmt *S) {
return type(S->getCond()); }
2194 QualType VisitCaseStmt(
const CaseStmt *S) {
return type(S->getLHS()); }
2195 QualType VisitCXXForRangeStmt(
const CXXForRangeStmt *S) {
2196 return S->getLoopVariable()->getType();
2198 QualType VisitReturnStmt(
const ReturnStmt *S) {
2199 return type(S->getRetValue());
2201 QualType VisitCoreturnStmt(
const CoreturnStmt *S) {
2202 return type(S->getOperand());
2204 QualType VisitCXXCatchStmt(
const CXXCatchStmt *S) {
2205 return S->getCaughtType();
2207 QualType VisitObjCAtThrowStmt(
const ObjCAtThrowStmt *S) {
2208 return type(S->getThrowExpr());
2210 QualType VisitObjCAtCatchStmt(
const ObjCAtCatchStmt *S) {
2211 return S->getCatchParamDecl() ? S->getCatchParamDecl()->getType()
2224 QualType T,
const HeuristicResolver* H, llvm::SmallVector<QualType>& Out) {
2229 if (
const auto *TDT = T->getAs<TypedefType>())
2230 return Out.push_back(QualType(TDT, 0));
2233 if (
const auto *PT = T->getAs<PointerType>())
2235 if (
const auto *RT = T->getAs<ReferenceType>())
2237 if (
const auto *AT = T->getAsArrayTypeUnsafe())
2241 if (
auto *FT = T->getAs<FunctionType>())
2243 if (
auto *CRD = T->getAsCXXRecordDecl()) {
2244 if (CRD->isLambda())
2245 return unwrapFindType(CRD->getLambdaCallOperator()->getReturnType(), H,
2253 if (
auto PointeeType = H->getPointeeType(T.getNonReferenceType());
2254 !PointeeType.isNull()) {
2256 return Out.push_back(T);
2259 return Out.push_back(T);
2264 QualType T,
const HeuristicResolver* H) {
2265 llvm::SmallVector<QualType> Result;
2272 const SourceManager &SM =
AST.getSourceManager();
2274 std::vector<LocatedSymbol> Result;
2276 elog(
"failed to convert position {0} for findTypes: {1}", Pos,
2277 Offset.takeError());
2281 auto SymbolsFromNode =
2283 std::vector<LocatedSymbol> LocatedSymbols;
2291 AST.getHeuristicResolver()))
2292 llvm::copy(locateSymbolForType(
AST,
Type, Index),
2293 std::back_inserter(LocatedSymbols));
2295 return LocatedSymbols;
2299 Result = SymbolsFromNode(ST.commonAncestor());
2300 return !Result.empty();
2305std::vector<const CXXRecordDecl *>
typeParents(
const CXXRecordDecl *CXXRD) {
2306 std::vector<const CXXRecordDecl *> Result;
2310 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
2311 if (CTSD->isInvalidDecl())
2312 CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
2316 if (!CXXRD->hasDefinition())
2319 for (
auto Base : CXXRD->bases()) {
2320 const CXXRecordDecl *ParentDecl =
nullptr;
2322 const Type *
Type = Base.getType().getTypePtr();
2323 if (
const RecordType *RT =
Type->getAs<RecordType>()) {
2324 ParentDecl = RT->getAsCXXRecordDecl();
2330 if (
const TemplateSpecializationType *TS =
2331 Type->getAs<TemplateSpecializationType>()) {
2332 TemplateName TN = TS->getTemplateName();
2333 if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
2334 ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
2340 Result.push_back(ParentDecl);
2346std::vector<TypeHierarchyItem>
2350 std::vector<TypeHierarchyItem> Results;
2364 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
2365 CXXRD = CTSD->getTemplateInstantiationPattern();
2368 std::optional<TypeHierarchyItem> Result =
2376 if (WantChildren && ResolveLevels > 0) {
2377 Result->children.emplace();
2381 fillSubTypes(ID, *Result->children, Index, ResolveLevels, TUPath);
2384 Results.emplace_back(std::move(*Result));
2390std::optional<std::vector<TypeHierarchyItem>>
2393 return std::nullopt;
2395 llvm::DenseMap<SymbolID, const TypeHierarchyItem::ResolveParams *> IDToData;
2397 Req.
IDs.insert(Parent.symbolID);
2398 IDToData[Parent.symbolID] = &Parent;
2400 std::vector<TypeHierarchyItem> Results;
2401 Index->
lookup(Req, [&Item, &Results, &IDToData](
const Symbol &S) {
2403 THI->data = *IDToData.lookup(S.
ID);
2404 Results.emplace_back(std::move(*THI));
2407 return Results.empty() ? std::nullopt
2408 : std::make_optional(std::move(Results));
2413 std::vector<TypeHierarchyItem> Results;
2415 for (
auto &ChildSym : Results)
2416 ChildSym.data.parents = {Item.
data};
2434std::vector<CallHierarchyItem>
2436 std::vector<CallHierarchyItem> Result;
2437 const auto &SM =
AST.getSourceManager();
2440 elog(
"prepareCallHierarchy failed to convert position to source location: "
2445 for (
const NamedDecl *Decl : getDeclAtPosition(
AST, *Loc, {})) {
2446 if (!(isa<DeclContext>(Decl) &&
2447 cast<DeclContext>(Decl)->isFunctionOrMethod()) &&
2448 Decl->getKind() != Decl::Kind::FunctionTemplate &&
2449 !(Decl->getKind() == Decl::Kind::Var &&
2450 !cast<VarDecl>(Decl)->isLocalVarDecl()) &&
2451 Decl->getKind() != Decl::Kind::Field &&
2452 Decl->getKind() != Decl::Kind::EnumConstant)
2455 Result.emplace_back(std::move(*CHI));
2460std::vector<CallHierarchyIncomingCall>
2462 std::vector<CallHierarchyIncomingCall> Results;
2463 if (!Index || Item.
data.empty())
2467 elog(
"incomingCalls failed to find symbol: {0}", ID.takeError());
2476 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs,
bool MightNeverCall) {
2478 Request.
IDs = std::move(IDs);
2487 llvm::DenseMap<SymbolID, std::vector<Location>> CallsIn;
2491 Index->
refs(Request, [&](
const Ref &R) {
2494 elog(
"incomingCalls failed to convert location: {0}", Loc.takeError());
2503 Index->
lookup(ContainerLookup, [&](
const Symbol &Caller) {
2504 auto It = CallsIn.find(Caller.
ID);
2505 assert(It != CallsIn.end());
2507 std::vector<Range> FromRanges;
2508 for (
const Location &L : It->second) {
2516 FromRanges.push_back(L.
range);
2519 std::move(*CHI), std::move(FromRanges), MightNeverCall});
2523 QueryIndex({ID.get()},
false);
2526 if (Item.
kind == SymbolKind::Method) {
2527 llvm::DenseSet<SymbolID> IDs;
2530 IDs.insert(Caller.
ID);
2532 QueryIndex(std::move(IDs),
true);
2537 return A.from.name < B.from.name;
2542std::vector<CallHierarchyOutgoingCall>
2544 std::vector<CallHierarchyOutgoingCall> Results;
2545 if (!Index || Item.
data.empty())
2549 elog(
"outgoingCalls failed to find symbol: {0}", ID.takeError());
2558 llvm::DenseMap<SymbolID, std::vector<Location>> CallsOut;
2565 elog(
"outgoingCalls failed to convert location: {0}", Loc.takeError());
2568 auto It = CallsOut.try_emplace(R.Symbol, std::vector<Location>{}).first;
2569 It->second.push_back(*Loc);
2571 CallsOutLookup.
IDs.insert(R.Symbol);
2575 Index->
lookup(CallsOutLookup, [&](
const Symbol &Callee) {
2578 using SK = index::SymbolKind;
2579 auto Kind = Callee.SymInfo.Kind;
2580 assert(Kind == SK::Function || Kind == SK::InstanceMethod ||
2581 Kind == SK::ClassMethod || Kind == SK::StaticMethod ||
2582 Kind == SK::Constructor || Kind == SK::Destructor ||
2583 Kind == SK::ConversionFunction);
2587 auto It = CallsOut.find(Callee.ID);
2588 assert(It != CallsOut.end());
2590 std::vector<Range> FromRanges;
2591 for (
const Location &L : It->second) {
2600 FromRanges.push_back(L.
range);
2609 return A.to.name < B.to.name;
2615 const FunctionDecl *FD) {
2618 llvm::DenseSet<const Decl *> DeclRefs;
2622 for (
const Decl *D :
Ref.Targets) {
2623 if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
2628 AST.getHeuristicResolver());
Include Cleaner is clangd functionality for providing diagnostics for misuse of transitive headers an...
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for Markdown output.")
void elog(const char *Fmt, Ts &&... Vals)
A context is an immutable container for per-request data that must be propagated through layers that ...
Stores and provides access to parsed AST.
static bool createEach(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End, llvm::function_ref< bool(SelectionTree)> Func)
static const Decl * getRefContainer(const Decl *Enclosing, const SymbolCollector::Options &Opts)
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
virtual bool fuzzyFind(const FuzzyFindRequest &Req, llvm::function_ref< void(const Symbol &)> Callback) const =0
Matches symbols in the index fuzzily and applies Callback on each matched symbol before returning.
virtual bool containedRefs(const ContainedRefsRequest &Req, llvm::function_ref< void(const ContainedRefsResult &)> Callback) const =0
Find all symbols that are referenced by a symbol and apply Callback on each result.
virtual void relations(const RelationsRequest &Req, llvm::function_ref< void(const SymbolID &Subject, const Symbol &Object)> Callback) const =0
Finds all relations (S, P, O) stored in the index such that S is among Req.Subjects and P is Req....
virtual bool refs(const RefsRequest &Req, llvm::function_ref< void(const Ref &)> Callback) const =0
Finds all occurrences (e.g.
virtual void lookup(const LookupRequest &Req, llvm::function_ref< void(const Symbol &)> Callback) const =0
Looks up symbols with any of the given symbol IDs and applies Callback on each matched symbol.
virtual void reverseRelations(const RelationsRequest &Req, llvm::function_ref< void(const SymbolID &Subject, const Symbol &Object)> Callback) const =0
Finds all relations (O, P, S) stored in the index such that S is among Req.Subjects and P is Req....
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
std::vector< TypeHierarchyItem > subTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct children of a TypeHierarchyItem.
std::pair< StringRef, StringRef > splitQualifiedName(StringRef QName)
std::optional< std::vector< TypeHierarchyItem > > superTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct parents of a TypeHierarchyItem using SymbolIDs stored inside the item.
llvm::Expected< Location > indexToLSPLocation(const SymbolLocation &Loc, llvm::StringRef TUPath)
Helper function for deriving an LSP Location from an index SymbolLocation.
std::vector< CallHierarchyIncomingCall > incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
SymbolID getSymbolID(const Decl *D)
Gets the symbol ID for a declaration. Returned SymbolID might be null.
static std::optional< TypeHierarchyItem > symbolToTypeHierarchyItem(const Symbol &S, PathRef TUPath)
std::optional< SourceRange > toHalfOpenFileRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R)
Turns a token range into a half-open range and checks its correctness.
static std::optional< CallHierarchyItem > symbolToCallHierarchyItem(const Symbol &S, PathRef TUPath)
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)
std::string printName(const ASTContext &Ctx, const NamedDecl &ND)
Prints unqualified name of the decl for the purpose of displaying it to the user.
llvm::SmallVector< std::pair< const NamedDecl *, DeclRelationSet >, 1 > allTargetDecls(const DynTypedNode &N, const HeuristicResolver *Resolver)
Similar to targetDecl(), however instead of applying a filter, all possible decls are returned along ...
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
llvm::SmallVector< const NamedDecl *, 1 > explicitReferenceTargets(DynTypedNode N, DeclRelationSet Mask, const HeuristicResolver *Resolver)
Find declarations explicitly referenced in the source code defined by N.
std::vector< LocatedSymbol > locateSymbolTextually(const SpelledWord &Word, ParsedAST &AST, const SymbolIndex *Index, llvm::StringRef MainFilePath, ASTNodeKind NodeKind)
std::vector< SymbolTag > getSymbolTags(const Symbol &S)
Returns the SymbolTag values for the given indexed S.
std::vector< DocumentLink > getDocumentLinks(ParsedAST &AST)
Get all document links.
Symbol mergeSymbol(const Symbol &L, const Symbol &R)
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
std::vector< include_cleaner::SymbolReference > collectMacroReferences(ParsedAST &AST)
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
llvm::Expected< Location > symbolToLocation(const Symbol &Sym, llvm::StringRef TUPath)
Helper function for deriving an LSP Location for a Symbol.
SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM)
Find the source location of the identifier for D.
void vlog(const char *Fmt, Ts &&... Vals)
include_cleaner::Includes convertIncludes(const ParsedAST &AST)
Converts the clangd include representation to include-cleaner include representation.
std::vector< LocatedSymbol > findType(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns symbols for types referenced at Pos.
void findExplicitReferences(const Stmt *S, llvm::function_ref< void(ReferenceLoc)> Out, const HeuristicResolver *Resolver)
Recursively traverse S and report all references explicitly written in the code.
static QualType typeForNode(const ASTContext &Ctx, const HeuristicResolver *H, const SelectionTree::Node *N)
std::vector< TypeHierarchyItem > getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index, PathRef TUPath)
Get type hierarchy information at Pos.
static std::optional< TypeHierarchyItem > declToTypeHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath)
std::optional< QualType > getDeducedType(ASTContext &ASTCtx, const HeuristicResolver *Resolver, SourceLocation Loc)
Retrieves the deduced type at a given location (auto, decltype).
llvm::SmallVector< const NamedDecl *, 1 > targetDecl(const DynTypedNode &N, DeclRelationSet Mask, const HeuristicResolver *Resolver)
targetDecl() finds the declaration referred to by an AST node.
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index, bool AddContext)
Returns references of the symbol at a specified Pos.
static void fillSuperTypes(const CXXRecordDecl &CXXRD, llvm::StringRef TUPath, TypeHierarchyItem &Item, RecursionProtectionSet &RPSet)
std::optional< DefinedMacro > locateMacroAt(const syntax::Token &SpelledTok, Preprocessor &PP)
Gets the macro referenced by SpelledTok.
std::vector< LocatedSymbol > locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
std::vector< std::string > visibleNamespaces(llvm::StringRef Code, const LangOptions &LangOpts)
Heuristically determine namespaces visible at a point, without parsing Code.
static std::optional< HierarchyItem > declToHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath)
std::optional< std::string > getCanonicalPath(const FileEntryRef F, FileManager &FileMgr)
Get the canonical path of F.
static void unwrapFindType(QualType T, const HeuristicResolver *H, llvm::SmallVector< QualType > &Out)
static std::optional< HierarchyItem > symbolToHierarchyItem(const Symbol &S, PathRef TUPath)
const syntax::Token * findNearbyIdentifier(const SpelledWord &Word, const syntax::TokenBuffer &TB)
llvm::SmallPtrSet< const CXXRecordDecl *, 4 > RecursionProtectionSet
static void fillSubTypes(const SymbolID &ID, std::vector< TypeHierarchyItem > &SubTypes, const SymbolIndex *Index, int Levels, PathRef TUPath)
void log(const char *Fmt, Ts &&... Vals)
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
@ Type
An inlay hint that for a type annotation.
std::vector< LocatedSymbol > findImplementations(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns implementations at a specified Pos:
ArrayRef< const CXXConstructorDecl * > getForwardedConstructors(const FunctionDecl *FD, ForwardingToConstructorCache &Cache)
Returns the constructors that FD forwards to, if FD is a template instantiation of a likely forwardin...
const ObjCImplDecl * getCorrespondingObjCImpl(const ObjCContainerDecl *D)
Return the corresponding implementation/definition for the given ObjC container if it has one,...
SymbolKind indexSymbolKindToSymbolKind(const index::SymbolInfo &Info)
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
llvm::DenseSet< const Decl * > getNonLocalDeclRefs(ParsedAST &AST, const FunctionDecl *FD)
Returns all decls that are referenced in the FD except local symbols.
clangd::Range rangeTillEOL(llvm::StringRef Code, unsigned HashOffset)
Returns the range starting at offset and spanning the whole line.
float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance)
Combine symbol quality and relevance into a single score.
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
std::vector< CallHierarchyOutgoingCall > outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
void elog(const char *Fmt, Ts &&... Vals)
@ Underlying
This is the underlying declaration for a renaming-alias, decltype etc.
@ TemplatePattern
This is the pattern the template specialization was instantiated from.
@ Alias
This declaration is an alias that was referred to.
static std::optional< CallHierarchyItem > declToCallHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath)
std::vector< const CXXRecordDecl * > findRecordTypeAt(ParsedAST &AST, Position Pos)
Find the record types referenced at Pos.
std::vector< CallHierarchyItem > prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath)
Get call hierarchy information at Pos.
std::vector< const CXXRecordDecl * > typeParents(const CXXRecordDecl *CXXRD)
Given a record type declaration, find its base (parent) types.
cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccessCheck P
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Represents an incoming call, e.g. a caller of a method or constructor.
Represents programming constructs like functions or constructors in the context of call hierarchy.
URIForFile uri
The resource identifier of this item.
SymbolKind kind
The kind of this item.
std::string data
An optional 'data' field, which can be used to identify a call hierarchy item in an incomingCalls or ...
Represents an outgoing call, e.g.
A document highlight is a range inside a text document which deserves special attention.
Range range
The range this highlight applies to.
A range in a text document that links to an internal or external resource, like another text document...
std::vector< std::string > Scopes
If this is non-empty, symbols must be in at least one of the scopes (e.g.
std::string Query
A query string for the fuzzy find.
std::vector< std::string > ProximityPaths
Contextually relevant files (e.g.
bool AnyScope
If set to true, allow symbols from any scope.
std::optional< uint32_t > Limit
The number of top candidates to return.
Location PreferredDeclaration
std::optional< Location > Definition
URIForFile uri
The text document's URI.
llvm::DenseSet< SymbolID > IDs
Represents a symbol occurrence in the source file.
SymbolID Container
The ID of the symbol whose definition contains this reference.
SymbolLocation Location
The source location where the symbol is named.
Information about a reference written in the source code, independent of the actual AST node that thi...
std::optional< std::string > containerName
clangd extension: contains the name of the function or class in which the reference occurs
std::vector< Reference > References
bool WantContainer
If set, populates the container of the reference.
llvm::DenseSet< SymbolID > IDs
std::optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
llvm::DenseSet< SymbolID > Subjects
const DeclContext & getDeclContext() const
static std::optional< SpelledWord > touching(SourceLocation SpelledLoc, const syntax::TokenBuffer &TB, const LangOptions &LangOpts)
const syntax::Token * ExpandedToken
const syntax::Token * PartOfSpelledToken
Represents information about identifier.
std::optional< Location > definitionRange
std::string containerName
std::optional< Location > declarationRange
std::string USR
Unified Symbol Resolution identifier This is an opaque string uniquely identifying a symbol.
Attributes of a symbol that affect how much we like it.
float evaluateHeuristics() const
void merge(const CodeCompletionResult &SemaCCResult)
Attributes of a symbol-query pair that affect how much we like it.
llvm::StringRef Name
The name of the symbol (for ContextWords). Must be explicitly assigned.
void merge(const CodeCompletionResult &SemaResult)
enum clang::clangd::SymbolRelevanceSignals::QueryType Query
float evaluateHeuristics() const
Ensure we have enough bits to represent all SymbolTag values.
@ Deprecated
Indicates if the symbol is deprecated.
SymbolLocation Definition
The location of the symbol's definition, if one was found.
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).
llvm::StringRef TemplateSpecializationArgs
Argument list in human-readable format, will be displayed to help disambiguate between different spec...
SymbolLocation CanonicalDeclaration
The location of the preferred declaration of the symbol.
SymbolID ID
The ID of the symbol.
std::optional< std::vector< ResolveParams > > parents
std::nullopt means parents aren't resolved and empty is no parents.
URIForFile uri
The resource identifier of this item.
std::optional< std::vector< TypeHierarchyItem > > children
If this type hierarchy item is resolved, it contains the direct children of the current item.
std::optional< std::vector< TypeHierarchyItem > > parents
This is a clangd exntesion.
ResolveParams data
A data entry field that is preserved between a type hierarchy prepare and supertypes or subtypes requ...
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
llvm::StringRef file() const
Retrieves absolute path to the file.
Represents measurements of clangd events, e.g.
@ Counter
An aggregate number whose rate of change over time is meaningful.