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/AST/TypeLoc.h"
45#include "clang/Basic/LLVM.h"
46#include "clang/Basic/Module.h"
47#include "clang/Basic/SourceLocation.h"
48#include "clang/Basic/SourceManager.h"
49#include "clang/Basic/TokenKinds.h"
50#include "clang/Index/IndexDataConsumer.h"
51#include "clang/Index/IndexSymbol.h"
52#include "clang/Index/IndexingAction.h"
53#include "clang/Index/IndexingOptions.h"
54#include "clang/Lex/Lexer.h"
55#include "clang/Sema/HeuristicResolver.h"
56#include "clang/Tooling/Syntax/Tokens.h"
57#include "clang/UnifiedSymbolResolution/USRGeneration.h"
58#include "llvm/ADT/ArrayRef.h"
59#include "llvm/ADT/DenseMap.h"
60#include "llvm/ADT/DenseSet.h"
61#include "llvm/ADT/STLExtras.h"
62#include "llvm/ADT/ScopeExit.h"
63#include "llvm/ADT/SmallVector.h"
64#include "llvm/ADT/StringRef.h"
65#include "llvm/Support/Casting.h"
66#include "llvm/Support/Error.h"
67#include "llvm/Support/ErrorHandling.h"
68#include "llvm/Support/Path.h"
69#include "llvm/Support/raw_ostream.h"
85const NamedDecl *getDefinition(
const NamedDecl *D) {
88 if (
const auto *TD = dyn_cast<TagDecl>(D))
89 return TD->getDefinition();
90 if (
const auto *VD = dyn_cast<VarDecl>(D))
91 return VD->getDefinition();
92 if (
const auto *FD = dyn_cast<FunctionDecl>(D))
93 return FD->getDefinition();
94 if (
const auto *CTD = dyn_cast<ClassTemplateDecl>(D))
95 if (
const auto *RD = CTD->getTemplatedDecl())
96 return RD->getDefinition();
97 if (
const auto *
MD = dyn_cast<ObjCMethodDecl>(D)) {
98 if (
MD->isThisDeclarationADefinition())
101 auto *DeclCtx = cast<Decl>(
MD->getDeclContext());
102 if (DeclCtx->isInvalidDecl())
105 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(DeclCtx))
107 return Impl->getMethod(
MD->getSelector(),
MD->isInstanceMethod());
109 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(D))
112 if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
113 isa<TemplateTemplateParmDecl>(D))
120 if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
121 log(
"Possible overflow in symbol location: {0}", Loc);
127 llvm::StringRef TUPath) {
132 elog(
"{0}", LSPLoc.takeError());
141 URIStorage = Loc.uri.uri();
142 SymLoc.FileURI = URIStorage.c_str();
143 SymLoc.Start.setLine(Loc.range.start.line);
144 SymLoc.Start.setColumn(Loc.range.start.character);
145 SymLoc.End.setLine(Loc.range.end.line);
146 SymLoc.End.setColumn(Loc.range.end.character);
153 std::string &Scratch) {
157 ASTSym.ID = IdxSym.ID =
SymbolID(
"mock_symbol_id");
158 ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
159 IdxSym.CanonicalDeclaration = IdxLoc;
161 return Merged.CanonicalDeclaration;
164std::vector<std::pair<const NamedDecl *, DeclRelationSet>>
165getDeclAtPositionWithRelations(
ParsedAST &
AST, SourceLocation Pos,
167 ASTNodeKind *NodeKind =
nullptr) {
168 unsigned Offset =
AST.getSourceManager().getDecomposedSpellingLoc(Pos).second;
169 std::vector<std::pair<const NamedDecl *, DeclRelationSet>> Result;
173 *NodeKind = N->ASTNode.getNodeKind();
178 if (N->ASTNode.get<Attr>() && N->Parent)
181 std::back_inserter(Result),
182 [&](
auto &Entry) { return !(Entry.second & ~Relations); });
184 return !Result.empty();
187 Offset, ResultFromTree);
191std::vector<const NamedDecl *>
193 ASTNodeKind *NodeKind =
nullptr) {
194 std::vector<const NamedDecl *> Result;
196 getDeclAtPositionWithRelations(
AST, Pos, Relations, NodeKind))
197 Result.push_back(Entry.first);
204const CallExpr *findEnclosingCallAt(
ParsedAST &
AST, SourceLocation Loc) {
205 unsigned Offset =
AST.getSourceManager().getDecomposedSpellingLoc(Loc).second;
206 const CallExpr *Found =
nullptr;
209 if (const SelectionTree::Node *N =
211 Found = N->ASTNode.get<CallExpr>();
219std::optional<Location> makeLocation(
const ASTContext &
AST, SourceLocation Loc,
220 llvm::StringRef TUPath) {
221 const auto &SM =
AST.getSourceManager();
222 const auto F = SM.getFileEntryRefForID(SM.getFileID(Loc));
227 log(
"failed to get path!");
234 auto TokLen = Lexer::MeasureTokenLength(Loc, SM,
AST.getLangOpts());
236 SM, CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(TokLen)));
240std::optional<LocatedSymbol>
241locateModuleReferent(
const syntax::Token &TouchedIdentifier,
ParsedAST &
AST,
242 llvm::StringRef MainFilePath) {
243 const SourceManager &SM =
AST.getSourceManager();
244 const ASTContext &
Context =
AST.getASTContext();
246 const Module *ResultModule =
nullptr;
248 for (
const ImportDecl *Import :
Context.local_imports()) {
249 const Module *Imported = Import->getImportedModule();
250 ArrayRef<SourceLocation> IdentifierLocs = Import->getIdentifierLocs();
251 if (!Imported || !Imported->isNamedModule() || IdentifierLocs.empty())
254 const SourceLocation NameBegin = SM.getSpellingLoc(IdentifierLocs.front());
256 if (SM.isBeforeInTranslationUnit(TouchedIdentifier.location(), NameBegin))
259 const std::string FullName = Imported->getFullModuleName();
260 const SourceLocation NameEnd =
261 NameBegin.getLocWithOffset(FullName.size() - 1);
263 if (SM.isPointWithin(TouchedIdentifier.location(), NameBegin, NameEnd)) {
264 ResultModule = Imported;
272 const SourceLocation DefinitionLoc =
273 SM.getSpellingLoc(ResultModule->DefinitionLoc);
280 Result.
Name = ResultModule->getFullModuleName();
287std::optional<LocatedSymbol> locateFileReferent(
const Position &Pos,
289 llvm::StringRef MainFilePath) {
290 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
291 if (!Inc.Resolved.empty() && Inc.HashLine == Pos.line) {
293 File.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
294 File.PreferredDeclaration = {
296 File.Definition =
File.PreferredDeclaration;
306std::optional<LocatedSymbol>
307locateMacroReferent(
const syntax::Token &TouchedIdentifier,
ParsedAST &
AST,
308 llvm::StringRef MainFilePath) {
311 makeLocation(
AST.getASTContext(), M->NameLoc, MainFilePath)) {
313 Macro.Name = std::string(M->Name);
314 Macro.PreferredDeclaration = *Loc;
315 Macro.Definition = std::move(Loc);
336const NamedDecl *getPreferredDecl(
const NamedDecl *D) {
341 D = llvm::cast<NamedDecl>(
D->getCanonicalDecl());
344 if (
const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
345 if (
const auto *DefinitionID = ID->getDefinition())
347 if (
const auto *PD = dyn_cast<ObjCProtocolDecl>(D))
348 if (
const auto *DefinitionID = PD->getDefinition())
354std::vector<LocatedSymbol> findImplementors(llvm::DenseSet<SymbolID> IDs,
357 llvm::StringRef MainFilePath) {
358 if (IDs.empty() || !Index)
364 FindImplementorsMetric.record(1,
"find-base");
367 FindImplementorsMetric.record(1,
"find-override");
373 llvm::DenseSet<SymbolID> SeenIDs;
374 llvm::DenseSet<SymbolID> Queue = std::move(IDs);
375 std::vector<LocatedSymbol> Results;
376 while (!Queue.empty()) {
377 Req.Subjects = std::move(Queue);
380 if (!SeenIDs.insert(
Object.ID).second)
386 elog(
"Find overrides: {0}", DeclLoc.takeError());
389 Results.emplace_back();
390 Results.back().Name =
Object.Name.str();
391 Results.back().PreferredDeclaration = *DeclLoc;
394 elog(
"Failed to convert location: {0}", DefLoc.takeError());
397 Results.back().Definition = *DefLoc;
405void enhanceLocatedSymbolsFromIndex(llvm::MutableArrayRef<LocatedSymbol> Result,
407 llvm::StringRef MainFilePath) {
409 llvm::DenseMap<SymbolID, unsigned> ResultIndex;
410 for (
unsigned I = 0; I < Result.size(); ++I) {
411 if (
auto ID = Result[I].ID) {
412 ResultIndex.try_emplace(ID, I);
413 QueryRequest.IDs.insert(ID);
416 if (!Index || QueryRequest.IDs.empty())
419 Index->lookup(QueryRequest, [&](
const Symbol &Sym) {
420 auto &R = Result[ResultIndex.lookup(Sym.ID)];
425 if (
auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
426 R.PreferredDeclaration = *Loc;
430 if (
auto Loc = toLSPLocation(
431 getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
435 R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
438 if (
auto Loc = toLSPLocation(
439 getPreferredLocation(R.PreferredDeclaration,
440 Sym.CanonicalDeclaration, Scratch),
442 R.PreferredDeclaration = *Loc;
447bool objcMethodIsTouched(
const SourceManager &SM,
const ObjCMethodDecl *OMD,
448 SourceLocation Loc) {
449 unsigned NumSels = OMD->getNumSelectorLocs();
450 for (
unsigned I = 0; I < NumSels; ++I)
451 if (SM.getSpellingLoc(OMD->getSelectorLoc(I)) == Loc)
460std::vector<LocatedSymbol>
461locateASTReferent(SourceLocation CurLoc,
const syntax::Token *TouchedIdentifier,
464 const SourceManager &SM =
AST.getSourceManager();
466 std::vector<LocatedSymbol> Result;
470 auto AddResultDecl = [&](
const NamedDecl *
D) {
471 D = getPreferredDecl(D);
477 Result.emplace_back();
478 Result.back().Name =
printName(
AST.getASTContext(), *D);
479 Result.back().PreferredDeclaration = *Loc;
481 if (
const NamedDecl *Def = getDefinition(D))
482 Result.back().Definition = makeLocation(
495 if (
const auto *CE = findEnclosingCallAt(
AST, CurLoc)) {
496 if (
const auto *Callee = CE->getDirectCallee()) {
497 llvm::SmallPtrSet<const CXXConstructorDecl *, 1> Seen;
498 for (
const auto *Ctor :
500 if (Seen.insert(Ctor).second) {
501 LocateASTReferentMetric.record(1,
"forwarded-constructor");
506 if (!Result.empty()) {
507 enhanceLocatedSymbolsFromIndex(Result, Index, MainFilePath);
515 getDeclAtPositionWithRelations(
AST, CurLoc, Relations, &NodeKind);
516 llvm::DenseSet<SymbolID> VirtualMethods;
517 for (
const auto &E : Candidates) {
518 const NamedDecl *
D = E.first;
519 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
523 if (CMD->isPureVirtual()) {
524 if (TouchedIdentifier && SM.getSpellingLoc(CMD->getLocation()) ==
525 TouchedIdentifier->location()) {
527 LocateASTReferentMetric.record(1,
"method-to-override");
531 if (NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverrideAttr>()) ||
532 NodeKind.isSame(ASTNodeKind::getFromNodeKind<FinalAttr>())) {
534 for (
const NamedDecl *ND : CMD->overridden_methods())
545 if (
const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(D)) {
546 if (OMD->isThisDeclarationADefinition() && TouchedIdentifier &&
547 objcMethodIsTouched(SM, OMD, TouchedIdentifier->location())) {
548 llvm::SmallVector<const ObjCMethodDecl *, 4>
Overrides;
552 AddResultDecl(Override);
553 LocateASTReferentMetric.record(1,
"objc-overriden-method");
567 SM.isPointWithin(TouchedIdentifier ? TouchedIdentifier->location()
569 D->getBeginLoc(),
D->getEndLoc()))
574 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
575 if (TouchedIdentifier &&
576 D->getLocation() == TouchedIdentifier->location()) {
577 LocateASTReferentMetric.record(1,
"template-specialization-to-primary");
578 AddResultDecl(CTSD->getSpecializedTemplate());
589 if (
const auto *CD = dyn_cast<ObjCCategoryDecl>(D))
590 if (
const auto *ID = CD->getClassInterface())
591 if (TouchedIdentifier &&
592 (CD->getLocation() == TouchedIdentifier->location() ||
593 ID->getName() == TouchedIdentifier->text(SM))) {
594 LocateASTReferentMetric.record(1,
"objc-category-to-class");
598 LocateASTReferentMetric.record(1,
"regular");
602 enhanceLocatedSymbolsFromIndex(Result, Index, MainFilePath);
605 Index, MainFilePath);
610std::vector<LocatedSymbol> locateSymbolForType(
const ParsedAST &
AST,
611 const QualType &
Type,
613 const auto &SM =
AST.getSourceManager();
614 auto MainFilePath =
AST.tuPath();
618 auto Decls =
targetDecl(DynTypedNode::create(
Type.getNonReferenceType()),
620 AST.getHeuristicResolver());
624 std::vector<LocatedSymbol> Results;
625 const auto &ASTContext =
AST.getASTContext();
627 for (
const NamedDecl *D : Decls) {
628 D = getPreferredDecl(D);
630 auto Loc = makeLocation(ASTContext,
nameLocation(*D, SM), MainFilePath);
634 Results.emplace_back();
635 Results.back().Name =
printName(ASTContext, *D);
636 Results.back().PreferredDeclaration = *Loc;
638 if (
const NamedDecl *Def = getDefinition(D))
639 Results.back().Definition =
640 makeLocation(ASTContext,
nameLocation(*Def, SM), MainFilePath);
642 enhanceLocatedSymbolsFromIndex(Results, Index, MainFilePath);
647bool tokenSpelledAt(SourceLocation SpellingLoc,
const syntax::TokenBuffer &TB) {
648 auto ExpandedTokens = TB.expandedTokens(
649 TB.sourceManager().getMacroArgExpandedLocation(SpellingLoc));
650 return !ExpandedTokens.empty();
653llvm::StringRef sourcePrefix(SourceLocation Loc,
const SourceManager &SM) {
654 auto D = SM.getDecomposedLoc(Loc);
655 bool Invalid =
false;
656 llvm::StringRef Buf = SM.getBufferData(
D.first, &Invalid);
657 if (Invalid ||
D.second > Buf.size())
659 return Buf.substr(0,
D.second);
662bool isDependentName(ASTNodeKind NodeKind) {
663 return NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverloadExpr>()) ||
665 ASTNodeKind::getFromNodeKind<CXXDependentScopeMemberExpr>()) ||
667 ASTNodeKind::getFromNodeKind<DependentScopeDeclRefExpr>());
675 llvm::StringRef MainFilePath,
676 ASTNodeKind NodeKind) {
690 const auto &SM =
AST.getSourceManager();
704 bool TooMany =
false;
705 using ScoredLocatedSymbol = std::pair<float, LocatedSymbol>;
706 std::vector<ScoredLocatedSymbol> ScoredResults;
717 if (Sym.
SymInfo.Kind == index::SymbolKind::Constructor)
723 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
733 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
740 if (ScoredResults.size() >= 5) {
753 Relevance.
merge(Sym);
756 dlog(
"locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym.
Scope,
757 Sym.
Name, Score, Quality, Relevance);
759 ScoredResults.push_back({Score, std::move(Located)});
763 vlog(
"Heuristic index lookup for {0} returned too many candidates, ignored",
768 llvm::sort(ScoredResults,
769 [](
const ScoredLocatedSymbol &A,
const ScoredLocatedSymbol &B) {
770 return A.first > B.first;
772 std::vector<LocatedSymbol> Results;
773 for (
auto &Res : std::move(ScoredResults))
774 Results.push_back(std::move(Res.second));
776 vlog(
"No heuristic index definition for {0}", Word.
Text);
778 log(
"Found definition heuristically in index for {0}", Word.
Text);
783 const syntax::TokenBuffer &TB) {
794 const SourceManager &SM = TB.sourceManager();
798 unsigned WordLine = SM.getSpellingLineNumber(Word.
Location);
799 auto Cost = [&](SourceLocation Loc) ->
unsigned {
800 assert(SM.getFileID(Loc) ==
File &&
"spelled token in wrong file?");
801 unsigned Line = SM.getSpellingLineNumber(Loc);
802 return Line >= WordLine ? Line - WordLine : 2 * (WordLine - Line);
804 const syntax::Token *BestTok =
nullptr;
805 unsigned BestCost = -1;
809 unsigned MaxDistance =
810 1U << std::min<unsigned>(Word.
Text.size(),
811 std::numeric_limits<unsigned>::digits - 1);
818 WordLine + 1 <= MaxDistance / 2 ? 1 : WordLine + 1 - MaxDistance / 2;
819 unsigned LineMax = WordLine + 1 + MaxDistance;
820 SourceLocation LocMin = SM.translateLineCol(
File, LineMin, 1);
821 assert(LocMin.isValid());
822 SourceLocation LocMax = SM.translateLineCol(
File, LineMax, 1);
823 assert(LocMax.isValid());
827 auto Consider = [&](
const syntax::Token &Tok) {
828 if (Tok.location() < LocMin || Tok.location() > LocMax)
830 if (!(Tok.kind() == tok::identifier && Tok.text(SM) == Word.
Text))
833 if (Tok.location() == Word.
Location)
836 unsigned TokCost = Cost(Tok.location());
837 if (TokCost >= BestCost)
841 if (!(tokenSpelledAt(Tok.location(), TB) || TB.expansionStartingAt(&Tok)))
848 auto SpelledTokens = TB.spelledTokens(
File);
850 auto *I = llvm::partition_point(SpelledTokens, [&](
const syntax::Token &T) {
851 assert(SM.getFileID(T.location()) == SM.getFileID(Word.
Location));
852 return T.location() < Word.
Location;
855 for (
const syntax::Token &Tok : llvm::ArrayRef(I, SpelledTokens.end()))
859 for (
const syntax::Token &Tok :
860 llvm::reverse(llvm::ArrayRef(SpelledTokens.begin(), I)))
866 "Word {0} under cursor {1} isn't a token (after PP), trying nearby {2}",
868 BestTok->location().printToString(SM));
875 const auto &SM =
AST.getSourceManager();
876 auto MainFilePath =
AST.tuPath();
878 if (
auto File = locateFileReferent(Pos,
AST, MainFilePath))
879 return {std::move(*
File)};
883 elog(
"locateSymbolAt failed to convert position to source location: {0}",
888 const syntax::Token *TouchedIdentifier =
nullptr;
889 auto TokensTouchingCursor =
890 syntax::spelledTokensTouching(*CurLoc,
AST.getTokens());
891 for (
const syntax::Token &Tok : TokensTouchingCursor) {
892 if (Tok.kind() == tok::identifier) {
893 if (
auto Macro = locateMacroReferent(Tok,
AST, MainFilePath))
897 return {*std::move(
Macro)};
899 TouchedIdentifier = &Tok;
903 if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
909 auto LocSym = locateSymbolForType(
AST, *
Deduced, Index);
916 if (TouchedIdentifier)
918 locateModuleReferent(*TouchedIdentifier,
AST, MainFilePath))
919 return {*std::move(
Module)};
921 ASTNodeKind NodeKind;
922 auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier,
AST,
923 MainFilePath, Index, NodeKind);
924 if (!ASTResults.empty())
932 if (
const syntax::Token *NearbyIdent =
934 if (
auto Macro = locateMacroReferent(*NearbyIdent,
AST, MainFilePath)) {
935 log(
"Found macro definition heuristically using nearby identifier {0}",
937 return {*std::move(
Macro)};
939 ASTResults = locateASTReferent(NearbyIdent->location(), NearbyIdent,
AST,
940 MainFilePath, Index, NodeKind);
941 if (!ASTResults.empty()) {
942 log(
"Found definition heuristically using nearby identifier {0}",
943 NearbyIdent->text(SM));
946 vlog(
"No definition found using nearby identifier {0} at {1}", Word->Text,
947 Word->Location.printToString(SM));
950 auto TextualResults =
952 if (!TextualResults.empty())
953 return TextualResults;
960 const auto &SM =
AST.getSourceManager();
962 std::vector<DocumentLink> Result;
963 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
964 if (Inc.Resolved.empty())
968 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
972 const auto *HashTok =
AST.getTokens().spelledTokenContaining(HashLoc);
973 assert(HashTok &&
"got inclusion at wrong offset");
974 const auto *IncludeTok = std::next(HashTok);
975 const auto *FileTok = std::next(IncludeTok);
983 CharSourceRange FileRange;
985 if (FileTok->kind() == tok::TokenKind::less) {
989 syntax::FileRange(SM, FileTok->location(), Inc.Written.length())
991 }
else if (FileTok->kind() == tok::TokenKind::string_literal) {
994 FileRange = FileTok->range(SM).toCharRange(SM);
1005 FileRange = FileTok->range(SM).toCharRange(SM);
1024llvm::SmallVector<SourceLocation, 4>
1025tokensSpelledInRange(
const syntax::TokenBuffer &TB,
const SourceManager &SM,
1026 SourceRange Range) {
1027 llvm::SmallVector<SourceLocation, 4> Locs;
1028 if (Range.getBegin().isInvalid() || Range.getEnd().isInvalid() ||
1029 !Range.getBegin().isFileID() || !Range.getEnd().isFileID())
1031 FileID FID = SM.getFileID(Range.getBegin());
1032 if (FID != SM.getFileID(Range.getEnd()))
1034 unsigned EndOffset = SM.getFileOffset(Range.getEnd());
1035 llvm::ArrayRef<syntax::Token> Toks = TB.spelledTokens(FID);
1036 auto It = llvm::partition_point(Toks, [&](
const syntax::Token &Tok) {
1037 return SM.getFileOffset(Tok.location()) <
1038 SM.getFileOffset(Range.getBegin());
1040 for (; It != Toks.end() && SM.getFileOffset(It->location()) <= EndOffset;
1042 Locs.push_back(It->location());
1054llvm::SmallVector<SourceLocation, 4>
1055operatorNameTokens(
const Decl *D,
1056 const index::IndexDataConsumer::ASTNodeInfo &
ASTNode,
1057 SourceLocation Loc,
const syntax::TokenBuffer &TB,
1058 const SourceManager &SM) {
1059 std::optional<DeclarationNameInfo> NameInfo;
1060 if (
auto *ME = llvm::dyn_cast_or_null<MemberExpr>(
ASTNode.OrigE))
1061 NameInfo = ME->getMemberNameInfo();
1062 else if (
auto *DRE = llvm::dyn_cast_or_null<DeclRefExpr>(
ASTNode.OrigE))
1063 NameInfo = DRE->getNameInfo();
1064 else if (
auto *DSME = llvm::dyn_cast_or_null<CXXDependentScopeMemberExpr>(
1066 NameInfo = DSME->getMemberNameInfo();
1067 else if (
auto *DSDRE =
1068 llvm::dyn_cast_or_null<DependentScopeDeclRefExpr>(
ASTNode.OrigE))
1069 NameInfo = DSDRE->getNameInfo();
1070 else if (
auto *OE = llvm::dyn_cast_or_null<OverloadExpr>(
ASTNode.OrigE))
1074 NameInfo = OE->getNameInfo();
1075 else if (
auto *FD = llvm::dyn_cast_or_null<FunctionDecl>(D))
1076 NameInfo = FD->getNameInfo();
1089 if (!NameInfo || NameInfo->getLoc() != Loc)
1092 SourceRange ExtraRange;
1093 switch (NameInfo->getName().getNameKind()) {
1094 case DeclarationName::CXXOperatorName:
1095 ExtraRange = NameInfo->getCXXOperatorNameRange();
1097 case DeclarationName::CXXLiteralOperatorName: {
1101 SourceLocation SuffixLoc = NameInfo->getCXXLiteralOperatorNameLoc();
1102 if (SuffixLoc.isValid())
1103 if (
const auto *Tok = TB.spelledTokenContaining(SM.getFileLoc(SuffixLoc)))
1104 ExtraRange = SourceRange(Tok->location(), Tok->location());
1107 case DeclarationName::CXXConversionFunctionName:
1108 if (TypeSourceInfo *TInfo = NameInfo->getNamedTypeInfo())
1109 ExtraRange = TInfo->getTypeLoc().getSourceRange();
1114 if (ExtraRange.getBegin().isInvalid())
1117 llvm::SmallVector<SourceLocation, 4> Result{Loc};
1118 llvm::append_range(Result, tokensSpelledInRange(TB, SM, ExtraRange));
1123class ReferenceFinder :
public index::IndexDataConsumer {
1126 syntax::Token SpelledTok;
1127 index::SymbolRoleSet Role;
1128 const Decl *Container;
1130 Range range(
const SourceManager &SM)
const {
1135 ReferenceFinder(ParsedAST &AST,
1136 const llvm::ArrayRef<const NamedDecl *> Targets,
1138 : PerToken(PerToken), AST(AST) {
1139 for (
const NamedDecl *ND : Targets) {
1140 TargetDecls.insert(ND->getCanonicalDecl());
1141 if (
auto *
Constructor = llvm::dyn_cast<clang::CXXConstructorDecl>(ND))
1146 std::vector<Reference> take() && {
1147 llvm::sort(References, [](
const Reference &L,
const Reference &R) {
1148 auto LTok = L.SpelledTok.location();
1149 auto RTok = R.SpelledTok.location();
1150 return std::tie(LTok, L.Role) < std::tie(RTok, R.Role);
1153 References.erase(llvm::unique(References,
1154 [](
const Reference &L,
const Reference &R) {
1155 auto LTok = L.SpelledTok.location();
1156 auto RTok = R.SpelledTok.location();
1157 return std::tie(LTok, L.Role) ==
1158 std::tie(RTok, R.Role);
1161 return std::move(References);
1164 bool forwardsToConstructor(
const Decl *D) {
1165 if (TargetConstructors.empty())
1167 const auto *FD = llvm::dyn_cast<clang::FunctionDecl>(D);
1170 for (
const auto *Ctor :
1172 if (TargetConstructors.contains(Ctor))
1178 handleDeclOccurrence(
const Decl *D, index::SymbolRoleSet Roles,
1179 llvm::ArrayRef<index::SymbolRelation>
Relations,
1181 index::IndexDataConsumer::ASTNodeInfo ASTNode)
override {
1182 if (!TargetDecls.contains(
D->getCanonicalDecl()) &&
1183 !forwardsToConstructor(ASTNode.OrigD))
1185 const SourceManager &SM = AST.getSourceManager();
1188 const auto &TB = AST.getTokens();
1190 llvm::SmallVector<SourceLocation, 1> Locs;
1194 if (
auto *OME = llvm::dyn_cast_or_null<ObjCMessageExpr>(ASTNode.OrigE)) {
1195 OME->getSelectorLocs(Locs);
1196 }
else if (
auto *OMD =
1197 llvm::dyn_cast_or_null<ObjCMethodDecl>(ASTNode.OrigD)) {
1198 OMD->getSelectorLocs(Locs);
1205 Locs = operatorNameTokens(D, ASTNode, Loc, TB, SM);
1209 if (!Locs.empty() && Locs.front() != Loc)
1213 Locs.push_back(Loc);
1215 SymbolCollector::Options CollectorOpts;
1216 CollectorOpts.CollectMainFileSymbols =
true;
1217 for (SourceLocation L : Locs) {
1218 L = SM.getFileLoc(L);
1219 if (
const auto *Tok = TB.spelledTokenContaining(L))
1220 References.push_back(
1229 std::vector<Reference> References;
1231 llvm::DenseSet<const Decl *> TargetDecls;
1233 llvm::DenseSet<const CXXConstructorDecl *> TargetConstructors;
1236std::vector<ReferenceFinder::Reference>
1237findRefs(
const llvm::ArrayRef<const NamedDecl *> TargetDecls,
ParsedAST &
AST,
1239 ReferenceFinder RefFinder(
AST, TargetDecls, PerToken);
1240 index::IndexingOptions IndexOpts;
1241 IndexOpts.SystemSymbolFilter =
1242 index::IndexingOptions::SystemSymbolFilterKind::All;
1243 IndexOpts.IndexFunctionLocals =
true;
1244 IndexOpts.IndexParametersInDeclarations =
true;
1245 IndexOpts.IndexTemplateParameters =
true;
1246 indexTopLevelDecls(
AST.getASTContext(),
AST.getPreprocessor(),
1247 AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
1248 return std::move(RefFinder).take();
1251const Stmt *getFunctionBody(DynTypedNode N) {
1252 if (
const auto *FD = N.get<FunctionDecl>())
1253 return FD->getBody();
1254 if (
const auto *FD = N.get<BlockDecl>())
1255 return FD->getBody();
1256 if (
const auto *FD = N.get<LambdaExpr>())
1257 return FD->getBody();
1258 if (
const auto *FD = N.get<ObjCMethodDecl>())
1259 return FD->getBody();
1263const Stmt *getLoopBody(DynTypedNode N) {
1264 if (
const auto *LS = N.get<ForStmt>())
1265 return LS->getBody();
1266 if (
const auto *LS = N.get<CXXForRangeStmt>())
1267 return LS->getBody();
1268 if (
const auto *LS = N.get<WhileStmt>())
1269 return LS->getBody();
1270 if (
const auto *LS = N.get<DoStmt>())
1271 return LS->getBody();
1278class FindControlFlow :
public RecursiveASTVisitor<FindControlFlow> {
1287 All = Break | Continue | Return | Case | Throw | Goto,
1291 std::vector<SourceLocation> &Result;
1292 const SourceManager &SM;
1296 template <
typename Func>
1297 bool filterAndTraverse(DynTypedNode D,
const Func &Delegate) {
1298 llvm::scope_exit RestoreIgnore(
1299 [OldIgnore(Ignore),
this] { Ignore = OldIgnore; });
1300 if (getFunctionBody(D))
1302 else if (getLoopBody(D))
1303 Ignore |= Continue | Break;
1304 else if (
D.get<SwitchStmt>())
1305 Ignore |= Break | Case;
1307 return (Ignore == All) ? true : Delegate();
1310 void found(Target T, SourceLocation Loc) {
1313 if (SM.isBeforeInTranslationUnit(Loc, Bounds.getBegin()) ||
1314 SM.isBeforeInTranslationUnit(Bounds.getEnd(), Loc))
1316 Result.push_back(Loc);
1320 FindControlFlow(SourceRange Bounds, std::vector<SourceLocation> &Result,
1321 const SourceManager &SM)
1322 : Bounds(Bounds), Result(Result), SM(SM) {}
1326 bool TraverseDecl(Decl *D) {
1327 return !
D || filterAndTraverse(DynTypedNode::create(*D), [&] {
1328 return RecursiveASTVisitor::TraverseDecl(D);
1331 bool TraverseStmt(Stmt *S) {
1332 return !S || filterAndTraverse(DynTypedNode::create(*S), [&] {
1333 return RecursiveASTVisitor::TraverseStmt(S);
1338 bool VisitReturnStmt(ReturnStmt *R) {
1339 found(Return, R->getReturnLoc());
1342 bool VisitBreakStmt(BreakStmt *B) {
1343 found(Break,
B->getKwLoc());
1346 bool VisitContinueStmt(ContinueStmt *C) {
1347 found(Continue,
C->getKwLoc());
1350 bool VisitSwitchCase(SwitchCase *C) {
1351 found(Case,
C->getKeywordLoc());
1354 bool VisitCXXThrowExpr(CXXThrowExpr *T) {
1355 found(Throw,
T->getThrowLoc());
1358 bool VisitGotoStmt(GotoStmt *G) {
1360 if (
const auto *LD = G->getLabel()) {
1361 if (SM.isBeforeInTranslationUnit(LD->getLocation(), Bounds.getBegin()) ||
1362 SM.isBeforeInTranslationUnit(Bounds.getEnd(), LD->getLocation()))
1363 found(Goto, G->getGotoLoc());
1372SourceRange findCaseBounds(
const SwitchStmt &Switch, SourceLocation Loc,
1373 const SourceManager &SM) {
1376 std::vector<const SwitchCase *> Cases;
1377 for (
const SwitchCase *Case = Switch.getSwitchCaseList(); Case;
1378 Case = Case->getNextSwitchCase())
1379 Cases.push_back(Case);
1380 llvm::sort(Cases, [&](
const SwitchCase *L,
const SwitchCase *R) {
1381 return SM.isBeforeInTranslationUnit(L->getKeywordLoc(), R->getKeywordLoc());
1385 auto CaseAfter = llvm::partition_point(Cases, [&](
const SwitchCase *C) {
1386 return !SM.isBeforeInTranslationUnit(Loc,
C->getKeywordLoc());
1388 SourceLocation End = CaseAfter == Cases.end() ? Switch.getEndLoc()
1389 : (*CaseAfter)->getKeywordLoc();
1392 if (CaseAfter == Cases.begin())
1393 return SourceRange(Switch.getBeginLoc(), End);
1395 auto CaseBefore = std::prev(CaseAfter);
1397 while (CaseBefore != Cases.begin() &&
1398 (*std::prev(CaseBefore))->getSubStmt() == *CaseBefore)
1400 return SourceRange((*CaseBefore)->getKeywordLoc(), End);
1411 const SourceManager &SM =
1412 N.getDeclContext().getParentASTContext().getSourceManager();
1413 std::vector<SourceLocation> Result;
1416 enum class Cur {
None, Break, Continue, Return, Case, Throw } Cursor;
1417 if (N.ASTNode.get<BreakStmt>()) {
1418 Cursor = Cur::Break;
1419 }
else if (N.ASTNode.get<ContinueStmt>()) {
1420 Cursor = Cur::Continue;
1421 }
else if (N.ASTNode.get<ReturnStmt>()) {
1422 Cursor = Cur::Return;
1423 }
else if (N.ASTNode.get<CXXThrowExpr>()) {
1424 Cursor = Cur::Throw;
1425 }
else if (N.ASTNode.get<SwitchCase>()) {
1427 }
else if (
const GotoStmt *GS = N.ASTNode.get<GotoStmt>()) {
1429 Result.push_back(GS->getGotoLoc());
1430 if (
const auto *LD = GS->getLabel())
1431 Result.push_back(LD->getLocation());
1437 const Stmt *Root =
nullptr;
1440 for (
const auto *P = &N;
P;
P =
P->Parent) {
1442 if (
const Stmt *FunctionBody = getFunctionBody(
P->ASTNode)) {
1443 if (Cursor == Cur::Return || Cursor == Cur::Throw) {
1444 Root = FunctionBody;
1449 if (
const Stmt *LoopBody = getLoopBody(
P->ASTNode)) {
1450 if (Cursor == Cur::None || Cursor == Cur::Break ||
1451 Cursor == Cur::Continue) {
1455 Result.push_back(
P->ASTNode.getSourceRange().getBegin());
1462 if (
const auto *SS =
P->ASTNode.get<SwitchStmt>()) {
1463 if (Cursor == Cur::Break || Cursor == Cur::Case) {
1464 Result.push_back(SS->getSwitchLoc());
1465 Root = SS->getBody();
1467 Bounds = findCaseBounds(*SS, N.ASTNode.getSourceRange().getBegin(), SM);
1472 if (Cursor == Cur::None)
1476 if (!Bounds.isValid())
1477 Bounds = Root->getSourceRange();
1478 FindControlFlow(Bounds, Result, SM).TraverseStmt(
const_cast<Stmt *
>(Root));
1484 const SourceManager &SM) {
1487 if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
1489 else if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
1496std::optional<DocumentHighlight> toHighlight(SourceLocation Loc,
1497 const syntax::TokenBuffer &TB) {
1498 Loc = TB.sourceManager().getFileLoc(Loc);
1499 if (
const auto *Tok = TB.spelledTokenContaining(Loc)) {
1503 CharSourceRange::getCharRange(Tok->location(), Tok->endLocation()));
1506 return std::nullopt;
1513 const SourceManager &SM =
AST.getSourceManager();
1517 llvm::consumeError(CurLoc.takeError());
1520 std::vector<DocumentHighlight> Result;
1526 targetDecl(N->ASTNode, Relations,
AST.getHeuristicResolver());
1527 if (!TargetDecls.empty()) {
1530 for (
const auto &
Ref : findRefs(TargetDecls,
AST,
true))
1531 Result.push_back(toHighlight(
Ref, SM));
1534 auto ControlFlow = relatedControlFlow(*N);
1535 if (!ControlFlow.empty()) {
1536 for (SourceLocation Loc : ControlFlow)
1537 if (
auto Highlight = toHighlight(Loc,
AST.getTokens()))
1538 Result.push_back(std::move(*Highlight));
1546 AST.getSourceManager().getDecomposedSpellingLoc(*CurLoc).second;
1559 const SourceManager &SM =
AST.getSourceManager();
1562 elog(
"Failed to convert position to source location: {0}",
1563 CurLoc.takeError());
1568 llvm::DenseSet<SymbolID> IDs;
1570 for (
const NamedDecl *ND : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1571 if (
const auto *CXXMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1572 if (CXXMD->isVirtual()) {
1576 }
else if (
const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
1579 }
else if (
const auto *OMD = dyn_cast<ObjCMethodDecl>(ND)) {
1582 }
else if (
const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) {
1587 return findImplementors(std::move(IDs), QueryKind, Index,
AST.tuPath());
1593void getOverriddenMethods(
const CXXMethodDecl *CMD,
1594 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1597 for (
const CXXMethodDecl *Base : CMD->overridden_methods()) {
1599 OverriddenMethods.insert(ID);
1600 getOverriddenMethods(Base, OverriddenMethods);
1606void getOverriddenMethods(
const ObjCMethodDecl *OMD,
1607 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1610 llvm::SmallVector<const ObjCMethodDecl *, 4>
Overrides;
1612 for (
const ObjCMethodDecl *Base :
Overrides) {
1614 OverriddenMethods.insert(ID);
1615 getOverriddenMethods(Base, OverriddenMethods);
1619std::optional<std::string>
1620stringifyContainerForMainFileRef(
const Decl *Container) {
1623 if (
auto *ND = llvm::dyn_cast_if_present<NamedDecl>(Container))
1628std::optional<ReferencesResult>
1631 const auto &Includes =
AST.getIncludeStructure().MainFileIncludes;
1632 auto IncludeOnLine = llvm::find_if(Includes, [&Pos](
const Inclusion &Inc) {
1633 return Inc.HashLine == Pos.line;
1635 if (IncludeOnLine == Includes.end())
1636 return std::nullopt;
1638 const SourceManager &SM =
AST.getSourceManager();
1641 include_cleaner::walkUsed(
1643 &
AST.getPragmaIncludes(),
AST.getPreprocessor(),
1644 [&](
const include_cleaner::SymbolReference &
Ref,
1645 llvm::ArrayRef<include_cleaner::Header> Providers) {
1646 if (Ref.RT != include_cleaner::RefType::Explicit ||
1647 !isPreferredProvider(*IncludeOnLine, Converted, Providers))
1650 auto Loc = SM.getFileLoc(Ref.RefLocation);
1653 while (SM.getFileID(Loc) != SM.getMainFileID())
1654 Loc = SM.getIncludeLoc(SM.getFileID(Loc));
1656 ReferencesResult::Reference Result;
1657 const auto *Token = AST.getTokens().spelledTokenContaining(Loc);
1658 assert(Token &&
"references expected token here");
1659 Result.Loc.range = Range{sourceLocToPosition(SM, Token->location()),
1660 sourceLocToPosition(SM, Token->endLocation())};
1661 Result.Loc.uri = URIMainFile;
1662 Results.References.push_back(std::move(Result));
1664 if (Results.References.empty())
1665 return std::nullopt;
1670 IncludeOnLine->HashOffset);
1671 Result.Loc.uri = std::move(URIMainFile);
1672 Results.References.push_back(std::move(Result));
1680 const SourceManager &SM =
AST.getSourceManager();
1681 auto MainFilePath =
AST.tuPath();
1685 llvm::consumeError(CurLoc.takeError());
1689 const auto IncludeReferences =
1690 maybeFindIncludeReferences(
AST, Pos, URIMainFile);
1691 if (IncludeReferences)
1692 return *IncludeReferences;
1694 llvm::DenseSet<SymbolID> IDsToQuery, OverriddenMethods;
1696 const auto *IdentifierAtCursor =
1697 syntax::spelledIdentifierTouching(*CurLoc,
AST.getTokens());
1698 std::optional<DefinedMacro>
Macro;
1699 if (IdentifierAtCursor)
1705 const auto &IDToRefs =
AST.getMacros().MacroRefs;
1706 auto Refs = IDToRefs.find(MacroSID);
1707 if (Refs != IDToRefs.end()) {
1708 for (
const auto &
Ref : Refs->second) {
1711 Result.
Loc.
uri = URIMainFile;
1712 if (
Ref.IsDefinition) {
1716 Results.
References.push_back(std::move(Result));
1719 IDsToQuery.insert(MacroSID);
1726 std::vector<const NamedDecl *> Decls =
1727 getDeclAtPosition(
AST, *CurLoc, Relations);
1728 llvm::SmallVector<const NamedDecl *> TargetsInMainFile;
1729 for (
const NamedDecl *D : Decls) {
1733 TargetsInMainFile.push_back(D);
1737 if (D->getParentFunctionOrMethod())
1739 IDsToQuery.insert(ID);
1745 for (
const NamedDecl *ND : Decls) {
1748 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1749 if (CMD->isVirtual()) {
1752 getOverriddenMethods(CMD, OverriddenMethods);
1757 if (
const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(ND)) {
1759 getOverriddenMethods(OMD, OverriddenMethods);
1765 auto MainFileRefs = findRefs(TargetsInMainFile,
AST,
false);
1769 MainFileRefs.erase(llvm::unique(MainFileRefs,
1770 [](
const ReferenceFinder::Reference &L,
1771 const ReferenceFinder::Reference &R) {
1772 return L.SpelledTok.location() ==
1773 R.SpelledTok.location();
1775 MainFileRefs.end());
1776 for (
const auto &
Ref : MainFileRefs) {
1779 Result.
Loc.
uri = URIMainFile;
1783 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Declaration))
1786 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Definition))
1789 Results.
References.push_back(std::move(Result));
1797 llvm::DenseMap<SymbolID, size_t> RefIndexForContainer;
1800 if (Limit && Results.
References.size() >= Limit) {
1804 const auto LSPLocDecl =
1805 toLSPLocation(
Object.CanonicalDeclaration, MainFilePath);
1806 const auto LSPLocDef = toLSPLocation(
Object.Definition, MainFilePath);
1807 if (LSPLocDecl && LSPLocDecl != LSPLocDef) {
1809 Result.
Loc = {std::move(*LSPLocDecl), std::nullopt};
1814 Results.
References.push_back(std::move(Result));
1818 Result.
Loc = {std::move(*LSPLocDef), std::nullopt};
1824 Results.
References.push_back(std::move(Result));
1828 if (!ContainerLookup.
IDs.empty() && AddContext)
1829 Index->
lookup(ContainerLookup, [&](
const Symbol &Container) {
1830 auto Ref = RefIndexForContainer.find(Container.ID);
1831 assert(
Ref != RefIndexForContainer.end());
1833 Container.Scope.str() + Container.Name.str();
1838 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs,
bool AllowAttributes,
1839 bool AllowMainFileSymbols) {
1840 if (IDs.empty() || !Index || Results.
HasMore)
1843 Req.
IDs = std::move(IDs);
1855 llvm::DenseMap<SymbolID, std::vector<size_t>> RefIndicesForContainer;
1857 auto LSPLoc = toLSPLocation(R.
Location, MainFilePath);
1860 (!AllowMainFileSymbols && LSPLoc->uri.file() == MainFilePath))
1863 Result.
Loc = {std::move(*LSPLoc), std::nullopt};
1864 if (AllowAttributes) {
1874 ContainerLookup.
IDs.insert(Container);
1875 RefIndicesForContainer[Container].push_back(Results.
References.size());
1877 Results.
References.push_back(std::move(Result));
1880 if (!ContainerLookup.
IDs.empty() && AddContext)
1881 Index->
lookup(ContainerLookup, [&](
const Symbol &Container) {
1882 auto Ref = RefIndicesForContainer.find(Container.ID);
1883 assert(
Ref != RefIndicesForContainer.end());
1884 auto ContainerName = Container.Scope.str() + Container.Name.str();
1885 for (
auto I :
Ref->getSecond()) {
1886 Results.
References[I].Loc.containerName = ContainerName;
1890 QueryIndex(std::move(IDsToQuery),
true,
1895 QueryIndex(std::move(OverriddenMethods),
false,
1901 const SourceManager &SM =
AST.getSourceManager();
1904 llvm::consumeError(CurLoc.takeError());
1907 auto MainFilePath =
AST.tuPath();
1908 std::vector<SymbolDetails> Results;
1914 for (
const NamedDecl *D : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1915 D = getPreferredDecl(D);
1921 NewSymbol.
name = std::string(SplitQName.second);
1924 if (
const auto *ParentND =
1925 dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
1928 llvm::SmallString<32> USR;
1929 if (!index::generateUSRForDecl(D, USR)) {
1930 NewSymbol.
USR = std::string(USR);
1933 if (
const NamedDecl *Def = getDefinition(D))
1937 makeLocation(
AST.getASTContext(),
nameLocation(*D, SM), MainFilePath);
1939 Results.push_back(std::move(NewSymbol));
1942 const auto *IdentifierAtCursor =
1943 syntax::spelledIdentifierTouching(*CurLoc,
AST.getTokens());
1944 if (!IdentifierAtCursor)
1949 NewMacro.
name = std::string(M->Name);
1950 llvm::SmallString<32> USR;
1951 if (!index::generateUSRForMacro(NewMacro.
name, M->Info->getDefinitionLoc(),
1953 NewMacro.
USR = std::string(USR);
1956 Results.push_back(std::move(NewMacro));
1977 OS <<
" [override]";
1981template <
typename HierarchyItem>
1982static std::optional<HierarchyItem>
1984 ASTContext &Ctx = ND.getASTContext();
1985 auto &SM = Ctx.getSourceManager();
1986 SourceLocation NameLoc =
nameLocation(ND, Ctx.getSourceManager());
1987 SourceLocation BeginLoc = SM.getFileLoc(ND.getBeginLoc());
1988 SourceLocation EndLoc = SM.getFileLoc(ND.getEndLoc());
1989 const auto DeclRange =
1992 return std::nullopt;
1993 const auto FE = SM.getFileEntryRefForID(SM.getFileID(NameLoc));
1995 return std::nullopt;
1998 return std::nullopt;
2002 SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
2004 index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
2016 HI.selectionRange =
Range{NameBegin, NameEnd};
2017 if (!HI.range.contains(HI.selectionRange)) {
2020 HI.range = HI.selectionRange;
2028static std::optional<TypeHierarchyItem>
2032 Result->deprecated = ND.isDeprecated();
2042static std::optional<CallHierarchyItem>
2047 if (ND.isDeprecated())
2050 Result->data = ID.str();
2054template <
typename HierarchyItem>
2059 elog(
"Failed to convert symbol to hierarchy item: {0}", Loc.takeError());
2060 return std::nullopt;
2063 HI.name = std::string(S.
Name);
2064 HI.detail = S.
Scope.empty() ? std::string()
2065 : S.
Scope.drop_back(2).str();
2068 HI.selectionRange = Loc->range;
2071 HI.range = HI.selectionRange;
2077static std::optional<TypeHierarchyItem>
2082 Result->data.symbolID = S.
ID;
2087static std::optional<CallHierarchyItem>
2092 Result->data = S.
ID.
str();
2097 std::vector<TypeHierarchyItem> &SubTypes,
2103 if (std::optional<TypeHierarchyItem> ChildSym =
2106 ChildSym->children.emplace();
2109 SubTypes.emplace_back(std::move(*ChildSym));
2127 auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD :
nullptr;
2129 if (!RPSet.insert(Pattern).second) {
2134 for (
const CXXRecordDecl *ParentDecl :
typeParents(&CXXRD)) {
2135 if (std::optional<TypeHierarchyItem> ParentSym =
2139 Item.
parents->emplace_back(std::move(*ParentSym));
2144 RPSet.erase(Pattern);
2151 std::vector<const CXXRecordDecl *> Records;
2160 AST.getHeuristicResolver());
2161 for (
const NamedDecl *D : Decls) {
2163 if (
const VarDecl *VD = dyn_cast<VarDecl>(D)) {
2165 if (
const auto *RD = VD->getType().getTypePtr()->getAsCXXRecordDecl())
2166 Records.push_back(RD);
2170 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(D)) {
2172 Records.push_back(
Method->getParent());
2180 if (
auto *RD = dyn_cast<CXXRecordDecl>(D))
2181 Records.push_back(RD);
2186 const SourceManager &SM =
AST.getSourceManager();
2187 std::vector<const CXXRecordDecl *> Result;
2190 llvm::consumeError(Offset.takeError());
2195 Result = RecordFromNode(ST.commonAncestor());
2196 return !Result.empty();
2203static QualType
typeForNode(
const ASTContext &Ctx,
const HeuristicResolver *H,
2207 while (N && N->
ASTNode.get<NestedNameSpecifierLoc>())
2213 if (
const TypeLoc *TL = N->
ASTNode.get<TypeLoc>()) {
2214 if (llvm::isa<DeducedType>(TL->getTypePtr()))
2216 N->
getDeclContext().getParentASTContext(), H, TL->getBeginLoc()))
2219 if (llvm::isa<TypedefType>(TL->getTypePtr()))
2220 return TL->getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
2221 return TL->getType();
2225 if (
const auto *CCI = N->
ASTNode.get<CXXCtorInitializer>()) {
2226 if (
const FieldDecl *FD = CCI->getAnyMember())
2227 return FD->getType();
2228 if (
const Type *Base = CCI->getBaseClass())
2229 return QualType(Base, 0);
2233 if (
const auto *CBS = N->
ASTNode.get<CXXBaseSpecifier>())
2234 return CBS->getType();
2236 if (
const Decl *D = N->
ASTNode.get<Decl>()) {
2237 struct Visitor : ConstDeclVisitor<Visitor, QualType> {
2238 const ASTContext &Ctx;
2239 Visitor(
const ASTContext &Ctx) : Ctx(Ctx) {}
2241 QualType VisitValueDecl(
const ValueDecl *D) {
return D->getType(); }
2243 QualType VisitTypeDecl(
const TypeDecl *D) {
2244 return Ctx.getTypeDeclType(D);
2247 QualType VisitTypedefNameDecl(
const TypedefNameDecl *D) {
2248 return D->getUnderlyingType();
2251 QualType VisitTemplateDecl(
const TemplateDecl *D) {
2252 if (
const auto *TD = D->getTemplatedDecl())
2261 if (
const Stmt *S = N->
ASTNode.get<Stmt>()) {
2262 struct Visitor : ConstStmtVisitor<Visitor, QualType> {
2264 QualType type(
const Stmt *S) {
return S ? Visit(S) : QualType(); }
2267 QualType VisitExpr(
const Expr *S) {
2268 return S->IgnoreImplicitAsWritten()->getType();
2270 QualType VisitMemberExpr(
const MemberExpr *S) {
2272 if (S->getType()->isSpecificBuiltinType(BuiltinType::BoundMember))
2273 return Expr::findBoundMemberType(S);
2274 return VisitExpr(S);
2277 QualType VisitCXXDeleteExpr(
const CXXDeleteExpr *S) {
2278 return S->getDestroyedType();
2280 QualType VisitCXXPseudoDestructorExpr(
const CXXPseudoDestructorExpr *S) {
2281 return S->getDestroyedType();
2283 QualType VisitCXXThrowExpr(
const CXXThrowExpr *S) {
2284 return S->getSubExpr()->getType();
2286 QualType VisitCoyieldExpr(
const CoyieldExpr *S) {
2287 return type(S->getOperand());
2290 QualType VisitDesignatedInitExpr(
const DesignatedInitExpr *S) {
2292 for (
auto &D : llvm::reverse(S->designators()))
2293 if (D.isFieldDesignator())
2294 if (
const auto *FD = D.getFieldDecl())
2295 return FD->getType();
2300 QualType VisitSwitchStmt(
const SwitchStmt *S) {
2301 return type(S->getCond());
2303 QualType VisitWhileStmt(
const WhileStmt *S) {
return type(S->getCond()); }
2304 QualType VisitDoStmt(
const DoStmt *S) {
return type(S->getCond()); }
2305 QualType VisitIfStmt(
const IfStmt *S) {
return type(S->getCond()); }
2306 QualType VisitCaseStmt(
const CaseStmt *S) {
return type(S->getLHS()); }
2307 QualType VisitCXXForRangeStmt(
const CXXForRangeStmt *S) {
2308 return S->getLoopVariable()->getType();
2310 QualType VisitReturnStmt(
const ReturnStmt *S) {
2311 return type(S->getRetValue());
2313 QualType VisitCoreturnStmt(
const CoreturnStmt *S) {
2314 return type(S->getOperand());
2316 QualType VisitCXXCatchStmt(
const CXXCatchStmt *S) {
2317 return S->getCaughtType();
2319 QualType VisitObjCAtThrowStmt(
const ObjCAtThrowStmt *S) {
2320 return type(S->getThrowExpr());
2322 QualType VisitObjCAtCatchStmt(
const ObjCAtCatchStmt *S) {
2323 return S->getCatchParamDecl() ? S->getCatchParamDecl()->getType()
2336 QualType T,
const HeuristicResolver* H, llvm::SmallVector<QualType>& Out) {
2341 if (
const auto *TDT = T->getAs<TypedefType>())
2342 return Out.push_back(QualType(TDT, 0));
2345 if (
const auto *PT = T->getAs<PointerType>())
2347 if (
const auto *RT = T->getAs<ReferenceType>())
2349 if (
const auto *AT = T->getAsArrayTypeUnsafe())
2353 if (
auto *FT = T->getAs<FunctionType>())
2355 if (
auto *CRD = T->getAsCXXRecordDecl()) {
2356 if (CRD->isLambda())
2357 return unwrapFindType(CRD->getLambdaCallOperator()->getReturnType(), H,
2365 if (
auto PointeeType = H->getPointeeType(T.getNonReferenceType());
2366 !PointeeType.isNull()) {
2368 return Out.push_back(T);
2371 return Out.push_back(T);
2376 QualType T,
const HeuristicResolver* H) {
2377 llvm::SmallVector<QualType> Result;
2384 const SourceManager &SM =
AST.getSourceManager();
2386 std::vector<LocatedSymbol> Result;
2388 elog(
"failed to convert position {0} for findTypes: {1}", Pos,
2389 Offset.takeError());
2393 auto SymbolsFromNode =
2395 std::vector<LocatedSymbol> LocatedSymbols;
2403 AST.getHeuristicResolver()))
2404 llvm::copy(locateSymbolForType(
AST,
Type, Index),
2405 std::back_inserter(LocatedSymbols));
2407 return LocatedSymbols;
2411 Result = SymbolsFromNode(ST.commonAncestor());
2412 return !Result.empty();
2417std::vector<const CXXRecordDecl *>
typeParents(
const CXXRecordDecl *CXXRD) {
2418 std::vector<const CXXRecordDecl *> Result;
2422 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
2423 if (CTSD->isInvalidDecl())
2424 CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
2428 if (!CXXRD->hasDefinition())
2431 for (
auto Base : CXXRD->bases()) {
2432 const CXXRecordDecl *ParentDecl =
nullptr;
2434 const Type *
Type = Base.getType().getTypePtr();
2435 if (
const RecordType *RT =
Type->getAs<RecordType>()) {
2436 ParentDecl = RT->getAsCXXRecordDecl();
2442 if (
const TemplateSpecializationType *TS =
2443 Type->getAs<TemplateSpecializationType>()) {
2444 TemplateName TN = TS->getTemplateName();
2445 if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
2446 ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
2452 Result.push_back(ParentDecl);
2458std::vector<TypeHierarchyItem>
2462 std::vector<TypeHierarchyItem> Results;
2476 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
2477 CXXRD = CTSD->getTemplateInstantiationPattern();
2480 std::optional<TypeHierarchyItem> Result =
2488 if (WantChildren && ResolveLevels > 0) {
2489 Result->children.emplace();
2493 fillSubTypes(ID, *Result->children, Index, ResolveLevels, TUPath);
2496 Results.emplace_back(std::move(*Result));
2502std::optional<std::vector<TypeHierarchyItem>>
2505 return std::nullopt;
2507 llvm::DenseMap<SymbolID, const TypeHierarchyItem::ResolveParams *> IDToData;
2509 Req.
IDs.insert(Parent.symbolID);
2510 IDToData[Parent.symbolID] = &Parent;
2512 std::vector<TypeHierarchyItem> Results;
2513 Index->
lookup(Req, [&Item, &Results, &IDToData](
const Symbol &S) {
2515 THI->data = *IDToData.lookup(S.
ID);
2516 Results.emplace_back(std::move(*THI));
2519 return Results.empty() ? std::nullopt
2520 : std::make_optional(std::move(Results));
2525 std::vector<TypeHierarchyItem> Results;
2527 for (
auto &ChildSym : Results)
2528 ChildSym.data.parents = {Item.
data};
2546std::vector<CallHierarchyItem>
2548 std::vector<CallHierarchyItem> Result;
2549 const auto &SM =
AST.getSourceManager();
2552 elog(
"prepareCallHierarchy failed to convert position to source location: "
2557 for (
const NamedDecl *Decl : getDeclAtPosition(
AST, *Loc, {})) {
2558 if (!(isa<DeclContext>(Decl) &&
2559 cast<DeclContext>(Decl)->isFunctionOrMethod()) &&
2560 Decl->getKind() != Decl::Kind::FunctionTemplate &&
2561 !(Decl->getKind() == Decl::Kind::Var &&
2562 !cast<VarDecl>(Decl)->isLocalVarDecl()) &&
2563 Decl->getKind() != Decl::Kind::Field &&
2564 Decl->getKind() != Decl::Kind::EnumConstant)
2567 Result.emplace_back(std::move(*CHI));
2572std::vector<CallHierarchyIncomingCall>
2574 std::vector<CallHierarchyIncomingCall> Results;
2575 if (!Index || Item.
data.empty())
2579 elog(
"incomingCalls failed to find symbol: {0}", ID.takeError());
2588 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs,
bool MightNeverCall) {
2590 Request.
IDs = std::move(IDs);
2599 llvm::DenseMap<SymbolID, std::vector<Location>> CallsIn;
2603 Index->
refs(Request, [&](
const Ref &R) {
2606 elog(
"incomingCalls failed to convert location: {0}", Loc.takeError());
2615 Index->
lookup(ContainerLookup, [&](
const Symbol &Caller) {
2616 auto It = CallsIn.find(Caller.
ID);
2617 assert(It != CallsIn.end());
2619 std::vector<Range> FromRanges;
2620 for (
const Location &L : It->second) {
2628 FromRanges.push_back(L.
range);
2631 std::move(*CHI), std::move(FromRanges), MightNeverCall});
2635 QueryIndex({ID.get()},
false);
2638 if (Item.
kind == SymbolKind::Method) {
2639 llvm::DenseSet<SymbolID> IDs;
2642 IDs.insert(Caller.
ID);
2644 QueryIndex(std::move(IDs),
true);
2649 return A.from.name < B.from.name;
2654std::vector<CallHierarchyOutgoingCall>
2656 std::vector<CallHierarchyOutgoingCall> Results;
2657 if (!Index || Item.
data.empty())
2661 elog(
"outgoingCalls failed to find symbol: {0}", ID.takeError());
2670 llvm::DenseMap<SymbolID, std::vector<Location>> CallsOut;
2677 elog(
"outgoingCalls failed to convert location: {0}", Loc.takeError());
2680 auto It = CallsOut.try_emplace(R.Symbol, std::vector<Location>{}).first;
2681 It->second.push_back(*Loc);
2683 CallsOutLookup.
IDs.insert(R.Symbol);
2687 Index->
lookup(CallsOutLookup, [&](
const Symbol &Callee) {
2690 using SK = index::SymbolKind;
2691 auto Kind = Callee.SymInfo.Kind;
2692 assert(Kind == SK::Function || Kind == SK::InstanceMethod ||
2693 Kind == SK::ClassMethod || Kind == SK::StaticMethod ||
2694 Kind == SK::Constructor || Kind == SK::Destructor ||
2695 Kind == SK::ConversionFunction);
2699 auto It = CallsOut.find(Callee.ID);
2700 assert(It != CallsOut.end());
2702 std::vector<Range> FromRanges;
2703 for (
const Location &L : It->second) {
2712 FromRanges.push_back(L.
range);
2721 return A.to.name < B.to.name;
2727 const FunctionDecl *FD) {
2730 llvm::DenseSet<const Decl *> DeclRefs;
2734 for (
const Decl *D :
Ref.Targets) {
2735 if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
2740 AST.getHeuristicResolver());
Include Cleaner is clangd functionality for providing diagnostics for misuse of transitive headers an...
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for Markdown output.")
void elog(const char *Fmt, Ts &&... Vals)
A context is an immutable container for per-request data that must be propagated through layers that ...
Stores and provides access to parsed AST.
static bool createEach(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End, llvm::function_ref< bool(SelectionTree)> Func)
static const Decl * getRefContainer(const Decl *Enclosing, const SymbolCollector::Options &Opts)
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
virtual bool fuzzyFind(const FuzzyFindRequest &Req, llvm::function_ref< void(const Symbol &)> Callback) const =0
Matches symbols in the index fuzzily and applies Callback on each matched symbol before returning.
virtual bool containedRefs(const ContainedRefsRequest &Req, llvm::function_ref< void(const ContainedRefsResult &)> Callback) const =0
Find all symbols that are referenced by a symbol and apply Callback on each result.
virtual void relations(const RelationsRequest &Req, llvm::function_ref< void(const SymbolID &Subject, const Symbol &Object)> Callback) const =0
Finds all relations (S, P, O) stored in the index such that S is among Req.Subjects and P is Req....
virtual bool refs(const RefsRequest &Req, llvm::function_ref< void(const Ref &)> Callback) const =0
Finds all occurrences (e.g.
virtual void lookup(const LookupRequest &Req, llvm::function_ref< void(const Symbol &)> Callback) const =0
Looks up symbols with any of the given symbol IDs and applies Callback on each matched symbol.
virtual void reverseRelations(const RelationsRequest &Req, llvm::function_ref< void(const SymbolID &Subject, const Symbol &Object)> Callback) const =0
Finds all relations (O, P, S) stored in the index such that S is among Req.Subjects and P is Req....
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
std::vector< TypeHierarchyItem > subTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct children of a TypeHierarchyItem.
std::pair< StringRef, StringRef > splitQualifiedName(StringRef QName)
std::optional< std::vector< TypeHierarchyItem > > superTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct parents of a TypeHierarchyItem using SymbolIDs stored inside the item.
llvm::Expected< Location > indexToLSPLocation(const SymbolLocation &Loc, llvm::StringRef TUPath)
Helper function for deriving an LSP Location from an index SymbolLocation.
std::vector< CallHierarchyIncomingCall > incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
SymbolID getSymbolID(const Decl *D)
Gets the symbol ID for a declaration. Returned SymbolID might be null.
static std::optional< TypeHierarchyItem > symbolToTypeHierarchyItem(const Symbol &S, PathRef TUPath)
std::optional< SourceRange > toHalfOpenFileRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R)
Turns a token range into a half-open range and checks its correctness.
static std::optional< CallHierarchyItem > symbolToCallHierarchyItem(const Symbol &S, PathRef TUPath)
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)
std::string printName(const ASTContext &Ctx, const NamedDecl &ND)
Prints unqualified name of the decl for the purpose of displaying it to the user.
llvm::SmallVector< std::pair< const NamedDecl *, DeclRelationSet >, 1 > allTargetDecls(const DynTypedNode &N, const HeuristicResolver *Resolver)
Similar to targetDecl(), however instead of applying a filter, all possible decls are returned along ...
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
llvm::SmallVector< const NamedDecl *, 1 > explicitReferenceTargets(DynTypedNode N, DeclRelationSet Mask, const HeuristicResolver *Resolver)
Find declarations explicitly referenced in the source code defined by N.
std::vector< LocatedSymbol > locateSymbolTextually(const SpelledWord &Word, ParsedAST &AST, const SymbolIndex *Index, llvm::StringRef MainFilePath, ASTNodeKind NodeKind)
std::vector< SymbolTag > getSymbolTags(const Symbol &S)
Returns the SymbolTag values for the given indexed S.
std::vector< DocumentLink > getDocumentLinks(ParsedAST &AST)
Get all document links.
Symbol mergeSymbol(const Symbol &L, const Symbol &R)
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
std::vector< include_cleaner::SymbolReference > collectMacroReferences(ParsedAST &AST)
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
llvm::Expected< Location > symbolToLocation(const Symbol &Sym, llvm::StringRef TUPath)
Helper function for deriving an LSP Location for a Symbol.
SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM)
Find the source location of the identifier for D.
void vlog(const char *Fmt, Ts &&... Vals)
include_cleaner::Includes convertIncludes(const ParsedAST &AST)
Converts the clangd include representation to include-cleaner include representation.
std::vector< LocatedSymbol > findType(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns symbols for types referenced at Pos.
void findExplicitReferences(const Stmt *S, llvm::function_ref< void(ReferenceLoc)> Out, const HeuristicResolver *Resolver)
Recursively traverse S and report all references explicitly written in the code.
static QualType typeForNode(const ASTContext &Ctx, const HeuristicResolver *H, const SelectionTree::Node *N)
std::vector< TypeHierarchyItem > getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index, PathRef TUPath)
Get type hierarchy information at Pos.
static std::optional< TypeHierarchyItem > declToTypeHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath)
std::optional< QualType > getDeducedType(ASTContext &ASTCtx, const HeuristicResolver *Resolver, SourceLocation Loc)
Retrieves the deduced type at a given location (auto, decltype).
llvm::SmallVector< const NamedDecl *, 1 > targetDecl(const DynTypedNode &N, DeclRelationSet Mask, const HeuristicResolver *Resolver)
targetDecl() finds the declaration referred to by an AST node.
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index, bool AddContext)
Returns references of the symbol at a specified Pos.
static void fillSuperTypes(const CXXRecordDecl &CXXRD, llvm::StringRef TUPath, TypeHierarchyItem &Item, RecursionProtectionSet &RPSet)
std::optional< DefinedMacro > locateMacroAt(const syntax::Token &SpelledTok, Preprocessor &PP)
Gets the macro referenced by SpelledTok.
std::vector< LocatedSymbol > locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
std::vector< std::string > visibleNamespaces(llvm::StringRef Code, const LangOptions &LangOpts)
Heuristically determine namespaces visible at a point, without parsing Code.
static std::optional< HierarchyItem > declToHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath)
std::optional< std::string > getCanonicalPath(const FileEntryRef F, FileManager &FileMgr)
Get the canonical path of F.
static void unwrapFindType(QualType T, const HeuristicResolver *H, llvm::SmallVector< QualType > &Out)
static std::optional< HierarchyItem > symbolToHierarchyItem(const Symbol &S, PathRef TUPath)
const syntax::Token * findNearbyIdentifier(const SpelledWord &Word, const syntax::TokenBuffer &TB)
llvm::SmallPtrSet< const CXXRecordDecl *, 4 > RecursionProtectionSet
static void fillSubTypes(const SymbolID &ID, std::vector< TypeHierarchyItem > &SubTypes, const SymbolIndex *Index, int Levels, PathRef TUPath)
void log(const char *Fmt, Ts &&... Vals)
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
@ Type
An inlay hint that for a type annotation.
std::vector< LocatedSymbol > findImplementations(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns implementations at a specified Pos:
ArrayRef< const CXXConstructorDecl * > getForwardedConstructors(const FunctionDecl *FD, ForwardingToConstructorCache &Cache)
Returns the constructors that FD forwards to, if FD is a template instantiation of a likely forwardin...
const ObjCImplDecl * getCorrespondingObjCImpl(const ObjCContainerDecl *D)
Return the corresponding implementation/definition for the given ObjC container if it has one,...
SymbolKind indexSymbolKindToSymbolKind(const index::SymbolInfo &Info)
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
llvm::DenseSet< const Decl * > getNonLocalDeclRefs(ParsedAST &AST, const FunctionDecl *FD)
Returns all decls that are referenced in the FD except local symbols.
clangd::Range rangeTillEOL(llvm::StringRef Code, unsigned HashOffset)
Returns the range starting at offset and spanning the whole line.
float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance)
Combine symbol quality and relevance into a single score.
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
std::vector< CallHierarchyOutgoingCall > outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
void elog(const char *Fmt, Ts &&... Vals)
@ Underlying
This is the underlying declaration for a renaming-alias, decltype etc.
@ TemplatePattern
This is the pattern the template specialization was instantiated from.
@ Alias
This declaration is an alias that was referred to.
static std::optional< CallHierarchyItem > declToCallHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath)
std::vector< const CXXRecordDecl * > findRecordTypeAt(ParsedAST &AST, Position Pos)
Find the record types referenced at Pos.
std::vector< CallHierarchyItem > prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath)
Get call hierarchy information at Pos.
std::vector< const CXXRecordDecl * > typeParents(const CXXRecordDecl *CXXRD)
Given a record type declaration, find its base (parent) types.
cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccessCheck P
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Simplified description of a clang AST node.
Represents an incoming call, e.g. a caller of a method or constructor.
Represents programming constructs like functions or constructors in the context of call hierarchy.
URIForFile uri
The resource identifier of this item.
SymbolKind kind
The kind of this item.
std::string data
An optional 'data' field, which can be used to identify a call hierarchy item in an incomingCalls or ...
Represents an outgoing call, e.g.
A document highlight is a range inside a text document which deserves special attention.
Range range
The range this highlight applies to.
A range in a text document that links to an internal or external resource, like another text document...
std::vector< std::string > Scopes
If this is non-empty, symbols must be in at least one of the scopes (e.g.
std::string Query
A query string for the fuzzy find.
std::vector< std::string > ProximityPaths
Contextually relevant files (e.g.
bool AnyScope
If set to true, allow symbols from any scope.
std::optional< uint32_t > Limit
The number of top candidates to return.
Location PreferredDeclaration
std::optional< Location > Definition
URIForFile uri
The text document's URI.
llvm::DenseSet< SymbolID > IDs
Represents a symbol occurrence in the source file.
SymbolID Container
The ID of the symbol whose definition contains this reference.
SymbolLocation Location
The source location where the symbol is named.
Information about a reference written in the source code, independent of the actual AST node that thi...
std::optional< std::string > containerName
clangd extension: contains the name of the function or class in which the reference occurs
std::vector< Reference > References
bool WantContainer
If set, populates the container of the reference.
llvm::DenseSet< SymbolID > IDs
std::optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
llvm::DenseSet< SymbolID > Subjects
const DeclContext & getDeclContext() const
static std::optional< SpelledWord > touching(SourceLocation SpelledLoc, const syntax::TokenBuffer &TB, const LangOptions &LangOpts)
const syntax::Token * ExpandedToken
const syntax::Token * PartOfSpelledToken
Represents information about identifier.
std::optional< Location > definitionRange
std::string containerName
std::optional< Location > declarationRange
std::string USR
Unified Symbol Resolution identifier This is an opaque string uniquely identifying a symbol.
Attributes of a symbol that affect how much we like it.
float evaluateHeuristics() const
void merge(const CodeCompletionResult &SemaCCResult)
Attributes of a symbol-query pair that affect how much we like it.
llvm::StringRef Name
The name of the symbol (for ContextWords). Must be explicitly assigned.
void merge(const CodeCompletionResult &SemaResult)
enum clang::clangd::SymbolRelevanceSignals::QueryType Query
float evaluateHeuristics() const
Ensure we have enough bits to represent all SymbolTag values.
@ Deprecated
Indicates if the symbol is deprecated.
SymbolLocation Definition
The location of the symbol's definition, if one was found.
index::SymbolInfo SymInfo
The symbol information, like symbol kind.
llvm::StringRef Name
The unqualified name of the symbol, e.g. "bar" (for ns::bar).
llvm::StringRef Scope
The containing namespace. e.g. "" (global), "ns::" (top-level namespace).
llvm::StringRef TemplateSpecializationArgs
Argument list in human-readable format, will be displayed to help disambiguate between different spec...
SymbolLocation CanonicalDeclaration
The location of the preferred declaration of the symbol.
SymbolID ID
The ID of the symbol.
std::optional< std::vector< ResolveParams > > parents
std::nullopt means parents aren't resolved and empty is no parents.
URIForFile uri
The resource identifier of this item.
std::optional< std::vector< TypeHierarchyItem > > children
If this type hierarchy item is resolved, it contains the direct children of the current item.
std::optional< std::vector< TypeHierarchyItem > > parents
This is a clangd exntesion.
ResolveParams data
A data entry field that is preserved between a type hierarchy prepare and supertypes or subtypes requ...
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
llvm::StringRef file() const
Retrieves absolute path to the file.
Represents measurements of clangd events, e.g.
@ Counter
An aggregate number whose rate of change over time is meaningful.