20#include "clang-include-cleaner/Analysis.h"
21#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/LangOptions.h"
46#include "clang/Basic/SourceLocation.h"
47#include "clang/Basic/SourceManager.h"
48#include "clang/Basic/TokenKinds.h"
49#include "clang/Index/IndexDataConsumer.h"
50#include "clang/Index/IndexSymbol.h"
51#include "clang/Index/IndexingAction.h"
52#include "clang/Index/IndexingOptions.h"
53#include "clang/Index/USRGeneration.h"
54#include "clang/Lex/Lexer.h"
55#include "clang/Sema/HeuristicResolver.h"
56#include "clang/Tooling/Syntax/Tokens.h"
57#include "llvm/ADT/ArrayRef.h"
58#include "llvm/ADT/DenseMap.h"
59#include "llvm/ADT/STLExtras.h"
60#include "llvm/ADT/ScopeExit.h"
61#include "llvm/ADT/SmallSet.h"
62#include "llvm/ADT/SmallVector.h"
63#include "llvm/ADT/StringRef.h"
64#include "llvm/Support/Casting.h"
65#include "llvm/Support/Error.h"
66#include "llvm/Support/ErrorHandling.h"
67#include "llvm/Support/Path.h"
68#include "llvm/Support/raw_ostream.h"
83const NamedDecl *getDefinition(
const NamedDecl *D) {
86 if (
const auto *TD = dyn_cast<TagDecl>(D))
87 return TD->getDefinition();
88 if (
const auto *VD = dyn_cast<VarDecl>(D))
89 return VD->getDefinition();
90 if (
const auto *FD = dyn_cast<FunctionDecl>(D))
91 return FD->getDefinition();
92 if (
const auto *CTD = dyn_cast<ClassTemplateDecl>(D))
93 if (
const auto *RD = CTD->getTemplatedDecl())
94 return RD->getDefinition();
95 if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
96 if (MD->isThisDeclarationADefinition())
99 auto *DeclCtx = cast<Decl>(MD->getDeclContext());
100 if (DeclCtx->isInvalidDecl())
103 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(DeclCtx))
105 return Impl->getMethod(MD->getSelector(), MD->isInstanceMethod());
107 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(D))
110 if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
111 isa<TemplateTemplateParmDecl>(D))
118 if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
119 log(
"Possible overflow in symbol location: {0}", Loc);
125 llvm::StringRef TUPath) {
130 elog(
"{0}", LSPLoc.takeError());
139 URIStorage = Loc.uri.uri();
140 SymLoc.FileURI = URIStorage.c_str();
141 SymLoc.Start.setLine(Loc.range.start.line);
142 SymLoc.Start.setColumn(Loc.range.start.character);
143 SymLoc.End.setLine(Loc.range.end.line);
144 SymLoc.End.setColumn(Loc.range.end.character);
151 std::string &Scratch) {
155 ASTSym.ID = IdxSym.ID =
SymbolID(
"mock_symbol_id");
156 ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);
157 IdxSym.CanonicalDeclaration = IdxLoc;
159 return Merged.CanonicalDeclaration;
162std::vector<std::pair<const NamedDecl *, DeclRelationSet>>
163getDeclAtPositionWithRelations(
ParsedAST &
AST, SourceLocation Pos,
165 ASTNodeKind *NodeKind =
nullptr) {
166 unsigned Offset =
AST.getSourceManager().getDecomposedSpellingLoc(Pos).second;
167 std::vector<std::pair<const NamedDecl *, DeclRelationSet>> Result;
171 *NodeKind = N->ASTNode.getNodeKind();
176 if (N->ASTNode.get<Attr>() && N->Parent)
179 std::back_inserter(Result),
180 [&](
auto &Entry) { return !(Entry.second & ~Relations); });
182 return !Result.empty();
185 Offset, ResultFromTree);
189std::vector<const NamedDecl *>
191 ASTNodeKind *NodeKind =
nullptr) {
192 std::vector<const NamedDecl *> Result;
194 getDeclAtPositionWithRelations(
AST, Pos, Relations, NodeKind))
195 Result.push_back(Entry.first);
201std::optional<Location> makeLocation(
const ASTContext &
AST, SourceLocation Loc,
202 llvm::StringRef TUPath) {
203 const auto &SM =
AST.getSourceManager();
204 const auto F = SM.getFileEntryRefForID(SM.getFileID(Loc));
209 log(
"failed to get path!");
216 auto TokLen = Lexer::MeasureTokenLength(Loc, SM,
AST.getLangOpts());
218 SM, CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(TokLen)));
223std::optional<LocatedSymbol> locateFileReferent(
const Position &Pos,
225 llvm::StringRef MainFilePath) {
226 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
227 if (!Inc.Resolved.empty() && Inc.HashLine == Pos.line) {
229 File.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
230 File.PreferredDeclaration = {
232 File.Definition =
File.PreferredDeclaration;
242std::optional<LocatedSymbol>
243locateMacroReferent(
const syntax::Token &TouchedIdentifier,
ParsedAST &
AST,
244 llvm::StringRef MainFilePath) {
247 makeLocation(
AST.getASTContext(), M->NameLoc, MainFilePath)) {
249 Macro.Name = std::string(M->Name);
250 Macro.PreferredDeclaration = *Loc;
251 Macro.Definition = Loc;
272const NamedDecl *getPreferredDecl(
const NamedDecl *D) {
277 D = llvm::cast<NamedDecl>(
D->getCanonicalDecl());
280 if (
const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
281 if (
const auto *DefinitionID = ID->getDefinition())
283 if (
const auto *PD = dyn_cast<ObjCProtocolDecl>(D))
284 if (
const auto *DefinitionID = PD->getDefinition())
290std::vector<LocatedSymbol> findImplementors(llvm::DenseSet<SymbolID> IDs,
293 llvm::StringRef MainFilePath) {
294 if (IDs.empty() || !Index)
300 FindImplementorsMetric.record(1,
"find-base");
303 FindImplementorsMetric.record(1,
"find-override");
309 Req.Subjects = std::move(IDs);
310 std::vector<LocatedSymbol> Results;
315 elog(
"Find overrides: {0}", DeclLoc.takeError());
318 Results.emplace_back();
319 Results.back().Name =
Object.Name.str();
320 Results.back().PreferredDeclaration = *DeclLoc;
323 elog(
"Failed to convert location: {0}", DefLoc.takeError());
326 Results.back().Definition = *DefLoc;
333void enhanceLocatedSymbolsFromIndex(llvm::MutableArrayRef<LocatedSymbol> Result,
335 llvm::StringRef MainFilePath) {
337 llvm::DenseMap<SymbolID, unsigned> ResultIndex;
338 for (
unsigned I = 0; I < Result.size(); ++I) {
339 if (
auto ID = Result[I].ID) {
340 ResultIndex.try_emplace(ID, I);
341 QueryRequest.IDs.insert(ID);
344 if (!Index || QueryRequest.IDs.empty())
347 Index->lookup(QueryRequest, [&](
const Symbol &Sym) {
348 auto &R = Result[ResultIndex.lookup(Sym.ID)];
353 if (
auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
354 R.PreferredDeclaration = *Loc;
358 if (
auto Loc = toLSPLocation(
359 getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
363 R.Definition = toLSPLocation(Sym.Definition, MainFilePath);
366 if (
auto Loc = toLSPLocation(
367 getPreferredLocation(R.PreferredDeclaration,
368 Sym.CanonicalDeclaration, Scratch),
370 R.PreferredDeclaration = *Loc;
375bool objcMethodIsTouched(
const SourceManager &SM,
const ObjCMethodDecl *OMD,
376 SourceLocation Loc) {
377 unsigned NumSels = OMD->getNumSelectorLocs();
378 for (
unsigned I = 0; I < NumSels; ++I)
379 if (SM.getSpellingLoc(OMD->getSelectorLoc(I)) == Loc)
388std::vector<LocatedSymbol>
389locateASTReferent(SourceLocation CurLoc,
const syntax::Token *TouchedIdentifier,
392 const SourceManager &SM =
AST.getSourceManager();
394 std::vector<LocatedSymbol> Result;
398 auto AddResultDecl = [&](
const NamedDecl *
D) {
399 D = getPreferredDecl(D);
405 Result.emplace_back();
406 Result.back().Name =
printName(
AST.getASTContext(), *D);
407 Result.back().PreferredDeclaration = *Loc;
409 if (
const NamedDecl *Def = getDefinition(D))
410 Result.back().Definition = makeLocation(
418 getDeclAtPositionWithRelations(
AST, CurLoc, Relations, &NodeKind);
419 llvm::DenseSet<SymbolID> VirtualMethods;
420 for (
const auto &E : Candidates) {
421 const NamedDecl *
D = E.first;
422 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
426 if (CMD->isPureVirtual()) {
427 if (TouchedIdentifier && SM.getSpellingLoc(CMD->getLocation()) ==
428 TouchedIdentifier->location()) {
430 LocateASTReferentMetric.record(1,
"method-to-override");
434 if (NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverrideAttr>()) ||
435 NodeKind.isSame(ASTNodeKind::getFromNodeKind<FinalAttr>())) {
437 for (
const NamedDecl *ND : CMD->overridden_methods())
448 if (
const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(D)) {
449 if (OMD->isThisDeclarationADefinition() && TouchedIdentifier &&
450 objcMethodIsTouched(SM, OMD, TouchedIdentifier->location())) {
451 llvm::SmallVector<const ObjCMethodDecl *, 4> Overrides;
452 OMD->getOverriddenMethods(Overrides);
453 if (!Overrides.empty()) {
454 for (
const auto *Override : Overrides)
455 AddResultDecl(Override);
456 LocateASTReferentMetric.record(1,
"objc-overriden-method");
470 SM.isPointWithin(TouchedIdentifier ? TouchedIdentifier->location()
472 D->getBeginLoc(),
D->getEndLoc()))
477 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
478 if (TouchedIdentifier &&
479 D->getLocation() == TouchedIdentifier->location()) {
480 LocateASTReferentMetric.record(1,
"template-specialization-to-primary");
481 AddResultDecl(CTSD->getSpecializedTemplate());
492 if (
const auto *CD = dyn_cast<ObjCCategoryDecl>(D))
493 if (
const auto *ID = CD->getClassInterface())
494 if (TouchedIdentifier &&
495 (CD->getLocation() == TouchedIdentifier->location() ||
496 ID->getName() == TouchedIdentifier->text(SM))) {
497 LocateASTReferentMetric.record(1,
"objc-category-to-class");
501 LocateASTReferentMetric.record(1,
"regular");
505 enhanceLocatedSymbolsFromIndex(Result, Index, MainFilePath);
508 Index, MainFilePath);
509 Result.insert(Result.end(), Overrides.begin(), Overrides.end());
513std::vector<LocatedSymbol> locateSymbolForType(
const ParsedAST &
AST,
514 const QualType &
Type,
516 const auto &SM =
AST.getSourceManager();
517 auto MainFilePath =
AST.tuPath();
521 auto Decls =
targetDecl(DynTypedNode::create(
Type.getNonReferenceType()),
523 AST.getHeuristicResolver());
527 std::vector<LocatedSymbol> Results;
528 const auto &ASTContext =
AST.getASTContext();
530 for (
const NamedDecl *D : Decls) {
531 D = getPreferredDecl(D);
533 auto Loc = makeLocation(ASTContext,
nameLocation(*D, SM), MainFilePath);
537 Results.emplace_back();
538 Results.back().Name =
printName(ASTContext, *D);
539 Results.back().PreferredDeclaration = *Loc;
541 if (
const NamedDecl *Def = getDefinition(D))
542 Results.back().Definition =
543 makeLocation(ASTContext,
nameLocation(*Def, SM), MainFilePath);
545 enhanceLocatedSymbolsFromIndex(Results, Index, MainFilePath);
550bool tokenSpelledAt(SourceLocation SpellingLoc,
const syntax::TokenBuffer &TB) {
551 auto ExpandedTokens = TB.expandedTokens(
552 TB.sourceManager().getMacroArgExpandedLocation(SpellingLoc));
553 return !ExpandedTokens.empty();
556llvm::StringRef sourcePrefix(SourceLocation Loc,
const SourceManager &SM) {
557 auto D = SM.getDecomposedLoc(Loc);
559 llvm::StringRef Buf = SM.getBufferData(
D.first, &Invalid);
560 if (Invalid ||
D.second > Buf.size())
562 return Buf.substr(0,
D.second);
565bool isDependentName(ASTNodeKind NodeKind) {
566 return NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverloadExpr>()) ||
568 ASTNodeKind::getFromNodeKind<CXXDependentScopeMemberExpr>()) ||
570 ASTNodeKind::getFromNodeKind<DependentScopeDeclRefExpr>());
578 llvm::StringRef MainFilePath,
579 ASTNodeKind NodeKind) {
593 const auto &SM =
AST.getSourceManager();
607 bool TooMany =
false;
608 using ScoredLocatedSymbol = std::pair<float, LocatedSymbol>;
609 std::vector<ScoredLocatedSymbol> ScoredResults;
620 if (Sym.
SymInfo.Kind == index::SymbolKind::Constructor)
626 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
636 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
643 if (ScoredResults.size() >= 5) {
656 Relevance.
merge(Sym);
659 dlog(
"locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym.
Scope,
660 Sym.
Name, Score, Quality, Relevance);
662 ScoredResults.push_back({Score, std::move(Located)});
666 vlog(
"Heuristic index lookup for {0} returned too many candidates, ignored",
671 llvm::sort(ScoredResults,
672 [](
const ScoredLocatedSymbol &A,
const ScoredLocatedSymbol &B) {
673 return A.first > B.first;
675 std::vector<LocatedSymbol> Results;
676 for (
auto &Res : std::move(ScoredResults))
677 Results.push_back(std::move(Res.second));
679 vlog(
"No heuristic index definition for {0}", Word.
Text);
681 log(
"Found definition heuristically in index for {0}", Word.
Text);
686 const syntax::TokenBuffer &TB) {
697 const SourceManager &SM = TB.sourceManager();
701 unsigned WordLine = SM.getSpellingLineNumber(Word.
Location);
702 auto Cost = [&](SourceLocation Loc) ->
unsigned {
703 assert(SM.getFileID(Loc) ==
File &&
"spelled token in wrong file?");
704 unsigned Line = SM.getSpellingLineNumber(Loc);
705 return Line >= WordLine ? Line - WordLine : 2 * (WordLine - Line);
707 const syntax::Token *BestTok =
nullptr;
708 unsigned BestCost = -1;
712 unsigned MaxDistance =
713 1U << std::min<unsigned>(Word.
Text.size(),
714 std::numeric_limits<unsigned>::digits - 1);
721 WordLine + 1 <= MaxDistance / 2 ? 1 : WordLine + 1 - MaxDistance / 2;
722 unsigned LineMax = WordLine + 1 + MaxDistance;
723 SourceLocation LocMin = SM.translateLineCol(
File, LineMin, 1);
724 assert(LocMin.isValid());
725 SourceLocation LocMax = SM.translateLineCol(
File, LineMax, 1);
726 assert(LocMax.isValid());
730 auto Consider = [&](
const syntax::Token &Tok) {
731 if (Tok.location() < LocMin || Tok.location() > LocMax)
733 if (!(Tok.kind() == tok::identifier && Tok.text(SM) == Word.
Text))
736 if (Tok.location() == Word.
Location)
739 unsigned TokCost = Cost(Tok.location());
740 if (TokCost >= BestCost)
744 if (!(tokenSpelledAt(Tok.location(), TB) || TB.expansionStartingAt(&Tok)))
751 auto SpelledTokens = TB.spelledTokens(
File);
753 auto *I = llvm::partition_point(SpelledTokens, [&](
const syntax::Token &T) {
754 assert(SM.getFileID(T.location()) == SM.getFileID(Word.
Location));
755 return T.location() < Word.
Location;
758 for (
const syntax::Token &Tok : llvm::ArrayRef(I, SpelledTokens.end()))
762 for (
const syntax::Token &Tok :
763 llvm::reverse(llvm::ArrayRef(SpelledTokens.begin(), I)))
769 "Word {0} under cursor {1} isn't a token (after PP), trying nearby {2}",
771 BestTok->location().printToString(SM));
778 const auto &SM =
AST.getSourceManager();
779 auto MainFilePath =
AST.tuPath();
781 if (
auto File = locateFileReferent(Pos,
AST, MainFilePath))
782 return {std::move(*
File)};
786 elog(
"locateSymbolAt failed to convert position to source location: {0}",
791 const syntax::Token *TouchedIdentifier =
nullptr;
792 auto TokensTouchingCursor =
793 syntax::spelledTokensTouching(*CurLoc,
AST.getTokens());
794 for (
const syntax::Token &Tok : TokensTouchingCursor) {
795 if (Tok.kind() == tok::identifier) {
796 if (
auto Macro = locateMacroReferent(Tok,
AST, MainFilePath))
800 return {*std::move(
Macro)};
802 TouchedIdentifier = &Tok;
806 if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
812 auto LocSym = locateSymbolForType(
AST, *
Deduced, Index);
819 ASTNodeKind NodeKind;
820 auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier,
AST,
821 MainFilePath, Index, NodeKind);
822 if (!ASTResults.empty())
830 if (
const syntax::Token *NearbyIdent =
832 if (
auto Macro = locateMacroReferent(*NearbyIdent,
AST, MainFilePath)) {
833 log(
"Found macro definition heuristically using nearby identifier {0}",
835 return {*std::move(
Macro)};
837 ASTResults = locateASTReferent(NearbyIdent->location(), NearbyIdent,
AST,
838 MainFilePath, Index, NodeKind);
839 if (!ASTResults.empty()) {
840 log(
"Found definition heuristically using nearby identifier {0}",
841 NearbyIdent->text(SM));
844 vlog(
"No definition found using nearby identifier {0} at {1}", Word->Text,
845 Word->Location.printToString(SM));
848 auto TextualResults =
850 if (!TextualResults.empty())
851 return TextualResults;
858 const auto &SM =
AST.getSourceManager();
860 std::vector<DocumentLink> Result;
861 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
862 if (Inc.Resolved.empty())
866 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
870 const auto *HashTok =
AST.getTokens().spelledTokenContaining(HashLoc);
871 assert(HashTok &&
"got inclusion at wrong offset");
872 const auto *IncludeTok = std::next(HashTok);
873 const auto *FileTok = std::next(IncludeTok);
881 CharSourceRange FileRange;
883 if (FileTok->kind() == tok::TokenKind::less) {
887 syntax::FileRange(SM, FileTok->location(), Inc.Written.length())
889 }
else if (FileTok->kind() == tok::TokenKind::string_literal) {
892 FileRange = FileTok->range(SM).toCharRange(SM);
903 FileRange = FileTok->range(SM).toCharRange(SM);
917class ReferenceFinder :
public index::IndexDataConsumer {
920 syntax::Token SpelledTok;
921 index::SymbolRoleSet Role;
922 const Decl *Container;
924 Range range(
const SourceManager &SM)
const {
929 ReferenceFinder(
const ParsedAST &AST,
930 const llvm::ArrayRef<const NamedDecl *> Targets,
932 : PerToken(PerToken), AST(AST) {
933 for (
const NamedDecl *ND : Targets)
934 TargetDecls.insert(ND->getCanonicalDecl());
937 std::vector<Reference> take() && {
938 llvm::sort(References, [](
const Reference &L,
const Reference &R) {
939 auto LTok = L.SpelledTok.location();
940 auto RTok = R.SpelledTok.location();
941 return std::tie(LTok, L.Role) < std::tie(RTok, R.Role);
944 References.erase(llvm::unique(References,
945 [](
const Reference &L,
const Reference &R) {
946 auto LTok = L.SpelledTok.location();
947 auto RTok = R.SpelledTok.location();
948 return std::tie(LTok, L.Role) ==
949 std::tie(RTok, R.Role);
952 return std::move(References);
956 handleDeclOccurrence(
const Decl *D, index::SymbolRoleSet Roles,
957 llvm::ArrayRef<index::SymbolRelation>
Relations,
959 index::IndexDataConsumer::ASTNodeInfo ASTNode)
override {
960 if (!TargetDecls.contains(
D->getCanonicalDecl()))
962 const SourceManager &SM = AST.getSourceManager();
965 const auto &TB = AST.getTokens();
967 llvm::SmallVector<SourceLocation, 1> Locs;
971 if (
auto *OME = llvm::dyn_cast_or_null<ObjCMessageExpr>(ASTNode.OrigE)) {
972 OME->getSelectorLocs(Locs);
973 }
else if (
auto *OMD =
974 llvm::dyn_cast_or_null<ObjCMethodDecl>(ASTNode.OrigD)) {
975 OMD->getSelectorLocs(Locs);
979 if (!Locs.empty() && Locs.front() != Loc)
985 SymbolCollector::Options CollectorOpts;
986 CollectorOpts.CollectMainFileSymbols =
true;
987 for (SourceLocation L : Locs) {
988 L = SM.getFileLoc(L);
989 if (
const auto *Tok = TB.spelledTokenContaining(L))
990 References.push_back(
999 std::vector<Reference> References;
1000 const ParsedAST &AST;
1001 llvm::DenseSet<const Decl *> TargetDecls;
1004std::vector<ReferenceFinder::Reference>
1005findRefs(
const llvm::ArrayRef<const NamedDecl *> TargetDecls,
ParsedAST &
AST,
1007 ReferenceFinder RefFinder(
AST, TargetDecls, PerToken);
1008 index::IndexingOptions IndexOpts;
1009 IndexOpts.SystemSymbolFilter =
1010 index::IndexingOptions::SystemSymbolFilterKind::All;
1011 IndexOpts.IndexFunctionLocals =
true;
1012 IndexOpts.IndexParametersInDeclarations =
true;
1013 IndexOpts.IndexTemplateParameters =
true;
1014 indexTopLevelDecls(
AST.getASTContext(),
AST.getPreprocessor(),
1015 AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
1016 return std::move(RefFinder).take();
1019const Stmt *getFunctionBody(DynTypedNode N) {
1020 if (
const auto *FD = N.get<FunctionDecl>())
1021 return FD->getBody();
1022 if (
const auto *FD = N.get<BlockDecl>())
1023 return FD->getBody();
1024 if (
const auto *FD = N.get<LambdaExpr>())
1025 return FD->getBody();
1026 if (
const auto *FD = N.get<ObjCMethodDecl>())
1027 return FD->getBody();
1031const Stmt *getLoopBody(DynTypedNode N) {
1032 if (
const auto *LS = N.get<ForStmt>())
1033 return LS->getBody();
1034 if (
const auto *LS = N.get<CXXForRangeStmt>())
1035 return LS->getBody();
1036 if (
const auto *LS = N.get<WhileStmt>())
1037 return LS->getBody();
1038 if (
const auto *LS = N.get<DoStmt>())
1039 return LS->getBody();
1046class FindControlFlow :
public RecursiveASTVisitor<FindControlFlow> {
1055 All = Break | Continue | Return | Case | Throw | Goto,
1059 std::vector<SourceLocation> &Result;
1060 const SourceManager &SM;
1064 template <
typename Func>
1065 bool filterAndTraverse(DynTypedNode D,
const Func &Delegate) {
1066 auto RestoreIgnore = llvm::make_scope_exit(
1067 [OldIgnore(Ignore),
this] { Ignore = OldIgnore; });
1068 if (getFunctionBody(D))
1070 else if (getLoopBody(D))
1071 Ignore |= Continue | Break;
1072 else if (
D.get<SwitchStmt>())
1073 Ignore |= Break | Case;
1075 return (Ignore == All) ? true : Delegate();
1078 void found(Target T, SourceLocation Loc) {
1081 if (SM.isBeforeInTranslationUnit(Loc, Bounds.getBegin()) ||
1082 SM.isBeforeInTranslationUnit(Bounds.getEnd(), Loc))
1084 Result.push_back(Loc);
1088 FindControlFlow(SourceRange Bounds, std::vector<SourceLocation> &Result,
1089 const SourceManager &SM)
1090 : Bounds(Bounds), Result(Result), SM(SM) {}
1094 bool TraverseDecl(Decl *D) {
1095 return !
D || filterAndTraverse(DynTypedNode::create(*D), [&] {
1096 return RecursiveASTVisitor::TraverseDecl(D);
1099 bool TraverseStmt(Stmt *S) {
1100 return !S || filterAndTraverse(DynTypedNode::create(*S), [&] {
1101 return RecursiveASTVisitor::TraverseStmt(S);
1106 bool VisitReturnStmt(ReturnStmt *R) {
1107 found(Return, R->getReturnLoc());
1110 bool VisitBreakStmt(BreakStmt *B) {
1111 found(Break,
B->getKwLoc());
1114 bool VisitContinueStmt(ContinueStmt *C) {
1115 found(Continue,
C->getKwLoc());
1118 bool VisitSwitchCase(SwitchCase *C) {
1119 found(Case,
C->getKeywordLoc());
1122 bool VisitCXXThrowExpr(CXXThrowExpr *T) {
1123 found(Throw,
T->getThrowLoc());
1126 bool VisitGotoStmt(GotoStmt *G) {
1128 if (
const auto *LD = G->getLabel()) {
1129 if (SM.isBeforeInTranslationUnit(LD->getLocation(), Bounds.getBegin()) ||
1130 SM.isBeforeInTranslationUnit(Bounds.getEnd(), LD->getLocation()))
1131 found(Goto, G->getGotoLoc());
1140SourceRange findCaseBounds(
const SwitchStmt &Switch, SourceLocation Loc,
1141 const SourceManager &SM) {
1144 std::vector<const SwitchCase *> Cases;
1145 for (
const SwitchCase *Case = Switch.getSwitchCaseList(); Case;
1146 Case = Case->getNextSwitchCase())
1147 Cases.push_back(Case);
1148 llvm::sort(Cases, [&](
const SwitchCase *L,
const SwitchCase *R) {
1149 return SM.isBeforeInTranslationUnit(L->getKeywordLoc(), R->getKeywordLoc());
1153 auto CaseAfter = llvm::partition_point(Cases, [&](
const SwitchCase *C) {
1154 return !SM.isBeforeInTranslationUnit(Loc,
C->getKeywordLoc());
1156 SourceLocation End = CaseAfter == Cases.end() ? Switch.getEndLoc()
1157 : (*CaseAfter)->getKeywordLoc();
1160 if (CaseAfter == Cases.begin())
1161 return SourceRange(Switch.getBeginLoc(), End);
1163 auto CaseBefore = std::prev(CaseAfter);
1165 while (CaseBefore != Cases.begin() &&
1166 (*std::prev(CaseBefore))->getSubStmt() == *CaseBefore)
1168 return SourceRange((*CaseBefore)->getKeywordLoc(), End);
1179 const SourceManager &SM =
1180 N.getDeclContext().getParentASTContext().getSourceManager();
1181 std::vector<SourceLocation> Result;
1184 enum class Cur {
None, Break, Continue, Return, Case, Throw } Cursor;
1185 if (N.ASTNode.get<BreakStmt>()) {
1186 Cursor = Cur::Break;
1187 }
else if (N.ASTNode.get<ContinueStmt>()) {
1188 Cursor = Cur::Continue;
1189 }
else if (N.ASTNode.get<ReturnStmt>()) {
1190 Cursor = Cur::Return;
1191 }
else if (N.ASTNode.get<CXXThrowExpr>()) {
1192 Cursor = Cur::Throw;
1193 }
else if (N.ASTNode.get<SwitchCase>()) {
1195 }
else if (
const GotoStmt *GS = N.ASTNode.get<GotoStmt>()) {
1197 Result.push_back(GS->getGotoLoc());
1198 if (
const auto *LD = GS->getLabel())
1199 Result.push_back(LD->getLocation());
1205 const Stmt *Root =
nullptr;
1208 for (
const auto *P = &N;
P;
P =
P->Parent) {
1210 if (
const Stmt *FunctionBody = getFunctionBody(
P->ASTNode)) {
1211 if (Cursor == Cur::Return || Cursor == Cur::Throw) {
1212 Root = FunctionBody;
1217 if (
const Stmt *LoopBody = getLoopBody(
P->ASTNode)) {
1218 if (Cursor == Cur::None || Cursor == Cur::Break ||
1219 Cursor == Cur::Continue) {
1223 Result.push_back(
P->ASTNode.getSourceRange().getBegin());
1230 if (
const auto *SS =
P->ASTNode.get<SwitchStmt>()) {
1231 if (Cursor == Cur::Break || Cursor == Cur::Case) {
1232 Result.push_back(SS->getSwitchLoc());
1233 Root = SS->getBody();
1235 Bounds = findCaseBounds(*SS, N.ASTNode.getSourceRange().getBegin(), SM);
1240 if (Cursor == Cur::None)
1244 if (!Bounds.isValid())
1245 Bounds = Root->getSourceRange();
1246 FindControlFlow(Bounds, Result, SM).TraverseStmt(
const_cast<Stmt *
>(Root));
1252 const SourceManager &SM) {
1255 if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
1257 else if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
1264std::optional<DocumentHighlight> toHighlight(SourceLocation Loc,
1265 const syntax::TokenBuffer &TB) {
1266 Loc = TB.sourceManager().getFileLoc(Loc);
1267 if (
const auto *Tok = TB.spelledTokenContaining(Loc)) {
1271 CharSourceRange::getCharRange(Tok->location(), Tok->endLocation()));
1274 return std::nullopt;
1281 const SourceManager &SM =
AST.getSourceManager();
1285 llvm::consumeError(CurLoc.takeError());
1288 std::vector<DocumentHighlight> Result;
1294 targetDecl(N->ASTNode, Relations,
AST.getHeuristicResolver());
1295 if (!TargetDecls.empty()) {
1298 for (
const auto &
Ref : findRefs(TargetDecls,
AST,
true))
1299 Result.push_back(toHighlight(
Ref, SM));
1302 auto ControlFlow = relatedControlFlow(*N);
1303 if (!ControlFlow.empty()) {
1304 for (SourceLocation Loc : ControlFlow)
1305 if (
auto Highlight = toHighlight(Loc,
AST.getTokens()))
1306 Result.push_back(std::move(*Highlight));
1314 AST.getSourceManager().getDecomposedSpellingLoc(*CurLoc).second;
1327 const SourceManager &SM =
AST.getSourceManager();
1330 elog(
"Failed to convert position to source location: {0}",
1331 CurLoc.takeError());
1336 llvm::DenseSet<SymbolID> IDs;
1338 for (
const NamedDecl *ND : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1339 if (
const auto *CXXMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1340 if (CXXMD->isVirtual()) {
1344 }
else if (
const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
1347 }
else if (
const auto *OMD = dyn_cast<ObjCMethodDecl>(ND)) {
1350 }
else if (
const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) {
1355 return findImplementors(std::move(IDs), QueryKind, Index,
AST.tuPath());
1361void getOverriddenMethods(
const CXXMethodDecl *CMD,
1362 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1365 for (
const CXXMethodDecl *Base : CMD->overridden_methods()) {
1367 OverriddenMethods.insert(ID);
1368 getOverriddenMethods(Base, OverriddenMethods);
1374void getOverriddenMethods(
const ObjCMethodDecl *OMD,
1375 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1378 llvm::SmallVector<const ObjCMethodDecl *, 4> Overrides;
1379 OMD->getOverriddenMethods(Overrides);
1380 for (
const ObjCMethodDecl *Base : Overrides) {
1382 OverriddenMethods.insert(ID);
1383 getOverriddenMethods(Base, OverriddenMethods);
1387std::optional<std::string>
1388stringifyContainerForMainFileRef(
const Decl *Container) {
1391 if (
auto *ND = llvm::dyn_cast_if_present<NamedDecl>(Container))
1396std::optional<ReferencesResult>
1399 const auto &Includes =
AST.getIncludeStructure().MainFileIncludes;
1400 auto IncludeOnLine = llvm::find_if(Includes, [&Pos](
const Inclusion &Inc) {
1401 return Inc.HashLine == Pos.line;
1403 if (IncludeOnLine == Includes.end())
1404 return std::nullopt;
1406 const SourceManager &SM =
AST.getSourceManager();
1409 include_cleaner::walkUsed(
1411 &
AST.getPragmaIncludes(),
AST.getPreprocessor(),
1412 [&](
const include_cleaner::SymbolReference &
Ref,
1413 llvm::ArrayRef<include_cleaner::Header> Providers) {
1414 if (Ref.RT != include_cleaner::RefType::Explicit ||
1415 !isPreferredProvider(*IncludeOnLine, Converted, Providers))
1418 auto Loc = SM.getFileLoc(Ref.RefLocation);
1421 while (SM.getFileID(Loc) != SM.getMainFileID())
1422 Loc = SM.getIncludeLoc(SM.getFileID(Loc));
1424 ReferencesResult::Reference Result;
1425 const auto *Token = AST.getTokens().spelledTokenContaining(Loc);
1426 assert(Token &&
"references expected token here");
1427 Result.Loc.range = Range{sourceLocToPosition(SM, Token->location()),
1428 sourceLocToPosition(SM, Token->endLocation())};
1429 Result.Loc.uri = URIMainFile;
1430 Results.References.push_back(std::move(Result));
1432 if (Results.References.empty())
1433 return std::nullopt;
1438 IncludeOnLine->HashOffset);
1439 Result.Loc.uri = URIMainFile;
1440 Results.References.push_back(std::move(Result));
1448 const SourceManager &SM =
AST.getSourceManager();
1449 auto MainFilePath =
AST.tuPath();
1453 llvm::consumeError(CurLoc.takeError());
1457 const auto IncludeReferences =
1458 maybeFindIncludeReferences(
AST, Pos, URIMainFile);
1459 if (IncludeReferences)
1460 return *IncludeReferences;
1462 llvm::DenseSet<SymbolID> IDsToQuery, OverriddenMethods;
1464 const auto *IdentifierAtCursor =
1465 syntax::spelledIdentifierTouching(*CurLoc,
AST.getTokens());
1466 std::optional<DefinedMacro>
Macro;
1467 if (IdentifierAtCursor)
1473 const auto &IDToRefs =
AST.getMacros().MacroRefs;
1474 auto Refs = IDToRefs.find(MacroSID);
1475 if (Refs != IDToRefs.end()) {
1476 for (
const auto &
Ref : Refs->second) {
1479 Result.
Loc.
uri = URIMainFile;
1480 if (
Ref.IsDefinition) {
1484 Results.
References.push_back(std::move(Result));
1487 IDsToQuery.insert(MacroSID);
1494 std::vector<const NamedDecl *> Decls =
1495 getDeclAtPosition(
AST, *CurLoc, Relations);
1496 llvm::SmallVector<const NamedDecl *> TargetsInMainFile;
1497 for (
const NamedDecl *D : Decls) {
1501 TargetsInMainFile.push_back(D);
1505 if (D->getParentFunctionOrMethod())
1507 IDsToQuery.insert(ID);
1513 for (
const NamedDecl *ND : Decls) {
1516 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1517 if (CMD->isVirtual()) {
1520 getOverriddenMethods(CMD, OverriddenMethods);
1525 if (
const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(ND)) {
1527 getOverriddenMethods(OMD, OverriddenMethods);
1533 auto MainFileRefs = findRefs(TargetsInMainFile,
AST,
false);
1537 MainFileRefs.erase(llvm::unique(MainFileRefs,
1538 [](
const ReferenceFinder::Reference &L,
1539 const ReferenceFinder::Reference &R) {
1540 return L.SpelledTok.location() ==
1541 R.SpelledTok.location();
1543 MainFileRefs.end());
1544 for (
const auto &
Ref : MainFileRefs) {
1547 Result.
Loc.
uri = URIMainFile;
1551 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Declaration))
1554 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Definition))
1557 Results.
References.push_back(std::move(Result));
1565 llvm::DenseMap<SymbolID, size_t> RefIndexForContainer;
1568 if (Limit && Results.
References.size() >= Limit) {
1572 const auto LSPLocDecl =
1573 toLSPLocation(
Object.CanonicalDeclaration, MainFilePath);
1574 const auto LSPLocDef = toLSPLocation(
Object.Definition, MainFilePath);
1575 if (LSPLocDecl && LSPLocDecl != LSPLocDef) {
1577 Result.
Loc = {std::move(*LSPLocDecl), std::nullopt};
1582 Results.
References.push_back(std::move(Result));
1586 Result.
Loc = {std::move(*LSPLocDef), std::nullopt};
1592 Results.
References.push_back(std::move(Result));
1596 if (!ContainerLookup.
IDs.empty() && AddContext)
1597 Index->
lookup(ContainerLookup, [&](
const Symbol &Container) {
1598 auto Ref = RefIndexForContainer.find(Container.ID);
1599 assert(
Ref != RefIndexForContainer.end());
1601 Container.Scope.str() + Container.Name.str();
1606 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs,
bool AllowAttributes,
1607 bool AllowMainFileSymbols) {
1608 if (IDs.empty() || !Index || Results.
HasMore)
1611 Req.
IDs = std::move(IDs);
1623 llvm::DenseMap<SymbolID, std::vector<size_t>> RefIndicesForContainer;
1625 auto LSPLoc = toLSPLocation(R.
Location, MainFilePath);
1628 (!AllowMainFileSymbols && LSPLoc->uri.file() == MainFilePath))
1631 Result.
Loc = {std::move(*LSPLoc), std::nullopt};
1632 if (AllowAttributes) {
1642 ContainerLookup.
IDs.insert(Container);
1643 RefIndicesForContainer[Container].push_back(Results.
References.size());
1645 Results.
References.push_back(std::move(Result));
1648 if (!ContainerLookup.
IDs.empty() && AddContext)
1649 Index->
lookup(ContainerLookup, [&](
const Symbol &Container) {
1650 auto Ref = RefIndicesForContainer.find(Container.ID);
1651 assert(
Ref != RefIndicesForContainer.end());
1652 auto ContainerName = Container.Scope.str() + Container.Name.str();
1653 for (
auto I :
Ref->getSecond()) {
1654 Results.
References[I].Loc.containerName = ContainerName;
1658 QueryIndex(std::move(IDsToQuery),
true,
1663 QueryIndex(std::move(OverriddenMethods),
false,
1669 const SourceManager &SM =
AST.getSourceManager();
1672 llvm::consumeError(CurLoc.takeError());
1675 auto MainFilePath =
AST.tuPath();
1676 std::vector<SymbolDetails> Results;
1682 for (
const NamedDecl *D : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1683 D = getPreferredDecl(D);
1689 NewSymbol.
name = std::string(SplitQName.second);
1692 if (
const auto *ParentND =
1693 dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
1696 llvm::SmallString<32> USR;
1697 if (!index::generateUSRForDecl(D, USR)) {
1698 NewSymbol.
USR = std::string(USR);
1701 if (
const NamedDecl *Def = getDefinition(D))
1705 makeLocation(
AST.getASTContext(),
nameLocation(*D, SM), MainFilePath);
1707 Results.push_back(std::move(NewSymbol));
1710 const auto *IdentifierAtCursor =
1711 syntax::spelledIdentifierTouching(*CurLoc,
AST.getTokens());
1712 if (!IdentifierAtCursor)
1717 NewMacro.
name = std::string(M->Name);
1718 llvm::SmallString<32> USR;
1719 if (!index::generateUSRForMacro(NewMacro.
name, M->Info->getDefinitionLoc(),
1721 NewMacro.
USR = std::string(USR);
1724 Results.push_back(std::move(NewMacro));
1745 OS <<
" [override]";
1749template <
typename HierarchyItem>
1750static std::optional<HierarchyItem>
1752 ASTContext &Ctx = ND.getASTContext();
1753 auto &SM = Ctx.getSourceManager();
1754 SourceLocation NameLoc =
nameLocation(ND, Ctx.getSourceManager());
1755 SourceLocation BeginLoc = SM.getFileLoc(ND.getBeginLoc());
1756 SourceLocation EndLoc = SM.getFileLoc(ND.getEndLoc());
1757 const auto DeclRange =
1760 return std::nullopt;
1761 const auto FE = SM.getFileEntryRefForID(SM.getFileID(NameLoc));
1763 return std::nullopt;
1766 return std::nullopt;
1770 SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
1772 index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
1783 HI.selectionRange =
Range{NameBegin, NameEnd};
1784 if (!HI.range.contains(HI.selectionRange)) {
1787 HI.range = HI.selectionRange;
1795static std::optional<TypeHierarchyItem>
1799 Result->deprecated = ND.isDeprecated();
1809static std::optional<CallHierarchyItem>
1814 if (ND.isDeprecated())
1817 Result->data = ID.str();
1821template <
typename HierarchyItem>
1826 elog(
"Failed to convert symbol to hierarchy item: {0}", Loc.takeError());
1827 return std::nullopt;
1830 HI.name = std::string(S.
Name);
1833 HI.selectionRange = Loc->range;
1836 HI.range = HI.selectionRange;
1842static std::optional<TypeHierarchyItem>
1847 Result->data.symbolID = S.
ID;
1852static std::optional<CallHierarchyItem>
1857 Result->data = S.
ID.
str();
1864 std::vector<TypeHierarchyItem> &SubTypes,
1870 if (std::optional<TypeHierarchyItem> ChildSym =
1873 ChildSym->children.emplace();
1876 SubTypes.emplace_back(std::move(*ChildSym));
1894 auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD :
nullptr;
1896 if (!RPSet.insert(Pattern).second) {
1901 for (
const CXXRecordDecl *ParentDecl :
typeParents(&CXXRD)) {
1902 if (std::optional<TypeHierarchyItem> ParentSym =
1906 Item.
parents->emplace_back(std::move(*ParentSym));
1911 RPSet.erase(Pattern);
1918 std::vector<const CXXRecordDecl *> Records;
1927 AST.getHeuristicResolver());
1928 for (
const NamedDecl *D : Decls) {
1930 if (
const VarDecl *VD = dyn_cast<VarDecl>(D)) {
1932 if (
const auto *RD = VD->getType().getTypePtr()->getAsCXXRecordDecl())
1933 Records.push_back(RD);
1937 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(D)) {
1939 Records.push_back(
Method->getParent());
1947 if (
auto *RD = dyn_cast<CXXRecordDecl>(D))
1948 Records.push_back(RD);
1953 const SourceManager &SM =
AST.getSourceManager();
1954 std::vector<const CXXRecordDecl *> Result;
1957 llvm::consumeError(Offset.takeError());
1962 Result = RecordFromNode(ST.commonAncestor());
1963 return !Result.empty();
1970static QualType
typeForNode(
const ASTContext &Ctx,
const HeuristicResolver *H,
1974 while (N && N->
ASTNode.get<NestedNameSpecifierLoc>())
1980 if (
const TypeLoc *TL = N->
ASTNode.get<TypeLoc>()) {
1981 if (llvm::isa<DeducedType>(TL->getTypePtr()))
1983 N->
getDeclContext().getParentASTContext(), H, TL->getBeginLoc()))
1986 if (llvm::isa<TypedefType>(TL->getTypePtr()))
1987 return TL->getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
1988 return TL->getType();
1992 if (
const auto *CCI = N->
ASTNode.get<CXXCtorInitializer>()) {
1993 if (
const FieldDecl *FD = CCI->getAnyMember())
1994 return FD->getType();
1995 if (
const Type *Base = CCI->getBaseClass())
1996 return QualType(Base, 0);
2000 if (
const auto *CBS = N->
ASTNode.get<CXXBaseSpecifier>())
2001 return CBS->getType();
2003 if (
const Decl *D = N->
ASTNode.get<Decl>()) {
2004 struct Visitor : ConstDeclVisitor<Visitor, QualType> {
2005 const ASTContext &Ctx;
2006 Visitor(
const ASTContext &Ctx) : Ctx(Ctx) {}
2008 QualType VisitValueDecl(
const ValueDecl *D) {
return D->getType(); }
2010 QualType VisitTypeDecl(
const TypeDecl *D) {
2011 return Ctx.getTypeDeclType(D);
2014 QualType VisitTypedefNameDecl(
const TypedefNameDecl *D) {
2015 return D->getUnderlyingType();
2018 QualType VisitTemplateDecl(
const TemplateDecl *D) {
2019 return Visit(D->getTemplatedDecl());
2025 if (
const Stmt *S = N->
ASTNode.get<Stmt>()) {
2026 struct Visitor : ConstStmtVisitor<Visitor, QualType> {
2028 QualType type(
const Stmt *S) {
return S ? Visit(S) : QualType(); }
2031 QualType VisitExpr(
const Expr *S) {
2032 return S->IgnoreImplicitAsWritten()->getType();
2034 QualType VisitMemberExpr(
const MemberExpr *S) {
2036 if (S->getType()->isSpecificBuiltinType(BuiltinType::BoundMember))
2037 return Expr::findBoundMemberType(S);
2038 return VisitExpr(S);
2041 QualType VisitCXXDeleteExpr(
const CXXDeleteExpr *S) {
2042 return S->getDestroyedType();
2044 QualType VisitCXXPseudoDestructorExpr(
const CXXPseudoDestructorExpr *S) {
2045 return S->getDestroyedType();
2047 QualType VisitCXXThrowExpr(
const CXXThrowExpr *S) {
2048 return S->getSubExpr()->getType();
2050 QualType VisitCoyieldExpr(
const CoyieldExpr *S) {
2051 return type(S->getOperand());
2054 QualType VisitDesignatedInitExpr(
const DesignatedInitExpr *S) {
2056 for (
auto &D : llvm::reverse(S->designators()))
2057 if (D.isFieldDesignator())
2058 if (
const auto *FD = D.getFieldDecl())
2059 return FD->getType();
2064 QualType VisitSwitchStmt(
const SwitchStmt *S) {
2065 return type(S->getCond());
2067 QualType VisitWhileStmt(
const WhileStmt *S) {
return type(S->getCond()); }
2068 QualType VisitDoStmt(
const DoStmt *S) {
return type(S->getCond()); }
2069 QualType VisitIfStmt(
const IfStmt *S) {
return type(S->getCond()); }
2070 QualType VisitCaseStmt(
const CaseStmt *S) {
return type(S->getLHS()); }
2071 QualType VisitCXXForRangeStmt(
const CXXForRangeStmt *S) {
2072 return S->getLoopVariable()->getType();
2074 QualType VisitReturnStmt(
const ReturnStmt *S) {
2075 return type(S->getRetValue());
2077 QualType VisitCoreturnStmt(
const CoreturnStmt *S) {
2078 return type(S->getOperand());
2080 QualType VisitCXXCatchStmt(
const CXXCatchStmt *S) {
2081 return S->getCaughtType();
2083 QualType VisitObjCAtThrowStmt(
const ObjCAtThrowStmt *S) {
2084 return type(S->getThrowExpr());
2086 QualType VisitObjCAtCatchStmt(
const ObjCAtCatchStmt *S) {
2087 return S->getCatchParamDecl() ? S->getCatchParamDecl()->getType()
2100 QualType T,
const HeuristicResolver* H, llvm::SmallVector<QualType>& Out) {
2105 if (
const auto* TDT = T->getAs<TypedefType>())
2106 return Out.push_back(QualType(TDT, 0));
2109 if (
const auto *PT = T->getAs<PointerType>())
2111 if (
const auto *RT = T->getAs<ReferenceType>())
2113 if (
const auto *AT = T->getAsArrayTypeUnsafe())
2117 if (
auto *FT = T->getAs<FunctionType>())
2119 if (
auto *CRD = T->getAsCXXRecordDecl()) {
2120 if (CRD->isLambda())
2121 return unwrapFindType(CRD->getLambdaCallOperator()->getReturnType(), H,
2129 if (
auto PointeeType = H->getPointeeType(T.getNonReferenceType());
2130 !PointeeType.isNull()) {
2132 return Out.push_back(T);
2135 return Out.push_back(T);
2140 QualType T,
const HeuristicResolver* H) {
2141 llvm::SmallVector<QualType> Result;
2148 const SourceManager &SM =
AST.getSourceManager();
2150 std::vector<LocatedSymbol> Result;
2152 elog(
"failed to convert position {0} for findTypes: {1}", Pos,
2153 Offset.takeError());
2157 auto SymbolsFromNode =
2159 std::vector<LocatedSymbol> LocatedSymbols;
2167 AST.getHeuristicResolver()))
2168 llvm::copy(locateSymbolForType(
AST,
Type, Index),
2169 std::back_inserter(LocatedSymbols));
2171 return LocatedSymbols;
2175 Result = SymbolsFromNode(ST.commonAncestor());
2176 return !Result.empty();
2181std::vector<const CXXRecordDecl *>
typeParents(
const CXXRecordDecl *CXXRD) {
2182 std::vector<const CXXRecordDecl *> Result;
2186 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
2187 if (CTSD->isInvalidDecl())
2188 CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
2192 if (!CXXRD->hasDefinition())
2195 for (
auto Base : CXXRD->bases()) {
2196 const CXXRecordDecl *ParentDecl =
nullptr;
2198 const Type *
Type = Base.getType().getTypePtr();
2199 if (
const RecordType *RT =
Type->getAs<RecordType>()) {
2200 ParentDecl = RT->getAsCXXRecordDecl();
2206 if (
const TemplateSpecializationType *TS =
2207 Type->getAs<TemplateSpecializationType>()) {
2208 TemplateName TN = TS->getTemplateName();
2209 if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
2210 ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
2216 Result.push_back(ParentDecl);
2222std::vector<TypeHierarchyItem>
2226 std::vector<TypeHierarchyItem> Results;
2240 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
2241 CXXRD = CTSD->getTemplateInstantiationPattern();
2244 std::optional<TypeHierarchyItem> Result =
2252 if (WantChildren && ResolveLevels > 0) {
2253 Result->children.emplace();
2257 fillSubTypes(ID, *Result->children, Index, ResolveLevels, TUPath);
2260 Results.emplace_back(std::move(*Result));
2266std::optional<std::vector<TypeHierarchyItem>>
2268 std::vector<TypeHierarchyItem> Results;
2270 return std::nullopt;
2274 llvm::DenseMap<SymbolID, const TypeHierarchyItem::ResolveParams *> IDToData;
2276 Req.
IDs.insert(Parent.symbolID);
2277 IDToData[Parent.symbolID] = &Parent;
2279 Index->
lookup(Req, [&Item, &Results, &IDToData](
const Symbol &S) {
2281 THI->data = *IDToData.lookup(S.
ID);
2282 Results.emplace_back(std::move(*THI));
2290 std::vector<TypeHierarchyItem> Results;
2292 for (
auto &ChildSym : Results)
2293 ChildSym.data.parents = {Item.
data};
2311std::vector<CallHierarchyItem>
2313 std::vector<CallHierarchyItem> Result;
2314 const auto &SM =
AST.getSourceManager();
2317 elog(
"prepareCallHierarchy failed to convert position to source location: "
2322 for (
const NamedDecl *Decl : getDeclAtPosition(
AST, *Loc, {})) {
2323 if (!(isa<DeclContext>(Decl) &&
2324 cast<DeclContext>(Decl)->isFunctionOrMethod()) &&
2325 Decl->getKind() != Decl::Kind::FunctionTemplate &&
2326 !(Decl->getKind() == Decl::Kind::Var &&
2327 !cast<VarDecl>(Decl)->isLocalVarDecl()) &&
2328 Decl->getKind() != Decl::Kind::Field &&
2329 Decl->getKind() != Decl::Kind::EnumConstant)
2332 Result.emplace_back(std::move(*CHI));
2337std::vector<CallHierarchyIncomingCall>
2339 std::vector<CallHierarchyIncomingCall> Results;
2340 if (!Index || Item.
data.empty())
2344 elog(
"incomingCalls failed to find symbol: {0}", ID.takeError());
2354 Request.
IDs.insert(*ID);
2363 llvm::DenseMap<SymbolID, std::vector<Location>> CallsIn;
2367 Index->
refs(Request, [&](
const Ref &R) {
2370 elog(
"incomingCalls failed to convert location: {0}", Loc.takeError());
2379 Index->
lookup(ContainerLookup, [&](
const Symbol &Caller) {
2380 auto It = CallsIn.find(Caller.
ID);
2381 assert(It != CallsIn.end());
2383 std::vector<Range> FromRanges;
2384 for (
const Location &L : It->second) {
2392 FromRanges.push_back(L.
range);
2401 return A.from.name < B.from.name;
2406std::vector<CallHierarchyOutgoingCall>
2408 std::vector<CallHierarchyOutgoingCall> Results;
2409 if (!Index || Item.
data.empty())
2413 elog(
"outgoingCalls failed to find symbol: {0}", ID.takeError());
2422 llvm::DenseMap<SymbolID, std::vector<Location>> CallsOut;
2429 elog(
"outgoingCalls failed to convert location: {0}", Loc.takeError());
2432 auto It = CallsOut.try_emplace(R.Symbol, std::vector<Location>{}).first;
2433 It->second.push_back(*Loc);
2435 CallsOutLookup.
IDs.insert(R.Symbol);
2439 Index->
lookup(CallsOutLookup, [&](
const Symbol &Callee) {
2442 using SK = index::SymbolKind;
2443 auto Kind = Callee.SymInfo.Kind;
2444 assert(Kind == SK::Function || Kind == SK::InstanceMethod ||
2445 Kind == SK::ClassMethod || Kind == SK::StaticMethod ||
2446 Kind == SK::Constructor || Kind == SK::Destructor ||
2447 Kind == SK::ConversionFunction);
2451 auto It = CallsOut.find(Callee.ID);
2452 assert(It != CallsOut.end());
2454 std::vector<Range> FromRanges;
2455 for (
const Location &L : It->second) {
2464 FromRanges.push_back(L.
range);
2473 return A.to.name < B.to.name;
2479 const FunctionDecl *FD) {
2482 llvm::DenseSet<const Decl *> DeclRefs;
2486 for (
const Decl *D :
Ref.Targets) {
2487 if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
2492 AST.getHeuristicResolver());
Include Cleaner is clangd functionality for providing diagnostics for misuse of transitive headers an...
void elog(const char *Fmt, Ts &&... Vals)
Stores and provides access to parsed AST.
static bool createEach(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End, llvm::function_ref< bool(SelectionTree)> Func)
static const Decl * getRefContainer(const Decl *Enclosing, const SymbolCollector::Options &Opts)
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
virtual bool fuzzyFind(const FuzzyFindRequest &Req, llvm::function_ref< void(const Symbol &)> Callback) const =0
Matches symbols in the index fuzzily and applies Callback on each matched symbol before returning.
virtual bool containedRefs(const ContainedRefsRequest &Req, llvm::function_ref< void(const ContainedRefsResult &)> Callback) const =0
Find all symbols that are referenced by a symbol and apply Callback on each result.
virtual void relations(const RelationsRequest &Req, llvm::function_ref< void(const SymbolID &Subject, const Symbol &Object)> Callback) const =0
Finds all relations (S, P, O) stored in the index such that S is among Req.Subjects and P is Req....
virtual bool refs(const RefsRequest &Req, llvm::function_ref< void(const Ref &)> Callback) const =0
Finds all occurrences (e.g.
virtual void lookup(const LookupRequest &Req, llvm::function_ref< void(const Symbol &)> Callback) const =0
Looks up symbols with any of the given symbol IDs and applies Callback on each matched symbol.
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< 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.
SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind)
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
@ Type
An inlay hint that for a type annotation.
std::vector< LocatedSymbol > findImplementations(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns implementations at a specified Pos:
const ObjCImplDecl * getCorrespondingObjCImpl(const ObjCContainerDecl *D)
Return the corresponding implementation/definition for the given ObjC container if it has one,...
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
llvm::DenseSet< const Decl * > getNonLocalDeclRefs(ParsedAST &AST, const FunctionDecl *FD)
Returns all decls that are referenced in the FD except local symbols.
clangd::Range rangeTillEOL(llvm::StringRef Code, unsigned HashOffset)
Returns the range starting at offset and spanning the whole line.
float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance)
Combine symbol quality and relevance into a single score.
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
std::vector< CallHierarchyOutgoingCall > outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
void elog(const char *Fmt, Ts &&... Vals)
@ Underlying
This is the underlying declaration for a renaming-alias, decltype etc.
@ TemplatePattern
This is the pattern the template specialization was instantiated from.
@ Alias
This declaration is an alias that was referred to.
static std::optional< CallHierarchyItem > declToCallHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath)
std::vector< const CXXRecordDecl * > findRecordTypeAt(ParsedAST &AST, Position Pos)
Find the record types referenced at Pos.
std::vector< CallHierarchyItem > prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath)
Get call hierarchy information at Pos.
std::vector< const CXXRecordDecl * > typeParents(const CXXRecordDecl *CXXRD)
Given a record type declaration, find its base (parent) types.
@ Invalid
Sentinel bit pattern. DO NOT USE!
cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccess 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.
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.