14 #include "clang/AST/DeclTemplate.h" 15 #include "clang/AST/RecursiveASTVisitor.h" 16 #include "clang/Index/IndexDataConsumer.h" 17 #include "clang/Index/IndexingAction.h" 18 #include "clang/Index/USRGeneration.h" 19 #include "llvm/Support/Path.h" 28 const Decl *getDefinition(
const Decl *
D) {
30 if (
const auto *TD = dyn_cast<TagDecl>(D))
31 return TD->getDefinition();
32 else if (
const auto *VD = dyn_cast<VarDecl>(D))
33 return VD->getDefinition();
34 else if (
const auto *FD = dyn_cast<FunctionDecl>(D))
35 return FD->getDefinition();
39 void logIfOverflow(
const SymbolLocation &
Loc) {
40 if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
41 log(
"Possible overflow in symbol location: {0}", Loc);
48 llvm::Optional<Location> toLSPLocation(
const SymbolLocation &Loc,
49 llvm::StringRef TUPath) {
54 elog(
"Could not parse URI {0}: {1}", Loc.FileURI, Uri.takeError());
59 elog(
"Could not resolve URI {0}: {1}", Loc.FileURI, U.takeError());
64 LSPLoc.uri = std::move(*U);
65 LSPLoc.range.start.line = Loc.Start.line();
66 LSPLoc.range.start.character = Loc.Start.column();
67 LSPLoc.range.end.line = Loc.End.line();
68 LSPLoc.range.end.character = Loc.End.column();
85 class DeclarationAndMacrosFinder :
public index::IndexDataConsumer {
86 std::vector<MacroDecl> MacroInfos;
91 llvm::DenseMap<const Decl *, bool> Decls;
92 const SourceLocation &SearchedLocation;
93 const ASTContext &
AST;
97 DeclarationAndMacrosFinder(
const SourceLocation &SearchedLocation,
98 ASTContext &AST, Preprocessor &PP)
99 : SearchedLocation(SearchedLocation),
AST(AST), PP(PP) {}
104 std::vector<DeclInfo> getFoundDecls()
const {
105 std::vector<DeclInfo>
Result;
106 for (
auto It : Decls) {
107 Result.emplace_back();
108 Result.back().D = It.first;
109 Result.back().IsReferencedExplicitly = It.second;
113 llvm::sort(Result, [](
const DeclInfo &L,
const DeclInfo &R) {
114 if (L.IsReferencedExplicitly != R.IsReferencedExplicitly)
115 return L.IsReferencedExplicitly > R.IsReferencedExplicitly;
116 return L.D->getBeginLoc() < R.D->getBeginLoc();
121 std::vector<MacroDecl> takeMacroInfos() {
123 llvm::sort(MacroInfos, [](
const MacroDecl &Left,
const MacroDecl &Right) {
124 return Left.Info < Right.Info;
127 auto Last = std::unique(MacroInfos.begin(), MacroInfos.end(),
128 [](
const MacroDecl &Left,
const MacroDecl &Right) {
129 return Left.Info == Right.Info;
131 MacroInfos.erase(Last, MacroInfos.end());
132 return std::move(MacroInfos);
136 handleDeclOccurence(
const Decl *D, index::SymbolRoleSet Roles,
137 llvm::ArrayRef<index::SymbolRelation> Relations,
139 index::IndexDataConsumer::ASTNodeInfo ASTNode)
override {
140 if (Loc == SearchedLocation) {
141 auto isImplicitExpr = [](
const Expr *E) {
147 if (
const auto *CtorExpr = dyn_cast<CXXConstructExpr>(E))
148 return CtorExpr->getNumArgs() > 0 &&
149 CtorExpr->getParenOrBraceRange().isInvalid();
150 return isa<ImplicitCastExpr>(E);
153 bool IsExplicit = !isImplicitExpr(ASTNode.OrigE);
158 if (
const auto *Def = getDefinition(D)) {
159 Decls[Def] |= IsExplicit;
162 Decls[
D] |= IsExplicit;
169 void finish()
override {
172 auto &Mgr = AST.getSourceManager();
173 if (!Lexer::getRawToken(Mgr.getSpellingLoc(SearchedLocation),
Result, Mgr,
174 AST.getLangOpts(),
false)) {
175 if (Result.is(tok::raw_identifier)) {
176 PP.LookUpIdentifierInfo(Result);
178 IdentifierInfo *IdentifierInfo = Result.getIdentifierInfo();
179 if (IdentifierInfo && IdentifierInfo->hadMacroDefinition()) {
180 std::pair<FileID, unsigned int> DecLoc =
181 Mgr.getDecomposedExpansionLoc(SearchedLocation);
184 SourceLocation BeforeSearchedLocation = Mgr.getMacroArgExpandedLocation(
185 Mgr.getLocForStartOfFile(DecLoc.first)
186 .getLocWithOffset(DecLoc.second - 1));
187 MacroDefinition MacroDef =
188 PP.getMacroDefinitionAtLoc(IdentifierInfo, BeforeSearchedLocation);
189 MacroInfo *MacroInf = MacroDef.getMacroInfo();
191 MacroInfos.push_back(MacroDecl{IdentifierInfo->getName(), MacroInf});
192 assert(Decls.empty());
199 struct IdentifiedSymbol {
200 std::vector<DeclInfo> Decls;
204 IdentifiedSymbol getSymbolAtPosition(ParsedAST &
AST, SourceLocation
Pos) {
205 auto DeclMacrosFinder = DeclarationAndMacrosFinder(Pos, AST.getASTContext(),
206 AST.getPreprocessor());
207 index::IndexingOptions IndexOpts;
208 IndexOpts.SystemSymbolFilter =
209 index::IndexingOptions::SystemSymbolFilterKind::All;
210 IndexOpts.IndexFunctionLocals =
true;
211 indexTopLevelDecls(AST.getASTContext(), AST.getPreprocessor(),
212 AST.getLocalTopLevelDecls(), DeclMacrosFinder, IndexOpts);
214 return {DeclMacrosFinder.getFoundDecls(), DeclMacrosFinder.takeMacroInfos()};
217 Range getTokenRange(ParsedAST &
AST, SourceLocation TokLoc) {
218 const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
219 SourceLocation LocEnd = Lexer::getLocForEndOfToken(
220 TokLoc, 0, SourceMgr, AST.getASTContext().getLangOpts());
225 llvm::Optional<Location> makeLocation(ParsedAST &AST, SourceLocation TokLoc,
226 llvm::StringRef TUPath) {
227 const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
228 const FileEntry *F = SourceMgr.getFileEntryForID(SourceMgr.getFileID(TokLoc));
233 log(
"failed to get path!");
238 L.range = getTokenRange(AST, TokLoc);
250 elog(
"Failed to get a path for the main file, so no references");
254 std::vector<Location>
Result;
257 if (!Inc.Resolved.empty() && Inc.R.start.line == Pos.
line)
259 Location{URIForFile::canonicalize(Inc.Resolved, *MainFilePath), {}});
265 SourceLocation SourceLocationBeg =
267 auto Symbols = getSymbolAtPosition(
AST, SourceLocationBeg);
269 for (
auto Item : Symbols.Macros) {
270 auto Loc = Item.Info->getDefinitionLoc();
271 auto L = makeLocation(
AST, Loc, *MainFilePath);
296 struct CandidateLocation {
297 llvm::Optional<Location> Def;
298 llvm::Optional<Location> Decl;
301 llvm::SmallVector<CandidateLocation, 8> ResultCandidates;
302 llvm::DenseMap<SymbolID, size_t> CandidatesIndex;
305 for (
const DeclInfo &DI : Symbols.Decls) {
306 const Decl *D = DI.D;
315 auto R = CandidatesIndex.try_emplace(Key, ResultCandidates.size());
317 ResultCandidates.emplace_back();
318 auto &Candidate = ResultCandidates[R.first->second];
321 auto L = makeLocation(
AST, Loc, *MainFilePath);
324 bool IsDef = getDefinition(D) ==
D;
335 for (
auto It : CandidatesIndex)
336 QueryRequest.
IDs.insert(It.first);
338 const FileEntry *FE = SM.getFileEntryForID(SM.getMainFileID());
342 Index->lookup(QueryRequest, [&TUPath, &ResultCandidates,
343 &CandidatesIndex](
const Symbol &Sym) {
344 auto It = CandidatesIndex.find(Sym.
ID);
345 assert(It != CandidatesIndex.end());
346 auto &
Value = ResultCandidates[It->second];
349 Value.Def = toLSPLocation(Sym.
Definition, TUPath);
356 for (
const auto &Candidate : ResultCandidates) {
358 Result.push_back(*Candidate.Def);
359 if (Candidate.Decl &&
360 Candidate.Decl != Candidate.Def)
361 Result.push_back(*Candidate.Decl);
370 class ReferenceFinder :
public index::IndexDataConsumer {
378 ReferenceFinder(ASTContext &
AST, Preprocessor &PP,
379 const std::vector<const Decl *> &TargetDecls)
381 for (
const Decl *D : TargetDecls)
382 CanonicalTargets.insert(D->getCanonicalDecl());
385 std::vector<Reference> take() && {
387 return std::tie(L.Loc, L.CanonicalTarget, L.Role) <
388 std::tie(R.Loc, R.CanonicalTarget, R.Role);
392 std::unique(References.begin(), References.end(),
394 return std::tie(L.CanonicalTarget, L.Loc, L.Role) ==
395 std::tie(R.CanonicalTarget, R.Loc, R.Role);
398 return std::move(References);
402 handleDeclOccurence(
const Decl *D, index::SymbolRoleSet Roles,
403 llvm::ArrayRef<index::SymbolRelation> Relations,
405 index::IndexDataConsumer::ASTNodeInfo ASTNode)
override {
406 assert(D->isCanonicalDecl() &&
"expect D to be a canonical declaration");
407 const SourceManager &SM =
AST.getSourceManager();
408 Loc = SM.getFileLoc(Loc);
409 if (SM.isWrittenInMainFile(Loc) && CanonicalTargets.count(D))
410 References.push_back({D, Loc, Roles});
415 llvm::SmallSet<const Decl *, 4> CanonicalTargets;
416 std::vector<Reference> References;
417 const ASTContext &
AST;
420 std::vector<ReferenceFinder::Reference>
421 findRefs(
const std::vector<const Decl *> &Decls, ParsedAST &
AST) {
422 ReferenceFinder RefFinder(AST.getASTContext(), AST.getPreprocessor(), Decls);
423 index::IndexingOptions IndexOpts;
424 IndexOpts.SystemSymbolFilter =
425 index::IndexingOptions::SystemSymbolFilterKind::All;
426 IndexOpts.IndexFunctionLocals =
true;
427 indexTopLevelDecls(AST.getASTContext(), AST.getPreprocessor(),
428 AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);
429 return std::move(RefFinder).take();
436 const SourceManager &SM = AST.
getASTContext().getSourceManager();
437 auto Symbols = getSymbolAtPosition(
439 std::vector<const Decl *> TargetDecls;
440 for (
const DeclInfo &DI : Symbols.Decls) {
441 TargetDecls.push_back(DI.D);
443 auto References = findRefs(TargetDecls, AST);
445 std::vector<DocumentHighlight>
Result;
446 for (
const auto &
Ref : References) {
448 DH.
range = getTokenRange(AST,
Ref.Loc);
449 if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
451 else if (
Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
455 Result.push_back(std::move(DH));
461 PrintingPolicy Policy(Base);
463 Policy.AnonymousTagLocations =
false;
464 Policy.TerseOutput =
true;
465 Policy.PolishForDeclaration =
true;
466 Policy.ConstantsAsWritten =
true;
467 Policy.SuppressTagKeyword =
false;
475 QualType Type = TD->getASTContext().getTypeDeclType(TD);
477 PrintingPolicy Policy =
481 llvm::raw_string_ostream Stream(Name);
482 Type.print(Stream, Policy);
490 llvm::StringRef Prefix) {
491 PrintingPolicy Policy =
495 llvm::raw_string_ostream Stream(Name);
496 Stream << Prefix <<
' ';
497 ND->printQualifiedName(Stream, Policy);
506 const DeclContext *DC = D->getDeclContext();
508 if (isa<TranslationUnitDecl>(DC))
509 return std::string(
"global namespace");
510 if (
const TypeDecl *TD = dyn_cast<TypeDecl>(DC))
512 else if (
const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC))
514 else if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
523 llvm::Optional<std::string> NamedScope =
getScopeName(D);
527 assert(!NamedScope->empty());
535 if (TemplateDecl *TD = D->getDescribedTemplate())
538 std::string DeclText;
539 llvm::raw_string_ostream OS(DeclText);
541 PrintingPolicy Policy =
544 D->print(OS, Policy);
555 std::string TypeText;
556 llvm::raw_string_ostream OS(TypeText);
583 class DeducedTypeVisitor :
public RecursiveASTVisitor<DeducedTypeVisitor> {
584 SourceLocation SearchedLocation;
585 llvm::Optional<QualType> DeducedType;
588 DeducedTypeVisitor(SourceLocation SearchedLocation)
589 : SearchedLocation(SearchedLocation) {}
598 bool VisitDeclaratorDecl(DeclaratorDecl *D) {
599 if (!D->getTypeSourceInfo() ||
600 D->getTypeSourceInfo()->getTypeLoc().getBeginLoc() != SearchedLocation)
603 if (
auto *AT = D->getType()->getContainedAutoType()) {
604 if (!AT->getDeducedType().isNull())
605 DeducedType = AT->getDeducedType();
616 bool VisitFunctionDecl(FunctionDecl *D) {
617 if (!D->getTypeSourceInfo())
620 auto CurLoc = D->getReturnTypeSourceRange().getBegin();
622 if (CurLoc.isInvalid() && dyn_cast<CXXConversionDecl>(
D))
623 CurLoc = D->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
625 if (CurLoc.isInvalid())
626 CurLoc = D->getSourceRange().getBegin();
627 if (CurLoc != SearchedLocation)
630 const AutoType *AT = D->getReturnType()->getContainedAutoType();
631 if (AT && !AT->getDeducedType().isNull()) {
632 DeducedType = AT->getDeducedType();
633 }
else if (
auto DT = dyn_cast<DecltypeType>(D->getReturnType())) {
636 if (!DT->getUnderlyingType().isNull())
637 DeducedType = DT->getUnderlyingType();
638 }
else if (!D->getReturnType().isNull()) {
639 DeducedType = D->getReturnType();
647 bool VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
648 if (TL.getBeginLoc() != SearchedLocation)
655 const DecltypeType *DT = dyn_cast<DecltypeType>(TL.getTypePtr());
656 while (DT && !DT->getUnderlyingType().isNull()) {
657 DeducedType = DT->getUnderlyingType();
658 DT = dyn_cast<DecltypeType>(DeducedType->getTypePtr());
667 SourceLocation SourceLocationBeg) {
671 if (!SourceLocationBeg.isValid() ||
672 Lexer::getRawToken(SourceLocationBeg, Tok, ASTCtx.getSourceManager(),
673 ASTCtx.getLangOpts(),
false) ||
674 !Tok.is(tok::raw_identifier)) {
678 if (!(Tok.is(tok::kw_auto) || Tok.is(tok::kw_decltype)))
681 DeducedTypeVisitor V(SourceLocationBeg);
683 return V.getDeducedType();
687 const SourceManager &SourceMgr = AST.
getASTContext().getSourceManager();
688 SourceLocation SourceLocationBeg =
691 auto Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
693 if (!Symbols.Macros.empty())
696 if (!Symbols.Decls.empty())
700 if (DeducedType && !DeducedType->isNull())
709 Limit = std::numeric_limits<uint32_t>::max();
711 const SourceManager &SM = AST.
getASTContext().getSourceManager();
715 elog(
"Failed to get a path for the main file, so no references");
719 auto Symbols = getSymbolAtPosition(AST, Loc);
721 std::vector<const Decl *> TargetDecls;
722 for (
const DeclInfo &DI : Symbols.Decls) {
723 if (DI.IsReferencedExplicitly)
724 TargetDecls.push_back(DI.D);
729 auto MainFileRefs = findRefs(TargetDecls, AST);
730 for (
const auto &
Ref : MainFileRefs) {
732 Result.
range = getTokenRange(AST,
Ref.Loc);
734 Results.push_back(std::move(Result));
738 if (Index && Results.size() < Limit) {
742 for (
const Decl *D : TargetDecls) {
746 if (D->getParentFunctionOrMethod())
753 Index->
refs(Req, [&](
const Ref &R) {
754 auto LSPLoc = toLSPLocation(R.
Location, *MainFilePath);
756 if (LSPLoc && LSPLoc->uri.file() != *MainFilePath)
757 Results.push_back(std::move(*LSPLoc));
760 if (Results.size() > Limit)
761 Results.resize(Limit);
766 const SourceManager &SM = AST.
getASTContext().getSourceManager();
769 auto Symbols = getSymbolAtPosition(AST, Loc);
771 std::vector<SymbolDetails>
Results;
773 for (
const auto &Sym : Symbols.Decls) {
775 if (
const NamedDecl *ND = dyn_cast<NamedDecl>(Sym.D)) {
781 if (
const auto *ParentND =
782 dyn_cast_or_null<NamedDecl>(ND->getDeclContext()))
786 llvm::SmallString<32> USR;
787 if (!index::generateUSRForDecl(Sym.D, USR)) {
788 NewSymbol.
USR = USR.str();
791 Results.push_back(std::move(NewSymbol));
794 for (
const auto &Macro : Symbols.Macros) {
796 NewMacro.
name = Macro.Name;
797 llvm::SmallString<32> USR;
798 if (!index::generateUSRForMacro(NewMacro.
name, Loc, SM, USR)) {
799 NewMacro.
USR = USR.str();
802 Results.push_back(std::move(NewMacro));
std::string USR
Unified Symbol Resolution identifier This is an opaque string uniquely identifying a symbol...
llvm::Optional< Hover > getHover(ParsedAST &AST, Position Pos)
Get the hover information when hovering at Pos.
static llvm::Optional< std::string > getScopeName(const Decl *D)
Given a declaration D, return a human-readable string representing the scope in which it is declared...
std::vector< Location > findDefinitions(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
llvm::DenseSet< SymbolID > IDs
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
llvm::Optional< SymbolID > getSymbolID(const Decl *D)
Gets the symbol ID for a declaration, if possible.
Range range
The range this highlight applies to.
Preprocessor & getPreprocessor()
bool IsReferencedExplicitly
const Decl * CanonicalTarget
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
static Hover getHoverContents(const Decl *D)
Generate a Hover object given the declaration D.
llvm::DenseSet< SymbolID > IDs
SourceLocation findNameLoc(const clang::Decl *D)
Find the identifier source location of the given D.
URIForFile uri
The text document's URI.
std::vector< CodeCompletionResult > Results
Documents should not be synced at all.
void elog(const char *Fmt, Ts &&... Vals)
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
MarkupContent contents
The hover's content.
A document highlight is a range inside a text document which deserves special attention.
static std::string typeDeclToString(const TypeDecl *TD)
Return a string representation (e.g.
SymbolLocation Definition
llvm::Optional< SymbolID > ID
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
const IncludeStructure & getIncludeStructure() const
static llvm::Expected< URIForFile > fromURI(const URI &U, llvm::StringRef HintPath)
static std::string namedDeclQualifiedName(const NamedDecl *ND, llvm::StringRef Prefix)
Return a string representation (e.g.
void log(const char *Fmt, Ts &&... Vals)
index::SymbolRoleSet Role
std::string Path
A typedef to represent a file path.
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
std::string containerName
SymbolLocation CanonicalDeclaration
virtual void refs(const RefsRequest &Req, llvm::function_ref< void(const Ref &)> Callback) const =0
Finds all occurrences (e.g.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
std::vector< MacroDecl > Macros
Stores and provides access to parsed AST.
int line
Line position in a document (zero-based).
std::vector< Location > findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index)
Returns reference locations of the symbol at a specified Pos.
std::vector< Inclusion > MainFileIncludes
SourceLocation getBeginningOfIdentifier(ParsedAST &Unit, const Position &Pos, const FileID FID)
Get the beginning SourceLocation at a specified Pos.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static PrintingPolicy printingPolicyForDecls(PrintingPolicy Base)
llvm::Optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
CharSourceRange Range
SourceRange for the file name.
std::pair< llvm::StringRef, llvm::StringRef > splitQualifiedName(llvm::StringRef QName)
From "a::b::c", return {"a::b::", "c"}.
DocumentHighlightKind kind
The highlight kind, default is DocumentHighlightKind.Text.
llvm::Optional< std::string > getCanonicalPath(const FileEntry *F, const SourceManager &SourceMgr)
Get the canonical path of F.
llvm::Optional< QualType > getDeducedType(ParsedAST &AST, SourceLocation SourceLocationBeg)
Retrieves the deduced type at a given location (auto, decltype).
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
std::array< uint8_t, 20 > SymbolID
Represents information about identifier.
const SymbolIndex * Index