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/SourceLocation.h"
46#include "clang/Basic/SourceManager.h"
47#include "clang/Basic/TokenKinds.h"
48#include "clang/Index/IndexDataConsumer.h"
49#include "clang/Index/IndexSymbol.h"
50#include "clang/Index/IndexingAction.h"
51#include "clang/Index/IndexingOptions.h"
52#include "clang/Index/USRGeneration.h"
53#include "clang/Lex/Lexer.h"
54#include "clang/Sema/HeuristicResolver.h"
55#include "clang/Tooling/Syntax/Tokens.h"
56#include "llvm/ADT/ArrayRef.h"
57#include "llvm/ADT/DenseMap.h"
58#include "llvm/ADT/DenseSet.h"
59#include "llvm/ADT/STLExtras.h"
60#include "llvm/ADT/ScopeExit.h"
61#include "llvm/ADT/SmallVector.h"
62#include "llvm/ADT/StringRef.h"
63#include "llvm/Support/Casting.h"
64#include "llvm/Support/Error.h"
65#include "llvm/Support/ErrorHandling.h"
66#include "llvm/Support/Path.h"
67#include "llvm/Support/raw_ostream.h"
83const NamedDecl *getDefinition(
const NamedDecl *D) {
86 if (
const auto *TD = dyn_cast<TagDecl>(D))
87 return TD->getDefinition();
88 if (
const auto *VD = dyn_cast<VarDecl>(D))
89 return VD->getDefinition();
90 if (
const auto *FD = dyn_cast<FunctionDecl>(D))
91 return FD->getDefinition();
92 if (
const auto *CTD = dyn_cast<ClassTemplateDecl>(D))
93 if (
const auto *RD = CTD->getTemplatedDecl())
94 return RD->getDefinition();
95 if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
96 if (MD->isThisDeclarationADefinition())
99 auto *DeclCtx = cast<Decl>(MD->getDeclContext());
100 if (DeclCtx->isInvalidDecl())
103 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(DeclCtx))
105 return Impl->getMethod(MD->getSelector(), MD->isInstanceMethod());
107 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(D))
110 if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
111 isa<TemplateTemplateParmDecl>(D))
118 if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
119 log(
"Possible overflow in symbol location: {0}", Loc);
125 llvm::StringRef TUPath) {
130 elog(
"{0}", LSPLoc.takeError());
139 URIStorage = Loc.uri.uri();
140 SymLoc.FileURI = URIStorage.c_str();
141 SymLoc.Start.setLine(Loc.range.start.line);
142 SymLoc.Start.setColumn(Loc.range.start.character);
143 SymLoc.End.setLine(Loc.range.end.line);
144 SymLoc.End.setColumn(Loc.range.end.character);
151 std::string &Scratch) {
155 ASTSym.ID = IdxSym.ID =
SymbolID(
"mock_symbol_id");
156 ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
157 IdxSym.CanonicalDeclaration = IdxLoc;
159 return Merged.CanonicalDeclaration;
162std::vector<std::pair<const NamedDecl *, DeclRelationSet>>
163getDeclAtPositionWithRelations(
ParsedAST &
AST, SourceLocation Pos,
165 ASTNodeKind *NodeKind =
nullptr) {
166 unsigned Offset =
AST.getSourceManager().getDecomposedSpellingLoc(Pos).second;
167 std::vector<std::pair<const NamedDecl *, DeclRelationSet>> Result;
171 *NodeKind = N->ASTNode.getNodeKind();
176 if (N->ASTNode.get<Attr>() && N->Parent)
179 std::back_inserter(Result),
180 [&](
auto &Entry) { return !(Entry.second & ~Relations); });
182 return !Result.empty();
185 Offset, ResultFromTree);
189std::vector<const NamedDecl *>
191 ASTNodeKind *NodeKind =
nullptr) {
192 std::vector<const NamedDecl *> Result;
194 getDeclAtPositionWithRelations(
AST, Pos, Relations, NodeKind))
195 Result.push_back(Entry.first);
201std::optional<Location> makeLocation(
const ASTContext &
AST, SourceLocation Loc,
202 llvm::StringRef TUPath) {
203 const auto &SM =
AST.getSourceManager();
204 const auto F = SM.getFileEntryRefForID(SM.getFileID(Loc));
209 log(
"failed to get path!");
216 auto TokLen = Lexer::MeasureTokenLength(Loc, SM,
AST.getLangOpts());
218 SM, CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(TokLen)));
223std::optional<LocatedSymbol> locateFileReferent(
const Position &Pos,
225 llvm::StringRef MainFilePath) {
226 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
227 if (!Inc.Resolved.empty() && Inc.HashLine == Pos.line) {
229 File.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
230 File.PreferredDeclaration = {
232 File.Definition =
File.PreferredDeclaration;
242std::optional<LocatedSymbol>
243locateMacroReferent(
const syntax::Token &TouchedIdentifier,
ParsedAST &
AST,
244 llvm::StringRef MainFilePath) {
247 makeLocation(
AST.getASTContext(), M->NameLoc, MainFilePath)) {
249 Macro.Name = std::string(M->Name);
250 Macro.PreferredDeclaration = *Loc;
251 Macro.Definition = Loc;
272const NamedDecl *getPreferredDecl(
const NamedDecl *D) {
277 D = llvm::cast<NamedDecl>(
D->getCanonicalDecl());
280 if (
const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
281 if (
const auto *DefinitionID = ID->getDefinition())
283 if (
const auto *PD = dyn_cast<ObjCProtocolDecl>(D))
284 if (
const auto *DefinitionID = PD->getDefinition())
290std::vector<LocatedSymbol> findImplementors(llvm::DenseSet<SymbolID> IDs,
293 llvm::StringRef MainFilePath) {
294 if (IDs.empty() || !Index)
300 FindImplementorsMetric.record(1,
"find-base");
303 FindImplementorsMetric.record(1,
"find-override");
309 Req.Subjects = std::move(IDs);
310 std::vector<LocatedSymbol> Results;
315 elog(
"Find overrides: {0}", DeclLoc.takeError());
318 Results.emplace_back();
319 Results.back().Name =
Object.Name.str();
320 Results.back().PreferredDeclaration = *DeclLoc;
323 elog(
"Failed to convert location: {0}", DefLoc.takeError());
326 Results.back().Definition = *DefLoc;
333void enhanceLocatedSymbolsFromIndex(llvm::MutableArrayRef<LocatedSymbol> Result,
335 llvm::StringRef MainFilePath) {
337 llvm::DenseMap<SymbolID, unsigned> ResultIndex;
338 for (
unsigned I = 0; I < Result.size(); ++I) {
339 if (
auto ID = Result[I].ID) {
340 ResultIndex.try_emplace(ID, I);
341 QueryRequest.IDs.insert(ID);
344 if (!Index || QueryRequest.IDs.empty())
347 Index->lookup(QueryRequest, [&](
const Symbol &Sym) {
348 auto &R = Result[ResultIndex.lookup(Sym.ID)];
353 if (
auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
354 R.PreferredDeclaration = *Loc;
358 if (
auto Loc = toLSPLocation(
359 getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
363 R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
366 if (
auto Loc = toLSPLocation(
367 getPreferredLocation(R.PreferredDeclaration,
368 Sym.CanonicalDeclaration, Scratch),
370 R.PreferredDeclaration = *Loc;
375bool objcMethodIsTouched(
const SourceManager &SM,
const ObjCMethodDecl *OMD,
376 SourceLocation Loc) {
377 unsigned NumSels = OMD->getNumSelectorLocs();
378 for (
unsigned I = 0; I < NumSels; ++I)
379 if (SM.getSpellingLoc(OMD->getSelectorLoc(I)) == Loc)
388std::vector<LocatedSymbol>
389locateASTReferent(SourceLocation CurLoc,
const syntax::Token *TouchedIdentifier,
392 const SourceManager &SM =
AST.getSourceManager();
394 std::vector<LocatedSymbol> Result;
398 auto AddResultDecl = [&](
const NamedDecl *
D) {
399 D = getPreferredDecl(D);
405 Result.emplace_back();
406 Result.back().Name =
printName(
AST.getASTContext(), *D);
407 Result.back().PreferredDeclaration = *Loc;
409 if (
const NamedDecl *Def = getDefinition(D))
410 Result.back().Definition = makeLocation(
418 getDeclAtPositionWithRelations(
AST, CurLoc, Relations, &NodeKind);
419 llvm::DenseSet<SymbolID> VirtualMethods;
420 for (
const auto &E : Candidates) {
421 const NamedDecl *
D = E.first;
422 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
426 if (CMD->isPureVirtual()) {
427 if (TouchedIdentifier && SM.getSpellingLoc(CMD->getLocation()) ==
428 TouchedIdentifier->location()) {
430 LocateASTReferentMetric.record(1,
"method-to-override");
434 if (NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverrideAttr>()) ||
435 NodeKind.isSame(ASTNodeKind::getFromNodeKind<FinalAttr>())) {
437 for (
const NamedDecl *ND : CMD->overridden_methods())
448 if (
const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(D)) {
449 if (OMD->isThisDeclarationADefinition() && TouchedIdentifier &&
450 objcMethodIsTouched(SM, OMD, TouchedIdentifier->location())) {
451 llvm::SmallVector<const ObjCMethodDecl *, 4> Overrides;
452 OMD->getOverriddenMethods(Overrides);
453 if (!Overrides.empty()) {
454 for (
const auto *Override : Overrides)
455 AddResultDecl(Override);
456 LocateASTReferentMetric.record(1,
"objc-overriden-method");
470 SM.isPointWithin(TouchedIdentifier ? TouchedIdentifier->location()
472 D->getBeginLoc(),
D->getEndLoc()))
477 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
478 if (TouchedIdentifier &&
479 D->getLocation() == TouchedIdentifier->location()) {
480 LocateASTReferentMetric.record(1,
"template-specialization-to-primary");
481 AddResultDecl(CTSD->getSpecializedTemplate());
492 if (
const auto *CD = dyn_cast<ObjCCategoryDecl>(D))
493 if (
const auto *ID = CD->getClassInterface())
494 if (TouchedIdentifier &&
495 (CD->getLocation() == TouchedIdentifier->location() ||
496 ID->getName() == TouchedIdentifier->text(SM))) {
497 LocateASTReferentMetric.record(1,
"objc-category-to-class");
501 LocateASTReferentMetric.record(1,
"regular");
505 enhanceLocatedSymbolsFromIndex(Result, Index, MainFilePath);
508 Index, MainFilePath);
509 Result.insert(Result.end(), Overrides.begin(), Overrides.end());
513std::vector<LocatedSymbol> locateSymbolForType(
const ParsedAST &
AST,
514 const QualType &
Type,
516 const auto &SM =
AST.getSourceManager();
517 auto MainFilePath =
AST.tuPath();
521 auto Decls =
targetDecl(DynTypedNode::create(
Type.getNonReferenceType()),
523 AST.getHeuristicResolver());
527 std::vector<LocatedSymbol> Results;
528 const auto &ASTContext =
AST.getASTContext();
530 for (
const NamedDecl *D : Decls) {
531 D = getPreferredDecl(D);
533 auto Loc = makeLocation(ASTContext,
nameLocation(*D, SM), MainFilePath);
537 Results.emplace_back();
538 Results.back().Name =
printName(ASTContext, *D);
539 Results.back().PreferredDeclaration = *Loc;
541 if (
const NamedDecl *Def = getDefinition(D))
542 Results.back().Definition =
543 makeLocation(ASTContext,
nameLocation(*Def, SM), MainFilePath);
545 enhanceLocatedSymbolsFromIndex(Results, Index, MainFilePath);
550bool tokenSpelledAt(SourceLocation SpellingLoc,
const syntax::TokenBuffer &TB) {
551 auto ExpandedTokens = TB.expandedTokens(
552 TB.sourceManager().getMacroArgExpandedLocation(SpellingLoc));
553 return !ExpandedTokens.empty();
556llvm::StringRef sourcePrefix(SourceLocation Loc,
const SourceManager &SM) {
557 auto D = SM.getDecomposedLoc(Loc);
558 bool Invalid =
false;
559 llvm::StringRef Buf = SM.getBufferData(
D.first, &Invalid);
560 if (Invalid ||
D.second > Buf.size())
562 return Buf.substr(0,
D.second);
565bool isDependentName(ASTNodeKind NodeKind) {
566 return NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverloadExpr>()) ||
568 ASTNodeKind::getFromNodeKind<CXXDependentScopeMemberExpr>()) ||
570 ASTNodeKind::getFromNodeKind<DependentScopeDeclRefExpr>());
578 llvm::StringRef MainFilePath,
579 ASTNodeKind NodeKind) {
593 const auto &SM =
AST.getSourceManager();
607 bool TooMany =
false;
608 using ScoredLocatedSymbol = std::pair<float, LocatedSymbol>;
609 std::vector<ScoredLocatedSymbol> ScoredResults;
620 if (Sym.
SymInfo.Kind == index::SymbolKind::Constructor)
626 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
636 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
643 if (ScoredResults.size() >= 5) {
656 Relevance.
merge(Sym);
659 dlog(
"locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym.
Scope,
660 Sym.
Name, Score, Quality, Relevance);
662 ScoredResults.push_back({Score, std::move(Located)});
666 vlog(
"Heuristic index lookup for {0} returned too many candidates, ignored",
671 llvm::sort(ScoredResults,
672 [](
const ScoredLocatedSymbol &A,
const ScoredLocatedSymbol &B) {
673 return A.first > B.first;
675 std::vector<LocatedSymbol> Results;
676 for (
auto &Res : std::move(ScoredResults))
677 Results.push_back(std::move(Res.second));
679 vlog(
"No heuristic index definition for {0}", Word.
Text);
681 log(
"Found definition heuristically in index for {0}", Word.
Text);
686 const syntax::TokenBuffer &TB) {
697 const SourceManager &SM = TB.sourceManager();
701 unsigned WordLine = SM.getSpellingLineNumber(Word.
Location);
702 auto Cost = [&](SourceLocation Loc) ->
unsigned {
703 assert(SM.getFileID(Loc) ==
File &&
"spelled token in wrong file?");
704 unsigned Line = SM.getSpellingLineNumber(Loc);
705 return Line >= WordLine ? Line - WordLine : 2 * (WordLine - Line);
707 const syntax::Token *BestTok =
nullptr;
708 unsigned BestCost = -1;
712 unsigned MaxDistance =
713 1U << std::min<unsigned>(Word.
Text.size(),
714 std::numeric_limits<unsigned>::digits - 1);
721 WordLine + 1 <= MaxDistance / 2 ? 1 : WordLine + 1 - MaxDistance / 2;
722 unsigned LineMax = WordLine + 1 + MaxDistance;
723 SourceLocation LocMin = SM.translateLineCol(
File, LineMin, 1);
724 assert(LocMin.isValid());
725 SourceLocation LocMax = SM.translateLineCol(
File, LineMax, 1);
726 assert(LocMax.isValid());
730 auto Consider = [&](
const syntax::Token &Tok) {
731 if (Tok.location() < LocMin || Tok.location() > LocMax)
733 if (!(Tok.kind() == tok::identifier && Tok.text(SM) == Word.
Text))
736 if (Tok.location() == Word.
Location)
739 unsigned TokCost = Cost(Tok.location());
740 if (TokCost >= BestCost)
744 if (!(tokenSpelledAt(Tok.location(), TB) || TB.expansionStartingAt(&Tok)))
751 auto SpelledTokens = TB.spelledTokens(
File);
753 auto *I = llvm::partition_point(SpelledTokens, [&](
const syntax::Token &T) {
754 assert(SM.getFileID(T.location()) == SM.getFileID(Word.
Location));
755 return T.location() < Word.
Location;
758 for (
const syntax::Token &Tok : llvm::ArrayRef(I, SpelledTokens.end()))
762 for (
const syntax::Token &Tok :
763 llvm::reverse(llvm::ArrayRef(SpelledTokens.begin(), I)))
769 "Word {0} under cursor {1} isn't a token (after PP), trying nearby {2}",
771 BestTok->location().printToString(SM));
778 const auto &SM =
AST.getSourceManager();
779 auto MainFilePath =
AST.tuPath();
781 if (
auto File = locateFileReferent(Pos,
AST, MainFilePath))
782 return {std::move(*
File)};
786 elog(
"locateSymbolAt failed to convert position to source location: {0}",
791 const syntax::Token *TouchedIdentifier =
nullptr;
792 auto TokensTouchingCursor =
793 syntax::spelledTokensTouching(*CurLoc,
AST.getTokens());
794 for (
const syntax::Token &Tok : TokensTouchingCursor) {
795 if (Tok.kind() == tok::identifier) {
796 if (
auto Macro = locateMacroReferent(Tok,
AST, MainFilePath))
800 return {*std::move(
Macro)};
802 TouchedIdentifier = &Tok;
806 if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
812 auto LocSym = locateSymbolForType(
AST, *
Deduced, Index);
819 ASTNodeKind NodeKind;
820 auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier,
AST,
821 MainFilePath, Index, NodeKind);
822 if (!ASTResults.empty())
830 if (
const syntax::Token *NearbyIdent =
832 if (
auto Macro = locateMacroReferent(*NearbyIdent,
AST, MainFilePath)) {
833 log(
"Found macro definition heuristically using nearby identifier {0}",
835 return {*std::move(
Macro)};
837 ASTResults = locateASTReferent(NearbyIdent->location(), NearbyIdent,
AST,
838 MainFilePath, Index, NodeKind);
839 if (!ASTResults.empty()) {
840 log(
"Found definition heuristically using nearby identifier {0}",
841 NearbyIdent->text(SM));
844 vlog(
"No definition found using nearby identifier {0} at {1}", Word->Text,
845 Word->Location.printToString(SM));
848 auto TextualResults =
850 if (!TextualResults.empty())
851 return TextualResults;
858 const auto &SM =
AST.getSourceManager();
860 std::vector<DocumentLink> Result;
861 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
862 if (Inc.Resolved.empty())
866 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
870 const auto *HashTok =
AST.getTokens().spelledTokenContaining(HashLoc);
871 assert(HashTok &&
"got inclusion at wrong offset");
872 const auto *IncludeTok = std::next(HashTok);
873 const auto *FileTok = std::next(IncludeTok);
881 CharSourceRange FileRange;
883 if (FileTok->kind() == tok::TokenKind::less) {
887 syntax::FileRange(SM, FileTok->location(), Inc.Written.length())
889 }
else if (FileTok->kind() == tok::TokenKind::string_literal) {
892 FileRange = FileTok->range(SM).toCharRange(SM);
903 FileRange = FileTok->range(SM).toCharRange(SM);
917class ReferenceFinder :
public index::IndexDataConsumer {
920 syntax::Token SpelledTok;
921 index::SymbolRoleSet Role;
922 const Decl *Container;
924 Range range(
const SourceManager &SM)
const {
929 ReferenceFinder(ParsedAST &AST,
930 const llvm::ArrayRef<const NamedDecl *> Targets,
932 : PerToken(PerToken), AST(AST) {
933 for (
const NamedDecl *ND : Targets) {
934 TargetDecls.insert(ND->getCanonicalDecl());
935 if (
auto *
Constructor = llvm::dyn_cast<clang::CXXConstructorDecl>(ND))
940 std::vector<Reference> take() && {
941 llvm::sort(References, [](
const Reference &L,
const Reference &R) {
942 auto LTok = L.SpelledTok.location();
943 auto RTok = R.SpelledTok.location();
944 return std::tie(LTok, L.Role) < std::tie(RTok, R.Role);
947 References.erase(llvm::unique(References,
948 [](
const Reference &L,
const Reference &R) {
949 auto LTok = L.SpelledTok.location();
950 auto RTok = R.SpelledTok.location();
951 return std::tie(LTok, L.Role) ==
952 std::tie(RTok, R.Role);
955 return std::move(References);
958 bool forwardsToConstructor(
const Decl *D) {
959 if (TargetConstructors.empty())
961 auto *FD = llvm::dyn_cast<clang::FunctionDecl>(D);
962 if (FD ==
nullptr || !FD->isTemplateInstantiation())
965 SmallVector<const CXXConstructorDecl *, 1> *Constructors =
nullptr;
966 if (
auto Entry = AST.ForwardingToConstructorCache.find(FD);
967 Entry != AST.ForwardingToConstructorCache.end())
968 Constructors = &Entry->getSecond();
969 if (Constructors ==
nullptr) {
970 if (
auto *PT = FD->getPrimaryTemplate();
974 SmallVector<const CXXConstructorDecl *, 1> FoundConstructors =
976 auto Iter = AST.ForwardingToConstructorCache.try_emplace(
977 FD, std::move(FoundConstructors));
978 Constructors = &Iter.first->getSecond();
987 handleDeclOccurrence(
const Decl *D, index::SymbolRoleSet Roles,
988 llvm::ArrayRef<index::SymbolRelation>
Relations,
990 index::IndexDataConsumer::ASTNodeInfo ASTNode)
override {
991 if (!TargetDecls.contains(
D->getCanonicalDecl()) &&
992 !forwardsToConstructor(ASTNode.OrigD))
994 const SourceManager &SM = AST.getSourceManager();
997 const auto &TB = AST.getTokens();
999 llvm::SmallVector<SourceLocation, 1> Locs;
1003 if (
auto *OME = llvm::dyn_cast_or_null<ObjCMessageExpr>(ASTNode.OrigE)) {
1004 OME->getSelectorLocs(Locs);
1005 }
else if (
auto *OMD =
1006 llvm::dyn_cast_or_null<ObjCMethodDecl>(ASTNode.OrigD)) {
1007 OMD->getSelectorLocs(Locs);
1011 if (!Locs.empty() && Locs.front() != Loc)
1015 Locs.push_back(Loc);
1017 SymbolCollector::Options CollectorOpts;
1018 CollectorOpts.CollectMainFileSymbols =
true;
1019 for (SourceLocation L : Locs) {
1020 L = SM.getFileLoc(L);
1021 if (
const auto *Tok = TB.spelledTokenContaining(L))
1022 References.push_back(
1031 std::vector<Reference> References;
1033 llvm::DenseSet<const Decl *> TargetDecls;
1035 llvm::DenseSet<const CXXConstructorDecl *> TargetConstructors;
1038std::vector<ReferenceFinder::Reference>
1039findRefs(
const llvm::ArrayRef<const NamedDecl *> TargetDecls,
ParsedAST &
AST,
1041 ReferenceFinder RefFinder(
AST, TargetDecls, PerToken);
1042 index::IndexingOptions IndexOpts;
1043 IndexOpts.SystemSymbolFilter =
1044 index::IndexingOptions::SystemSymbolFilterKind::All;
1045 IndexOpts.IndexFunctionLocals =
true;
1046 IndexOpts.IndexParametersInDeclarations =
true;
1047 IndexOpts.IndexTemplateParameters =
true;
1048 indexTopLevelDecls(
AST.getASTContext(),
AST.getPreprocessor(),
1049 AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
1050 return std::move(RefFinder).take();
1053const Stmt *getFunctionBody(DynTypedNode N) {
1054 if (
const auto *FD = N.get<FunctionDecl>())
1055 return FD->getBody();
1056 if (
const auto *FD = N.get<BlockDecl>())
1057 return FD->getBody();
1058 if (
const auto *FD = N.get<LambdaExpr>())
1059 return FD->getBody();
1060 if (
const auto *FD = N.get<ObjCMethodDecl>())
1061 return FD->getBody();
1065const Stmt *getLoopBody(DynTypedNode N) {
1066 if (
const auto *LS = N.get<ForStmt>())
1067 return LS->getBody();
1068 if (
const auto *LS = N.get<CXXForRangeStmt>())
1069 return LS->getBody();
1070 if (
const auto *LS = N.get<WhileStmt>())
1071 return LS->getBody();
1072 if (
const auto *LS = N.get<DoStmt>())
1073 return LS->getBody();
1080class FindControlFlow :
public RecursiveASTVisitor<FindControlFlow> {
1089 All = Break | Continue | Return | Case | Throw | Goto,
1093 std::vector<SourceLocation> &Result;
1094 const SourceManager &SM;
1098 template <
typename Func>
1099 bool filterAndTraverse(DynTypedNode D,
const Func &Delegate) {
1100 llvm::scope_exit RestoreIgnore(
1101 [OldIgnore(Ignore),
this] { Ignore = OldIgnore; });
1102 if (getFunctionBody(D))
1104 else if (getLoopBody(D))
1105 Ignore |= Continue | Break;
1106 else if (
D.get<SwitchStmt>())
1107 Ignore |= Break | Case;
1109 return (Ignore == All) ? true : Delegate();
1112 void found(Target T, SourceLocation Loc) {
1115 if (SM.isBeforeInTranslationUnit(Loc, Bounds.getBegin()) ||
1116 SM.isBeforeInTranslationUnit(Bounds.getEnd(), Loc))
1118 Result.push_back(Loc);
1122 FindControlFlow(SourceRange Bounds, std::vector<SourceLocation> &Result,
1123 const SourceManager &SM)
1124 : Bounds(Bounds), Result(Result), SM(SM) {}
1128 bool TraverseDecl(Decl *D) {
1129 return !
D || filterAndTraverse(DynTypedNode::create(*D), [&] {
1130 return RecursiveASTVisitor::TraverseDecl(D);
1133 bool TraverseStmt(Stmt *S) {
1134 return !S || filterAndTraverse(DynTypedNode::create(*S), [&] {
1135 return RecursiveASTVisitor::TraverseStmt(S);
1140 bool VisitReturnStmt(ReturnStmt *R) {
1141 found(Return, R->getReturnLoc());
1144 bool VisitBreakStmt(BreakStmt *B) {
1145 found(Break,
B->getKwLoc());
1148 bool VisitContinueStmt(ContinueStmt *C) {
1149 found(Continue,
C->getKwLoc());
1152 bool VisitSwitchCase(SwitchCase *C) {
1153 found(Case,
C->getKeywordLoc());
1156 bool VisitCXXThrowExpr(CXXThrowExpr *T) {
1157 found(Throw,
T->getThrowLoc());
1160 bool VisitGotoStmt(GotoStmt *G) {
1162 if (
const auto *LD = G->getLabel()) {
1163 if (SM.isBeforeInTranslationUnit(LD->getLocation(), Bounds.getBegin()) ||
1164 SM.isBeforeInTranslationUnit(Bounds.getEnd(), LD->getLocation()))
1165 found(Goto, G->getGotoLoc());
1174SourceRange findCaseBounds(
const SwitchStmt &Switch, SourceLocation Loc,
1175 const SourceManager &SM) {
1178 std::vector<const SwitchCase *> Cases;
1179 for (
const SwitchCase *Case = Switch.getSwitchCaseList(); Case;
1180 Case = Case->getNextSwitchCase())
1181 Cases.push_back(Case);
1182 llvm::sort(Cases, [&](
const SwitchCase *L,
const SwitchCase *R) {
1183 return SM.isBeforeInTranslationUnit(L->getKeywordLoc(), R->getKeywordLoc());
1187 auto CaseAfter = llvm::partition_point(Cases, [&](
const SwitchCase *C) {
1188 return !SM.isBeforeInTranslationUnit(Loc,
C->getKeywordLoc());
1190 SourceLocation End = CaseAfter == Cases.end() ? Switch.getEndLoc()
1191 : (*CaseAfter)->getKeywordLoc();
1194 if (CaseAfter == Cases.begin())
1195 return SourceRange(Switch.getBeginLoc(), End);
1197 auto CaseBefore = std::prev(CaseAfter);
1199 while (CaseBefore != Cases.begin() &&
1200 (*std::prev(CaseBefore))->getSubStmt() == *CaseBefore)
1202 return SourceRange((*CaseBefore)->getKeywordLoc(), End);
1213 const SourceManager &SM =
1214 N.getDeclContext().getParentASTContext().getSourceManager();
1215 std::vector<SourceLocation> Result;
1218 enum class Cur {
None, Break, Continue, Return, Case, Throw } Cursor;
1219 if (N.ASTNode.get<BreakStmt>()) {
1220 Cursor = Cur::Break;
1221 }
else if (N.ASTNode.get<ContinueStmt>()) {
1222 Cursor = Cur::Continue;
1223 }
else if (N.ASTNode.get<ReturnStmt>()) {
1224 Cursor = Cur::Return;
1225 }
else if (N.ASTNode.get<CXXThrowExpr>()) {
1226 Cursor = Cur::Throw;
1227 }
else if (N.ASTNode.get<SwitchCase>()) {
1229 }
else if (
const GotoStmt *GS = N.ASTNode.get<GotoStmt>()) {
1231 Result.push_back(GS->getGotoLoc());
1232 if (
const auto *LD = GS->getLabel())
1233 Result.push_back(LD->getLocation());
1239 const Stmt *Root =
nullptr;
1242 for (
const auto *P = &N;
P;
P =
P->Parent) {
1244 if (
const Stmt *FunctionBody = getFunctionBody(
P->ASTNode)) {
1245 if (Cursor == Cur::Return || Cursor == Cur::Throw) {
1246 Root = FunctionBody;
1251 if (
const Stmt *LoopBody = getLoopBody(
P->ASTNode)) {
1252 if (Cursor == Cur::None || Cursor == Cur::Break ||
1253 Cursor == Cur::Continue) {
1257 Result.push_back(
P->ASTNode.getSourceRange().getBegin());
1264 if (
const auto *SS =
P->ASTNode.get<SwitchStmt>()) {
1265 if (Cursor == Cur::Break || Cursor == Cur::Case) {
1266 Result.push_back(SS->getSwitchLoc());
1267 Root = SS->getBody();
1269 Bounds = findCaseBounds(*SS, N.ASTNode.getSourceRange().getBegin(), SM);
1274 if (Cursor == Cur::None)
1278 if (!Bounds.isValid())
1279 Bounds = Root->getSourceRange();
1280 FindControlFlow(Bounds, Result, SM).TraverseStmt(
const_cast<Stmt *
>(Root));
1286 const SourceManager &SM) {
1289 if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
1291 else if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
1298std::optional<DocumentHighlight> toHighlight(SourceLocation Loc,
1299 const syntax::TokenBuffer &TB) {
1300 Loc = TB.sourceManager().getFileLoc(Loc);
1301 if (
const auto *Tok = TB.spelledTokenContaining(Loc)) {
1305 CharSourceRange::getCharRange(Tok->location(), Tok->endLocation()));
1308 return std::nullopt;
1315 const SourceManager &SM =
AST.getSourceManager();
1319 llvm::consumeError(CurLoc.takeError());
1322 std::vector<DocumentHighlight> Result;
1328 targetDecl(N->ASTNode, Relations,
AST.getHeuristicResolver());
1329 if (!TargetDecls.empty()) {
1332 for (
const auto &
Ref : findRefs(TargetDecls,
AST,
true))
1333 Result.push_back(toHighlight(
Ref, SM));
1336 auto ControlFlow = relatedControlFlow(*N);
1337 if (!ControlFlow.empty()) {
1338 for (SourceLocation Loc : ControlFlow)
1339 if (
auto Highlight = toHighlight(Loc,
AST.getTokens()))
1340 Result.push_back(std::move(*Highlight));
1348 AST.getSourceManager().getDecomposedSpellingLoc(*CurLoc).second;
1361 const SourceManager &SM =
AST.getSourceManager();
1364 elog(
"Failed to convert position to source location: {0}",
1365 CurLoc.takeError());
1370 llvm::DenseSet<SymbolID> IDs;
1372 for (
const NamedDecl *ND : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1373 if (
const auto *CXXMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1374 if (CXXMD->isVirtual()) {
1378 }
else if (
const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
1381 }
else if (
const auto *OMD = dyn_cast<ObjCMethodDecl>(ND)) {
1384 }
else if (
const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) {
1389 return findImplementors(std::move(IDs), QueryKind, Index,
AST.tuPath());
1395void getOverriddenMethods(
const CXXMethodDecl *CMD,
1396 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1399 for (
const CXXMethodDecl *Base : CMD->overridden_methods()) {
1401 OverriddenMethods.insert(ID);
1402 getOverriddenMethods(Base, OverriddenMethods);
1408void getOverriddenMethods(
const ObjCMethodDecl *OMD,
1409 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1412 llvm::SmallVector<const ObjCMethodDecl *, 4> Overrides;
1413 OMD->getOverriddenMethods(Overrides);
1414 for (
const ObjCMethodDecl *Base : Overrides) {
1416 OverriddenMethods.insert(ID);
1417 getOverriddenMethods(Base, OverriddenMethods);
1421std::optional<std::string>
1422stringifyContainerForMainFileRef(
const Decl *Container) {
1425 if (
auto *ND = llvm::dyn_cast_if_present<NamedDecl>(Container))
1430std::optional<ReferencesResult>
1433 const auto &Includes =
AST.getIncludeStructure().MainFileIncludes;
1434 auto IncludeOnLine = llvm::find_if(Includes, [&Pos](
const Inclusion &Inc) {
1435 return Inc.HashLine == Pos.line;
1437 if (IncludeOnLine == Includes.end())
1438 return std::nullopt;
1440 const SourceManager &SM =
AST.getSourceManager();
1443 include_cleaner::walkUsed(
1445 &
AST.getPragmaIncludes(),
AST.getPreprocessor(),
1446 [&](
const include_cleaner::SymbolReference &
Ref,
1447 llvm::ArrayRef<include_cleaner::Header> Providers) {
1448 if (Ref.RT != include_cleaner::RefType::Explicit ||
1449 !isPreferredProvider(*IncludeOnLine, Converted, Providers))
1452 auto Loc = SM.getFileLoc(Ref.RefLocation);
1455 while (SM.getFileID(Loc) != SM.getMainFileID())
1456 Loc = SM.getIncludeLoc(SM.getFileID(Loc));
1458 ReferencesResult::Reference Result;
1459 const auto *Token = AST.getTokens().spelledTokenContaining(Loc);
1460 assert(Token &&
"references expected token here");
1461 Result.Loc.range = Range{sourceLocToPosition(SM, Token->location()),
1462 sourceLocToPosition(SM, Token->endLocation())};
1463 Result.Loc.uri = URIMainFile;
1464 Results.References.push_back(std::move(Result));
1466 if (Results.References.empty())
1467 return std::nullopt;
1472 IncludeOnLine->HashOffset);
1473 Result.Loc.uri = URIMainFile;
1474 Results.References.push_back(std::move(Result));
1482 const SourceManager &SM =
AST.getSourceManager();
1483 auto MainFilePath =
AST.tuPath();
1487 llvm::consumeError(CurLoc.takeError());
1491 const auto IncludeReferences =
1492 maybeFindIncludeReferences(
AST, Pos, URIMainFile);
1493 if (IncludeReferences)
1494 return *IncludeReferences;
1496 llvm::DenseSet<SymbolID> IDsToQuery, OverriddenMethods;
1498 const auto *IdentifierAtCursor =
1499 syntax::spelledIdentifierTouching(*CurLoc,
AST.getTokens());
1500 std::optional<DefinedMacro>
Macro;
1501 if (IdentifierAtCursor)
1507 const auto &IDToRefs =
AST.getMacros().MacroRefs;
1508 auto Refs = IDToRefs.find(MacroSID);
1509 if (Refs != IDToRefs.end()) {
1510 for (
const auto &
Ref : Refs->second) {
1513 Result.
Loc.
uri = URIMainFile;
1514 if (
Ref.IsDefinition) {
1518 Results.
References.push_back(std::move(Result));
1521 IDsToQuery.insert(MacroSID);
1528 std::vector<const NamedDecl *> Decls =
1529 getDeclAtPosition(
AST, *CurLoc, Relations);
1530 llvm::SmallVector<const NamedDecl *> TargetsInMainFile;
1531 for (
const NamedDecl *D : Decls) {
1535 TargetsInMainFile.push_back(D);
1539 if (D->getParentFunctionOrMethod())
1541 IDsToQuery.insert(ID);
1547 for (
const NamedDecl *ND : Decls) {
1550 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1551 if (CMD->isVirtual()) {
1554 getOverriddenMethods(CMD, OverriddenMethods);
1559 if (
const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(ND)) {
1561 getOverriddenMethods(OMD, OverriddenMethods);
1567 auto MainFileRefs = findRefs(TargetsInMainFile,
AST,
false);
1571 MainFileRefs.erase(llvm::unique(MainFileRefs,
1572 [](
const ReferenceFinder::Reference &L,
1573 const ReferenceFinder::Reference &R) {
1574 return L.SpelledTok.location() ==
1575 R.SpelledTok.location();
1577 MainFileRefs.end());
1578 for (
const auto &
Ref : MainFileRefs) {
1581 Result.
Loc.
uri = URIMainFile;
1585 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Declaration))
1588 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Definition))
1591 Results.
References.push_back(std::move(Result));
1599 llvm::DenseMap<SymbolID, size_t> RefIndexForContainer;
1602 if (Limit && Results.
References.size() >= Limit) {
1606 const auto LSPLocDecl =
1607 toLSPLocation(
Object.CanonicalDeclaration, MainFilePath);
1608 const auto LSPLocDef = toLSPLocation(
Object.Definition, MainFilePath);
1609 if (LSPLocDecl && LSPLocDecl != LSPLocDef) {
1611 Result.
Loc = {std::move(*LSPLocDecl), std::nullopt};
1616 Results.
References.push_back(std::move(Result));
1620 Result.
Loc = {std::move(*LSPLocDef), std::nullopt};
1626 Results.
References.push_back(std::move(Result));
1630 if (!ContainerLookup.
IDs.empty() && AddContext)
1631 Index->
lookup(ContainerLookup, [&](
const Symbol &Container) {
1632 auto Ref = RefIndexForContainer.find(Container.ID);
1633 assert(
Ref != RefIndexForContainer.end());
1635 Container.Scope.str() + Container.Name.str();
1640 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs,
bool AllowAttributes,
1641 bool AllowMainFileSymbols) {
1642 if (IDs.empty() || !Index || Results.
HasMore)
1645 Req.
IDs = std::move(IDs);
1657 llvm::DenseMap<SymbolID, std::vector<size_t>> RefIndicesForContainer;
1659 auto LSPLoc = toLSPLocation(R.
Location, MainFilePath);
1662 (!AllowMainFileSymbols && LSPLoc->uri.file() == MainFilePath))
1665 Result.
Loc = {std::move(*LSPLoc), std::nullopt};
1666 if (AllowAttributes) {
1676 ContainerLookup.
IDs.insert(Container);
1677 RefIndicesForContainer[Container].push_back(Results.
References.size());
1679 Results.
References.push_back(std::move(Result));
1682 if (!ContainerLookup.
IDs.empty() && AddContext)
1683 Index->
lookup(ContainerLookup, [&](
const Symbol &Container) {
1684 auto Ref = RefIndicesForContainer.find(Container.ID);
1685 assert(
Ref != RefIndicesForContainer.end());
1686 auto ContainerName = Container.Scope.str() + Container.Name.str();
1687 for (
auto I :
Ref->getSecond()) {
1688 Results.
References[I].Loc.containerName = ContainerName;
1692 QueryIndex(std::move(IDsToQuery),
true,
1697 QueryIndex(std::move(OverriddenMethods),
false,
1703 const SourceManager &SM =
AST.getSourceManager();
1706 llvm::consumeError(CurLoc.takeError());
1709 auto MainFilePath =
AST.tuPath();
1710 std::vector<SymbolDetails> Results;
1716 for (
const NamedDecl *D : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1717 D = getPreferredDecl(D);
1723 NewSymbol.
name = std::string(SplitQName.second);
1726 if (
const auto *ParentND =
1727 dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
1730 llvm::SmallString<32> USR;
1731 if (!index::generateUSRForDecl(D, USR)) {
1732 NewSymbol.
USR = std::string(USR);
1735 if (
const NamedDecl *Def = getDefinition(D))
1739 makeLocation(
AST.getASTContext(),
nameLocation(*D, SM), MainFilePath);
1741 Results.push_back(std::move(NewSymbol));
1744 const auto *IdentifierAtCursor =
1745 syntax::spelledIdentifierTouching(*CurLoc,
AST.getTokens());
1746 if (!IdentifierAtCursor)
1751 NewMacro.
name = std::string(M->Name);
1752 llvm::SmallString<32> USR;
1753 if (!index::generateUSRForMacro(NewMacro.
name, M->Info->getDefinitionLoc(),
1755 NewMacro.
USR = std::string(USR);
1758 Results.push_back(std::move(NewMacro));
1779 OS <<
" [override]";
1783template <
typename HierarchyItem>
1784static std::optional<HierarchyItem>
1786 ASTContext &Ctx = ND.getASTContext();
1787 auto &SM = Ctx.getSourceManager();
1788 SourceLocation NameLoc =
nameLocation(ND, Ctx.getSourceManager());
1789 SourceLocation BeginLoc = SM.getFileLoc(ND.getBeginLoc());
1790 SourceLocation EndLoc = SM.getFileLoc(ND.getEndLoc());
1791 const auto DeclRange =
1794 return std::nullopt;
1795 const auto FE = SM.getFileEntryRefForID(SM.getFileID(NameLoc));
1797 return std::nullopt;
1800 return std::nullopt;
1804 SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
1806 index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
1817 HI.selectionRange =
Range{NameBegin, NameEnd};
1818 if (!HI.range.contains(HI.selectionRange)) {
1821 HI.range = HI.selectionRange;
1829static std::optional<TypeHierarchyItem>
1833 Result->deprecated = ND.isDeprecated();
1843static std::optional<CallHierarchyItem>
1848 if (ND.isDeprecated())
1851 Result->data = ID.str();
1855template <
typename HierarchyItem>
1860 elog(
"Failed to convert symbol to hierarchy item: {0}", Loc.takeError());
1861 return std::nullopt;
1864 HI.name = std::string(S.
Name);
1867 HI.selectionRange = Loc->range;
1870 HI.range = HI.selectionRange;
1876static std::optional<TypeHierarchyItem>
1881 Result->data.symbolID = S.
ID;
1886static std::optional<CallHierarchyItem>
1891 Result->data = S.
ID.
str();
1898 std::vector<TypeHierarchyItem> &SubTypes,
1904 if (std::optional<TypeHierarchyItem> ChildSym =
1907 ChildSym->children.emplace();
1910 SubTypes.emplace_back(std::move(*ChildSym));
1928 auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD :
nullptr;
1930 if (!RPSet.insert(Pattern).second) {
1935 for (
const CXXRecordDecl *ParentDecl :
typeParents(&CXXRD)) {
1936 if (std::optional<TypeHierarchyItem> ParentSym =
1940 Item.
parents->emplace_back(std::move(*ParentSym));
1945 RPSet.erase(Pattern);
1952 std::vector<const CXXRecordDecl *> Records;
1961 AST.getHeuristicResolver());
1962 for (
const NamedDecl *D : Decls) {
1964 if (
const VarDecl *VD = dyn_cast<VarDecl>(D)) {
1966 if (
const auto *RD = VD->getType().getTypePtr()->getAsCXXRecordDecl())
1967 Records.push_back(RD);
1971 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(D)) {
1973 Records.push_back(
Method->getParent());
1981 if (
auto *RD = dyn_cast<CXXRecordDecl>(D))
1982 Records.push_back(RD);
1987 const SourceManager &SM =
AST.getSourceManager();
1988 std::vector<const CXXRecordDecl *> Result;
1991 llvm::consumeError(Offset.takeError());
1996 Result = RecordFromNode(ST.commonAncestor());
1997 return !Result.empty();
2004static QualType
typeForNode(
const ASTContext &Ctx,
const HeuristicResolver *H,
2008 while (N && N->
ASTNode.get<NestedNameSpecifierLoc>())
2014 if (
const TypeLoc *TL = N->
ASTNode.get<TypeLoc>()) {
2015 if (llvm::isa<DeducedType>(TL->getTypePtr()))
2017 N->
getDeclContext().getParentASTContext(), H, TL->getBeginLoc()))
2020 if (llvm::isa<TypedefType>(TL->getTypePtr()))
2021 return TL->getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
2022 return TL->getType();
2026 if (
const auto *CCI = N->
ASTNode.get<CXXCtorInitializer>()) {
2027 if (
const FieldDecl *FD = CCI->getAnyMember())
2028 return FD->getType();
2029 if (
const Type *Base = CCI->getBaseClass())
2030 return QualType(Base, 0);
2034 if (
const auto *CBS = N->
ASTNode.get<CXXBaseSpecifier>())
2035 return CBS->getType();
2037 if (
const Decl *D = N->
ASTNode.get<Decl>()) {
2038 struct Visitor : ConstDeclVisitor<Visitor, QualType> {
2039 const ASTContext &Ctx;
2040 Visitor(
const ASTContext &Ctx) : Ctx(Ctx) {}
2042 QualType VisitValueDecl(
const ValueDecl *D) {
return D->getType(); }
2044 QualType VisitTypeDecl(
const TypeDecl *D) {
2045 return Ctx.getTypeDeclType(D);
2048 QualType VisitTypedefNameDecl(
const TypedefNameDecl *D) {
2049 return D->getUnderlyingType();
2052 QualType VisitTemplateDecl(
const TemplateDecl *D) {
2053 return Visit(D->getTemplatedDecl());
2059 if (
const Stmt *S = N->
ASTNode.get<Stmt>()) {
2060 struct Visitor : ConstStmtVisitor<Visitor, QualType> {
2062 QualType type(
const Stmt *S) {
return S ? Visit(S) : QualType(); }
2065 QualType VisitExpr(
const Expr *S) {
2066 return S->IgnoreImplicitAsWritten()->getType();
2068 QualType VisitMemberExpr(
const MemberExpr *S) {
2070 if (S->getType()->isSpecificBuiltinType(BuiltinType::BoundMember))
2071 return Expr::findBoundMemberType(S);
2072 return VisitExpr(S);
2075 QualType VisitCXXDeleteExpr(
const CXXDeleteExpr *S) {
2076 return S->getDestroyedType();
2078 QualType VisitCXXPseudoDestructorExpr(
const CXXPseudoDestructorExpr *S) {
2079 return S->getDestroyedType();
2081 QualType VisitCXXThrowExpr(
const CXXThrowExpr *S) {
2082 return S->getSubExpr()->getType();
2084 QualType VisitCoyieldExpr(
const CoyieldExpr *S) {
2085 return type(S->getOperand());
2088 QualType VisitDesignatedInitExpr(
const DesignatedInitExpr *S) {
2090 for (
auto &D : llvm::reverse(S->designators()))
2091 if (D.isFieldDesignator())
2092 if (
const auto *FD = D.getFieldDecl())
2093 return FD->getType();
2098 QualType VisitSwitchStmt(
const SwitchStmt *S) {
2099 return type(S->getCond());
2101 QualType VisitWhileStmt(
const WhileStmt *S) {
return type(S->getCond()); }
2102 QualType VisitDoStmt(
const DoStmt *S) {
return type(S->getCond()); }
2103 QualType VisitIfStmt(
const IfStmt *S) {
return type(S->getCond()); }
2104 QualType VisitCaseStmt(
const CaseStmt *S) {
return type(S->getLHS()); }
2105 QualType VisitCXXForRangeStmt(
const CXXForRangeStmt *S) {
2106 return S->getLoopVariable()->getType();
2108 QualType VisitReturnStmt(
const ReturnStmt *S) {
2109 return type(S->getRetValue());
2111 QualType VisitCoreturnStmt(
const CoreturnStmt *S) {
2112 return type(S->getOperand());
2114 QualType VisitCXXCatchStmt(
const CXXCatchStmt *S) {
2115 return S->getCaughtType();
2117 QualType VisitObjCAtThrowStmt(
const ObjCAtThrowStmt *S) {
2118 return type(S->getThrowExpr());
2120 QualType VisitObjCAtCatchStmt(
const ObjCAtCatchStmt *S) {
2121 return S->getCatchParamDecl() ? S->getCatchParamDecl()->getType()
2134 QualType T,
const HeuristicResolver* H, llvm::SmallVector<QualType>& Out) {
2139 if (
const auto* TDT = T->getAs<TypedefType>())
2140 return Out.push_back(QualType(TDT, 0));
2143 if (
const auto *PT = T->getAs<PointerType>())
2145 if (
const auto *RT = T->getAs<ReferenceType>())
2147 if (
const auto *AT = T->getAsArrayTypeUnsafe())
2151 if (
auto *FT = T->getAs<FunctionType>())
2153 if (
auto *CRD = T->getAsCXXRecordDecl()) {
2154 if (CRD->isLambda())
2155 return unwrapFindType(CRD->getLambdaCallOperator()->getReturnType(), H,
2163 if (
auto PointeeType = H->getPointeeType(T.getNonReferenceType());
2164 !PointeeType.isNull()) {
2166 return Out.push_back(T);
2169 return Out.push_back(T);
2174 QualType T,
const HeuristicResolver* H) {
2175 llvm::SmallVector<QualType> Result;
2182 const SourceManager &SM =
AST.getSourceManager();
2184 std::vector<LocatedSymbol> Result;
2186 elog(
"failed to convert position {0} for findTypes: {1}", Pos,
2187 Offset.takeError());
2191 auto SymbolsFromNode =
2193 std::vector<LocatedSymbol> LocatedSymbols;
2201 AST.getHeuristicResolver()))
2202 llvm::copy(locateSymbolForType(
AST,
Type, Index),
2203 std::back_inserter(LocatedSymbols));
2205 return LocatedSymbols;
2209 Result = SymbolsFromNode(ST.commonAncestor());
2210 return !Result.empty();
2215std::vector<const CXXRecordDecl *>
typeParents(
const CXXRecordDecl *CXXRD) {
2216 std::vector<const CXXRecordDecl *> Result;
2220 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
2221 if (CTSD->isInvalidDecl())
2222 CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
2226 if (!CXXRD->hasDefinition())
2229 for (
auto Base : CXXRD->bases()) {
2230 const CXXRecordDecl *ParentDecl =
nullptr;
2232 const Type *
Type = Base.getType().getTypePtr();
2233 if (
const RecordType *RT =
Type->getAs<RecordType>()) {
2234 ParentDecl = RT->getAsCXXRecordDecl();
2240 if (
const TemplateSpecializationType *TS =
2241 Type->getAs<TemplateSpecializationType>()) {
2242 TemplateName TN = TS->getTemplateName();
2243 if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
2244 ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
2250 Result.push_back(ParentDecl);
2256std::vector<TypeHierarchyItem>
2260 std::vector<TypeHierarchyItem> Results;
2274 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
2275 CXXRD = CTSD->getTemplateInstantiationPattern();
2278 std::optional<TypeHierarchyItem> Result =
2286 if (WantChildren && ResolveLevels > 0) {
2287 Result->children.emplace();
2291 fillSubTypes(ID, *Result->children, Index, ResolveLevels, TUPath);
2294 Results.emplace_back(std::move(*Result));
2300std::optional<std::vector<TypeHierarchyItem>>
2302 std::vector<TypeHierarchyItem> Results;
2304 return std::nullopt;
2308 llvm::DenseMap<SymbolID, const TypeHierarchyItem::ResolveParams *> IDToData;
2310 Req.
IDs.insert(Parent.symbolID);
2311 IDToData[Parent.symbolID] = &Parent;
2313 Index->
lookup(Req, [&Item, &Results, &IDToData](
const Symbol &S) {
2315 THI->data = *IDToData.lookup(S.
ID);
2316 Results.emplace_back(std::move(*THI));
2324 std::vector<TypeHierarchyItem> Results;
2326 for (
auto &ChildSym : Results)
2327 ChildSym.data.parents = {Item.
data};
2345std::vector<CallHierarchyItem>
2347 std::vector<CallHierarchyItem> Result;
2348 const auto &SM =
AST.getSourceManager();
2351 elog(
"prepareCallHierarchy failed to convert position to source location: "
2356 for (
const NamedDecl *Decl : getDeclAtPosition(
AST, *Loc, {})) {
2357 if (!(isa<DeclContext>(Decl) &&
2358 cast<DeclContext>(Decl)->isFunctionOrMethod()) &&
2359 Decl->getKind() != Decl::Kind::FunctionTemplate &&
2360 !(Decl->getKind() == Decl::Kind::Var &&
2361 !cast<VarDecl>(Decl)->isLocalVarDecl()) &&
2362 Decl->getKind() != Decl::Kind::Field &&
2363 Decl->getKind() != Decl::Kind::EnumConstant)
2366 Result.emplace_back(std::move(*CHI));
2371std::vector<CallHierarchyIncomingCall>
2373 std::vector<CallHierarchyIncomingCall> Results;
2374 if (!Index || Item.
data.empty())
2378 elog(
"incomingCalls failed to find symbol: {0}", ID.takeError());
2387 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs,
bool MightNeverCall) {
2389 Request.
IDs = std::move(IDs);
2398 llvm::DenseMap<SymbolID, std::vector<Location>> CallsIn;
2402 Index->
refs(Request, [&](
const Ref &R) {
2405 elog(
"incomingCalls failed to convert location: {0}", Loc.takeError());
2414 Index->
lookup(ContainerLookup, [&](
const Symbol &Caller) {
2415 auto It = CallsIn.find(Caller.
ID);
2416 assert(It != CallsIn.end());
2418 std::vector<Range> FromRanges;
2419 for (
const Location &L : It->second) {
2427 FromRanges.push_back(L.
range);
2430 std::move(*CHI), std::move(FromRanges), MightNeverCall});
2434 QueryIndex({ID.get()},
false);
2437 if (Item.
kind == SymbolKind::Method) {
2438 llvm::DenseSet<SymbolID> IDs;
2441 IDs.insert(Caller.
ID);
2443 QueryIndex(std::move(IDs),
true);
2448 return A.from.name < B.from.name;
2453std::vector<CallHierarchyOutgoingCall>
2455 std::vector<CallHierarchyOutgoingCall> Results;
2456 if (!Index || Item.
data.empty())
2460 elog(
"outgoingCalls failed to find symbol: {0}", ID.takeError());
2469 llvm::DenseMap<SymbolID, std::vector<Location>> CallsOut;
2476 elog(
"outgoingCalls failed to convert location: {0}", Loc.takeError());
2479 auto It = CallsOut.try_emplace(R.Symbol, std::vector<Location>{}).first;
2480 It->second.push_back(*Loc);
2482 CallsOutLookup.
IDs.insert(R.Symbol);
2486 Index->
lookup(CallsOutLookup, [&](
const Symbol &Callee) {
2489 using SK = index::SymbolKind;
2490 auto Kind = Callee.SymInfo.Kind;
2491 assert(Kind == SK::Function || Kind == SK::InstanceMethod ||
2492 Kind == SK::ClassMethod || Kind == SK::StaticMethod ||
2493 Kind == SK::Constructor || Kind == SK::Destructor ||
2494 Kind == SK::ConversionFunction);
2498 auto It = CallsOut.find(Callee.ID);
2499 assert(It != CallsOut.end());
2501 std::vector<Range> FromRanges;
2502 for (
const Location &L : It->second) {
2511 FromRanges.push_back(L.
range);
2520 return A.to.name < B.to.name;
2526 const FunctionDecl *FD) {
2529 llvm::DenseSet<const Decl *> DeclRefs;
2533 for (
const Decl *D :
Ref.Targets) {
2534 if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
2539 AST.getHeuristicResolver());
Include Cleaner is clangd functionality for providing diagnostics for misuse of transitive headers an...
void elog(const char *Fmt, Ts &&... Vals)
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)
bool isLikelyForwardingFunction(const FunctionTemplateDecl *FT)
Heuristic that checks if FT is likely to be forwarding a parameter pack to another function (e....
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< 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)
SmallVector< const CXXConstructorDecl *, 1 > searchConstructorsInForwardingFunction(const FunctionDecl *FD)
Only call if FD is a likely forwarding function.
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.
SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind)
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:
const ObjCImplDecl * getCorrespondingObjCImpl(const ObjCContainerDecl *D)
Return the corresponding implementation/definition for the given ObjC container if it has one,...
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
The class presents a C++ symbol, e.g.
@ 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.