21#include "clang-include-cleaner/Analysis.h"
22#include "clang-include-cleaner/Types.h"
30#include "clang/AST/ASTContext.h"
31#include "clang/AST/ASTTypeTraits.h"
32#include "clang/AST/Attr.h"
33#include "clang/AST/Attrs.inc"
34#include "clang/AST/Decl.h"
35#include "clang/AST/DeclCXX.h"
36#include "clang/AST/DeclObjC.h"
37#include "clang/AST/DeclTemplate.h"
38#include "clang/AST/DeclVisitor.h"
39#include "clang/AST/ExprCXX.h"
40#include "clang/AST/RecursiveASTVisitor.h"
41#include "clang/AST/Stmt.h"
42#include "clang/AST/StmtCXX.h"
43#include "clang/AST/StmtVisitor.h"
44#include "clang/AST/Type.h"
45#include "clang/Basic/LLVM.h"
46#include "clang/Basic/LangOptions.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/Index/USRGeneration.h"
55#include "clang/Lex/Lexer.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))
117void logIfOverflow(
const SymbolLocation &
Loc) {
118 if (
Loc.Start.hasOverflow() ||
Loc.End.hasOverflow())
119 log(
"Possible overflow in symbol location: {0}",
Loc);
124std::optional<Location> toLSPLocation(
const SymbolLocation &
Loc,
125 llvm::StringRef TUPath) {
130 elog(
"{0}", LSPLoc.takeError());
137SymbolLocation toIndexLocation(
const Location &
Loc, std::string &URIStorage) {
138 SymbolLocation SymLoc;
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);
149SymbolLocation getPreferredLocation(
const Location &ASTLoc,
150 const SymbolLocation &IdxLoc,
151 std::string &Scratch) {
154 Symbol ASTSym, IdxSym;
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,
164 DeclRelationSet Relations,
165 ASTNodeKind *NodeKind =
nullptr) {
166 unsigned Offset =
AST.getSourceManager().getDecomposedSpellingLoc(
Pos).second;
167 std::vector<std::pair<const NamedDecl *, DeclRelationSet>> Result;
168 auto ResultFromTree = [&](SelectionTree ST) {
169 if (
const SelectionTree::Node *N = ST.commonAncestor()) {
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();
189std::vector<const NamedDecl *>
190getDeclAtPosition(ParsedAST &
AST, SourceLocation
Pos, DeclRelationSet Relations,
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);
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,
292 const SymbolIndex *Index,
293 llvm::StringRef MainFilePath) {
294 if (IDs.empty() || !Index)
296 static constexpr trace::Metric FindImplementorsMetric(
300 FindImplementorsMetric.record(1,
"find-base");
303 FindImplementorsMetric.record(1,
"find-override");
307 RelationsRequest Req;
308 Req.Predicate = Predicate;
309 Req.Subjects = std::move(IDs);
310 std::vector<LocatedSymbol>
Results;
311 Index->relations(Req, [&](
const SymbolID &Subject,
const Symbol &
Object) {
315 elog(
"Find overrides: {0}", DeclLoc.takeError());
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,
334 const SymbolIndex *Index,
335 llvm::StringRef MainFilePath) {
336 LookupRequest QueryRequest;
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;
379std::vector<LocatedSymbol>
380locateASTReferent(SourceLocation CurLoc,
const syntax::Token *TouchedIdentifier,
381 ParsedAST &
AST, llvm::StringRef MainFilePath,
382 const SymbolIndex *Index, ASTNodeKind &NodeKind) {
383 const SourceManager &SM =
AST.getSourceManager();
385 std::vector<LocatedSymbol> Result;
387 static constexpr trace::Metric LocateASTReferentMetric(
389 auto AddResultDecl = [&](
const NamedDecl *D) {
390 D = getPreferredDecl(D);
396 Result.emplace_back();
397 Result.back().Name =
printName(
AST.getASTContext(), *D);
398 Result.back().PreferredDeclaration = *
Loc;
400 if (
const NamedDecl *Def = getDefinition(D))
401 Result.back().Definition = makeLocation(
406 DeclRelationSet Relations =
409 getDeclAtPositionWithRelations(
AST, CurLoc, Relations, &NodeKind);
410 llvm::DenseSet<SymbolID> VirtualMethods;
411 for (
const auto &
E : Candidates) {
412 const NamedDecl *D =
E.first;
413 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
417 if (CMD->isPureVirtual()) {
418 if (TouchedIdentifier && SM.getSpellingLoc(CMD->getLocation()) ==
419 TouchedIdentifier->location()) {
421 LocateASTReferentMetric.record(1,
"method-to-override");
425 if (NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverrideAttr>()) ||
426 NodeKind.isSame(ASTNodeKind::getFromNodeKind<FinalAttr>())) {
428 for (
const NamedDecl *ND : CMD->overridden_methods())
441 SM.isPointWithin(TouchedIdentifier ? TouchedIdentifier->location()
443 D->getBeginLoc(), D->getEndLoc()))
448 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
449 if (TouchedIdentifier &&
450 D->getLocation() == TouchedIdentifier->location()) {
451 LocateASTReferentMetric.record(1,
"template-specialization-to-primary");
452 AddResultDecl(CTSD->getSpecializedTemplate());
463 if (
const auto *CD = dyn_cast<ObjCCategoryDecl>(D))
464 if (
const auto *
ID = CD->getClassInterface())
465 if (TouchedIdentifier &&
466 (CD->getLocation() == TouchedIdentifier->location() ||
467 ID->getName() == TouchedIdentifier->text(SM))) {
468 LocateASTReferentMetric.record(1,
"objc-category-to-class");
472 LocateASTReferentMetric.record(1,
"regular");
476 enhanceLocatedSymbolsFromIndex(Result, Index, MainFilePath);
479 Index, MainFilePath);
480 Result.insert(Result.end(), Overrides.begin(), Overrides.end());
484std::vector<LocatedSymbol> locateSymbolForType(
const ParsedAST &
AST,
485 const QualType &
Type,
486 const SymbolIndex *Index) {
487 const auto &SM =
AST.getSourceManager();
488 auto MainFilePath =
AST.tuPath();
492 auto Decls =
targetDecl(DynTypedNode::create(
Type.getNonReferenceType()),
494 AST.getHeuristicResolver());
498 std::vector<LocatedSymbol>
Results;
499 const auto &ASTContext =
AST.getASTContext();
501 for (
const NamedDecl *D : Decls) {
502 D = getPreferredDecl(D);
504 auto Loc = makeLocation(ASTContext,
nameLocation(*D, SM), MainFilePath);
512 if (
const NamedDecl *Def = getDefinition(D))
514 makeLocation(ASTContext,
nameLocation(*Def, SM), MainFilePath);
516 enhanceLocatedSymbolsFromIndex(
Results, Index, MainFilePath);
521bool tokenSpelledAt(SourceLocation SpellingLoc,
const syntax::TokenBuffer &TB) {
522 auto ExpandedTokens = TB.expandedTokens(
523 TB.sourceManager().getMacroArgExpandedLocation(SpellingLoc));
524 return !ExpandedTokens.empty();
527llvm::StringRef sourcePrefix(SourceLocation
Loc,
const SourceManager &SM) {
528 auto D = SM.getDecomposedLoc(
Loc);
530 llvm::StringRef Buf = SM.getBufferData(D.first, &Invalid);
531 if (Invalid || D.second > Buf.size())
533 return Buf.substr(0, D.second);
536bool isDependentName(ASTNodeKind NodeKind) {
537 return NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverloadExpr>()) ||
539 ASTNodeKind::getFromNodeKind<CXXDependentScopeMemberExpr>()) ||
541 ASTNodeKind::getFromNodeKind<DependentScopeDeclRefExpr>());
549 llvm::StringRef MainFilePath,
550 ASTNodeKind NodeKind) {
555 if ((
Word.ExpandedToken && !isDependentName(NodeKind)) ||
556 !
Word.LikelyIdentifier || !Index)
560 if (
Word.PartOfSpelledToken &&
561 isStringLiteral(
Word.PartOfSpelledToken->kind()))
564 const auto &SM =
AST.getSourceManager();
578 bool TooMany =
false;
579 using ScoredLocatedSymbol = std::pair<float, LocatedSymbol>;
580 std::vector<ScoredLocatedSymbol> ScoredResults;
581 Index->fuzzyFind(Req, [&](
const Symbol &Sym) {
591 if (Sym.
SymInfo.Kind == index::SymbolKind::Constructor)
597 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());
607 log(
"locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());
614 if (ScoredResults.size() >= 5) {
627 Relevance.
merge(Sym);
630 dlog(
"locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym.
Scope,
633 ScoredResults.push_back({
Score, std::move(Located)});
637 vlog(
"Heuristic index lookup for {0} returned too many candidates, ignored",
642 llvm::sort(ScoredResults,
643 [](
const ScoredLocatedSymbol &A,
const ScoredLocatedSymbol &B) {
644 return A.first > B.first;
646 std::vector<LocatedSymbol>
Results;
647 for (
auto &Res : std::move(ScoredResults))
648 Results.push_back(std::move(Res.second));
650 vlog(
"No heuristic index definition for {0}",
Word.Text);
652 log(
"Found definition heuristically in index for {0}",
Word.Text);
657 const syntax::TokenBuffer &TB) {
660 if (
Word.ExpandedToken)
664 if (
Word.PartOfSpelledToken &&
665 isStringLiteral(
Word.PartOfSpelledToken->kind()))
668 const SourceManager &SM = TB.sourceManager();
671 auto File = SM.getFileID(
Word.Location);
672 unsigned WordLine = SM.getSpellingLineNumber(
Word.Location);
673 auto Cost = [&](SourceLocation
Loc) ->
unsigned {
674 assert(SM.getFileID(
Loc) ==
File &&
"spelled token in wrong file?");
675 unsigned Line = SM.getSpellingLineNumber(
Loc);
676 return Line >= WordLine ?
Line - WordLine : 2 * (WordLine -
Line);
678 const syntax::Token *BestTok =
nullptr;
679 unsigned BestCost = -1;
683 unsigned MaxDistance =
684 1U << std::min<unsigned>(
Word.Text.size(),
685 std::numeric_limits<unsigned>::digits - 1);
692 WordLine + 1 <= MaxDistance / 2 ? 1 : WordLine + 1 - MaxDistance / 2;
693 unsigned LineMax = WordLine + 1 + MaxDistance;
694 SourceLocation LocMin = SM.translateLineCol(
File, LineMin, 1);
695 assert(LocMin.isValid());
696 SourceLocation LocMax = SM.translateLineCol(
File, LineMax, 1);
697 assert(LocMax.isValid());
701 auto Consider = [&](
const syntax::Token &Tok) {
702 if (Tok.location() < LocMin || Tok.location() > LocMax)
704 if (!(Tok.kind() == tok::identifier && Tok.
text(SM) ==
Word.Text))
707 if (Tok.location() ==
Word.Location)
710 unsigned TokCost = Cost(Tok.location());
711 if (TokCost >= BestCost)
715 if (!(tokenSpelledAt(Tok.location(), TB) || TB.expansionStartingAt(&Tok)))
722 auto SpelledTokens = TB.spelledTokens(
File);
724 auto *I = llvm::partition_point(SpelledTokens, [&](
const syntax::Token &T) {
725 assert(SM.getFileID(T.location()) == SM.getFileID(
Word.Location));
726 return T.location() <
Word.Location;
729 for (
const syntax::Token &Tok : llvm::ArrayRef(I, SpelledTokens.end()))
733 for (
const syntax::Token &Tok :
734 llvm::reverse(llvm::ArrayRef(SpelledTokens.begin(), I)))
740 "Word {0} under cursor {1} isn't a token (after PP), trying nearby {2}",
741 Word.Text,
Word.Location.printToString(SM),
742 BestTok->location().printToString(SM));
749 const auto &SM =
AST.getSourceManager();
750 auto MainFilePath =
AST.tuPath();
752 if (
auto File = locateFileReferent(
Pos,
AST, MainFilePath))
753 return {std::move(*
File)};
757 elog(
"locateSymbolAt failed to convert position to source location: {0}",
762 const syntax::Token *TouchedIdentifier =
nullptr;
763 auto TokensTouchingCursor =
764 syntax::spelledTokensTouching(*CurLoc,
AST.getTokens());
765 for (
const syntax::Token &Tok : TokensTouchingCursor) {
766 if (Tok.kind() == tok::identifier) {
767 if (
auto Macro = locateMacroReferent(Tok,
AST, MainFilePath))
771 return {*std::move(
Macro)};
773 TouchedIdentifier = &Tok;
777 if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
781 auto LocSym = locateSymbolForType(
AST, *
Deduced, Index);
788 ASTNodeKind NodeKind;
789 auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier,
AST,
790 MainFilePath, Index, NodeKind);
791 if (!ASTResults.empty())
799 if (
const syntax::Token *NearbyIdent =
801 if (
auto Macro = locateMacroReferent(*NearbyIdent,
AST, MainFilePath)) {
802 log(
"Found macro definition heuristically using nearby identifier {0}",
804 return {*std::move(
Macro)};
806 ASTResults = locateASTReferent(NearbyIdent->location(), NearbyIdent,
AST,
807 MainFilePath, Index, NodeKind);
808 if (!ASTResults.empty()) {
809 log(
"Found definition heuristically using nearby identifier {0}",
810 NearbyIdent->text(SM));
813 vlog(
"No definition found using nearby identifier {0} at {1}",
Word->Text,
814 Word->Location.printToString(SM));
817 auto TextualResults =
819 if (!TextualResults.empty())
820 return TextualResults;
827 const auto &SM =
AST.getSourceManager();
829 std::vector<DocumentLink> Result;
830 for (
auto &Inc :
AST.getIncludeStructure().MainFileIncludes) {
831 if (Inc.Resolved.empty())
833 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
834 const auto *HashTok =
AST.getTokens().spelledTokenContaining(HashLoc);
835 assert(HashTok &&
"got inclusion at wrong offset");
836 const auto *IncludeTok = std::next(HashTok);
837 const auto *FileTok = std::next(IncludeTok);
842 syntax::FileRange(SM, FileTok->location(), Inc.Written.length())
856class ReferenceFinder :
public index::IndexDataConsumer {
863 Range range(
const SourceManager &SM)
const {
868 ReferenceFinder(
const ParsedAST &AST,
869 const llvm::ArrayRef<const NamedDecl *> Targets,
871 : PerToken(PerToken), AST(AST) {
872 for (
const NamedDecl *ND : Targets)
873 TargetDecls.insert(ND->getCanonicalDecl());
876 std::vector<Reference> take() && {
877 llvm::sort(References, [](
const Reference &L,
const Reference &R) {
878 auto LTok = L.SpelledTok.location();
879 auto RTok = R.SpelledTok.location();
880 return std::tie(LTok, L.Role) < std::tie(RTok, R.Role);
884 [](
const Reference &L,
const Reference &R) {
885 auto LTok = L.SpelledTok.location();
886 auto RTok = R.SpelledTok.location();
887 return std::tie(LTok, L.Role) ==
888 std::tie(RTok, R.Role);
891 return std::move(References);
895 handleDeclOccurrence(
const Decl *D, index::SymbolRoleSet Roles,
896 llvm::ArrayRef<index::SymbolRelation> Relations,
898 index::IndexDataConsumer::ASTNodeInfo ASTNode)
override {
899 if (!TargetDecls.contains(D->getCanonicalDecl()))
901 const SourceManager &SM = AST.getSourceManager();
904 const auto &TB = AST.getTokens();
906 llvm::SmallVector<SourceLocation, 1> Locs;
910 if (
auto *OME = llvm::dyn_cast_or_null<ObjCMessageExpr>(ASTNode.OrigE)) {
911 OME->getSelectorLocs(Locs);
912 }
else if (
auto *OMD =
913 llvm::dyn_cast_or_null<ObjCMethodDecl>(ASTNode.OrigD)) {
914 OMD->getSelectorLocs(Locs);
918 if (!Locs.empty() && Locs.front() !=
Loc)
926 for (SourceLocation L : Locs) {
927 L = SM.getFileLoc(L);
928 if (
const auto *Tok = TB.spelledTokenContaining(L))
939 const ParsedAST &AST;
940 llvm::DenseSet<const Decl *> TargetDecls;
943std::vector<ReferenceFinder::Reference>
944findRefs(
const llvm::ArrayRef<const NamedDecl *> TargetDecls, ParsedAST &
AST,
946 ReferenceFinder RefFinder(
AST, TargetDecls, PerToken);
947 index::IndexingOptions IndexOpts;
948 IndexOpts.SystemSymbolFilter =
949 index::IndexingOptions::SystemSymbolFilterKind::All;
950 IndexOpts.IndexFunctionLocals =
true;
951 IndexOpts.IndexParametersInDeclarations =
true;
952 IndexOpts.IndexTemplateParameters =
true;
953 indexTopLevelDecls(
AST.getASTContext(),
AST.getPreprocessor(),
954 AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
955 return std::move(RefFinder).take();
958const Stmt *getFunctionBody(DynTypedNode N) {
959 if (
const auto *FD = N.get<FunctionDecl>())
960 return FD->getBody();
961 if (
const auto *FD = N.get<BlockDecl>())
962 return FD->getBody();
963 if (
const auto *FD = N.get<LambdaExpr>())
964 return FD->getBody();
965 if (
const auto *FD = N.get<ObjCMethodDecl>())
966 return FD->getBody();
970const Stmt *getLoopBody(DynTypedNode N) {
971 if (
const auto *LS = N.get<ForStmt>())
972 return LS->getBody();
973 if (
const auto *LS = N.get<CXXForRangeStmt>())
974 return LS->getBody();
975 if (
const auto *LS = N.get<WhileStmt>())
976 return LS->getBody();
977 if (
const auto *LS = N.get<DoStmt>())
978 return LS->getBody();
994 All = Break | Continue | Return | Case | Throw | Goto,
998 std::vector<SourceLocation> &Result;
999 const SourceManager &SM;
1003 template <
typename Func>
1004 bool filterAndTraverse(DynTypedNode D,
const Func &Delegate) {
1005 auto RestoreIgnore = llvm::make_scope_exit(
1006 [OldIgnore(Ignore),
this] { Ignore = OldIgnore; });
1007 if (getFunctionBody(D))
1009 else if (getLoopBody(D))
1010 Ignore |= Continue | Break;
1011 else if (D.get<SwitchStmt>())
1012 Ignore |= Break | Case;
1014 return (Ignore == All) ? true : Delegate();
1017 void found(Target T, SourceLocation
Loc) {
1020 if (SM.isBeforeInTranslationUnit(
Loc,
Bounds.getBegin()) ||
1021 SM.isBeforeInTranslationUnit(
Bounds.getEnd(),
Loc))
1023 Result.push_back(
Loc);
1027 FindControlFlow(SourceRange Bounds, std::vector<SourceLocation> &Result,
1028 const SourceManager &SM)
1033 bool TraverseDecl(
Decl *D) {
1034 return !D || filterAndTraverse(DynTypedNode::create(*D), [&] {
1035 return RecursiveASTVisitor::TraverseDecl(D);
1038 bool TraverseStmt(Stmt *S) {
1039 return !S || filterAndTraverse(DynTypedNode::create(*S), [&] {
1040 return RecursiveASTVisitor::TraverseStmt(S);
1045 bool VisitReturnStmt(ReturnStmt *R) {
1046 found(Return, R->getReturnLoc());
1049 bool VisitBreakStmt(BreakStmt *B) {
1050 found(Break,
B->getBreakLoc());
1053 bool VisitContinueStmt(ContinueStmt *
C) {
1054 found(Continue,
C->getContinueLoc());
1057 bool VisitSwitchCase(SwitchCase *
C) {
1058 found(Case,
C->getKeywordLoc());
1061 bool VisitCXXThrowExpr(CXXThrowExpr *T) {
1062 found(Throw,
T->getThrowLoc());
1065 bool VisitGotoStmt(GotoStmt *G) {
1067 if (
const auto *LD = G->getLabel()) {
1068 if (SM.isBeforeInTranslationUnit(LD->getLocation(),
Bounds.getBegin()) ||
1069 SM.isBeforeInTranslationUnit(
Bounds.getEnd(), LD->getLocation()))
1070 found(Goto, G->getGotoLoc());
1079SourceRange findCaseBounds(
const SwitchStmt &Switch, SourceLocation
Loc,
1080 const SourceManager &SM) {
1083 std::vector<const SwitchCase *> Cases;
1084 for (
const SwitchCase *Case = Switch.getSwitchCaseList(); Case;
1085 Case = Case->getNextSwitchCase())
1086 Cases.push_back(Case);
1087 llvm::sort(Cases, [&](
const SwitchCase *L,
const SwitchCase *R) {
1088 return SM.isBeforeInTranslationUnit(L->getKeywordLoc(), R->getKeywordLoc());
1092 auto CaseAfter = llvm::partition_point(Cases, [&](
const SwitchCase *
C) {
1093 return !SM.isBeforeInTranslationUnit(
Loc,
C->getKeywordLoc());
1095 SourceLocation End = CaseAfter == Cases.end() ? Switch.getEndLoc()
1096 : (*CaseAfter)->getKeywordLoc();
1099 if (CaseAfter == Cases.begin())
1100 return SourceRange(Switch.getBeginLoc(), End);
1102 auto CaseBefore = std::prev(CaseAfter);
1104 while (CaseBefore != Cases.begin() &&
1105 (*std::prev(CaseBefore))->getSubStmt() == *CaseBefore)
1107 return SourceRange((*CaseBefore)->getKeywordLoc(), End);
1117std::vector<SourceLocation> relatedControlFlow(
const SelectionTree::Node &N) {
1118 const SourceManager &SM =
1119 N.getDeclContext().getParentASTContext().getSourceManager();
1120 std::vector<SourceLocation> Result;
1123 enum class Cur {
None, Break, Continue, Return, Case, Throw } Cursor;
1124 if (N.ASTNode.get<BreakStmt>()) {
1125 Cursor = Cur::Break;
1126 }
else if (N.ASTNode.get<ContinueStmt>()) {
1127 Cursor = Cur::Continue;
1128 }
else if (N.ASTNode.get<ReturnStmt>()) {
1129 Cursor = Cur::Return;
1130 }
else if (N.ASTNode.get<CXXThrowExpr>()) {
1131 Cursor = Cur::Throw;
1132 }
else if (N.ASTNode.get<SwitchCase>()) {
1134 }
else if (
const GotoStmt *GS = N.ASTNode.get<GotoStmt>()) {
1136 Result.push_back(GS->getGotoLoc());
1137 if (
const auto *LD = GS->getLabel())
1138 Result.push_back(LD->getLocation());
1144 const Stmt *
Root =
nullptr;
1147 for (
const auto *P = &N; P; P = P->Parent) {
1149 if (
const Stmt *FunctionBody = getFunctionBody(P->ASTNode)) {
1150 if (Cursor == Cur::Return || Cursor == Cur::Throw) {
1151 Root = FunctionBody;
1156 if (
const Stmt *LoopBody = getLoopBody(P->ASTNode)) {
1157 if (Cursor == Cur::None || Cursor == Cur::Break ||
1158 Cursor == Cur::Continue) {
1162 Result.push_back(P->ASTNode.getSourceRange().getBegin());
1169 if (
const auto *SS = P->ASTNode.get<SwitchStmt>()) {
1170 if (Cursor == Cur::Break || Cursor == Cur::Case) {
1171 Result.push_back(SS->getSwitchLoc());
1172 Root = SS->getBody();
1174 Bounds = findCaseBounds(*SS, N.ASTNode.getSourceRange().getBegin(), SM);
1179 if (Cursor == Cur::None)
1185 FindControlFlow(
Bounds, Result, SM).TraverseStmt(
const_cast<Stmt *
>(
Root));
1190DocumentHighlight toHighlight(
const ReferenceFinder::Reference &Ref,
1191 const SourceManager &SM) {
1192 DocumentHighlight DH;
1193 DH.range = Ref.range(SM);
1194 if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
1196 else if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
1203std::optional<DocumentHighlight> toHighlight(SourceLocation
Loc,
1204 const syntax::TokenBuffer &TB) {
1205 Loc = TB.sourceManager().getFileLoc(
Loc);
1206 if (
const auto *Tok = TB.spelledTokenContaining(
Loc)) {
1207 DocumentHighlight Result;
1210 CharSourceRange::getCharRange(Tok->location(), Tok->endLocation()));
1213 return std::nullopt;
1220 const SourceManager &SM =
AST.getSourceManager();
1224 llvm::consumeError(CurLoc.takeError());
1227 std::vector<DocumentHighlight> Result;
1233 targetDecl(N->ASTNode, Relations,
AST.getHeuristicResolver());
1234 if (!TargetDecls.empty()) {
1237 for (
const auto &
Ref : findRefs(TargetDecls,
AST,
true))
1238 Result.push_back(toHighlight(
Ref, SM));
1241 auto ControlFlow = relatedControlFlow(*N);
1242 if (!ControlFlow.empty()) {
1243 for (SourceLocation
Loc : ControlFlow)
1244 if (
auto Highlight = toHighlight(
Loc,
AST.getTokens()))
1245 Result.push_back(std::move(*Highlight));
1253 AST.getSourceManager().getDecomposedSpellingLoc(*CurLoc).second;
1266 const SourceManager &SM =
AST.getSourceManager();
1269 elog(
"Failed to convert position to source location: {0}",
1270 CurLoc.takeError());
1275 llvm::DenseSet<SymbolID> IDs;
1277 for (
const NamedDecl *ND : getDeclAtPosition(
AST, *CurLoc, Relations)) {
1278 if (
const auto *CXXMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1279 if (CXXMD->isVirtual()) {
1283 }
else if (
const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
1288 return findImplementors(std::move(IDs), QueryKind, Index,
AST.tuPath());
1294void getOverriddenMethods(
const CXXMethodDecl *CMD,
1295 llvm::DenseSet<SymbolID> &OverriddenMethods) {
1298 for (
const CXXMethodDecl *Base : CMD->overridden_methods()) {
1300 OverriddenMethods.insert(
ID);
1301 getOverriddenMethods(Base, OverriddenMethods);
1305std::optional<std::string>
1309 if (
auto *ND = llvm::dyn_cast_if_present<NamedDecl>(
Container))
1314std::optional<ReferencesResult>
1315maybeFindIncludeReferences(ParsedAST &
AST, Position
Pos,
1316 URIForFile URIMainFile) {
1317 const auto &Includes =
AST.getIncludeStructure().MainFileIncludes;
1318 auto IncludeOnLine = llvm::find_if(Includes, [&
Pos](
const Inclusion &Inc) {
1319 return Inc.HashLine ==
Pos.line;
1321 if (IncludeOnLine == Includes.end())
1322 return std::nullopt;
1324 const SourceManager &SM =
AST.getSourceManager();
1327 include_cleaner::walkUsed(
1329 &
AST.getPragmaIncludes(),
AST.getPreprocessor(),
1330 [&](
const include_cleaner::SymbolReference &Ref,
1331 llvm::ArrayRef<include_cleaner::Header> Providers) {
1332 if (Ref.RT != include_cleaner::RefType::Explicit ||
1333 !isPreferredProvider(*IncludeOnLine, Converted, Providers))
1336 auto Loc = SM.getFileLoc(Ref.RefLocation);
1339 while (SM.getFileID(Loc) != SM.getMainFileID())
1340 Loc = SM.getIncludeLoc(SM.getFileID(Loc));
1342 ReferencesResult::Reference Result;
1343 const auto *Token = AST.getTokens().spelledTokenContaining(Loc);
1344 assert(Token &&
"references expected token here");
1345 Result.Loc.range = Range{sourceLocToPosition(SM, Token->location()),
1346 sourceLocToPosition(SM, Token->endLocation())};
1347 Result.Loc.uri = URIMainFile;
1348 Results.References.push_back(std::move(Result));
1350 if (
Results.References.empty())
1351 return std::nullopt;
1354 ReferencesResult::Reference Result;
1355 Result.Loc.range =
rangeTillEOL(SM.getBufferData(SM.getMainFileID()),
1356 IncludeOnLine->HashOffset);
1357 Result.Loc.uri = URIMainFile;
1358 Results.References.push_back(std::move(Result));
1366 const SourceManager &SM = AST.getSourceManager();
1367 auto MainFilePath = AST.tuPath();
1368 auto URIMainFile = URIForFile::canonicalize(MainFilePath, MainFilePath);
1371 llvm::consumeError(CurLoc.takeError());
1375 const auto IncludeReferences =
1376 maybeFindIncludeReferences(AST,
Pos, URIMainFile);
1377 if (IncludeReferences)
1378 return *IncludeReferences;
1380 llvm::DenseSet<SymbolID> IDsToQuery, OverriddenMethods;
1382 const auto *IdentifierAtCursor =
1383 syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
1384 std::optional<DefinedMacro>
Macro;
1385 if (IdentifierAtCursor)
1391 const auto &IDToRefs = AST.getMacros().MacroRefs;
1392 auto Refs = IDToRefs.find(MacroSID);
1393 if (Refs != IDToRefs.end()) {
1394 for (
const auto &
Ref : Refs->second) {
1396 Result.Loc.range =
Ref.toRange(SM);
1397 Result.Loc.uri = URIMainFile;
1398 if (
Ref.IsDefinition) {
1399 Result.Attributes |= ReferencesResult::Declaration;
1400 Result.Attributes |= ReferencesResult::Definition;
1402 Results.References.push_back(std::move(Result));
1405 IDsToQuery.insert(MacroSID);
1411 DeclRelation::TemplatePattern | DeclRelation::Alias;
1412 std::vector<const NamedDecl *> Decls =
1413 getDeclAtPosition(AST, *CurLoc, Relations);
1414 llvm::SmallVector<const NamedDecl *> TargetsInMainFile;
1415 for (
const NamedDecl *D : Decls) {
1419 TargetsInMainFile.push_back(D);
1423 if (D->getParentFunctionOrMethod())
1425 IDsToQuery.insert(
ID);
1431 for (
const NamedDecl *ND : Decls) {
1434 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1435 if (CMD->isVirtual()) {
1438 getOverriddenMethods(CMD, OverriddenMethods);
1445 auto MainFileRefs = findRefs(TargetsInMainFile, AST,
false);
1449 MainFileRefs.erase(std::unique(MainFileRefs.begin(), MainFileRefs.end(),
1450 [](
const ReferenceFinder::Reference &L,
1451 const ReferenceFinder::Reference &R) {
1452 return L.SpelledTok.location() ==
1453 R.SpelledTok.location();
1455 MainFileRefs.end());
1456 for (
const auto &
Ref : MainFileRefs) {
1458 Result.Loc.range =
Ref.range(SM);
1459 Result.Loc.uri = URIMainFile;
1461 Result.Loc.containerName =
1463 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Declaration))
1464 Result.Attributes |= ReferencesResult::Declaration;
1466 if (
Ref.Role &
static_cast<unsigned>(index::SymbolRole::Definition))
1467 Result.Attributes |=
1468 ReferencesResult::Definition | ReferencesResult::Declaration;
1469 Results.References.push_back(std::move(Result));
1477 llvm::DenseMap<SymbolID, size_t> RefIndexForContainer;
1480 if (Limit &&
Results.References.size() >= Limit) {
1481 Results.HasMore = true;
1484 const auto LSPLocDecl =
1485 toLSPLocation(
Object.CanonicalDeclaration, MainFilePath);
1486 const auto LSPLocDef = toLSPLocation(
Object.Definition, MainFilePath);
1487 if (LSPLocDecl && LSPLocDecl != LSPLocDef) {
1489 Result.Loc = {std::move(*LSPLocDecl), std::nullopt};
1491 ReferencesResult::Declaration | ReferencesResult::Override;
1492 RefIndexForContainer.insert({
Object.ID,
Results.References.size()});
1494 Results.References.push_back(std::move(Result));
1498 Result.Loc = {std::move(*LSPLocDef), std::nullopt};
1499 Result.Attributes = ReferencesResult::Declaration |
1500 ReferencesResult::Definition |
1501 ReferencesResult::Override;
1502 RefIndexForContainer.insert({
Object.ID,
Results.References.size()});
1504 Results.References.push_back(std::move(Result));
1508 if (!ContainerLookup.
IDs.empty() && AddContext)
1511 assert(
Ref != RefIndexForContainer.end());
1512 Results.References[
Ref->getSecond()].Loc.containerName =
1518 auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs,
bool AllowAttributes,
1519 bool AllowMainFileSymbols) {
1520 if (IDs.empty() || !Index ||
Results.HasMore)
1523 Req.
IDs = std::move(IDs);
1525 if (Limit <
Results.References.size()) {
1535 llvm::DenseMap<SymbolID, std::vector<size_t>> RefIndicesForContainer;
1536 Results.HasMore |= Index->refs(Req, [&](
const Ref &R) {
1537 auto LSPLoc = toLSPLocation(R.
Location, MainFilePath);
1540 (!AllowMainFileSymbols && LSPLoc->uri.file() == MainFilePath))
1543 Result.Loc = {std::move(*LSPLoc), std::nullopt};
1544 if (AllowAttributes) {
1545 if ((R.
Kind & RefKind::Declaration) == RefKind::Declaration)
1546 Result.Attributes |= ReferencesResult::Declaration;
1548 if ((R.
Kind & RefKind::Definition) == RefKind::Definition)
1549 Result.Attributes |=
1550 ReferencesResult::Declaration | ReferencesResult::Definition;
1557 Results.References.push_back(std::move(Result));
1560 if (!ContainerLookup.
IDs.empty() && AddContext)
1563 assert(
Ref != RefIndicesForContainer.end());
1565 for (
auto I :
Ref->getSecond()) {
1566 Results.References[I].Loc.containerName = ContainerName;
1570 QueryIndex(std::move(IDsToQuery),
true,
1575 QueryIndex(std::move(OverriddenMethods),
false,
1581 const SourceManager &SM = AST.getSourceManager();
1584 llvm::consumeError(CurLoc.takeError());
1587 auto MainFilePath = AST.tuPath();
1588 std::vector<SymbolDetails>
Results;
1593 DeclRelation::Alias | DeclRelation::Underlying;
1594 for (
const NamedDecl *D : getDeclAtPosition(AST, *CurLoc, Relations)) {
1595 D = getPreferredDecl(D);
1601 NewSymbol.
name = std::string(SplitQName.second);
1604 if (
const auto *ParentND =
1605 dyn_cast_or_null<NamedDecl>(D->getDeclContext()))
1608 llvm::SmallString<32>
USR;
1609 if (!index::generateUSRForDecl(D,
USR)) {
1610 NewSymbol.
USR = std::string(
USR);
1613 if (
const NamedDecl *Def = getDefinition(D))
1615 AST.getASTContext(),
nameLocation(*Def, SM), MainFilePath);
1617 makeLocation(AST.getASTContext(),
nameLocation(*D, SM), MainFilePath);
1619 Results.push_back(std::move(NewSymbol));
1622 const auto *IdentifierAtCursor =
1623 syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
1624 if (!IdentifierAtCursor)
1627 if (
auto M =
locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor())) {
1629 NewMacro.
name = std::string(
M->Name);
1630 llvm::SmallString<32>
USR;
1631 if (!index::generateUSRForMacro(NewMacro.
name,
M->Info->getDefinitionLoc(),
1633 NewMacro.
USR = std::string(
USR);
1636 Results.push_back(std::move(NewMacro));
1643 OS << S.Name <<
": " << S.PreferredDeclaration;
1645 OS <<
" def=" << *S.Definition;
1652 if (R.
Attributes & ReferencesResult::Declaration)
1654 if (R.
Attributes & ReferencesResult::Definition)
1656 if (R.
Attributes & ReferencesResult::Override)
1657 OS <<
" [override]";
1661template <
typename HierarchyItem>
1662static std::optional<HierarchyItem>
1664 ASTContext &Ctx = ND.getASTContext();
1665 auto &SM = Ctx.getSourceManager();
1666 SourceLocation NameLoc =
nameLocation(ND, Ctx.getSourceManager());
1667 SourceLocation BeginLoc = SM.getFileLoc(ND.getBeginLoc());
1668 SourceLocation EndLoc = SM.getFileLoc(ND.getEndLoc());
1669 const auto DeclRange =
1672 return std::nullopt;
1673 const auto FE = SM.getFileEntryRefForID(SM.getFileID(NameLoc));
1675 return std::nullopt;
1678 return std::nullopt;
1682 SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
1684 index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
1695 HI.selectionRange =
Range{NameBegin, NameEnd};
1696 if (!HI.range.contains(HI.selectionRange)) {
1699 HI.range = HI.selectionRange;
1702 HI.uri = URIForFile::canonicalize(*FilePath, TUPath);
1707static std::optional<TypeHierarchyItem>
1709 auto Result = declToHierarchyItem<TypeHierarchyItem>(ND, TUPath);
1711 Result->deprecated = ND.isDeprecated();
1721static std::optional<CallHierarchyItem>
1723 auto Result = declToHierarchyItem<CallHierarchyItem>(ND, TUPath);
1726 if (ND.isDeprecated())
1727 Result->tags.push_back(SymbolTag::Deprecated);
1729 Result->data =
ID.str();
1733template <
typename HierarchyItem>
1738 elog(
"Failed to convert symbol to hierarchy item: {0}",
Loc.takeError());
1739 return std::nullopt;
1742 HI.name = std::string(S.Name);
1743 HI.detail = (S.Scope + S.Name).str();
1745 HI.selectionRange =
Loc->range;
1748 HI.range = HI.selectionRange;
1754static std::optional<TypeHierarchyItem>
1756 auto Result = symbolToHierarchyItem<TypeHierarchyItem>(S, TUPath);
1758 Result->deprecated = (S.Flags & Symbol::Deprecated);
1759 Result->data.symbolID = S.ID;
1764static std::optional<CallHierarchyItem>
1766 auto Result = symbolToHierarchyItem<CallHierarchyItem>(S, TUPath);
1769 Result->data = S.ID.str();
1770 if (S.Flags & Symbol::Deprecated)
1771 Result->tags.push_back(SymbolTag::Deprecated);
1776 std::vector<TypeHierarchyItem> &SubTypes,
1782 if (std::optional<TypeHierarchyItem> ChildSym =
1785 ChildSym->children.emplace();
1788 SubTypes.emplace_back(std::move(*ChildSym));
1806 auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD :
nullptr;
1808 if (!RPSet.insert(Pattern).second) {
1813 for (
const CXXRecordDecl *ParentDecl :
typeParents(&CXXRD)) {
1814 if (std::optional<TypeHierarchyItem> ParentSym =
1818 Item.
parents->emplace_back(std::move(*ParentSym));
1823 RPSet.erase(Pattern);
1830 std::vector<const CXXRecordDecl *>
Records;
1839 AST.getHeuristicResolver());
1840 for (
const NamedDecl *D : Decls) {
1842 if (
const VarDecl *VD = dyn_cast<VarDecl>(D)) {
1844 if (
const auto *RD = VD->getType().getTypePtr()->getAsCXXRecordDecl())
1849 if (
const CXXMethodDecl *
Method = dyn_cast<CXXMethodDecl>(D)) {
1859 if (
auto *RD = dyn_cast<CXXRecordDecl>(D))
1865 const SourceManager &SM = AST.getSourceManager();
1866 std::vector<const CXXRecordDecl *> Result;
1869 llvm::consumeError(
Offset.takeError());
1872 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), *
Offset,
1874 Result = RecordFromNode(ST.commonAncestor());
1875 return !Result.empty();
1885 while (N && N->
ASTNode.get<NestedNameSpecifierLoc>())
1891 if (
const TypeLoc *TL = N->
ASTNode.get<TypeLoc>()) {
1892 if (llvm::isa<DeducedType>(TL->getTypePtr()))
1897 if (llvm::isa<TypedefType>(TL->getTypePtr()))
1898 return TL->getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
1899 return TL->getType();
1903 if (
const auto *CCI = N->
ASTNode.get<CXXCtorInitializer>()) {
1904 if (
const FieldDecl *FD = CCI->getAnyMember())
1905 return FD->getType();
1906 if (
const Type *Base = CCI->getBaseClass())
1907 return QualType(Base, 0);
1911 if (
const auto *CBS = N->
ASTNode.get<CXXBaseSpecifier>())
1912 return CBS->getType();
1915 struct Visitor : ConstDeclVisitor<Visitor, QualType> {
1916 QualType VisitValueDecl(
const ValueDecl *D) {
return D->getType(); }
1918 QualType VisitTypeDecl(
const TypeDecl *D) {
1919 return QualType(D->getTypeForDecl(), 0);
1922 QualType VisitTypedefNameDecl(
const TypedefNameDecl *D) {
1923 return D->getUnderlyingType();
1926 QualType VisitTemplateDecl(
const TemplateDecl *D) {
1927 return Visit(D->getTemplatedDecl());
1933 if (
const Stmt *S = N->
ASTNode.get<Stmt>()) {
1934 struct Visitor : ConstStmtVisitor<Visitor, QualType> {
1936 QualType type(
const Stmt *S) {
return S ? Visit(S) : QualType(); }
1939 QualType VisitExpr(
const Expr *S) {
1940 return S->IgnoreImplicitAsWritten()->getType();
1942 QualType VisitMemberExpr(
const MemberExpr *S) {
1944 if (S->getType()->isSpecificBuiltinType(BuiltinType::BoundMember))
1945 return Expr::findBoundMemberType(S);
1946 return VisitExpr(S);
1949 QualType VisitCXXDeleteExpr(
const CXXDeleteExpr *S) {
1950 return S->getDestroyedType();
1952 QualType VisitCXXPseudoDestructorExpr(
const CXXPseudoDestructorExpr *S) {
1953 return S->getDestroyedType();
1955 QualType VisitCXXThrowExpr(
const CXXThrowExpr *S) {
1956 return S->getSubExpr()->getType();
1958 QualType VisitCoyieldExpr(
const CoyieldExpr *S) {
1959 return type(S->getOperand());
1962 QualType VisitDesignatedInitExpr(
const DesignatedInitExpr *S) {
1964 for (
auto &D : llvm::reverse(S->designators()))
1965 if (D.isFieldDesignator())
1966 if (
const auto *FD = D.getFieldDecl())
1967 return FD->getType();
1972 QualType VisitSwitchStmt(
const SwitchStmt *S) {
1973 return type(S->getCond());
1975 QualType VisitWhileStmt(
const WhileStmt *S) {
return type(S->getCond()); }
1976 QualType VisitDoStmt(
const DoStmt *S) {
return type(S->getCond()); }
1977 QualType VisitIfStmt(
const IfStmt *S) {
return type(S->getCond()); }
1978 QualType VisitCaseStmt(
const CaseStmt *S) {
return type(S->getLHS()); }
1979 QualType VisitCXXForRangeStmt(
const CXXForRangeStmt *S) {
1980 return S->getLoopVariable()->getType();
1982 QualType VisitReturnStmt(
const ReturnStmt *S) {
1983 return type(S->getRetValue());
1985 QualType VisitCoreturnStmt(
const CoreturnStmt *S) {
1986 return type(S->getOperand());
1988 QualType VisitCXXCatchStmt(
const CXXCatchStmt *S) {
1989 return S->getCaughtType();
1991 QualType VisitObjCAtThrowStmt(
const ObjCAtThrowStmt *S) {
1992 return type(S->getThrowExpr());
1994 QualType VisitObjCAtCatchStmt(
const ObjCAtCatchStmt *S) {
1995 return S->getCatchParamDecl() ? S->getCatchParamDecl()->getType()
2013 if (
const auto* TDT = T->getAs<TypedefType>())
2014 return Out.push_back(QualType(TDT, 0));
2017 if (
const auto *PT = T->getAs<PointerType>())
2019 if (
const auto *RT = T->getAs<ReferenceType>())
2021 if (
const auto *AT = T->getAsArrayTypeUnsafe())
2025 if (
auto *FT = T->getAs<FunctionType>())
2027 if (
auto *CRD = T->getAsCXXRecordDecl()) {
2028 if (CRD->isLambda())
2029 return unwrapFindType(CRD->getLambdaCallOperator()->getReturnType(), H,
2037 if (
const auto* PointeeType = H->getPointeeType(T.getNonReferenceType().getTypePtr())) {
2039 return Out.push_back(T);
2042 return Out.push_back(T);
2048 llvm::SmallVector<QualType> Result;
2055 const SourceManager &SM = AST.getSourceManager();
2057 std::vector<LocatedSymbol> Result;
2059 elog(
"failed to convert position {0} for findTypes: {1}",
Pos,
2064 auto SymbolsFromNode =
2066 std::vector<LocatedSymbol> LocatedSymbols;
2073 llvm::copy(locateSymbolForType(AST,
Type, Index),
2074 std::back_inserter(LocatedSymbols));
2076 return LocatedSymbols;
2078 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), *
Offset,
2080 Result = SymbolsFromNode(ST.commonAncestor());
2081 return !Result.empty();
2086std::vector<const CXXRecordDecl *>
typeParents(
const CXXRecordDecl *CXXRD) {
2087 std::vector<const CXXRecordDecl *> Result;
2091 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
2092 if (CTSD->isInvalidDecl())
2093 CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
2097 if (!CXXRD->hasDefinition())
2100 for (
auto Base : CXXRD->bases()) {
2101 const CXXRecordDecl *ParentDecl =
nullptr;
2103 const Type *
Type = Base.getType().getTypePtr();
2104 if (
const RecordType *RT =
Type->getAs<RecordType>()) {
2105 ParentDecl = RT->getAsCXXRecordDecl();
2111 if (
const TemplateSpecializationType *TS =
2112 Type->getAs<TemplateSpecializationType>()) {
2113 TemplateName TN = TS->getTemplateName();
2114 if (TemplateDecl *TD = TN.getAsTemplateDecl()) {
2115 ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());
2121 Result.push_back(ParentDecl);
2127std::vector<TypeHierarchyItem>
2131 std::vector<TypeHierarchyItem>
Results;
2134 bool WantChildren = Direction == TypeHierarchyDirection::Children ||
2135 Direction == TypeHierarchyDirection::Both;
2145 if (
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))
2146 CXXRD = CTSD->getTemplateInstantiationPattern();
2149 std::optional<TypeHierarchyItem> Result =
2157 if (WantChildren && ResolveLevels > 0) {
2158 Result->children.emplace();
2162 fillSubTypes(
ID, *Result->children, Index, ResolveLevels, TUPath);
2165 Results.emplace_back(std::move(*Result));
2171std::optional<std::vector<TypeHierarchyItem>>
2173 std::vector<TypeHierarchyItem>
Results;
2175 return std::nullopt;
2179 llvm::DenseMap<SymbolID, const TypeHierarchyItem::ResolveParams *> IDToData;
2184 Index->lookup(Req, [&Item, &
Results, &IDToData](
const Symbol &S) {
2186 THI->data = *IDToData.lookup(S.ID);
2187 Results.emplace_back(std::move(*THI));
2195 std::vector<TypeHierarchyItem>
Results;
2197 for (
auto &ChildSym :
Results)
2198 ChildSym.data.parents = {Item.
data};
2207 if (!Index || Direction == TypeHierarchyDirection::Parents ||
2216std::vector<CallHierarchyItem>
2218 std::vector<CallHierarchyItem> Result;
2219 const auto &SM = AST.getSourceManager();
2222 elog(
"prepareCallHierarchy failed to convert position to source location: "
2227 for (
const NamedDecl *
Decl : getDeclAtPosition(AST, *
Loc, {})) {
2228 if (!(isa<DeclContext>(
Decl) &&
2229 cast<DeclContext>(
Decl)->isFunctionOrMethod()) &&
2230 Decl->getKind() != Decl::Kind::FunctionTemplate &&
2231 !(
Decl->getKind() == Decl::Kind::Var &&
2232 !cast<VarDecl>(
Decl)->isLocalVarDecl()) &&
2233 Decl->getKind() != Decl::Kind::Field)
2236 Result.emplace_back(std::move(*CHI));
2241std::vector<CallHierarchyIncomingCall>
2243 std::vector<CallHierarchyIncomingCall>
Results;
2244 if (!Index || Item.
data.empty())
2246 auto ID = SymbolID::fromStr(Item.
data);
2248 elog(
"incomingCalls failed to find symbol: {0}",
ID.takeError());
2258 Request.
IDs.insert(*
ID);
2263 Request.
Filter = RefKind::Reference;
2267 llvm::DenseMap<SymbolID, std::vector<Location>> CallsIn;
2271 Index->refs(Request, [&](
const Ref &R) {
2274 elog(
"incomingCalls failed to convert location: {0}",
Loc.takeError());
2283 Index->lookup(ContainerLookup, [&](
const Symbol &Caller) {
2284 auto It = CallsIn.find(Caller.
ID);
2285 assert(It != CallsIn.end());
2287 std::vector<Range> FromRanges;
2288 for (
const Location &L : It->second) {
2289 if (L.uri != CHI->uri) {
2296 FromRanges.push_back(L.range);
2305 return A.from.name < B.from.name;
2310std::vector<CallHierarchyOutgoingCall>
2312 std::vector<CallHierarchyOutgoingCall>
Results;
2313 if (!Index || Item.
data.empty())
2315 auto ID = SymbolID::fromStr(Item.
data);
2317 elog(
"outgoingCalls failed to find symbol: {0}",
ID.takeError());
2326 llvm::DenseMap<SymbolID, std::vector<Range>> CallsOut;
2330 Index->containedRefs(Request, [&](
const auto &R) {
2333 elog(
"outgoingCalls failed to convert location: {0}",
Loc.takeError());
2336 auto It = CallsOut.try_emplace(R.Symbol, std::vector<Range>{}).first;
2337 It->second.push_back(
Loc->range);
2339 CallsOutLookup.
IDs.insert(R.Symbol);
2343 Index->lookup(CallsOutLookup, [&](
const Symbol &Callee) {
2346 using SK = index::SymbolKind;
2348 assert(
Kind == SK::Function ||
Kind == SK::InstanceMethod ||
2349 Kind == SK::ClassMethod ||
Kind == SK::StaticMethod ||
2350 Kind == SK::Constructor ||
Kind == SK::Destructor ||
2351 Kind == SK::ConversionFunction);
2355 auto It = CallsOut.find(Callee.
ID);
2356 assert(It != CallsOut.end());
2364 return A.to.name < B.to.name;
2370 const FunctionDecl *FD) {
2373 llvm::DenseSet<const Decl *> DeclRefs;
2377 for (
const Decl *D :
Ref.Targets) {
2378 if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
2383 AST.getHeuristicResolver());
const FunctionDecl * Decl
std::vector< CodeCompletionResult > Results
SignatureQualitySignals Quality
CompiledFragmentImpl & Out
std::optional< float > Score
Include Cleaner is clangd functionality for providing diagnostics for misuse of transitive headers an...
CharSourceRange Range
SourceRange for the file name.
llvm::StringMap< llvm::TimeRecord > Records
const google::protobuf::Message & M
SymbolCollector::Options CollectorOpts
index::SymbolRoleSet Role
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)
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
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.
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)
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)
llvm::SmallSet< const CXXRecordDecl *, 4 > RecursionProtectionSet
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 QualType typeForNode(const SelectionTree::Node *N)
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)
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.
@ 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)
llvm::StringRef PathRef
A typedef to represent a ref to file path.
void elog(const char *Fmt, Ts &&... Vals)
@ 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.
std::optional< QualType > getDeducedType(ASTContext &ASTCtx, SourceLocation Loc)
Retrieves the deduced type at a given location (auto, decltype).
std::array< uint8_t, 20 > SymbolID
@ Invalid
Sentinel bit pattern. DO NOT USE!
@ All
Only model a unidirectional implicit conversion and within it only one standard conversion sequence.
===– 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 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
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...
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)
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.
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.
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.
StringRef text() const
The token text.
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.
@ Counter
An aggregate number whose rate of change over time is meaningful.