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/Lex/Lexer.h"
53#include "clang/Sema/HeuristicResolver.h"
54#include "clang/Tooling/Syntax/Tokens.h"
55#include "clang/UnifiedSymbolResolution/USRGeneration.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);
202const CallExpr *findEnclosingCallAt(
ParsedAST &
AST, SourceLocation Loc) {
203 unsigned Offset =
AST.getSourceManager().getDecomposedSpellingLoc(Loc).second;
204 const CallExpr *Found =
nullptr;
207 if (const SelectionTree::Node *N =
209 Found = N->ASTNode.get<CallExpr>();
217std::optional<Location> makeLocation(
const ASTContext &
AST, SourceLocation Loc,
218 llvm::StringRef TUPath) {
219 const auto &SM =
AST.getSourceManager();
220 const auto F = SM.getFileEntryRefForID(SM.getFileID(Loc));
225 log(
"failed to get path!");
232 auto TokLen = Lexer::MeasureTokenLength(Loc, SM,
AST.getLangOpts());
234 SM, CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(TokLen)));
239std::optional<LocatedSymbol> locateFileReferent(
const Position &Pos,
241 llvm::StringRef MainFilePath) {
242 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
243 if (!Inc.Resolved.empty() && Inc.HashLine == Pos.line) {
245 File.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
246 File.PreferredDeclaration = {
248 File.Definition =
File.PreferredDeclaration;
258std::optional<LocatedSymbol>
259locateMacroReferent(
const syntax::Token &TouchedIdentifier,
ParsedAST &
AST,
260 llvm::StringRef MainFilePath) {
263 makeLocation(
AST.getASTContext(), M->NameLoc, MainFilePath)) {
265 Macro.Name = std::string(M->Name);
266 Macro.PreferredDeclaration = *Loc;
267 Macro.Definition = std::move(Loc);
288const NamedDecl *getPreferredDecl(
const NamedDecl *D) {
293 D = llvm::cast<NamedDecl>(
D->getCanonicalDecl());
296 if (
const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
297 if (
const auto *DefinitionID = ID->getDefinition())
299 if (
const auto *PD = dyn_cast<ObjCProtocolDecl>(D))
300 if (
const auto *DefinitionID = PD->getDefinition())
306std::vector<LocatedSymbol> findImplementors(llvm::DenseSet<SymbolID> IDs,
309 llvm::StringRef MainFilePath) {
310 if (IDs.empty() || !Index)
316 FindImplementorsMetric.record(1,
"find-base");
319 FindImplementorsMetric.record(1,
"find-override");
325 llvm::DenseSet<SymbolID> SeenIDs;
326 llvm::DenseSet<SymbolID> Queue = std::move(IDs);
327 std::vector<LocatedSymbol> Results;
328 while (!Queue.empty()) {
329 Req.Subjects = std::move(Queue);
332 if (!SeenIDs.insert(
Object.ID).second)
338 elog(
"Find overrides: {0}", DeclLoc.takeError());
341 Results.emplace_back();
342 Results.back().Name =
Object.Name.str();
343 Results.back().PreferredDeclaration = *DeclLoc;
346 elog(
"Failed to convert location: {0}", DefLoc.takeError());
349 Results.back().Definition = *DefLoc;
357void enhanceLocatedSymbolsFromIndex(llvm::MutableArrayRef<LocatedSymbol> Result,
359 llvm::StringRef MainFilePath) {
361 llvm::DenseMap<SymbolID, unsigned> ResultIndex;
362 for (
unsigned I = 0; I < Result.size(); ++I) {
363 if (
auto ID = Result[I].ID) {
364 ResultIndex.try_emplace(ID, I);
365 QueryRequest.IDs.insert(ID);
368 if (!Index || QueryRequest.IDs.empty())
371 Index->lookup(QueryRequest, [&](
const Symbol &Sym) {
372 auto &R = Result[ResultIndex.lookup(Sym.ID)];
377 if (
auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
378 R.PreferredDeclaration = *Loc;
382 if (
auto Loc = toLSPLocation(
383 getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
387 R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
390 if (
auto Loc = toLSPLocation(
391 getPreferredLocation(R.PreferredDeclaration,
392 Sym.CanonicalDeclaration, Scratch),
394 R.PreferredDeclaration = *Loc;
399bool objcMethodIsTouched(
const SourceManager &SM,
const ObjCMethodDecl *OMD,
400 SourceLocation Loc) {
401 unsigned NumSels = OMD->getNumSelectorLocs();
402 for (
unsigned I = 0; I < NumSels; ++I)
403 if (SM.getSpellingLoc(OMD->getSelectorLoc(I)) == Loc)
412std::vector<LocatedSymbol>
413locateASTReferent(SourceLocation CurLoc,
const syntax::Token *TouchedIdentifier,
416 const SourceManager &SM =
AST.getSourceManager();
418 std::vector<LocatedSymbol> Result;
422 auto AddResultDecl = [&](
const NamedDecl *
D) {
423 D = getPreferredDecl(D);
429 Result.emplace_back();
430 Result.back().Name =
printName(
AST.getASTContext(), *D);
431 Result.back().PreferredDeclaration = *Loc;
433 if (
const NamedDecl *Def = getDefinition(D))
434 Result.back().Definition = makeLocation(
447 if (
const auto *CE = findEnclosingCallAt(
AST, CurLoc)) {
448 if (
const auto *Callee = CE->getDirectCallee()) {
449 llvm::SmallPtrSet<const CXXConstructorDecl *, 1> Seen;
450 for (
const auto *Ctor :
452 if (Seen.insert(Ctor).second) {
453 LocateASTReferentMetric.record(1,
"forwarded-constructor");
458 if (!Result.empty()) {
459 enhanceLocatedSymbolsFromIndex(Result, Index, MainFilePath);
467 getDeclAtPositionWithRelations(
AST, CurLoc, Relations, &NodeKind);
468 llvm::DenseSet<SymbolID> VirtualMethods;
469 for (
const auto &E : Candidates) {
470 const NamedDecl *
D = E.first;
471 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
475 if (CMD->isPureVirtual()) {
476 if (TouchedIdentifier && SM.getSpellingLoc(CMD->getLocation()) ==
477 TouchedIdentifier->location()) {
479 LocateASTReferentMetric.record(1,
"method-to-override");
483 if (
NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverrideAttr>()) ||
484 NodeKind.isSame(ASTNodeKind::getFromNodeKind<FinalAttr>())) {
486 for (
const NamedDecl *ND : CMD->overridden_methods())
497 if (
const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(D)) {
498 if (OMD->isThisDeclarationADefinition() && TouchedIdentifier &&
499 objcMethodIsTouched(SM, OMD, TouchedIdentifier->location())) {
500 llvm::SmallVector<const ObjCMethodDecl *, 4> Overrides;
501 OMD->getOverriddenMethods(Overrides);
502 if (!Overrides.empty()) {
503 for (
const auto *Override : Overrides)
504 AddResultDecl(Override);
505 LocateASTReferentMetric.record(1,
"objc-overriden-method");
519 SM.isPointWithin(TouchedIdentifier ? TouchedIdentifier->location()
521 D->getBeginLoc(),
D->getEndLoc()))
526 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
527 if (TouchedIdentifier &&
528 D->getLocation() == TouchedIdentifier->location()) {
529 LocateASTReferentMetric.record(1,
"template-specialization-to-primary");
530 AddResultDecl(CTSD->getSpecializedTemplate());
541 if (
const auto *CD = dyn_cast<ObjCCategoryDecl>(D))
542 if (
const auto *ID = CD->getClassInterface())
543 if (TouchedIdentifier &&
544 (CD->getLocation() == TouchedIdentifier->location() ||
545 ID->getName() == TouchedIdentifier->text(SM))) {
546 LocateASTReferentMetric.record(1,
"objc-category-to-class");
550 LocateASTReferentMetric.record(1,
"regular");
554 enhanceLocatedSymbolsFromIndex(Result, Index, MainFilePath);
557 Index, MainFilePath);
558 Result.insert(Result.end(), Overrides.begin(), Overrides.end());
562std::vector<LocatedSymbol> locateSymbolForType(
const ParsedAST &
AST,
563 const QualType &
Type,
565 const auto &SM =
AST.getSourceManager();
566 auto MainFilePath =
AST.tuPath();
570 auto Decls =
targetDecl(DynTypedNode::create(
Type.getNonReferenceType()),
572 AST.getHeuristicResolver());
576 std::vector<LocatedSymbol> Results;
577 const auto &ASTContext =
AST.getASTContext();
579 for (
const NamedDecl *D : Decls) {
580 D = getPreferredDecl(D);
582 auto Loc = makeLocation(ASTContext,
nameLocation(*D, SM), MainFilePath);
586 Results.emplace_back();
587 Results.back().Name =
printName(ASTContext, *D);
588 Results.back().PreferredDeclaration = *Loc;
590 if (
const NamedDecl *Def = getDefinition(D))
591 Results.back().Definition =
592 makeLocation(ASTContext,
nameLocation(*Def, SM), MainFilePath);
594 enhanceLocatedSymbolsFromIndex(Results, Index, MainFilePath);
599bool tokenSpelledAt(SourceLocation SpellingLoc,
const syntax::TokenBuffer &TB) {
600 auto ExpandedTokens = TB.expandedTokens(
601 TB.sourceManager().getMacroArgExpandedLocation(SpellingLoc));
602 return !ExpandedTokens.empty();
605llvm::StringRef sourcePrefix(SourceLocation Loc,
const SourceManager &SM) {
606 auto D = SM.getDecomposedLoc(Loc);
607 bool Invalid =
false;
608 llvm::StringRef Buf = SM.getBufferData(
D.first, &Invalid);
609 if (Invalid ||
D.second > Buf.size())
611 return Buf.substr(0,
D.second);
614bool isDependentName(ASTNodeKind NodeKind) {
615 return NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverloadExpr>()) ||
617 ASTNodeKind::getFromNodeKind<CXXDependentScopeMemberExpr>()) ||
619 ASTNodeKind::getFromNodeKind<DependentScopeDeclRefExpr>());
627 llvm::StringRef MainFilePath,
628 ASTNodeKind NodeKind) {
642 const auto &SM =
AST.getSourceManager();
656 bool TooMany =
false;
657 using ScoredLocatedSymbol = std::pair<float, LocatedSymbol>;
658 std::vector<ScoredLocatedSymbol> ScoredResults;
669 if (Sym.
SymInfo.Kind == index::SymbolKind::Constructor)
675 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
685 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
692 if (ScoredResults.size() >= 5) {
705 Relevance.
merge(Sym);
708 dlog(
"locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym.
Scope,
709 Sym.
Name, Score, Quality, Relevance);
711 ScoredResults.push_back({Score, std::move(Located)});
715 vlog(
"Heuristic index lookup for {0} returned too many candidates, ignored",
720 llvm::sort(ScoredResults,
721 [](
const ScoredLocatedSymbol &A,
const ScoredLocatedSymbol &B) {
722 return A.first > B.first;
724 std::vector<LocatedSymbol> Results;
725 for (
auto &Res : std::move(ScoredResults))
726 Results.push_back(std::move(Res.second));
728 vlog(
"No heuristic index definition for {0}", Word.
Text);
730 log(
"Found definition heuristically in index for {0}", Word.
Text);
735 const syntax::TokenBuffer &TB) {
746 const SourceManager &SM = TB.sourceManager();
750 unsigned WordLine = SM.getSpellingLineNumber(Word.
Location);
751 auto Cost = [&](SourceLocation Loc) ->
unsigned {
752 assert(SM.getFileID(Loc) ==
File &&
"spelled token in wrong file?");
753 unsigned Line = SM.getSpellingLineNumber(Loc);
754 return Line >= WordLine ? Line - WordLine : 2 * (WordLine - Line);
756 const syntax::Token *BestTok =
nullptr;
757 unsigned BestCost = -1;
761 unsigned MaxDistance =
762 1U << std::min<unsigned>(Word.
Text.size(),
763 std::numeric_limits<unsigned>::digits - 1);
770 WordLine + 1 <= MaxDistance / 2 ? 1 : WordLine + 1 - MaxDistance / 2;
771 unsigned LineMax = WordLine + 1 + MaxDistance;
772 SourceLocation LocMin = SM.translateLineCol(
File, LineMin, 1);
773 assert(LocMin.isValid());
774 SourceLocation LocMax = SM.translateLineCol(
File, LineMax, 1);
775 assert(LocMax.isValid());
779 auto Consider = [&](
const syntax::Token &Tok) {
780 if (Tok.location() < LocMin || Tok.location() > LocMax)
782 if (!(Tok.kind() == tok::identifier && Tok.text(SM) == Word.
Text))
785 if (Tok.location() == Word.
Location)
788 unsigned TokCost = Cost(Tok.location());
789 if (TokCost >= BestCost)
793 if (!(tokenSpelledAt(Tok.location(), TB) || TB.expansionStartingAt(&Tok)))
800 auto SpelledTokens = TB.spelledTokens(
File);
802 auto *I = llvm::partition_point(SpelledTokens, [&](
const syntax::Token &T) {
803 assert(SM.getFileID(T.location()) == SM.getFileID(Word.
Location));
804 return T.location() < Word.
Location;
807 for (
const syntax::Token &Tok : llvm::ArrayRef(I, SpelledTokens.end()))
811 for (
const syntax::Token &Tok :
812 llvm::reverse(llvm::ArrayRef(SpelledTokens.begin(), I)))
818 "Word {0} under cursor {1} isn't a token (after PP), trying nearby {2}",
820 BestTok->location().printToString(SM));
827 const auto &SM =
AST.getSourceManager();
828 auto MainFilePath =
AST.tuPath();
830 if (
auto File = locateFileReferent(Pos,
AST, MainFilePath))
831 return {std::move(*
File)};
835 elog(
"locateSymbolAt failed to convert position to source location: {0}",
840 const syntax::Token *TouchedIdentifier =
nullptr;
841 auto TokensTouchingCursor =
842 syntax::spelledTokensTouching(*CurLoc,
AST.getTokens());
843 for (
const syntax::Token &Tok : TokensTouchingCursor) {
844 if (Tok.kind() == tok::identifier) {
845 if (
auto Macro = locateMacroReferent(Tok,
AST, MainFilePath))
849 return {*std::move(
Macro)};
851 TouchedIdentifier = &Tok;
855 if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
861 auto LocSym = locateSymbolForType(
AST, *
Deduced, Index);
868 ASTNodeKind NodeKind;
869 auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier,
AST,
870 MainFilePath, Index, NodeKind);
871 if (!ASTResults.empty())
879 if (
const syntax::Token *NearbyIdent =
881 if (
auto Macro = locateMacroReferent(*NearbyIdent,
AST, MainFilePath)) {
882 log(
"Found macro definition heuristically using nearby identifier {0}",
884 return {*std::move(
Macro)};
886 ASTResults = locateASTReferent(NearbyIdent->location(), NearbyIdent,
AST,
887 MainFilePath, Index, NodeKind);
888 if (!ASTResults.empty()) {
889 log(
"Found definition heuristically using nearby identifier {0}",
890 NearbyIdent->text(SM));
893 vlog(
"No definition found using nearby identifier {0} at {1}", Word->Text,
894 Word->Location.printToString(SM));
897 auto TextualResults =
899 if (!TextualResults.empty())
900 return TextualResults;
907 const auto &SM =
AST.getSourceManager();
909 std::vector<DocumentLink> Result;
910 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
911 if (Inc.Resolved.empty())
915 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
919 const auto *HashTok =
AST.getTokens().spelledTokenContaining(HashLoc);
920 assert(HashTok &&
"got inclusion at wrong offset");
921 const auto *IncludeTok = std::next(HashTok);
922 const auto *FileTok = std::next(IncludeTok);
930 CharSourceRange FileRange;
932 if (FileTok->kind() == tok::TokenKind::less) {
936 syntax::FileRange(SM, FileTok->location(), Inc.Written.length())
938 }
else if (FileTok->kind() == tok::TokenKind::string_literal) {
941 FileRange = FileTok->range(SM).toCharRange(SM);
952 FileRange = FileTok->range(SM).toCharRange(SM);
966class ReferenceFinder :
public index::IndexDataConsumer {
969 syntax::Token SpelledTok;
970 index::SymbolRoleSet Role;
971 const Decl *Container;
973 Range range(
const SourceManager &SM)
const {
978 ReferenceFinder(ParsedAST &AST,
979 const llvm::ArrayRef<const NamedDecl *> Targets,
981 : PerToken(PerToken), AST(AST) {
982 for (
const NamedDecl *ND : Targets) {
983 TargetDecls.insert(ND->getCanonicalDecl());
984 if (
auto *
Constructor = llvm::dyn_cast<clang::CXXConstructorDecl>(ND))
989 std::vector<Reference> take() && {
990 llvm::sort(References, [](
const Reference &L,
const Reference &R) {
991 auto LTok = L.SpelledTok.location();
992 auto RTok = R.SpelledTok.location();
993 return std::tie(LTok, L.Role) < std::tie(RTok, R.Role);
996 References.erase(llvm::unique(References,
997 [](
const Reference &L,
const Reference &R) {
998 auto LTok = L.SpelledTok.location();
999 auto RTok = R.SpelledTok.location();
1000 return std::tie(LTok, L.Role) ==
1001 std::tie(RTok, R.Role);
1004 return std::move(References);
1007 bool forwardsToConstructor(
const Decl *D) {
1008 if (TargetConstructors.empty())
1010 const auto *FD = llvm::dyn_cast<clang::FunctionDecl>(D);
1013 for (
const auto *Ctor :
1015 if (TargetConstructors.contains(Ctor))
1021 handleDeclOccurrence(
const Decl *D, index::SymbolRoleSet Roles,
1022 llvm::ArrayRef<index::SymbolRelation>
Relations,
1024 index::IndexDataConsumer::ASTNodeInfo ASTNode)
override {
1025 if (!TargetDecls.contains(
D->getCanonicalDecl()) &&
1026 !forwardsToConstructor(ASTNode.OrigD))
1028 const SourceManager &SM = AST.getSourceManager();
1031 const auto &TB = AST.getTokens();
1033 llvm::SmallVector<SourceLocation, 1> Locs;
1037 if (
auto *OME = llvm::dyn_cast_or_null<ObjCMessageExpr>(ASTNode.OrigE)) {
1038 OME->getSelectorLocs(Locs);
1039 }
else if (
auto *OMD =
1040 llvm::dyn_cast_or_null<ObjCMethodDecl>(ASTNode.OrigD)) {
1041 OMD->getSelectorLocs(Locs);
1045 if (!Locs.empty() && Locs.front() != Loc)
1049 Locs.push_back(Loc);
1051 SymbolCollector::Options CollectorOpts;
1052 CollectorOpts.CollectMainFileSymbols =
true;
1053 for (SourceLocation L : Locs) {
1054 L = SM.getFileLoc(L);
1055 if (
const auto *Tok = TB.spelledTokenContaining(L))
1056 References.push_back(
1065 std::vector<Reference> References;
1067 llvm::DenseSet<const Decl *> TargetDecls;
1069 llvm::DenseSet<const CXXConstructorDecl *> TargetConstructors;
1072std::vector<ReferenceFinder::Reference>
1073findRefs(
const llvm::ArrayRef<const NamedDecl *> TargetDecls,
ParsedAST &
AST,
1075 ReferenceFinder RefFinder(
AST, TargetDecls, PerToken);
1076 index::IndexingOptions IndexOpts;
1077 IndexOpts.SystemSymbolFilter =
1078 index::IndexingOptions::SystemSymbolFilterKind::All;
1079 IndexOpts.IndexFunctionLocals =
true;
1080 IndexOpts.IndexParametersInDeclarations =
true;
1081 IndexOpts.IndexTemplateParameters =
true;
1082 indexTopLevelDecls(
AST.getASTContext(),
AST.getPreprocessor(),
1083 AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
1084 return std::move(RefFinder).take();
1087const Stmt *getFunctionBody(DynTypedNode N) {
1088 if (
const auto *FD = N.get<FunctionDecl>())
1089 return FD->getBody();
1090 if (
const auto *FD = N.get<BlockDecl>())
1091 return FD->getBody();
1092 if (
const auto *FD = N.get<LambdaExpr>())
1093 return FD->getBody();
1094 if (
const auto *FD = N.get<ObjCMethodDecl>())
1095 return FD->getBody();
1099const Stmt *getLoopBody(DynTypedNode N) {
1100 if (
const auto *LS = N.get<ForStmt>())
1101 return LS->getBody();
1102 if (
const auto *LS = N.get<CXXForRangeStmt>())
1103 return LS->getBody();
1104 if (
const auto *LS = N.get<WhileStmt>())
1105 return LS->getBody();
1106 if (
const auto *LS = N.get<DoStmt>())
1107 return LS->getBody();
1114class FindControlFlow :
public RecursiveASTVisitor<FindControlFlow> {
1123 All = Break | Continue | Return | Case | Throw | Goto,
1127 std::vector<SourceLocation> &Result;
1128 const SourceManager &SM;
1132 template <
typename Func>
1133 bool filterAndTraverse(DynTypedNode D,
const Func &Delegate) {
1134 llvm::scope_exit RestoreIgnore(
1135 [OldIgnore(Ignore),
this] { Ignore = OldIgnore; });
1136 if (getFunctionBody(D))
1138 else if (getLoopBody(D))
1139 Ignore |= Continue | Break;
1140 else if (
D.get<SwitchStmt>())
1141 Ignore |= Break | Case;
1143 return (Ignore == All) ? true : Delegate();
1146 void found(Target T, SourceLocation Loc) {
1149 if (SM.isBeforeInTranslationUnit(Loc, Bounds.getBegin()) ||
1150 SM.isBeforeInTranslationUnit(Bounds.getEnd(), Loc))
1152 Result.push_back(Loc);
1156 FindControlFlow(SourceRange Bounds, std::vector<SourceLocation> &Result,
1157 const SourceManager &SM)
1158 : Bounds(Bounds), Result(Result), SM(SM) {}
1162 bool TraverseDecl(Decl *D) {
1163 return !
D || filterAndTraverse(DynTypedNode::create(*D), [&] {
1164 return RecursiveASTVisitor::TraverseDecl(D);
1167 bool TraverseStmt(Stmt *S) {
1168 return !S || filterAndTraverse(DynTypedNode::create(*S), [&] {
1169 return RecursiveASTVisitor::TraverseStmt(S);
1174 bool VisitReturnStmt(ReturnStmt *R) {
1175 found(Return, R->getReturnLoc());
1178 bool VisitBreakStmt(BreakStmt *B) {
1179 found(Break,
B->getKwLoc());
1182 bool VisitContinueStmt(ContinueStmt *C) {
1183 found(Continue,
C->getKwLoc());
1186 bool VisitSwitchCase(SwitchCase *C) {
1187 found(Case,
C->getKeywordLoc());
1190 bool VisitCXXThrowExpr(CXXThrowExpr *T) {
1191 found(Throw,
T->getThrowLoc());
1194 bool VisitGotoStmt(GotoStmt *G) {
1196 if (
const auto *LD = G->getLabel()) {
1197 if (SM.isBeforeInTranslationUnit(LD->getLocation(), Bounds.getBegin()) ||
1198 SM.isBeforeInTranslationUnit(Bounds.getEnd(), LD->getLocation()))
1199 found(Goto, G->getGotoLoc());
1208SourceRange findCaseBounds(
const SwitchStmt &Switch, SourceLocation Loc,
1209 const SourceManager &SM) {
1212 std::vector<const SwitchCase *> Cases;
1213 for (
const SwitchCase *Case = Switch.getSwitchCaseList(); Case;
1214 Case = Case->getNextSwitchCase())
1215 Cases.push_back(Case);
1216 llvm::sort(Cases, [&](
const SwitchCase *L,
const SwitchCase *R) {
1217 return SM.isBeforeInTranslationUnit(L->getKeywordLoc(), R->getKeywordLoc());
1221 auto CaseAfter = llvm::partition_point(Cases, [&](
const SwitchCase *C) {
1222 return !SM.isBeforeInTranslationUnit(Loc,
C->getKeywordLoc());
1224 SourceLocation End = CaseAfter == Cases.end() ? Switch.getEndLoc()
1225 : (*CaseAfter)->getKeywordLoc();
1228 if (CaseAfter == Cases.begin())
1229 return SourceRange(Switch.getBeginLoc(), End);
1231 auto CaseBefore = std::prev(CaseAfter);
1233 while (CaseBefore != Cases.begin() &&
1234 (*std::prev(CaseBefore))->getSubStmt() == *CaseBefore)
1236 return SourceRange((*CaseBefore)->getKeywordLoc(), End);
1247 const SourceManager &SM =
1248 N.getDeclContext().getParentASTContext().getSourceManager();
1249 std::vector<SourceLocation> Result;
1252 enum class Cur {
None, Break, Continue, Return, Case, Throw } Cursor;
1253 if (N.ASTNode.get<BreakStmt>()) {
1254 Cursor = Cur::Break;
1255 }
else if (N.ASTNode.get<ContinueStmt>()) {
1256 Cursor = Cur::Continue;
1257 }
else if (N.ASTNode.get<ReturnStmt>()) {
1258 Cursor = Cur::Return;
1259 }
else if (N.ASTNode.get<CXXThrowExpr>()) {
1260 Cursor = Cur::Throw;
1261 }
else if (N.ASTNode.get<SwitchCase>()) {
1263 }
else if (
const GotoStmt *GS = N.ASTNode.get<GotoStmt>()) {
1265 Result.push_back(GS->getGotoLoc());
1266 if (
const auto *LD = GS->getLabel())
1267 Result.push_back(LD->getLocation());
1273 const Stmt *Root =
nullptr;
1276 for (
const auto *P = &N;
P;
P =
P->Parent) {
1278 if (
const Stmt *FunctionBody = getFunctionBody(
P->ASTNode)) {
1279 if (Cursor == Cur::Return || Cursor == Cur::Throw) {
1280 Root = FunctionBody;
1285 if (
const Stmt *LoopBody = getLoopBody(
P->ASTNode)) {
1286 if (Cursor == Cur::None || Cursor == Cur::Break ||
1287 Cursor == Cur::Continue) {
1291 Result.push_back(
P->ASTNode.getSourceRange().getBegin());
1298 if (
const auto *SS =
P->ASTNode.get<SwitchStmt>()) {
1299 if (Cursor == Cur::Break || Cursor == Cur::Case) {
1300 Result.push_back(SS->getSwitchLoc());
1301 Root = SS->getBody();
1303 Bounds = findCaseBounds(*SS, N.ASTNode.getSourceRange().getBegin(), SM);
1308 if (Cursor == Cur::None)
1312 if (!Bounds.isValid())
1313 Bounds = Root->getSourceRange();
1314 FindControlFlow(Bounds, Result, SM).TraverseStmt(
const_cast<Stmt *
>(Root));
1320 const SourceManager &SM) {
1323 if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
1325 else if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
1332std::optional<DocumentHighlight> toHighlight(SourceLocation Loc,
1333 const syntax::TokenBuffer &TB) {
1334 Loc = TB.sourceManager().getFileLoc(Loc);
1335 if (
const auto *Tok = TB.spelledTokenContaining(Loc)) {
1339 CharSourceRange::getCharRange(Tok->location(), Tok->endLocation()));
1342 return std::nullopt;
1349 const SourceManager &SM =
AST.getSourceManager();
1353 llvm::consumeError(CurLoc.takeError());
1356 std::vector<DocumentHighlight> Result;
1362 targetDecl(N->ASTNode, Relations,
AST.getHeuristicResolver());
1363 if (!TargetDecls.empty()) {
1366 for (
const auto &
Ref : findRefs(TargetDecls,
AST,
true))
1367 Result.push_back(toHighlight(
Ref, SM));
1370 auto ControlFlow = relatedControlFlow(*N);
1371 if (!ControlFlow.empty()) {
1372 for (SourceLocation Loc : ControlFlow)
1373 if (
auto Highlight = toHighlight(Loc,
AST.getTokens()))
1374 Result.push_back(std::move(*Highlight));
1382 AST.getSourceManager().getDecomposedSpellingLoc(*CurLoc).second;
1395 const SourceManager &SM =
AST.getSourceManager();
1398 elog(
"Failed to convert position to source location: {0}",
1399 CurLoc.takeError());
1404 llvm::DenseSet<SymbolID> IDs;
1406 for (
const NamedDecl *ND : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1407 if (
const auto *CXXMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1408 if (CXXMD->isVirtual()) {
1412 }
else if (
const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
1415 }
else if (
const auto *OMD = dyn_cast<ObjCMethodDecl>(ND)) {
1418 }
else if (
const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) {
1423 return findImplementors(std::move(IDs), QueryKind, Index,
AST.tuPath());
1429void getOverriddenMethods(
const CXXMethodDecl *CMD,
1430 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1433 for (
const CXXMethodDecl *Base : CMD->overridden_methods()) {
1435 OverriddenMethods.insert(ID);
1436 getOverriddenMethods(Base, OverriddenMethods);
1442void getOverriddenMethods(
const ObjCMethodDecl *OMD,
1443 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1446 llvm::SmallVector<const ObjCMethodDecl *, 4> Overrides;
1447 OMD->getOverriddenMethods(Overrides);
1448 for (
const ObjCMethodDecl *Base : Overrides) {
1450 OverriddenMethods.insert(ID);
1451 getOverriddenMethods(Base, OverriddenMethods);
1455std::optional<std::string>
1456stringifyContainerForMainFileRef(
const Decl *Container) {
1459 if (
auto *ND = llvm::dyn_cast_if_present<NamedDecl>(Container))
1464std::optional<ReferencesResult>
1467 const auto &Includes =
AST.getIncludeStructure().MainFileIncludes;
1468 auto IncludeOnLine = llvm::find_if(Includes, [&Pos](
const Inclusion &Inc) {
1469 return Inc.HashLine == Pos.line;
1471 if (IncludeOnLine == Includes.end())
1472 return std::nullopt;
1474 const SourceManager &SM =
AST.getSourceManager();
1477 include_cleaner::walkUsed(
1479 &
AST.getPragmaIncludes(),
AST.getPreprocessor(),
1480 [&](
const include_cleaner::SymbolReference &
Ref,
1481 llvm::ArrayRef<include_cleaner::Header> Providers) {
1482 if (Ref.RT != include_cleaner::RefType::Explicit ||
1483 !isPreferredProvider(*IncludeOnLine, Converted, Providers))
1486 auto Loc = SM.getFileLoc(Ref.RefLocation);
1489 while (SM.getFileID(Loc) != SM.getMainFileID())
1490 Loc = SM.getIncludeLoc(SM.getFileID(Loc));
1492 ReferencesResult::Reference Result;
1493 const auto *Token = AST.getTokens().spelledTokenContaining(Loc);
1494 assert(Token &&
"references expected token here");
1495 Result.Loc.range = Range{sourceLocToPosition(SM, Token->location()),
1496 sourceLocToPosition(SM, Token->endLocation())};
1497 Result.Loc.uri = URIMainFile;
1498 Results.References.push_back(std::move(Result));
1500 if (Results.References.empty())
1501 return std::nullopt;
1506 IncludeOnLine->HashOffset);
1507 Result.Loc.uri = std::move(URIMainFile);
1508 Results.References.push_back(std::move(Result));
1516 const SourceManager &SM =
AST.getSourceManager();
1517 auto MainFilePath =
AST.tuPath();
1521 llvm::consumeError(CurLoc.takeError());
1525 const auto IncludeReferences =
1526 maybeFindIncludeReferences(
AST, Pos, URIMainFile);
1527 if (IncludeReferences)
1528 return *IncludeReferences;
1530 llvm::DenseSet<SymbolID> IDsToQuery, OverriddenMethods;
1532 const auto *IdentifierAtCursor =
1533 syntax::spelledIdentifierTouching(*CurLoc,
AST.getTokens());
1534 std::optional<DefinedMacro>
Macro;
1535 if (IdentifierAtCursor)
1541 const auto &IDToRefs =
AST.getMacros().MacroRefs;
1542 auto Refs = IDToRefs.find(MacroSID);
1543 if (Refs != IDToRefs.end()) {
1544 for (
const auto &
Ref : Refs->second) {
1547 Result.
Loc.
uri = URIMainFile;
1548 if (
Ref.IsDefinition) {
1552 Results.
References.push_back(std::move(Result));
1555 IDsToQuery.insert(MacroSID);
1562 std::vector<const NamedDecl *> Decls =
1563 getDeclAtPosition(
AST, *CurLoc, Relations);
1564 llvm::SmallVector<const NamedDecl *> TargetsInMainFile;
1565 for (
const NamedDecl *D : Decls) {
1569 TargetsInMainFile.push_back(D);
1573 if (D->getParentFunctionOrMethod())
1575 IDsToQuery.insert(ID);
1581 for (
const NamedDecl *ND : Decls) {
1584 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1585 if (CMD->isVirtual()) {
1588 getOverriddenMethods(CMD, OverriddenMethods);
1593 if (
const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(ND)) {
1595 getOverriddenMethods(OMD, OverriddenMethods);
1601 auto MainFileRefs = findRefs(TargetsInMainFile,
AST,
false);
1605 MainFileRefs.erase(llvm::unique(MainFileRefs,
1606 [](
const ReferenceFinder::Reference &L,
1607 const ReferenceFinder::Reference &R) {
1608 return L.SpelledTok.location() ==
1609 R.SpelledTok.location();
1611 MainFileRefs.end());
1612 for (
const auto &
Ref : MainFileRefs) {
1615 Result.
Loc.
uri = URIMainFile;
1619 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Declaration))
1622 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Definition))
1625 Results.
References.push_back(std::move(Result));
1633 llvm::DenseMap<SymbolID, size_t> RefIndexForContainer;
1636 if (Limit && Results.
References.size() >= Limit) {
1640 const auto LSPLocDecl =
1641 toLSPLocation(
Object.CanonicalDeclaration, MainFilePath);
1642 const auto LSPLocDef = toLSPLocation(
Object.Definition, MainFilePath);
1643 if (LSPLocDecl && LSPLocDecl != LSPLocDef) {
1645 Result.
Loc = {std::move(*LSPLocDecl), std::nullopt};
1650 Results.
References.push_back(std::move(Result));
1654 Result.
Loc = {std::move(*LSPLocDef), std::nullopt};
1660 Results.
References.push_back(std::move(Result));
1664 if (!ContainerLookup.
IDs.empty() && AddContext)
1665 Index->
lookup(ContainerLookup, [&](
const Symbol &Container) {
1666 auto Ref = RefIndexForContainer.find(Container.ID);
1667 assert(
Ref != RefIndexForContainer.end());
1669 Container.Scope.str() + Container.Name.str();
1674 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs,
bool AllowAttributes,
1675 bool AllowMainFileSymbols) {
1676 if (IDs.empty() || !Index || Results.
HasMore)
1679 Req.
IDs = std::move(IDs);
1691 llvm::DenseMap<SymbolID, std::vector<size_t>> RefIndicesForContainer;
1693 auto LSPLoc = toLSPLocation(R.
Location, MainFilePath);
1696 (!AllowMainFileSymbols && LSPLoc->uri.file() == MainFilePath))
1699 Result.
Loc = {std::move(*LSPLoc), std::nullopt};
1700 if (AllowAttributes) {
1710 ContainerLookup.
IDs.insert(Container);
1711 RefIndicesForContainer[Container].push_back(Results.
References.size());
1713 Results.
References.push_back(std::move(Result));
1716 if (!ContainerLookup.
IDs.empty() && AddContext)
1717 Index->
lookup(ContainerLookup, [&](
const Symbol &Container) {
1718 auto Ref = RefIndicesForContainer.find(Container.ID);
1719 assert(
Ref != RefIndicesForContainer.end());
1720 auto ContainerName = Container.Scope.str() + Container.Name.str();
1721 for (
auto I :
Ref->getSecond()) {
1722 Results.
References[I].Loc.containerName = ContainerName;
1726 QueryIndex(std::move(IDsToQuery),
true,
1731 QueryIndex(std::move(OverriddenMethods),
false,
1737 const SourceManager &SM =
AST.getSourceManager();
1740 llvm::consumeError(CurLoc.takeError());
1743 auto MainFilePath =
AST.tuPath();
1744 std::vector<SymbolDetails> Results;
1750 for (
const NamedDecl *D : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1751 D = getPreferredDecl(D);
1757 NewSymbol.
name = std::string(SplitQName.second);
1760 if (
const auto *ParentND =
1761 dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
1764 llvm::SmallString<32> USR;
1765 if (!index::generateUSRForDecl(D, USR)) {
1766 NewSymbol.
USR = std::string(USR);
1769 if (
const NamedDecl *Def = getDefinition(D))
1773 makeLocation(
AST.getASTContext(),
nameLocation(*D, SM), MainFilePath);
1775 Results.push_back(std::move(NewSymbol));
1778 const auto *IdentifierAtCursor =
1779 syntax::spelledIdentifierTouching(*CurLoc,
AST.getTokens());
1780 if (!IdentifierAtCursor)
1785 NewMacro.
name = std::string(M->Name);
1786 llvm::SmallString<32> USR;
1787 if (!index::generateUSRForMacro(NewMacro.
name, M->Info->getDefinitionLoc(),
1789 NewMacro.
USR = std::string(USR);
1792 Results.push_back(std::move(NewMacro));
1813 OS <<
" [override]";
1817template <
typename HierarchyItem>
1818static std::optional<HierarchyItem>
1820 ASTContext &Ctx = ND.getASTContext();
1821 auto &SM = Ctx.getSourceManager();
1822 SourceLocation NameLoc =
nameLocation(ND, Ctx.getSourceManager());
1823 SourceLocation BeginLoc = SM.getFileLoc(ND.getBeginLoc());
1824 SourceLocation EndLoc = SM.getFileLoc(ND.getEndLoc());
1825 const auto DeclRange =
1828 return std::nullopt;
1829 const auto FE = SM.getFileEntryRefForID(SM.getFileID(NameLoc));
1831 return std::nullopt;
1834 return std::nullopt;
1838 SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
1840 index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
1851 HI.selectionRange =
Range{NameBegin, NameEnd};
1852 if (!HI.range.contains(HI.selectionRange)) {
1855 HI.range = HI.selectionRange;
1863static std::optional<TypeHierarchyItem>
1867 Result->deprecated = ND.isDeprecated();
1877static std::optional<CallHierarchyItem>
1882 if (ND.isDeprecated())
1885 Result->data = ID.str();
1889template <
typename HierarchyItem>
1894 elog(
"Failed to convert symbol to hierarchy item: {0}", Loc.takeError());
1895 return std::nullopt;
1898 HI.name = std::string(S.
Name);
1899 HI.detail = S.
Scope.empty() ? std::string()
1900 : S.
Scope.drop_back(2).str();
1902 HI.selectionRange = Loc->range;
1905 HI.range = HI.selectionRange;
1911static std::optional<TypeHierarchyItem>
1916 Result->data.symbolID = S.
ID;
1921static std::optional<CallHierarchyItem>
1926 Result->data = S.
ID.
str();
1933 std::vector<TypeHierarchyItem> &SubTypes,
1939 if (std::optional<TypeHierarchyItem> ChildSym =
1942 ChildSym->children.emplace();
1945 SubTypes.emplace_back(std::move(*ChildSym));
1963 auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD :
nullptr;
1965 if (!RPSet.insert(Pattern).second) {
1970 for (
const CXXRecordDecl *ParentDecl :
typeParents(&CXXRD)) {
1971 if (std::optional<TypeHierarchyItem> ParentSym =
1975 Item.
parents->emplace_back(std::move(*ParentSym));
1980 RPSet.erase(Pattern);
1987 std::vector<const CXXRecordDecl *> Records;
1996 AST.getHeuristicResolver());
1997 for (
const NamedDecl *D : Decls) {
1999 if (
const VarDecl *VD = dyn_cast<VarDecl>(D)) {
2001 if (
const auto *RD = VD->getType().getTypePtr()->getAsCXXRecordDecl())
2002 Records.push_back(RD);
2006 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(D)) {
2008 Records.push_back(
Method->getParent());
2016 if (
auto *RD = dyn_cast<CXXRecordDecl>(D))
2017 Records.push_back(RD);
2022 const SourceManager &SM =
AST.getSourceManager();
2023 std::vector<const CXXRecordDecl *> Result;
2026 llvm::consumeError(Offset.takeError());
2031 Result = RecordFromNode(ST.commonAncestor());
2032 return !Result.empty();
2039static QualType
typeForNode(
const ASTContext &Ctx,
const HeuristicResolver *H,
2043 while (N && N->
ASTNode.get<NestedNameSpecifierLoc>())
2049 if (
const TypeLoc *TL = N->
ASTNode.get<TypeLoc>()) {
2050 if (llvm::isa<DeducedType>(TL->getTypePtr()))
2052 N->
getDeclContext().getParentASTContext(), H, TL->getBeginLoc()))
2055 if (llvm::isa<TypedefType>(TL->getTypePtr()))
2056 return TL->getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
2057 return TL->getType();
2061 if (
const auto *CCI = N->
ASTNode.get<CXXCtorInitializer>()) {
2062 if (
const FieldDecl *FD = CCI->getAnyMember())
2063 return FD->getType();
2064 if (
const Type *Base = CCI->getBaseClass())
2065 return QualType(Base, 0);
2069 if (
const auto *CBS = N->
ASTNode.get<CXXBaseSpecifier>())
2070 return CBS->getType();
2072 if (
const Decl *D = N->
ASTNode.get<Decl>()) {
2073 struct Visitor : ConstDeclVisitor<Visitor, QualType> {
2074 const ASTContext &Ctx;
2075 Visitor(
const ASTContext &Ctx) : Ctx(Ctx) {}
2077 QualType VisitValueDecl(
const ValueDecl *D) {
return D->getType(); }
2079 QualType VisitTypeDecl(
const TypeDecl *D) {
2080 return Ctx.getTypeDeclType(D);
2083 QualType VisitTypedefNameDecl(
const TypedefNameDecl *D) {
2084 return D->getUnderlyingType();
2087 QualType VisitTemplateDecl(
const TemplateDecl *D) {
2088 if (
const auto *TD = D->getTemplatedDecl())
2097 if (
const Stmt *S = N->
ASTNode.get<Stmt>()) {
2098 struct Visitor : ConstStmtVisitor<Visitor, QualType> {
2100 QualType type(
const Stmt *S) {
return S ? Visit(S) : QualType(); }
2103 QualType VisitExpr(
const Expr *S) {
2104 return S->IgnoreImplicitAsWritten()->getType();
2106 QualType VisitMemberExpr(
const MemberExpr *S) {
2108 if (S->getType()->isSpecificBuiltinType(BuiltinType::BoundMember))
2109 return Expr::findBoundMemberType(S);
2110 return VisitExpr(S);
2113 QualType VisitCXXDeleteExpr(
const CXXDeleteExpr *S) {
2114 return S->getDestroyedType();
2116 QualType VisitCXXPseudoDestructorExpr(
const CXXPseudoDestructorExpr *S) {
2117 return S->getDestroyedType();
2119 QualType VisitCXXThrowExpr(
const CXXThrowExpr *S) {
2120 return S->getSubExpr()->getType();
2122 QualType VisitCoyieldExpr(
const CoyieldExpr *S) {
2123 return type(S->getOperand());
2126 QualType VisitDesignatedInitExpr(
const DesignatedInitExpr *S) {
2128 for (
auto &D : llvm::reverse(S->designators()))
2129 if (D.isFieldDesignator())
2130 if (
const auto *FD = D.getFieldDecl())
2131 return FD->getType();
2136 QualType VisitSwitchStmt(
const SwitchStmt *S) {
2137 return type(S->getCond());
2139 QualType VisitWhileStmt(
const WhileStmt *S) {
return type(S->getCond()); }
2140 QualType VisitDoStmt(
const DoStmt *S) {
return type(S->getCond()); }
2141 QualType VisitIfStmt(
const IfStmt *S) {
return type(S->getCond()); }
2142 QualType VisitCaseStmt(
const CaseStmt *S) {
return type(S->getLHS()); }
2143 QualType VisitCXXForRangeStmt(
const CXXForRangeStmt *S) {
2144 return S->getLoopVariable()->getType();
2146 QualType VisitReturnStmt(
const ReturnStmt *S) {
2147 return type(S->getRetValue());
2149 QualType VisitCoreturnStmt(
const CoreturnStmt *S) {
2150 return type(S->getOperand());
2152 QualType VisitCXXCatchStmt(
const CXXCatchStmt *S) {
2153 return S->getCaughtType();
2155 QualType VisitObjCAtThrowStmt(
const ObjCAtThrowStmt *S) {
2156 return type(S->getThrowExpr());
2158 QualType VisitObjCAtCatchStmt(
const ObjCAtCatchStmt *S) {
2159 return S->getCatchParamDecl() ? S->getCatchParamDecl()->getType()
2172 QualType T,
const HeuristicResolver* H, llvm::SmallVector<QualType>& Out) {
2177 if (
const auto* TDT = T->getAs<TypedefType>())
2178 return Out.push_back(QualType(TDT, 0));
2181 if (
const auto *PT = T->getAs<PointerType>())
2183 if (
const auto *RT = T->getAs<ReferenceType>())
2185 if (
const auto *AT = T->getAsArrayTypeUnsafe())
2189 if (
auto *FT = T->getAs<FunctionType>())
2191 if (
auto *CRD = T->getAsCXXRecordDecl()) {
2192 if (CRD->isLambda())
2193 return unwrapFindType(CRD->getLambdaCallOperator()->getReturnType(), H,
2201 if (
auto PointeeType = H->getPointeeType(T.getNonReferenceType());
2202 !PointeeType.isNull()) {
2204 return Out.push_back(T);
2207 return Out.push_back(T);
2212 QualType T,
const HeuristicResolver* H) {
2213 llvm::SmallVector<QualType> Result;
2220 const SourceManager &SM =
AST.getSourceManager();
2222 std::vector<LocatedSymbol> Result;
2224 elog(
"failed to convert position {0} for findTypes: {1}", Pos,
2225 Offset.takeError());
2229 auto SymbolsFromNode =
2231 std::vector<LocatedSymbol> LocatedSymbols;
2239 AST.getHeuristicResolver()))
2240 llvm::copy(locateSymbolForType(
AST,
Type, Index),
2241 std::back_inserter(LocatedSymbols));
2243 return LocatedSymbols;
2247 Result = SymbolsFromNode(ST.commonAncestor());
2248 return !Result.empty();
2253std::vector<const CXXRecordDecl *>
typeParents(
const CXXRecordDecl *CXXRD) {
2254 std::vector<const CXXRecordDecl *> Result;
2258 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
2259 if (CTSD->isInvalidDecl())
2260 CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
2264 if (!CXXRD->hasDefinition())
2267 for (
auto Base : CXXRD->bases()) {
2268 const CXXRecordDecl *ParentDecl =
nullptr;
2270 const Type *
Type = Base.getType().getTypePtr();
2271 if (
const RecordType *RT =
Type->getAs<RecordType>()) {
2272 ParentDecl = RT->getAsCXXRecordDecl();
2278 if (
const TemplateSpecializationType *TS =
2279 Type->getAs<TemplateSpecializationType>()) {
2280 TemplateName TN = TS->getTemplateName();
2281 if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
2282 ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
2288 Result.push_back(ParentDecl);
2294std::vector<TypeHierarchyItem>
2298 std::vector<TypeHierarchyItem> Results;
2312 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
2313 CXXRD = CTSD->getTemplateInstantiationPattern();
2316 std::optional<TypeHierarchyItem> Result =
2324 if (WantChildren && ResolveLevels > 0) {
2325 Result->children.emplace();
2329 fillSubTypes(ID, *Result->children, Index, ResolveLevels, TUPath);
2332 Results.emplace_back(std::move(*Result));
2338std::optional<std::vector<TypeHierarchyItem>>
2340 std::vector<TypeHierarchyItem> Results;
2342 return std::nullopt;
2346 llvm::DenseMap<SymbolID, const TypeHierarchyItem::ResolveParams *> IDToData;
2348 Req.
IDs.insert(Parent.symbolID);
2349 IDToData[Parent.symbolID] = &Parent;
2351 Index->
lookup(Req, [&Item, &Results, &IDToData](
const Symbol &S) {
2353 THI->data = *IDToData.lookup(S.
ID);
2354 Results.emplace_back(std::move(*THI));
2362 std::vector<TypeHierarchyItem> Results;
2364 for (
auto &ChildSym : Results)
2365 ChildSym.data.parents = {Item.
data};
2383std::vector<CallHierarchyItem>
2385 std::vector<CallHierarchyItem> Result;
2386 const auto &SM =
AST.getSourceManager();
2389 elog(
"prepareCallHierarchy failed to convert position to source location: "
2394 for (
const NamedDecl *Decl : getDeclAtPosition(
AST, *Loc, {})) {
2395 if (!(isa<DeclContext>(Decl) &&
2396 cast<DeclContext>(Decl)->isFunctionOrMethod()) &&
2397 Decl->getKind() != Decl::Kind::FunctionTemplate &&
2398 !(Decl->getKind() == Decl::Kind::Var &&
2399 !cast<VarDecl>(Decl)->isLocalVarDecl()) &&
2400 Decl->getKind() != Decl::Kind::Field &&
2401 Decl->getKind() != Decl::Kind::EnumConstant)
2404 Result.emplace_back(std::move(*CHI));
2409std::vector<CallHierarchyIncomingCall>
2411 std::vector<CallHierarchyIncomingCall> Results;
2412 if (!Index || Item.
data.empty())
2416 elog(
"incomingCalls failed to find symbol: {0}", ID.takeError());
2425 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs,
bool MightNeverCall) {
2427 Request.
IDs = std::move(IDs);
2436 llvm::DenseMap<SymbolID, std::vector<Location>> CallsIn;
2440 Index->
refs(Request, [&](
const Ref &R) {
2443 elog(
"incomingCalls failed to convert location: {0}", Loc.takeError());
2452 Index->
lookup(ContainerLookup, [&](
const Symbol &Caller) {
2453 auto It = CallsIn.find(Caller.
ID);
2454 assert(It != CallsIn.end());
2456 std::vector<Range> FromRanges;
2457 for (
const Location &L : It->second) {
2465 FromRanges.push_back(L.
range);
2468 std::move(*CHI), std::move(FromRanges), MightNeverCall});
2472 QueryIndex({ID.get()},
false);
2475 if (Item.
kind == SymbolKind::Method) {
2476 llvm::DenseSet<SymbolID> IDs;
2479 IDs.insert(Caller.
ID);
2481 QueryIndex(std::move(IDs),
true);
2486 return A.from.name < B.from.name;
2491std::vector<CallHierarchyOutgoingCall>
2493 std::vector<CallHierarchyOutgoingCall> Results;
2494 if (!Index || Item.
data.empty())
2498 elog(
"outgoingCalls failed to find symbol: {0}", ID.takeError());
2507 llvm::DenseMap<SymbolID, std::vector<Location>> CallsOut;
2514 elog(
"outgoingCalls failed to convert location: {0}", Loc.takeError());
2517 auto It = CallsOut.try_emplace(R.Symbol, std::vector<Location>{}).first;
2518 It->second.push_back(*Loc);
2520 CallsOutLookup.
IDs.insert(R.Symbol);
2524 Index->
lookup(CallsOutLookup, [&](
const Symbol &Callee) {
2527 using SK = index::SymbolKind;
2528 auto Kind = Callee.SymInfo.Kind;
2529 assert(Kind == SK::Function || Kind == SK::InstanceMethod ||
2530 Kind == SK::ClassMethod || Kind == SK::StaticMethod ||
2531 Kind == SK::Constructor || Kind == SK::Destructor ||
2532 Kind == SK::ConversionFunction);
2536 auto It = CallsOut.find(Callee.ID);
2537 assert(It != CallsOut.end());
2539 std::vector<Range> FromRanges;
2540 for (
const Location &L : It->second) {
2549 FromRanges.push_back(L.
range);
2558 return A.to.name < B.to.name;
2564 const FunctionDecl *FD) {
2567 llvm::DenseSet<const Decl *> DeclRefs;
2571 for (
const Decl *D :
Ref.Targets) {
2572 if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
2577 AST.getHeuristicResolver());
Include Cleaner is clangd functionality for providing diagnostics for misuse of transitive headers an...
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for MD output.")
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)
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)
const syntax::Token * findNearbyIdentifier(const SpelledWord &Word, const syntax::TokenBuffer &TB)
llvm::SmallPtrSet< const CXXRecordDecl *, 4 > RecursionProtectionSet
static void fillSubTypes(const SymbolID &ID, std::vector< TypeHierarchyItem > &SubTypes, const SymbolIndex *Index, int Levels, PathRef TUPath)
void log(const char *Fmt, Ts &&... Vals)
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
@ Type
An inlay hint that for a type annotation.
std::vector< LocatedSymbol > findImplementations(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns implementations at a specified Pos:
ArrayRef< const CXXConstructorDecl * > getForwardedConstructors(const FunctionDecl *FD, ForwardingToConstructorCache &Cache)
Returns the constructors that FD forwards to, if FD is a template instantiation of a likely forwardin...
const ObjCImplDecl * getCorrespondingObjCImpl(const ObjCContainerDecl *D)
Return the corresponding implementation/definition for the given ObjC container if it has one,...
SymbolKind indexSymbolKindToSymbolKind(const index::SymbolInfo &Info)
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
llvm::DenseSet< const Decl * > getNonLocalDeclRefs(ParsedAST &AST, const FunctionDecl *FD)
Returns all decls that are referenced in the FD except local symbols.
clangd::Range rangeTillEOL(llvm::StringRef Code, unsigned HashOffset)
Returns the range starting at offset and spanning the whole line.
float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance)
Combine symbol quality and relevance into a single score.
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
std::vector< CallHierarchyOutgoingCall > outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
void elog(const char *Fmt, Ts &&... Vals)
@ Underlying
This is the underlying declaration for a renaming-alias, decltype etc.
@ TemplatePattern
This is the pattern the template specialization was instantiated from.
@ Alias
This declaration is an alias that was referred to.
static std::optional< CallHierarchyItem > declToCallHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath)
std::vector< const CXXRecordDecl * > findRecordTypeAt(ParsedAST &AST, Position Pos)
Find the record types referenced at Pos.
std::vector< CallHierarchyItem > prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath)
Get call hierarchy information at Pos.
std::vector< const CXXRecordDecl * > typeParents(const CXXRecordDecl *CXXRD)
Given a record type declaration, find its base (parent) types.
cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccessCheck P
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Represents an incoming call, e.g. a caller of a method or constructor.
Represents programming constructs like functions or constructors in the context of call hierarchy.
URIForFile uri
The resource identifier of this item.
SymbolKind kind
The kind of this item.
std::string data
An optional 'data' field, which can be used to identify a call hierarchy item in an incomingCalls or ...
Represents an outgoing call, e.g.
A document highlight is a range inside a text document which deserves special attention.
Range range
The range this highlight applies to.
A range in a text document that links to an internal or external resource, like another text document...
std::vector< std::string > Scopes
If this is non-empty, symbols must be in at least one of the scopes (e.g.
std::string Query
A query string for the fuzzy find.
std::vector< std::string > ProximityPaths
Contextually relevant files (e.g.
bool AnyScope
If set to true, allow symbols from any scope.
std::optional< uint32_t > Limit
The number of top candidates to return.
Location PreferredDeclaration
std::optional< Location > Definition
URIForFile uri
The text document's URI.
llvm::DenseSet< SymbolID > IDs
Represents a symbol occurrence in the source file.
SymbolID Container
The ID of the symbol whose definition contains this reference.
SymbolLocation Location
The source location where the symbol is named.
Information about a reference written in the source code, independent of the actual AST node that thi...
std::optional< std::string > containerName
clangd extension: contains the name of the function or class in which the reference occurs
std::vector< Reference > References
bool WantContainer
If set, populates the container of the reference.
llvm::DenseSet< SymbolID > IDs
std::optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
llvm::DenseSet< SymbolID > Subjects
const DeclContext & getDeclContext() const
static std::optional< SpelledWord > touching(SourceLocation SpelledLoc, const syntax::TokenBuffer &TB, const LangOptions &LangOpts)
const syntax::Token * ExpandedToken
const syntax::Token * PartOfSpelledToken
Represents information about identifier.
std::optional< Location > definitionRange
std::string containerName
std::optional< Location > declarationRange
std::string USR
Unified Symbol Resolution identifier This is an opaque string uniquely identifying a symbol.
Attributes of a symbol that affect how much we like it.
float evaluateHeuristics() const
void merge(const CodeCompletionResult &SemaCCResult)
Attributes of a symbol-query pair that affect how much we like it.
llvm::StringRef Name
The name of the symbol (for ContextWords). Must be explicitly assigned.
void merge(const CodeCompletionResult &SemaResult)
enum clang::clangd::SymbolRelevanceSignals::QueryType Query
float evaluateHeuristics() const
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.