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 llvm::DenseSet<SymbolID> SeenIDs;
310 llvm::DenseSet<SymbolID> Queue = std::move(IDs);
311 std::vector<LocatedSymbol> Results;
312 while (!Queue.empty()) {
313 Req.Subjects = std::move(Queue);
316 if (!SeenIDs.insert(
Object.ID).second)
322 elog(
"Find overrides: {0}", DeclLoc.takeError());
325 Results.emplace_back();
326 Results.back().Name =
Object.Name.str();
327 Results.back().PreferredDeclaration = *DeclLoc;
330 elog(
"Failed to convert location: {0}", DefLoc.takeError());
333 Results.back().Definition = *DefLoc;
341void enhanceLocatedSymbolsFromIndex(llvm::MutableArrayRef<LocatedSymbol> Result,
343 llvm::StringRef MainFilePath) {
345 llvm::DenseMap<SymbolID, unsigned> ResultIndex;
346 for (
unsigned I = 0; I < Result.size(); ++I) {
347 if (
auto ID = Result[I].ID) {
348 ResultIndex.try_emplace(ID, I);
349 QueryRequest.IDs.insert(ID);
352 if (!Index || QueryRequest.IDs.empty())
355 Index->lookup(QueryRequest, [&](
const Symbol &Sym) {
356 auto &R = Result[ResultIndex.lookup(Sym.ID)];
361 if (
auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
362 R.PreferredDeclaration = *Loc;
366 if (
auto Loc = toLSPLocation(
367 getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
371 R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
374 if (
auto Loc = toLSPLocation(
375 getPreferredLocation(R.PreferredDeclaration,
376 Sym.CanonicalDeclaration, Scratch),
378 R.PreferredDeclaration = *Loc;
383bool objcMethodIsTouched(
const SourceManager &SM,
const ObjCMethodDecl *OMD,
384 SourceLocation Loc) {
385 unsigned NumSels = OMD->getNumSelectorLocs();
386 for (
unsigned I = 0; I < NumSels; ++I)
387 if (SM.getSpellingLoc(OMD->getSelectorLoc(I)) == Loc)
396std::vector<LocatedSymbol>
397locateASTReferent(SourceLocation CurLoc,
const syntax::Token *TouchedIdentifier,
400 const SourceManager &SM =
AST.getSourceManager();
402 std::vector<LocatedSymbol> Result;
406 auto AddResultDecl = [&](
const NamedDecl *
D) {
407 D = getPreferredDecl(D);
413 Result.emplace_back();
414 Result.back().Name =
printName(
AST.getASTContext(), *D);
415 Result.back().PreferredDeclaration = *Loc;
417 if (
const NamedDecl *Def = getDefinition(D))
418 Result.back().Definition = makeLocation(
426 getDeclAtPositionWithRelations(
AST, CurLoc, Relations, &NodeKind);
427 llvm::DenseSet<SymbolID> VirtualMethods;
428 for (
const auto &E : Candidates) {
429 const NamedDecl *
D = E.first;
430 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
434 if (CMD->isPureVirtual()) {
435 if (TouchedIdentifier && SM.getSpellingLoc(CMD->getLocation()) ==
436 TouchedIdentifier->location()) {
438 LocateASTReferentMetric.record(1,
"method-to-override");
442 if (NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverrideAttr>()) ||
443 NodeKind.isSame(ASTNodeKind::getFromNodeKind<FinalAttr>())) {
445 for (
const NamedDecl *ND : CMD->overridden_methods())
456 if (
const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(D)) {
457 if (OMD->isThisDeclarationADefinition() && TouchedIdentifier &&
458 objcMethodIsTouched(SM, OMD, TouchedIdentifier->location())) {
459 llvm::SmallVector<const ObjCMethodDecl *, 4> Overrides;
460 OMD->getOverriddenMethods(Overrides);
461 if (!Overrides.empty()) {
462 for (
const auto *Override : Overrides)
463 AddResultDecl(Override);
464 LocateASTReferentMetric.record(1,
"objc-overriden-method");
478 SM.isPointWithin(TouchedIdentifier ? TouchedIdentifier->location()
480 D->getBeginLoc(),
D->getEndLoc()))
485 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
486 if (TouchedIdentifier &&
487 D->getLocation() == TouchedIdentifier->location()) {
488 LocateASTReferentMetric.record(1,
"template-specialization-to-primary");
489 AddResultDecl(CTSD->getSpecializedTemplate());
500 if (
const auto *CD = dyn_cast<ObjCCategoryDecl>(D))
501 if (
const auto *ID = CD->getClassInterface())
502 if (TouchedIdentifier &&
503 (CD->getLocation() == TouchedIdentifier->location() ||
504 ID->getName() == TouchedIdentifier->text(SM))) {
505 LocateASTReferentMetric.record(1,
"objc-category-to-class");
509 LocateASTReferentMetric.record(1,
"regular");
513 enhanceLocatedSymbolsFromIndex(Result, Index, MainFilePath);
516 Index, MainFilePath);
517 Result.insert(Result.end(), Overrides.begin(), Overrides.end());
521std::vector<LocatedSymbol> locateSymbolForType(
const ParsedAST &
AST,
522 const QualType &
Type,
524 const auto &SM =
AST.getSourceManager();
525 auto MainFilePath =
AST.tuPath();
529 auto Decls =
targetDecl(DynTypedNode::create(
Type.getNonReferenceType()),
531 AST.getHeuristicResolver());
535 std::vector<LocatedSymbol> Results;
536 const auto &ASTContext =
AST.getASTContext();
538 for (
const NamedDecl *D : Decls) {
539 D = getPreferredDecl(D);
541 auto Loc = makeLocation(ASTContext,
nameLocation(*D, SM), MainFilePath);
545 Results.emplace_back();
546 Results.back().Name =
printName(ASTContext, *D);
547 Results.back().PreferredDeclaration = *Loc;
549 if (
const NamedDecl *Def = getDefinition(D))
550 Results.back().Definition =
551 makeLocation(ASTContext,
nameLocation(*Def, SM), MainFilePath);
553 enhanceLocatedSymbolsFromIndex(Results, Index, MainFilePath);
558bool tokenSpelledAt(SourceLocation SpellingLoc,
const syntax::TokenBuffer &TB) {
559 auto ExpandedTokens = TB.expandedTokens(
560 TB.sourceManager().getMacroArgExpandedLocation(SpellingLoc));
561 return !ExpandedTokens.empty();
564llvm::StringRef sourcePrefix(SourceLocation Loc,
const SourceManager &SM) {
565 auto D = SM.getDecomposedLoc(Loc);
566 bool Invalid =
false;
567 llvm::StringRef Buf = SM.getBufferData(
D.first, &Invalid);
568 if (Invalid ||
D.second > Buf.size())
570 return Buf.substr(0,
D.second);
573bool isDependentName(ASTNodeKind NodeKind) {
574 return NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverloadExpr>()) ||
576 ASTNodeKind::getFromNodeKind<CXXDependentScopeMemberExpr>()) ||
578 ASTNodeKind::getFromNodeKind<DependentScopeDeclRefExpr>());
586 llvm::StringRef MainFilePath,
587 ASTNodeKind NodeKind) {
601 const auto &SM =
AST.getSourceManager();
615 bool TooMany =
false;
616 using ScoredLocatedSymbol = std::pair<float, LocatedSymbol>;
617 std::vector<ScoredLocatedSymbol> ScoredResults;
628 if (Sym.
SymInfo.Kind == index::SymbolKind::Constructor)
634 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
644 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
651 if (ScoredResults.size() >= 5) {
664 Relevance.
merge(Sym);
667 dlog(
"locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym.
Scope,
668 Sym.
Name, Score, Quality, Relevance);
670 ScoredResults.push_back({Score, std::move(Located)});
674 vlog(
"Heuristic index lookup for {0} returned too many candidates, ignored",
679 llvm::sort(ScoredResults,
680 [](
const ScoredLocatedSymbol &A,
const ScoredLocatedSymbol &B) {
681 return A.first > B.first;
683 std::vector<LocatedSymbol> Results;
684 for (
auto &Res : std::move(ScoredResults))
685 Results.push_back(std::move(Res.second));
687 vlog(
"No heuristic index definition for {0}", Word.
Text);
689 log(
"Found definition heuristically in index for {0}", Word.
Text);
694 const syntax::TokenBuffer &TB) {
705 const SourceManager &SM = TB.sourceManager();
709 unsigned WordLine = SM.getSpellingLineNumber(Word.
Location);
710 auto Cost = [&](SourceLocation Loc) ->
unsigned {
711 assert(SM.getFileID(Loc) ==
File &&
"spelled token in wrong file?");
712 unsigned Line = SM.getSpellingLineNumber(Loc);
713 return Line >= WordLine ? Line - WordLine : 2 * (WordLine - Line);
715 const syntax::Token *BestTok =
nullptr;
716 unsigned BestCost = -1;
720 unsigned MaxDistance =
721 1U << std::min<unsigned>(Word.
Text.size(),
722 std::numeric_limits<unsigned>::digits - 1);
729 WordLine + 1 <= MaxDistance / 2 ? 1 : WordLine + 1 - MaxDistance / 2;
730 unsigned LineMax = WordLine + 1 + MaxDistance;
731 SourceLocation LocMin = SM.translateLineCol(
File, LineMin, 1);
732 assert(LocMin.isValid());
733 SourceLocation LocMax = SM.translateLineCol(
File, LineMax, 1);
734 assert(LocMax.isValid());
738 auto Consider = [&](
const syntax::Token &Tok) {
739 if (Tok.location() < LocMin || Tok.location() > LocMax)
741 if (!(Tok.kind() == tok::identifier && Tok.text(SM) == Word.
Text))
744 if (Tok.location() == Word.
Location)
747 unsigned TokCost = Cost(Tok.location());
748 if (TokCost >= BestCost)
752 if (!(tokenSpelledAt(Tok.location(), TB) || TB.expansionStartingAt(&Tok)))
759 auto SpelledTokens = TB.spelledTokens(
File);
761 auto *I = llvm::partition_point(SpelledTokens, [&](
const syntax::Token &T) {
762 assert(SM.getFileID(T.location()) == SM.getFileID(Word.
Location));
763 return T.location() < Word.
Location;
766 for (
const syntax::Token &Tok : llvm::ArrayRef(I, SpelledTokens.end()))
770 for (
const syntax::Token &Tok :
771 llvm::reverse(llvm::ArrayRef(SpelledTokens.begin(), I)))
777 "Word {0} under cursor {1} isn't a token (after PP), trying nearby {2}",
779 BestTok->location().printToString(SM));
786 const auto &SM =
AST.getSourceManager();
787 auto MainFilePath =
AST.tuPath();
789 if (
auto File = locateFileReferent(Pos,
AST, MainFilePath))
790 return {std::move(*
File)};
794 elog(
"locateSymbolAt failed to convert position to source location: {0}",
799 const syntax::Token *TouchedIdentifier =
nullptr;
800 auto TokensTouchingCursor =
801 syntax::spelledTokensTouching(*CurLoc,
AST.getTokens());
802 for (
const syntax::Token &Tok : TokensTouchingCursor) {
803 if (Tok.kind() == tok::identifier) {
804 if (
auto Macro = locateMacroReferent(Tok,
AST, MainFilePath))
808 return {*std::move(
Macro)};
810 TouchedIdentifier = &Tok;
814 if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
820 auto LocSym = locateSymbolForType(
AST, *
Deduced, Index);
827 ASTNodeKind NodeKind;
828 auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier,
AST,
829 MainFilePath, Index, NodeKind);
830 if (!ASTResults.empty())
838 if (
const syntax::Token *NearbyIdent =
840 if (
auto Macro = locateMacroReferent(*NearbyIdent,
AST, MainFilePath)) {
841 log(
"Found macro definition heuristically using nearby identifier {0}",
843 return {*std::move(
Macro)};
845 ASTResults = locateASTReferent(NearbyIdent->location(), NearbyIdent,
AST,
846 MainFilePath, Index, NodeKind);
847 if (!ASTResults.empty()) {
848 log(
"Found definition heuristically using nearby identifier {0}",
849 NearbyIdent->text(SM));
852 vlog(
"No definition found using nearby identifier {0} at {1}", Word->Text,
853 Word->Location.printToString(SM));
856 auto TextualResults =
858 if (!TextualResults.empty())
859 return TextualResults;
866 const auto &SM =
AST.getSourceManager();
868 std::vector<DocumentLink> Result;
869 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
870 if (Inc.Resolved.empty())
874 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
878 const auto *HashTok =
AST.getTokens().spelledTokenContaining(HashLoc);
879 assert(HashTok &&
"got inclusion at wrong offset");
880 const auto *IncludeTok = std::next(HashTok);
881 const auto *FileTok = std::next(IncludeTok);
889 CharSourceRange FileRange;
891 if (FileTok->kind() == tok::TokenKind::less) {
895 syntax::FileRange(SM, FileTok->location(), Inc.Written.length())
897 }
else if (FileTok->kind() == tok::TokenKind::string_literal) {
900 FileRange = FileTok->range(SM).toCharRange(SM);
911 FileRange = FileTok->range(SM).toCharRange(SM);
925class ReferenceFinder :
public index::IndexDataConsumer {
928 syntax::Token SpelledTok;
929 index::SymbolRoleSet Role;
930 const Decl *Container;
932 Range range(
const SourceManager &SM)
const {
937 ReferenceFinder(ParsedAST &AST,
938 const llvm::ArrayRef<const NamedDecl *> Targets,
940 : PerToken(PerToken), AST(AST) {
941 for (
const NamedDecl *ND : Targets) {
942 TargetDecls.insert(ND->getCanonicalDecl());
943 if (
auto *
Constructor = llvm::dyn_cast<clang::CXXConstructorDecl>(ND))
948 std::vector<Reference> take() && {
949 llvm::sort(References, [](
const Reference &L,
const Reference &R) {
950 auto LTok = L.SpelledTok.location();
951 auto RTok = R.SpelledTok.location();
952 return std::tie(LTok, L.Role) < std::tie(RTok, R.Role);
955 References.erase(llvm::unique(References,
956 [](
const Reference &L,
const Reference &R) {
957 auto LTok = L.SpelledTok.location();
958 auto RTok = R.SpelledTok.location();
959 return std::tie(LTok, L.Role) ==
960 std::tie(RTok, R.Role);
963 return std::move(References);
966 bool forwardsToConstructor(
const Decl *D) {
967 if (TargetConstructors.empty())
969 auto *FD = llvm::dyn_cast<clang::FunctionDecl>(D);
970 if (FD ==
nullptr || !FD->isTemplateInstantiation())
973 SmallVector<const CXXConstructorDecl *, 1> *Constructors =
nullptr;
974 if (
auto Entry = AST.ForwardingToConstructorCache.find(FD);
975 Entry != AST.ForwardingToConstructorCache.end())
976 Constructors = &Entry->getSecond();
977 if (Constructors ==
nullptr) {
978 if (
auto *PT = FD->getPrimaryTemplate();
982 SmallVector<const CXXConstructorDecl *, 1> FoundConstructors =
984 auto Iter = AST.ForwardingToConstructorCache.try_emplace(
985 FD, std::move(FoundConstructors));
986 Constructors = &Iter.first->getSecond();
995 handleDeclOccurrence(
const Decl *D, index::SymbolRoleSet Roles,
996 llvm::ArrayRef<index::SymbolRelation>
Relations,
998 index::IndexDataConsumer::ASTNodeInfo ASTNode)
override {
999 if (!TargetDecls.contains(
D->getCanonicalDecl()) &&
1000 !forwardsToConstructor(ASTNode.OrigD))
1002 const SourceManager &SM = AST.getSourceManager();
1005 const auto &TB = AST.getTokens();
1007 llvm::SmallVector<SourceLocation, 1> Locs;
1011 if (
auto *OME = llvm::dyn_cast_or_null<ObjCMessageExpr>(ASTNode.OrigE)) {
1012 OME->getSelectorLocs(Locs);
1013 }
else if (
auto *OMD =
1014 llvm::dyn_cast_or_null<ObjCMethodDecl>(ASTNode.OrigD)) {
1015 OMD->getSelectorLocs(Locs);
1019 if (!Locs.empty() && Locs.front() != Loc)
1023 Locs.push_back(Loc);
1025 SymbolCollector::Options CollectorOpts;
1026 CollectorOpts.CollectMainFileSymbols =
true;
1027 for (SourceLocation L : Locs) {
1028 L = SM.getFileLoc(L);
1029 if (
const auto *Tok = TB.spelledTokenContaining(L))
1030 References.push_back(
1039 std::vector<Reference> References;
1041 llvm::DenseSet<const Decl *> TargetDecls;
1043 llvm::DenseSet<const CXXConstructorDecl *> TargetConstructors;
1046std::vector<ReferenceFinder::Reference>
1047findRefs(
const llvm::ArrayRef<const NamedDecl *> TargetDecls,
ParsedAST &
AST,
1049 ReferenceFinder RefFinder(
AST, TargetDecls, PerToken);
1050 index::IndexingOptions IndexOpts;
1051 IndexOpts.SystemSymbolFilter =
1052 index::IndexingOptions::SystemSymbolFilterKind::All;
1053 IndexOpts.IndexFunctionLocals =
true;
1054 IndexOpts.IndexParametersInDeclarations =
true;
1055 IndexOpts.IndexTemplateParameters =
true;
1056 indexTopLevelDecls(
AST.getASTContext(),
AST.getPreprocessor(),
1057 AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
1058 return std::move(RefFinder).take();
1061const Stmt *getFunctionBody(DynTypedNode N) {
1062 if (
const auto *FD = N.get<FunctionDecl>())
1063 return FD->getBody();
1064 if (
const auto *FD = N.get<BlockDecl>())
1065 return FD->getBody();
1066 if (
const auto *FD = N.get<LambdaExpr>())
1067 return FD->getBody();
1068 if (
const auto *FD = N.get<ObjCMethodDecl>())
1069 return FD->getBody();
1073const Stmt *getLoopBody(DynTypedNode N) {
1074 if (
const auto *LS = N.get<ForStmt>())
1075 return LS->getBody();
1076 if (
const auto *LS = N.get<CXXForRangeStmt>())
1077 return LS->getBody();
1078 if (
const auto *LS = N.get<WhileStmt>())
1079 return LS->getBody();
1080 if (
const auto *LS = N.get<DoStmt>())
1081 return LS->getBody();
1088class FindControlFlow :
public RecursiveASTVisitor<FindControlFlow> {
1097 All = Break | Continue | Return | Case | Throw | Goto,
1101 std::vector<SourceLocation> &Result;
1102 const SourceManager &SM;
1106 template <
typename Func>
1107 bool filterAndTraverse(DynTypedNode D,
const Func &Delegate) {
1108 llvm::scope_exit RestoreIgnore(
1109 [OldIgnore(Ignore),
this] { Ignore = OldIgnore; });
1110 if (getFunctionBody(D))
1112 else if (getLoopBody(D))
1113 Ignore |= Continue | Break;
1114 else if (
D.get<SwitchStmt>())
1115 Ignore |= Break | Case;
1117 return (Ignore == All) ? true : Delegate();
1120 void found(Target T, SourceLocation Loc) {
1123 if (SM.isBeforeInTranslationUnit(Loc, Bounds.getBegin()) ||
1124 SM.isBeforeInTranslationUnit(Bounds.getEnd(), Loc))
1126 Result.push_back(Loc);
1130 FindControlFlow(SourceRange Bounds, std::vector<SourceLocation> &Result,
1131 const SourceManager &SM)
1132 : Bounds(Bounds), Result(Result), SM(SM) {}
1136 bool TraverseDecl(Decl *D) {
1137 return !
D || filterAndTraverse(DynTypedNode::create(*D), [&] {
1138 return RecursiveASTVisitor::TraverseDecl(D);
1141 bool TraverseStmt(Stmt *S) {
1142 return !S || filterAndTraverse(DynTypedNode::create(*S), [&] {
1143 return RecursiveASTVisitor::TraverseStmt(S);
1148 bool VisitReturnStmt(ReturnStmt *R) {
1149 found(Return, R->getReturnLoc());
1152 bool VisitBreakStmt(BreakStmt *B) {
1153 found(Break,
B->getKwLoc());
1156 bool VisitContinueStmt(ContinueStmt *C) {
1157 found(Continue,
C->getKwLoc());
1160 bool VisitSwitchCase(SwitchCase *C) {
1161 found(Case,
C->getKeywordLoc());
1164 bool VisitCXXThrowExpr(CXXThrowExpr *T) {
1165 found(Throw,
T->getThrowLoc());
1168 bool VisitGotoStmt(GotoStmt *G) {
1170 if (
const auto *LD = G->getLabel()) {
1171 if (SM.isBeforeInTranslationUnit(LD->getLocation(), Bounds.getBegin()) ||
1172 SM.isBeforeInTranslationUnit(Bounds.getEnd(), LD->getLocation()))
1173 found(Goto, G->getGotoLoc());
1182SourceRange findCaseBounds(
const SwitchStmt &Switch, SourceLocation Loc,
1183 const SourceManager &SM) {
1186 std::vector<const SwitchCase *> Cases;
1187 for (
const SwitchCase *Case = Switch.getSwitchCaseList(); Case;
1188 Case = Case->getNextSwitchCase())
1189 Cases.push_back(Case);
1190 llvm::sort(Cases, [&](
const SwitchCase *L,
const SwitchCase *R) {
1191 return SM.isBeforeInTranslationUnit(L->getKeywordLoc(), R->getKeywordLoc());
1195 auto CaseAfter = llvm::partition_point(Cases, [&](
const SwitchCase *C) {
1196 return !SM.isBeforeInTranslationUnit(Loc,
C->getKeywordLoc());
1198 SourceLocation End = CaseAfter == Cases.end() ? Switch.getEndLoc()
1199 : (*CaseAfter)->getKeywordLoc();
1202 if (CaseAfter == Cases.begin())
1203 return SourceRange(Switch.getBeginLoc(), End);
1205 auto CaseBefore = std::prev(CaseAfter);
1207 while (CaseBefore != Cases.begin() &&
1208 (*std::prev(CaseBefore))->getSubStmt() == *CaseBefore)
1210 return SourceRange((*CaseBefore)->getKeywordLoc(), End);
1221 const SourceManager &SM =
1222 N.getDeclContext().getParentASTContext().getSourceManager();
1223 std::vector<SourceLocation> Result;
1226 enum class Cur {
None, Break, Continue, Return, Case, Throw } Cursor;
1227 if (N.ASTNode.get<BreakStmt>()) {
1228 Cursor = Cur::Break;
1229 }
else if (N.ASTNode.get<ContinueStmt>()) {
1230 Cursor = Cur::Continue;
1231 }
else if (N.ASTNode.get<ReturnStmt>()) {
1232 Cursor = Cur::Return;
1233 }
else if (N.ASTNode.get<CXXThrowExpr>()) {
1234 Cursor = Cur::Throw;
1235 }
else if (N.ASTNode.get<SwitchCase>()) {
1237 }
else if (
const GotoStmt *GS = N.ASTNode.get<GotoStmt>()) {
1239 Result.push_back(GS->getGotoLoc());
1240 if (
const auto *LD = GS->getLabel())
1241 Result.push_back(LD->getLocation());
1247 const Stmt *Root =
nullptr;
1250 for (
const auto *P = &N;
P;
P =
P->Parent) {
1252 if (
const Stmt *FunctionBody = getFunctionBody(
P->ASTNode)) {
1253 if (Cursor == Cur::Return || Cursor == Cur::Throw) {
1254 Root = FunctionBody;
1259 if (
const Stmt *LoopBody = getLoopBody(
P->ASTNode)) {
1260 if (Cursor == Cur::None || Cursor == Cur::Break ||
1261 Cursor == Cur::Continue) {
1265 Result.push_back(
P->ASTNode.getSourceRange().getBegin());
1272 if (
const auto *SS =
P->ASTNode.get<SwitchStmt>()) {
1273 if (Cursor == Cur::Break || Cursor == Cur::Case) {
1274 Result.push_back(SS->getSwitchLoc());
1275 Root = SS->getBody();
1277 Bounds = findCaseBounds(*SS, N.ASTNode.getSourceRange().getBegin(), SM);
1282 if (Cursor == Cur::None)
1286 if (!Bounds.isValid())
1287 Bounds = Root->getSourceRange();
1288 FindControlFlow(Bounds, Result, SM).TraverseStmt(
const_cast<Stmt *
>(Root));
1294 const SourceManager &SM) {
1297 if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
1299 else if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
1306std::optional<DocumentHighlight> toHighlight(SourceLocation Loc,
1307 const syntax::TokenBuffer &TB) {
1308 Loc = TB.sourceManager().getFileLoc(Loc);
1309 if (
const auto *Tok = TB.spelledTokenContaining(Loc)) {
1313 CharSourceRange::getCharRange(Tok->location(), Tok->endLocation()));
1316 return std::nullopt;
1323 const SourceManager &SM =
AST.getSourceManager();
1327 llvm::consumeError(CurLoc.takeError());
1330 std::vector<DocumentHighlight> Result;
1336 targetDecl(N->ASTNode, Relations,
AST.getHeuristicResolver());
1337 if (!TargetDecls.empty()) {
1340 for (
const auto &
Ref : findRefs(TargetDecls,
AST,
true))
1341 Result.push_back(toHighlight(
Ref, SM));
1344 auto ControlFlow = relatedControlFlow(*N);
1345 if (!ControlFlow.empty()) {
1346 for (SourceLocation Loc : ControlFlow)
1347 if (
auto Highlight = toHighlight(Loc,
AST.getTokens()))
1348 Result.push_back(std::move(*Highlight));
1356 AST.getSourceManager().getDecomposedSpellingLoc(*CurLoc).second;
1369 const SourceManager &SM =
AST.getSourceManager();
1372 elog(
"Failed to convert position to source location: {0}",
1373 CurLoc.takeError());
1378 llvm::DenseSet<SymbolID> IDs;
1380 for (
const NamedDecl *ND : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1381 if (
const auto *CXXMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1382 if (CXXMD->isVirtual()) {
1386 }
else if (
const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
1389 }
else if (
const auto *OMD = dyn_cast<ObjCMethodDecl>(ND)) {
1392 }
else if (
const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) {
1397 return findImplementors(std::move(IDs), QueryKind, Index,
AST.tuPath());
1403void getOverriddenMethods(
const CXXMethodDecl *CMD,
1404 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1407 for (
const CXXMethodDecl *Base : CMD->overridden_methods()) {
1409 OverriddenMethods.insert(ID);
1410 getOverriddenMethods(Base, OverriddenMethods);
1416void getOverriddenMethods(
const ObjCMethodDecl *OMD,
1417 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1420 llvm::SmallVector<const ObjCMethodDecl *, 4> Overrides;
1421 OMD->getOverriddenMethods(Overrides);
1422 for (
const ObjCMethodDecl *Base : Overrides) {
1424 OverriddenMethods.insert(ID);
1425 getOverriddenMethods(Base, OverriddenMethods);
1429std::optional<std::string>
1430stringifyContainerForMainFileRef(
const Decl *Container) {
1433 if (
auto *ND = llvm::dyn_cast_if_present<NamedDecl>(Container))
1438std::optional<ReferencesResult>
1441 const auto &Includes =
AST.getIncludeStructure().MainFileIncludes;
1442 auto IncludeOnLine = llvm::find_if(Includes, [&Pos](
const Inclusion &Inc) {
1443 return Inc.HashLine == Pos.line;
1445 if (IncludeOnLine == Includes.end())
1446 return std::nullopt;
1448 const SourceManager &SM =
AST.getSourceManager();
1451 include_cleaner::walkUsed(
1453 &
AST.getPragmaIncludes(),
AST.getPreprocessor(),
1454 [&](
const include_cleaner::SymbolReference &
Ref,
1455 llvm::ArrayRef<include_cleaner::Header> Providers) {
1456 if (Ref.RT != include_cleaner::RefType::Explicit ||
1457 !isPreferredProvider(*IncludeOnLine, Converted, Providers))
1460 auto Loc = SM.getFileLoc(Ref.RefLocation);
1463 while (SM.getFileID(Loc) != SM.getMainFileID())
1464 Loc = SM.getIncludeLoc(SM.getFileID(Loc));
1466 ReferencesResult::Reference Result;
1467 const auto *Token = AST.getTokens().spelledTokenContaining(Loc);
1468 assert(Token &&
"references expected token here");
1469 Result.Loc.range = Range{sourceLocToPosition(SM, Token->location()),
1470 sourceLocToPosition(SM, Token->endLocation())};
1471 Result.Loc.uri = URIMainFile;
1472 Results.References.push_back(std::move(Result));
1474 if (Results.References.empty())
1475 return std::nullopt;
1480 IncludeOnLine->HashOffset);
1481 Result.Loc.uri = URIMainFile;
1482 Results.References.push_back(std::move(Result));
1490 const SourceManager &SM =
AST.getSourceManager();
1491 auto MainFilePath =
AST.tuPath();
1495 llvm::consumeError(CurLoc.takeError());
1499 const auto IncludeReferences =
1500 maybeFindIncludeReferences(
AST, Pos, URIMainFile);
1501 if (IncludeReferences)
1502 return *IncludeReferences;
1504 llvm::DenseSet<SymbolID> IDsToQuery, OverriddenMethods;
1506 const auto *IdentifierAtCursor =
1507 syntax::spelledIdentifierTouching(*CurLoc,
AST.getTokens());
1508 std::optional<DefinedMacro>
Macro;
1509 if (IdentifierAtCursor)
1515 const auto &IDToRefs =
AST.getMacros().MacroRefs;
1516 auto Refs = IDToRefs.find(MacroSID);
1517 if (Refs != IDToRefs.end()) {
1518 for (
const auto &
Ref : Refs->second) {
1521 Result.
Loc.
uri = URIMainFile;
1522 if (
Ref.IsDefinition) {
1526 Results.
References.push_back(std::move(Result));
1529 IDsToQuery.insert(MacroSID);
1536 std::vector<const NamedDecl *> Decls =
1537 getDeclAtPosition(
AST, *CurLoc, Relations);
1538 llvm::SmallVector<const NamedDecl *> TargetsInMainFile;
1539 for (
const NamedDecl *D : Decls) {
1543 TargetsInMainFile.push_back(D);
1547 if (D->getParentFunctionOrMethod())
1549 IDsToQuery.insert(ID);
1555 for (
const NamedDecl *ND : Decls) {
1558 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1559 if (CMD->isVirtual()) {
1562 getOverriddenMethods(CMD, OverriddenMethods);
1567 if (
const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(ND)) {
1569 getOverriddenMethods(OMD, OverriddenMethods);
1575 auto MainFileRefs = findRefs(TargetsInMainFile,
AST,
false);
1579 MainFileRefs.erase(llvm::unique(MainFileRefs,
1580 [](
const ReferenceFinder::Reference &L,
1581 const ReferenceFinder::Reference &R) {
1582 return L.SpelledTok.location() ==
1583 R.SpelledTok.location();
1585 MainFileRefs.end());
1586 for (
const auto &
Ref : MainFileRefs) {
1589 Result.
Loc.
uri = URIMainFile;
1593 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Declaration))
1596 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Definition))
1599 Results.
References.push_back(std::move(Result));
1607 llvm::DenseMap<SymbolID, size_t> RefIndexForContainer;
1610 if (Limit && Results.
References.size() >= Limit) {
1614 const auto LSPLocDecl =
1615 toLSPLocation(
Object.CanonicalDeclaration, MainFilePath);
1616 const auto LSPLocDef = toLSPLocation(
Object.Definition, MainFilePath);
1617 if (LSPLocDecl && LSPLocDecl != LSPLocDef) {
1619 Result.
Loc = {std::move(*LSPLocDecl), std::nullopt};
1624 Results.
References.push_back(std::move(Result));
1628 Result.
Loc = {std::move(*LSPLocDef), std::nullopt};
1634 Results.
References.push_back(std::move(Result));
1638 if (!ContainerLookup.
IDs.empty() && AddContext)
1639 Index->
lookup(ContainerLookup, [&](
const Symbol &Container) {
1640 auto Ref = RefIndexForContainer.find(Container.ID);
1641 assert(
Ref != RefIndexForContainer.end());
1643 Container.Scope.str() + Container.Name.str();
1648 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs,
bool AllowAttributes,
1649 bool AllowMainFileSymbols) {
1650 if (IDs.empty() || !Index || Results.
HasMore)
1653 Req.
IDs = std::move(IDs);
1665 llvm::DenseMap<SymbolID, std::vector<size_t>> RefIndicesForContainer;
1667 auto LSPLoc = toLSPLocation(R.
Location, MainFilePath);
1670 (!AllowMainFileSymbols && LSPLoc->uri.file() == MainFilePath))
1673 Result.
Loc = {std::move(*LSPLoc), std::nullopt};
1674 if (AllowAttributes) {
1684 ContainerLookup.
IDs.insert(Container);
1685 RefIndicesForContainer[Container].push_back(Results.
References.size());
1687 Results.
References.push_back(std::move(Result));
1690 if (!ContainerLookup.
IDs.empty() && AddContext)
1691 Index->
lookup(ContainerLookup, [&](
const Symbol &Container) {
1692 auto Ref = RefIndicesForContainer.find(Container.ID);
1693 assert(
Ref != RefIndicesForContainer.end());
1694 auto ContainerName = Container.Scope.str() + Container.Name.str();
1695 for (
auto I :
Ref->getSecond()) {
1696 Results.
References[I].Loc.containerName = ContainerName;
1700 QueryIndex(std::move(IDsToQuery),
true,
1705 QueryIndex(std::move(OverriddenMethods),
false,
1711 const SourceManager &SM =
AST.getSourceManager();
1714 llvm::consumeError(CurLoc.takeError());
1717 auto MainFilePath =
AST.tuPath();
1718 std::vector<SymbolDetails> Results;
1724 for (
const NamedDecl *D : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1725 D = getPreferredDecl(D);
1731 NewSymbol.
name = std::string(SplitQName.second);
1734 if (
const auto *ParentND =
1735 dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
1738 llvm::SmallString<32> USR;
1739 if (!index::generateUSRForDecl(D, USR)) {
1740 NewSymbol.
USR = std::string(USR);
1743 if (
const NamedDecl *Def = getDefinition(D))
1747 makeLocation(
AST.getASTContext(),
nameLocation(*D, SM), MainFilePath);
1749 Results.push_back(std::move(NewSymbol));
1752 const auto *IdentifierAtCursor =
1753 syntax::spelledIdentifierTouching(*CurLoc,
AST.getTokens());
1754 if (!IdentifierAtCursor)
1759 NewMacro.
name = std::string(M->Name);
1760 llvm::SmallString<32> USR;
1761 if (!index::generateUSRForMacro(NewMacro.
name, M->Info->getDefinitionLoc(),
1763 NewMacro.
USR = std::string(USR);
1766 Results.push_back(std::move(NewMacro));
1787 OS <<
" [override]";
1791template <
typename HierarchyItem>
1792static std::optional<HierarchyItem>
1794 ASTContext &Ctx = ND.getASTContext();
1795 auto &SM = Ctx.getSourceManager();
1796 SourceLocation NameLoc =
nameLocation(ND, Ctx.getSourceManager());
1797 SourceLocation BeginLoc = SM.getFileLoc(ND.getBeginLoc());
1798 SourceLocation EndLoc = SM.getFileLoc(ND.getEndLoc());
1799 const auto DeclRange =
1802 return std::nullopt;
1803 const auto FE = SM.getFileEntryRefForID(SM.getFileID(NameLoc));
1805 return std::nullopt;
1808 return std::nullopt;
1812 SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
1814 index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
1825 HI.selectionRange =
Range{NameBegin, NameEnd};
1826 if (!HI.range.contains(HI.selectionRange)) {
1829 HI.range = HI.selectionRange;
1837static std::optional<TypeHierarchyItem>
1841 Result->deprecated = ND.isDeprecated();
1851static std::optional<CallHierarchyItem>
1856 if (ND.isDeprecated())
1859 Result->data = ID.str();
1863template <
typename HierarchyItem>
1868 elog(
"Failed to convert symbol to hierarchy item: {0}", Loc.takeError());
1869 return std::nullopt;
1872 HI.name = std::string(S.
Name);
1875 HI.selectionRange = Loc->range;
1878 HI.range = HI.selectionRange;
1884static std::optional<TypeHierarchyItem>
1889 Result->data.symbolID = S.
ID;
1894static std::optional<CallHierarchyItem>
1899 Result->data = S.
ID.
str();
1906 std::vector<TypeHierarchyItem> &SubTypes,
1912 if (std::optional<TypeHierarchyItem> ChildSym =
1915 ChildSym->children.emplace();
1918 SubTypes.emplace_back(std::move(*ChildSym));
1936 auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD :
nullptr;
1938 if (!RPSet.insert(Pattern).second) {
1943 for (
const CXXRecordDecl *ParentDecl :
typeParents(&CXXRD)) {
1944 if (std::optional<TypeHierarchyItem> ParentSym =
1948 Item.
parents->emplace_back(std::move(*ParentSym));
1953 RPSet.erase(Pattern);
1960 std::vector<const CXXRecordDecl *> Records;
1969 AST.getHeuristicResolver());
1970 for (
const NamedDecl *D : Decls) {
1972 if (
const VarDecl *VD = dyn_cast<VarDecl>(D)) {
1974 if (
const auto *RD = VD->getType().getTypePtr()->getAsCXXRecordDecl())
1975 Records.push_back(RD);
1979 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(D)) {
1981 Records.push_back(
Method->getParent());
1989 if (
auto *RD = dyn_cast<CXXRecordDecl>(D))
1990 Records.push_back(RD);
1995 const SourceManager &SM =
AST.getSourceManager();
1996 std::vector<const CXXRecordDecl *> Result;
1999 llvm::consumeError(Offset.takeError());
2004 Result = RecordFromNode(ST.commonAncestor());
2005 return !Result.empty();
2012static QualType
typeForNode(
const ASTContext &Ctx,
const HeuristicResolver *H,
2016 while (N && N->
ASTNode.get<NestedNameSpecifierLoc>())
2022 if (
const TypeLoc *TL = N->
ASTNode.get<TypeLoc>()) {
2023 if (llvm::isa<DeducedType>(TL->getTypePtr()))
2025 N->
getDeclContext().getParentASTContext(), H, TL->getBeginLoc()))
2028 if (llvm::isa<TypedefType>(TL->getTypePtr()))
2029 return TL->getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
2030 return TL->getType();
2034 if (
const auto *CCI = N->
ASTNode.get<CXXCtorInitializer>()) {
2035 if (
const FieldDecl *FD = CCI->getAnyMember())
2036 return FD->getType();
2037 if (
const Type *Base = CCI->getBaseClass())
2038 return QualType(Base, 0);
2042 if (
const auto *CBS = N->
ASTNode.get<CXXBaseSpecifier>())
2043 return CBS->getType();
2045 if (
const Decl *D = N->
ASTNode.get<Decl>()) {
2046 struct Visitor : ConstDeclVisitor<Visitor, QualType> {
2047 const ASTContext &Ctx;
2048 Visitor(
const ASTContext &Ctx) : Ctx(Ctx) {}
2050 QualType VisitValueDecl(
const ValueDecl *D) {
return D->getType(); }
2052 QualType VisitTypeDecl(
const TypeDecl *D) {
2053 return Ctx.getTypeDeclType(D);
2056 QualType VisitTypedefNameDecl(
const TypedefNameDecl *D) {
2057 return D->getUnderlyingType();
2060 QualType VisitTemplateDecl(
const TemplateDecl *D) {
2061 return Visit(D->getTemplatedDecl());
2067 if (
const Stmt *S = N->
ASTNode.get<Stmt>()) {
2068 struct Visitor : ConstStmtVisitor<Visitor, QualType> {
2070 QualType type(
const Stmt *S) {
return S ? Visit(S) : QualType(); }
2073 QualType VisitExpr(
const Expr *S) {
2074 return S->IgnoreImplicitAsWritten()->getType();
2076 QualType VisitMemberExpr(
const MemberExpr *S) {
2078 if (S->getType()->isSpecificBuiltinType(BuiltinType::BoundMember))
2079 return Expr::findBoundMemberType(S);
2080 return VisitExpr(S);
2083 QualType VisitCXXDeleteExpr(
const CXXDeleteExpr *S) {
2084 return S->getDestroyedType();
2086 QualType VisitCXXPseudoDestructorExpr(
const CXXPseudoDestructorExpr *S) {
2087 return S->getDestroyedType();
2089 QualType VisitCXXThrowExpr(
const CXXThrowExpr *S) {
2090 return S->getSubExpr()->getType();
2092 QualType VisitCoyieldExpr(
const CoyieldExpr *S) {
2093 return type(S->getOperand());
2096 QualType VisitDesignatedInitExpr(
const DesignatedInitExpr *S) {
2098 for (
auto &D : llvm::reverse(S->designators()))
2099 if (D.isFieldDesignator())
2100 if (
const auto *FD = D.getFieldDecl())
2101 return FD->getType();
2106 QualType VisitSwitchStmt(
const SwitchStmt *S) {
2107 return type(S->getCond());
2109 QualType VisitWhileStmt(
const WhileStmt *S) {
return type(S->getCond()); }
2110 QualType VisitDoStmt(
const DoStmt *S) {
return type(S->getCond()); }
2111 QualType VisitIfStmt(
const IfStmt *S) {
return type(S->getCond()); }
2112 QualType VisitCaseStmt(
const CaseStmt *S) {
return type(S->getLHS()); }
2113 QualType VisitCXXForRangeStmt(
const CXXForRangeStmt *S) {
2114 return S->getLoopVariable()->getType();
2116 QualType VisitReturnStmt(
const ReturnStmt *S) {
2117 return type(S->getRetValue());
2119 QualType VisitCoreturnStmt(
const CoreturnStmt *S) {
2120 return type(S->getOperand());
2122 QualType VisitCXXCatchStmt(
const CXXCatchStmt *S) {
2123 return S->getCaughtType();
2125 QualType VisitObjCAtThrowStmt(
const ObjCAtThrowStmt *S) {
2126 return type(S->getThrowExpr());
2128 QualType VisitObjCAtCatchStmt(
const ObjCAtCatchStmt *S) {
2129 return S->getCatchParamDecl() ? S->getCatchParamDecl()->getType()
2142 QualType T,
const HeuristicResolver* H, llvm::SmallVector<QualType>& Out) {
2147 if (
const auto* TDT = T->getAs<TypedefType>())
2148 return Out.push_back(QualType(TDT, 0));
2151 if (
const auto *PT = T->getAs<PointerType>())
2153 if (
const auto *RT = T->getAs<ReferenceType>())
2155 if (
const auto *AT = T->getAsArrayTypeUnsafe())
2159 if (
auto *FT = T->getAs<FunctionType>())
2161 if (
auto *CRD = T->getAsCXXRecordDecl()) {
2162 if (CRD->isLambda())
2163 return unwrapFindType(CRD->getLambdaCallOperator()->getReturnType(), H,
2171 if (
auto PointeeType = H->getPointeeType(T.getNonReferenceType());
2172 !PointeeType.isNull()) {
2174 return Out.push_back(T);
2177 return Out.push_back(T);
2182 QualType T,
const HeuristicResolver* H) {
2183 llvm::SmallVector<QualType> Result;
2190 const SourceManager &SM =
AST.getSourceManager();
2192 std::vector<LocatedSymbol> Result;
2194 elog(
"failed to convert position {0} for findTypes: {1}", Pos,
2195 Offset.takeError());
2199 auto SymbolsFromNode =
2201 std::vector<LocatedSymbol> LocatedSymbols;
2209 AST.getHeuristicResolver()))
2210 llvm::copy(locateSymbolForType(
AST,
Type, Index),
2211 std::back_inserter(LocatedSymbols));
2213 return LocatedSymbols;
2217 Result = SymbolsFromNode(ST.commonAncestor());
2218 return !Result.empty();
2223std::vector<const CXXRecordDecl *>
typeParents(
const CXXRecordDecl *CXXRD) {
2224 std::vector<const CXXRecordDecl *> Result;
2228 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
2229 if (CTSD->isInvalidDecl())
2230 CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
2234 if (!CXXRD->hasDefinition())
2237 for (
auto Base : CXXRD->bases()) {
2238 const CXXRecordDecl *ParentDecl =
nullptr;
2240 const Type *
Type = Base.getType().getTypePtr();
2241 if (
const RecordType *RT =
Type->getAs<RecordType>()) {
2242 ParentDecl = RT->getAsCXXRecordDecl();
2248 if (
const TemplateSpecializationType *TS =
2249 Type->getAs<TemplateSpecializationType>()) {
2250 TemplateName TN = TS->getTemplateName();
2251 if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
2252 ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
2258 Result.push_back(ParentDecl);
2264std::vector<TypeHierarchyItem>
2268 std::vector<TypeHierarchyItem> Results;
2282 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
2283 CXXRD = CTSD->getTemplateInstantiationPattern();
2286 std::optional<TypeHierarchyItem> Result =
2294 if (WantChildren && ResolveLevels > 0) {
2295 Result->children.emplace();
2299 fillSubTypes(ID, *Result->children, Index, ResolveLevels, TUPath);
2302 Results.emplace_back(std::move(*Result));
2308std::optional<std::vector<TypeHierarchyItem>>
2310 std::vector<TypeHierarchyItem> Results;
2312 return std::nullopt;
2316 llvm::DenseMap<SymbolID, const TypeHierarchyItem::ResolveParams *> IDToData;
2318 Req.
IDs.insert(Parent.symbolID);
2319 IDToData[Parent.symbolID] = &Parent;
2321 Index->
lookup(Req, [&Item, &Results, &IDToData](
const Symbol &S) {
2323 THI->data = *IDToData.lookup(S.
ID);
2324 Results.emplace_back(std::move(*THI));
2332 std::vector<TypeHierarchyItem> Results;
2334 for (
auto &ChildSym : Results)
2335 ChildSym.data.parents = {Item.
data};
2353std::vector<CallHierarchyItem>
2355 std::vector<CallHierarchyItem> Result;
2356 const auto &SM =
AST.getSourceManager();
2359 elog(
"prepareCallHierarchy failed to convert position to source location: "
2364 for (
const NamedDecl *Decl : getDeclAtPosition(
AST, *Loc, {})) {
2365 if (!(isa<DeclContext>(Decl) &&
2366 cast<DeclContext>(Decl)->isFunctionOrMethod()) &&
2367 Decl->getKind() != Decl::Kind::FunctionTemplate &&
2368 !(Decl->getKind() == Decl::Kind::Var &&
2369 !cast<VarDecl>(Decl)->isLocalVarDecl()) &&
2370 Decl->getKind() != Decl::Kind::Field &&
2371 Decl->getKind() != Decl::Kind::EnumConstant)
2374 Result.emplace_back(std::move(*CHI));
2379std::vector<CallHierarchyIncomingCall>
2381 std::vector<CallHierarchyIncomingCall> Results;
2382 if (!Index || Item.
data.empty())
2386 elog(
"incomingCalls failed to find symbol: {0}", ID.takeError());
2395 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs,
bool MightNeverCall) {
2397 Request.
IDs = std::move(IDs);
2406 llvm::DenseMap<SymbolID, std::vector<Location>> CallsIn;
2410 Index->
refs(Request, [&](
const Ref &R) {
2413 elog(
"incomingCalls failed to convert location: {0}", Loc.takeError());
2422 Index->
lookup(ContainerLookup, [&](
const Symbol &Caller) {
2423 auto It = CallsIn.find(Caller.
ID);
2424 assert(It != CallsIn.end());
2426 std::vector<Range> FromRanges;
2427 for (
const Location &L : It->second) {
2435 FromRanges.push_back(L.
range);
2438 std::move(*CHI), std::move(FromRanges), MightNeverCall});
2442 QueryIndex({ID.get()},
false);
2445 if (Item.
kind == SymbolKind::Method) {
2446 llvm::DenseSet<SymbolID> IDs;
2449 IDs.insert(Caller.
ID);
2451 QueryIndex(std::move(IDs),
true);
2456 return A.from.name < B.from.name;
2461std::vector<CallHierarchyOutgoingCall>
2463 std::vector<CallHierarchyOutgoingCall> Results;
2464 if (!Index || Item.
data.empty())
2468 elog(
"outgoingCalls failed to find symbol: {0}", ID.takeError());
2477 llvm::DenseMap<SymbolID, std::vector<Location>> CallsOut;
2484 elog(
"outgoingCalls failed to convert location: {0}", Loc.takeError());
2487 auto It = CallsOut.try_emplace(R.Symbol, std::vector<Location>{}).first;
2488 It->second.push_back(*Loc);
2490 CallsOutLookup.
IDs.insert(R.Symbol);
2494 Index->
lookup(CallsOutLookup, [&](
const Symbol &Callee) {
2497 using SK = index::SymbolKind;
2498 auto Kind = Callee.SymInfo.Kind;
2499 assert(Kind == SK::Function || Kind == SK::InstanceMethod ||
2500 Kind == SK::ClassMethod || Kind == SK::StaticMethod ||
2501 Kind == SK::Constructor || Kind == SK::Destructor ||
2502 Kind == SK::ConversionFunction);
2506 auto It = CallsOut.find(Callee.ID);
2507 assert(It != CallsOut.end());
2509 std::vector<Range> FromRanges;
2510 for (
const Location &L : It->second) {
2519 FromRanges.push_back(L.
range);
2528 return A.to.name < B.to.name;
2534 const FunctionDecl *FD) {
2537 llvm::DenseSet<const Decl *> DeclRefs;
2541 for (
const Decl *D :
Ref.Targets) {
2542 if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
2547 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)
Ensure we have enough bits to represent all SymbolTag values.
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.