clang-tools 8.0.0

XRefs.cpp
Go to the documentation of this file.
1 //===--- XRefs.cpp -----------------------------------------------*- C++-*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #include "XRefs.h"
10 #include "AST.h"
11 #include "Logger.h"
12 #include "SourceCode.h"
13 #include "URI.h"
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"
20
21 namespace clang {
22 namespace clangd {
23 namespace {
24
25 // Get the definition from a given declaration `D`.
26 // Return nullptr if no definition is found, or the declaration type of `D` is
27 // not supported.
28 const Decl *getDefinition(const Decl *D) {
29 assert(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();
36 return nullptr;
37 }
38
39 void logIfOverflow(const SymbolLocation &Loc) {
40 if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())
41 log("Possible overflow in symbol location: {0}", Loc);
42 }
43
44 // Convert a SymbolLocation to LSP's Location.
45 // TUPath is used to resolve the path of URI.
46 // FIXME: figure out a good home for it, and share the implementation with
47 // FindSymbols.
48 llvm::Optional<Location> toLSPLocation(const SymbolLocation &Loc,
49 llvm::StringRef TUPath) {
50 if (!Loc)
51 return None;
52 auto Uri = URI::parse(Loc.FileURI);
53 if (!Uri) {
54 elog("Could not parse URI {0}: {1}", Loc.FileURI, Uri.takeError());
55 return None;
56 }
57 auto U = URIForFile::fromURI(*Uri, TUPath);
58 if (!U) {
59 elog("Could not resolve URI {0}: {1}", Loc.FileURI, U.takeError());
60 return None;
61 }
62
63 Location LSPLoc;
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();
69 logIfOverflow(Loc);
70 return LSPLoc;
71 }
72
73 struct MacroDecl {
74 llvm::StringRef Name;
75 const MacroInfo *Info;
76 };
77
78 struct DeclInfo {
79 const Decl *D;
80 // Indicates the declaration is referenced by an explicit AST node.
81 bool IsReferencedExplicitly = false;
82 };
83
84 /// Finds declarations locations that a given source location refers to.
85 class DeclarationAndMacrosFinder : public index::IndexDataConsumer {
86 std::vector<MacroDecl> MacroInfos;
87 // The value of the map indicates whether the declaration has been referenced
88 // explicitly in the code.
89 // True means the declaration is explicitly referenced at least once; false
90 // otherwise.
91 llvm::DenseMap<const Decl *, bool> Decls;
92 const SourceLocation &SearchedLocation;
93 const ASTContext &AST;
94 Preprocessor &PP;
95
96 public:
97 DeclarationAndMacrosFinder(const SourceLocation &SearchedLocation,
98 ASTContext &AST, Preprocessor &PP)
99 : SearchedLocation(SearchedLocation), AST(AST), PP(PP) {}
100
101 // Get all DeclInfo of the found declarations.
102 // The results are sorted by "IsReferencedExplicitly" and declaration
103 // location.
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;
110 }
111
112 // Sort results. Declarations being referenced explicitly come first.
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();
117 });
118 return Result;
119 }
120
121 std::vector<MacroDecl> takeMacroInfos() {
122 // Don't keep the same Macro info multiple times.
123 llvm::sort(MacroInfos, [](const MacroDecl &Left, const MacroDecl &Right) {
124 return Left.Info < Right.Info;
125 });
126
127 auto Last = std::unique(MacroInfos.begin(), MacroInfos.end(),
128 [](const MacroDecl &Left, const MacroDecl &Right) {
129 return Left.Info == Right.Info;
130 });
131 MacroInfos.erase(Last, MacroInfos.end());
132 return std::move(MacroInfos);
133 }
134
135 bool
136 handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
137 llvm::ArrayRef<index::SymbolRelation> Relations,
138 SourceLocation Loc,
139 index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
140 if (Loc == SearchedLocation) {
141 auto isImplicitExpr = [](const Expr *E) {
142 if (!E)
143 return false;
144 // We assume that a constructor expression is implict (was inserted by
145 // clang) if it has an invalid paren/brace location, since such
146 // experssion is impossible to write down.
147 if (const auto *CtorExpr = dyn_cast<CXXConstructExpr>(E))
148 return CtorExpr->getNumArgs() > 0 &&
149 CtorExpr->getParenOrBraceRange().isInvalid();
150 return isa<ImplicitCastExpr>(E);
151 };
152
153 bool IsExplicit = !isImplicitExpr(ASTNode.OrigE);
154 // Find and add definition declarations (for GoToDefinition).
155 // We don't use parameter `D`, as Parameter `D` is the canonical
156 // declaration, which is the first declaration of a redeclarable
157 // declaration, and it could be a forward declaration.
158 if (const auto *Def = getDefinition(D)) {
159 Decls[Def] |= IsExplicit;
160 } else {
161 // Couldn't find a definition, fall back to use `D`.
162 Decls[D] |= IsExplicit;
163 }
164 }
165 return true;
166 }
167
168 private:
169 void finish() override {
170 // Also handle possible macro at the searched location.
171 Token Result;
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);
177 }
178 IdentifierInfo *IdentifierInfo = Result.getIdentifierInfo();
179 if (IdentifierInfo && IdentifierInfo->hadMacroDefinition()) {
180 std::pair<FileID, unsigned int> DecLoc =
181 Mgr.getDecomposedExpansionLoc(SearchedLocation);
182 // Get the definition just before the searched location so that a macro
183 // referenced in a '#undef MACRO' can still be found.
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();
190 if (MacroInf) {
191 MacroInfos.push_back(MacroDecl{IdentifierInfo->getName(), MacroInf});
192 assert(Decls.empty());
193 }
194 }
195 }
196 }
197 };
198
199 struct IdentifiedSymbol {
200 std::vector<DeclInfo> Decls;
201 std::vector<MacroDecl> Macros;
202 };
203
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);
213
214 return {DeclMacrosFinder.getFoundDecls(), DeclMacrosFinder.takeMacroInfos()};
215 }
216
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());
221 return {sourceLocToPosition(SourceMgr, TokLoc),
222 sourceLocToPosition(SourceMgr, LocEnd)};
223 }
224
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));
229 if (!F)
230 return None;
231 auto FilePath = getCanonicalPath(F, SourceMgr);
232 if (!FilePath) {
233 log("failed to get path!");
234 return None;
235 }
236 Location L;
237 L.uri = URIForFile::canonicalize(*FilePath, TUPath);
238 L.range = getTokenRange(AST, TokLoc);
239 return L;
240 }
241
242 } // namespace
243
244 std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
245 const SymbolIndex *Index) {
246 const auto &SM = AST.getASTContext().getSourceManager();
247 auto MainFilePath =
248 getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
249 if (!MainFilePath) {
250 elog("Failed to get a path for the main file, so no references");
251 return {};
252 }
253
254 std::vector<Location> Result;
255 // Handle goto definition for #include.
256 for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
257 if (!Inc.Resolved.empty() && Inc.R.start.line == Pos.line)
258 Result.push_back(
259 Location{URIForFile::canonicalize(Inc.Resolved, *MainFilePath), {}});
260 }
261 if (!Result.empty())
262 return Result;
263
264 // Identified symbols at a specific position.
265 SourceLocation SourceLocationBeg =
266 getBeginningOfIdentifier(AST, Pos, SM.getMainFileID());
267 auto Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
268
269 for (auto Item : Symbols.Macros) {
270 auto Loc = Item.Info->getDefinitionLoc();
271 auto L = makeLocation(AST, Loc, *MainFilePath);
272 if (L)
273 Result.push_back(*L);
274 }
275
276 // Declaration and definition are different terms in C-family languages, and
277 // LSP only defines the "GoToDefinition" specification, so we try to perform
278 // the "most sensible" GoTo operation:
279 //
280 // - We use the location from AST and index (if available) to provide the
281 // final results. When there are duplicate results, we prefer AST over
282 // index because AST is more up-to-date.
283 //
284 // - For each symbol, we will return a location of the canonical declaration
285 // (e.g. function declaration in header), and a location of definition if
286 // they are available.
287 //
288 // So the work flow:
289 //
290 // 1. Identify the symbols being search for by traversing the AST.
291 // 2. Populate one of the locations with the AST location.
292 // 3. Use the AST information to query the index, and populate the index
293 // location (if available).
294 // 4. Return all populated locations for all symbols, definition first (
295 // which we think is the users wants most often).
296 struct CandidateLocation {
297 llvm::Optional<Location> Def;
298 llvm::Optional<Location> Decl;
299 };
300 // We respect the order in Symbols.Decls.
301 llvm::SmallVector<CandidateLocation, 8> ResultCandidates;
302 llvm::DenseMap<SymbolID, size_t> CandidatesIndex;
303
304 // Emit all symbol locations (declaration or definition) from AST.
305 for (const DeclInfo &DI : Symbols.Decls) {
306 const Decl *D = DI.D;
307 // Fake key for symbols don't have USR (no SymbolID).
308 // Ideally, there should be a USR for each identified symbols. Symbols
309 // without USR are rare and unimportant cases, we use the a fake holder to
310 // minimize the invasiveness of these cases.
311 SymbolID Key("");
312 if (auto ID = getSymbolID(D))
313 Key = *ID;
314
315 auto R = CandidatesIndex.try_emplace(Key, ResultCandidates.size());
316 if (R.second) // new entry
317 ResultCandidates.emplace_back();
318 auto &Candidate = ResultCandidates[R.first->second];
319
320 auto Loc = findNameLoc(D);
321 auto L = makeLocation(AST, Loc, *MainFilePath);
322 // The declaration in the identified symbols is a definition if possible
323 // otherwise it is declaration.
324 bool IsDef = getDefinition(D) == D;
325 // Populate one of the slots with location for the AST.
326 if (!IsDef)
327 Candidate.Decl = L;
328 else
329 Candidate.Def = L;
330 }
331
332 if (Index) {
333 LookupRequest QueryRequest;
334 // Build request for index query, using SymbolID.
335 for (auto It : CandidatesIndex)
336 QueryRequest.IDs.insert(It.first);
337 std::string TUPath;
338 const FileEntry *FE = SM.getFileEntryForID(SM.getMainFileID());
339 if (auto Path = getCanonicalPath(FE, SM))
340 TUPath = *Path;
341 // Query the index and populate the empty slot.
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];
347
348 if (!Value.Def)
349 Value.Def = toLSPLocation(Sym.Definition, TUPath);
350 if (!Value.Decl)
351 Value.Decl = toLSPLocation(Sym.CanonicalDeclaration, TUPath);
352 });
353 }
354
355 // Populate the results, definition first.
356 for (const auto &Candidate : ResultCandidates) {
357 if (Candidate.Def)
358 Result.push_back(*Candidate.Def);
359 if (Candidate.Decl &&
360 Candidate.Decl != Candidate.Def) // Decl and Def might be the same
361 Result.push_back(*Candidate.Decl);
362 }
363
364 return Result;
365 }
366
367 namespace {
368
369 /// Collects references to symbols within the main file.
370 class ReferenceFinder : public index::IndexDataConsumer {
371 public:
372 struct Reference {
373 const Decl *CanonicalTarget;
374 SourceLocation Loc;
375 index::SymbolRoleSet Role;
376 };
377
378 ReferenceFinder(ASTContext &AST, Preprocessor &PP,
379 const std::vector<const Decl *> &TargetDecls)
380 : AST(AST) {
381 for (const Decl *D : TargetDecls)
382 CanonicalTargets.insert(D->getCanonicalDecl());
383 }
384
385 std::vector<Reference> take() && {
386 llvm::sort(References, [](const Reference &L, const Reference &R) {
387 return std::tie(L.Loc, L.CanonicalTarget, L.Role) <
388 std::tie(R.Loc, R.CanonicalTarget, R.Role);
389 });
390 // We sometimes see duplicates when parts of the AST get traversed twice.
391 References.erase(
392 std::unique(References.begin(), References.end(),
393 [](const Reference &L, const Reference &R) {
394 return std::tie(L.CanonicalTarget, L.Loc, L.Role) ==
395 std::tie(R.CanonicalTarget, R.Loc, R.Role);
396 }),
397 References.end());
398 return std::move(References);
399 }
400
401 bool
402 handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
403 llvm::ArrayRef<index::SymbolRelation> Relations,
404 SourceLocation Loc,
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});
411 return true;
412 }
413
414 private:
415 llvm::SmallSet<const Decl *, 4> CanonicalTargets;
416 std::vector<Reference> References;
417 const ASTContext &AST;
418 };
419
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();
430 }
431
432 } // namespace
433
434 std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
435 Position Pos) {
436 const SourceManager &SM = AST.getASTContext().getSourceManager();
437 auto Symbols = getSymbolAtPosition(
438 AST, getBeginningOfIdentifier(AST, Pos, SM.getMainFileID()));
439 std::vector<const Decl *> TargetDecls;
440 for (const DeclInfo &DI : Symbols.Decls) {
441 TargetDecls.push_back(DI.D);
442 }
443 auto References = findRefs(TargetDecls, AST);
444
445 std::vector<DocumentHighlight> Result;
446 for (const auto &Ref : References) {
447 DocumentHighlight DH;
448 DH.range = getTokenRange(AST, Ref.Loc);
449 if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
450 DH.kind = DocumentHighlightKind::Write;
451 else if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))
452 DH.kind = DocumentHighlightKind::Read;
453 else
454 DH.kind = DocumentHighlightKind::Text;
455 Result.push_back(std::move(DH));
456 }
457 return Result;
458 }
459
460 static PrintingPolicy printingPolicyForDecls(PrintingPolicy Base) {
461 PrintingPolicy Policy(Base);
462
463 Policy.AnonymousTagLocations = false;
464 Policy.TerseOutput = true;
465 Policy.PolishForDeclaration = true;
466 Policy.ConstantsAsWritten = true;
467 Policy.SuppressTagKeyword = false;
468
469 return Policy;
470 }
471
472 /// Return a string representation (e.g. "class MyNamespace::MyClass") of
473 /// the type declaration \p TD.
474 static std::string typeDeclToString(const TypeDecl *TD) {
475 QualType Type = TD->getASTContext().getTypeDeclType(TD);
476
477 PrintingPolicy Policy =
478 printingPolicyForDecls(TD->getASTContext().getPrintingPolicy());
479
480 std::string Name;
481 llvm::raw_string_ostream Stream(Name);
482 Type.print(Stream, Policy);
483
484 return Stream.str();
485 }
486
487 /// Return a string representation (e.g. "namespace ns1::ns2") of
488 /// the named declaration \p ND.
489 static std::string namedDeclQualifiedName(const NamedDecl *ND,
490 llvm::StringRef Prefix) {
491 PrintingPolicy Policy =
492 printingPolicyForDecls(ND->getASTContext().getPrintingPolicy());
493
494 std::string Name;
495 llvm::raw_string_ostream Stream(Name);
496 Stream << Prefix << ' ';
497 ND->printQualifiedName(Stream, Policy);
498
499 return Stream.str();
500 }
501
502 /// Given a declaration \p D, return a human-readable string representing the
503 /// scope in which it is declared. If the declaration is in the global scope,
504 /// return the string "global namespace".
505 static llvm::Optional<std::string> getScopeName(const Decl *D) {
506 const DeclContext *DC = D->getDeclContext();
507
508 if (isa<TranslationUnitDecl>(DC))
509 return std::string("global namespace");
510 if (const TypeDecl *TD = dyn_cast<TypeDecl>(DC))
511 return typeDeclToString(TD);
512 else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC))
513 return namedDeclQualifiedName(ND, "namespace");
514 else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
515 return namedDeclQualifiedName(FD, "function");
516
517 return None;
518 }
519
520 /// Generate a \p Hover object given the declaration \p D.
521 static Hover getHoverContents(const Decl *D) {
522 Hover H;
523 llvm::Optional<std::string> NamedScope = getScopeName(D);
524
525 // Generate the "Declared in" section.
526 if (NamedScope) {
527 assert(!NamedScope->empty());
528
529 H.contents.value += "Declared in ";
530 H.contents.value += *NamedScope;
531 H.contents.value += "\n\n";
532 }
533
534 // We want to include the template in the Hover.
535 if (TemplateDecl *TD = D->getDescribedTemplate())
536 D = TD;
537
538 std::string DeclText;
539 llvm::raw_string_ostream OS(DeclText);
540
541 PrintingPolicy Policy =
542 printingPolicyForDecls(D->getASTContext().getPrintingPolicy());
543
544 D->print(OS, Policy);
545
546 OS.flush();
547
548 H.contents.value += DeclText;
549 return H;
550 }
551
552 /// Generate a \p Hover object given the type \p T.
553 static Hover getHoverContents(QualType T, ASTContext &ASTCtx) {
554 Hover H;
555 std::string TypeText;
556 llvm::raw_string_ostream OS(TypeText);
557 PrintingPolicy Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
558 T.print(OS, Policy);
559 OS.flush();
560 H.contents.value += TypeText;
561 return H;
562 }
563
564 /// Generate a \p Hover object given the macro \p MacroInf.
565 static Hover getHoverContents(llvm::StringRef MacroName) {
566 Hover H;
567
568 H.contents.value = "#define ";
569 H.contents.value += MacroName;
570
571 return H;
572 }
573
574 namespace {
575 /// Computes the deduced type at a given location by visiting the relevant
576 /// nodes. We use this to display the actual type when hovering over an "auto"
577 /// keyword or "decltype()" expression.
578 /// FIXME: This could have been a lot simpler by visiting AutoTypeLocs but it
579 /// seems that the AutoTypeLocs that can be visited along with their AutoType do
580 /// not have the deduced type set. Instead, we have to go to the appropriate
581 /// DeclaratorDecl/FunctionDecl and work our back to the AutoType that does have
582 /// a deduced type set. The AST should be improved to simplify this scenario.
583 class DeducedTypeVisitor : public RecursiveASTVisitor<DeducedTypeVisitor> {
584 SourceLocation SearchedLocation;
585 llvm::Optional<QualType> DeducedType;
586
587 public:
588 DeducedTypeVisitor(SourceLocation SearchedLocation)
589 : SearchedLocation(SearchedLocation) {}
590
591 llvm::Optional<QualType> getDeducedType() { return DeducedType; }
592
593 // Handle auto initializers:
594 //- auto i = 1;
595 //- decltype(auto) i = 1;
596 //- auto& i = 1;
597 //- auto* i = &a;
598 bool VisitDeclaratorDecl(DeclaratorDecl *D) {
599 if (!D->getTypeSourceInfo() ||
600 D->getTypeSourceInfo()->getTypeLoc().getBeginLoc() != SearchedLocation)
601 return true;
602
603 if (auto *AT = D->getType()->getContainedAutoType()) {
604 if (!AT->getDeducedType().isNull())
605 DeducedType = AT->getDeducedType();
606 }
607 return true;
608 }
609
610 // Handle auto return types:
611 //- auto foo() {}
612 //- auto& foo() {}
613 //- auto foo() -> int {}
614 //- auto foo() -> decltype(1+1) {}
615 //- operator auto() const { return 10; }
616 bool VisitFunctionDecl(FunctionDecl *D) {
617 if (!D->getTypeSourceInfo())
618 return true;
619 // Loc of auto in return type (c++14).
620 auto CurLoc = D->getReturnTypeSourceRange().getBegin();
621 // Loc of "auto" in operator auto()
622 if (CurLoc.isInvalid() && dyn_cast<CXXConversionDecl>(D))
623 CurLoc = D->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
624 // Loc of "auto" in function with traling return type (c++11).
625 if (CurLoc.isInvalid())
626 CurLoc = D->getSourceRange().getBegin();
627 if (CurLoc != SearchedLocation)
628 return true;
629
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())) {
634 // auto in a trailing return type just points to a DecltypeType and
635 // getContainedAutoType does not unwrap it.
636 if (!DT->getUnderlyingType().isNull())
637 DeducedType = DT->getUnderlyingType();
638 } else if (!D->getReturnType().isNull()) {
639 DeducedType = D->getReturnType();
640 }
641 return true;
642 }
643
644 // Handle non-auto decltype, e.g.:
645 // - auto foo() -> decltype(expr) {}
646 // - decltype(expr);
647 bool VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
648 if (TL.getBeginLoc() != SearchedLocation)
649 return true;
650
651 // A DecltypeType's underlying type can be another DecltypeType! E.g.
652 // int I = 0;
653 // decltype(I) J = I;
654 // decltype(J) K = J;
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());
659 }
660 return true;
661 }
662 };
663 } // namespace
664
665 /// Retrieves the deduced type at a given location (auto, decltype).
666 llvm::Optional<QualType> getDeducedType(ParsedAST &AST,
667 SourceLocation SourceLocationBeg) {
668 Token Tok;
669 auto &ASTCtx = AST.getASTContext();
670 // Only try to find a deduced type if the token is auto or decltype.
671 if (!SourceLocationBeg.isValid() ||
672 Lexer::getRawToken(SourceLocationBeg, Tok, ASTCtx.getSourceManager(),
673 ASTCtx.getLangOpts(), false) ||
674 !Tok.is(tok::raw_identifier)) {
675 return {};
676 }
677 AST.getPreprocessor().LookUpIdentifierInfo(Tok);
678 if (!(Tok.is(tok::kw_auto) || Tok.is(tok::kw_decltype)))
679 return {};
680
681 DeducedTypeVisitor V(SourceLocationBeg);
682 V.TraverseAST(AST.getASTContext());
683 return V.getDeducedType();
684 }
685
686 llvm::Optional<Hover> getHover(ParsedAST &AST, Position Pos) {
687 const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
688 SourceLocation SourceLocationBeg =
689 getBeginningOfIdentifier(AST, Pos, SourceMgr.getMainFileID());
690 // Identified symbols at a specific position.
691 auto Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
692
693 if (!Symbols.Macros.empty())
694 return getHoverContents(Symbols.Macros[0].Name);
695
696 if (!Symbols.Decls.empty())
697 return getHoverContents(Symbols.Decls[0].D);
698
699 auto DeducedType = getDeducedType(AST, SourceLocationBeg);
700 if (DeducedType && !DeducedType->isNull())
701 return getHoverContents(*DeducedType, AST.getASTContext());
702
703 return None;
704 }
705
706 std::vector<Location> findReferences(ParsedAST &AST, Position Pos,
707 uint32_t Limit, const SymbolIndex *Index) {
708 if (!Limit)
709 Limit = std::numeric_limits<uint32_t>::max();
710 std::vector<Location> Results;
711 const SourceManager &SM = AST.getASTContext().getSourceManager();
712 auto MainFilePath =
713 getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
714 if (!MainFilePath) {
715 elog("Failed to get a path for the main file, so no references");
716 return Results;
717 }
718 auto Loc = getBeginningOfIdentifier(AST, Pos, SM.getMainFileID());
719 auto Symbols = getSymbolAtPosition(AST, Loc);
720
721 std::vector<const Decl *> TargetDecls;
722 for (const DeclInfo &DI : Symbols.Decls) {
723 if (DI.IsReferencedExplicitly)
724 TargetDecls.push_back(DI.D);
725 }
726
727 // We traverse the AST to find references in the main file.
728 // TODO: should we handle macros, too?
729 auto MainFileRefs = findRefs(TargetDecls, AST);
730 for (const auto &Ref : MainFileRefs) {
731 Location Result;
732 Result.range = getTokenRange(AST, Ref.Loc);
733 Result.uri = URIForFile::canonicalize(*MainFilePath, *MainFilePath);
734 Results.push_back(std::move(Result));
735 }
736
737 // Now query the index for references from other files.
738 if (Index && Results.size() < Limit) {
739 RefsRequest Req;
740 Req.Limit = Limit;
741
742 for (const Decl *D : TargetDecls) {
743 // Not all symbols can be referenced from outside (e.g. function-locals).
744 // TODO: we could skip TU-scoped symbols here (e.g. static functions) if
745 // we know this file isn't a header. The details might be tricky.
746 if (D->getParentFunctionOrMethod())
747 continue;
748 if (auto ID = getSymbolID(D))
749 Req.IDs.insert(*ID);
750 }
751 if (Req.IDs.empty())
752 return Results;
753 Index->refs(Req, [&](const Ref &R) {
754 auto LSPLoc = toLSPLocation(R.Location, *MainFilePath);
755 // Avoid indexed results for the main file - the AST is authoritative.
756 if (LSPLoc && LSPLoc->uri.file() != *MainFilePath)
757 Results.push_back(std::move(*LSPLoc));
758 });
759 }
760 if (Results.size() > Limit)
761 Results.resize(Limit);
762 return Results;
763 }
764
765 std::vector<SymbolDetails> getSymbolInfo(ParsedAST &AST, Position Pos) {
766 const SourceManager &SM = AST.getASTContext().getSourceManager();
767
768 auto Loc = getBeginningOfIdentifier(AST, Pos, SM.getMainFileID());
769 auto Symbols = getSymbolAtPosition(AST, Loc);
770
771 std::vector<SymbolDetails> Results;
772
773 for (const auto &Sym : Symbols.Decls) {
774 SymbolDetails NewSymbol;
775 if (const NamedDecl *ND = dyn_cast<NamedDecl>(Sym.D)) {
776 std::string QName = printQualifiedName(*ND);
777 std::tie(NewSymbol.containerName, NewSymbol.name) =
778 splitQualifiedName(QName);
779
780 if (NewSymbol.containerName.empty()) {
781 if (const auto *ParentND =
782 dyn_cast_or_null<NamedDecl>(ND->getDeclContext()))
783 NewSymbol.containerName = printQualifiedName(*ParentND);
784 }
785 }
786 llvm::SmallString<32> USR;
787 if (!index::generateUSRForDecl(Sym.D, USR)) {
788 NewSymbol.USR = USR.str();
789 NewSymbol.ID = SymbolID(NewSymbol.USR);
790 }
791 Results.push_back(std::move(NewSymbol));
792 }
793
794 for (const auto &Macro : Symbols.Macros) {
795 SymbolDetails NewMacro;
796 NewMacro.name = Macro.Name;
797 llvm::SmallString<32> USR;
798 if (!index::generateUSRForMacro(NewMacro.name, Loc, SM, USR)) {
799 NewMacro.USR = USR.str();
800 NewMacro.ID = SymbolID(NewMacro.USR);
801 }
802 Results.push_back(std::move(NewMacro));
803 }
804
805 return Results;
806 }
807
808 } // namespace clangd
809 } // namespace clang
clang::clangd::SymbolDetails::USR
std::string USR
Unified Symbol Resolution identifier This is an opaque string uniquely identifying a symbol...
Definition: Protocol.h:749
clang::clangd::getHover
llvm::Optional< Hover > getHover(ParsedAST &AST, Position Pos)
Get the hover information when hovering at Pos.
Definition: XRefs.cpp:686
clang::clangd::getScopeName
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...
Definition: XRefs.cpp:505
clang::clangd::findDefinitions
std::vector< Location > findDefinitions(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
Definition: XRefs.cpp:244
clang::clangd::RefsRequest::IDs
llvm::DenseSet< SymbolID > IDs
Definition: Index.h:477
AST.h
clang::clangd::printQualifiedName
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
Definition: AST.cpp:54
clang::clangd::Location::range
Range range
Definition: Protocol.h:183
clang::clangd::getSymbolID
llvm::Optional< SymbolID > getSymbolID(const Decl *D)
Gets the symbol ID for a declaration, if possible.
Definition: AST.cpp:117
clang::clangd::DocumentHighlight::range
Range range
The range this highlight applies to.
Definition: Protocol.h:979
clang::clangd::ParsedAST::getPreprocessor
Preprocessor & getPreprocessor()
Definition: ClangdUnit.cpp:354
IsReferencedExplicitly
bool IsReferencedExplicitly
Definition: XRefs.cpp:81
CanonicalTarget
const Decl * CanonicalTarget
Definition: XRefs.cpp:373
clang::clangd::SymbolIndex
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Definition: Index.h:487
SourceCode.h
clang::clangd::getHoverContents
static Hover getHoverContents(const Decl *D)
Generate a Hover object given the declaration D.
Definition: XRefs.cpp:521
clang::clangd::LookupRequest::IDs
llvm::DenseSet< SymbolID > IDs
Definition: Index.h:473
clang::clangd::MarkupContent::value
std::string value
Definition: Protocol.h:810
clang::clangd::Ref
Definition: Index.h:373
clang::clangd::findNameLoc
SourceLocation findNameLoc(const clang::Decl *D)
Find the identifier source location of the given D.
Definition: AST.cpp:46
clang::clangd::RefsRequest
Definition: Index.h:476
clang::clangd::Position
Definition: Protocol.h:125
clang::clangd::Location::uri
URIForFile uri
The text document&#39;s URI.
Definition: Protocol.h:182
Results
std::vector< CodeCompletionResult > Results
Definition: CodeComplete.cpp:702
clang::clangd::TextDocumentSyncKind::None
Documents should not be synced at all.
clang::clangd::Hover
Definition: Protocol.h:814
clang::clangd::elog
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:57
clang::clangd::SymbolKind::Key
clang::clangd::ParsedAST::getASTContext
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
Definition: ClangdUnit.cpp:348
clang::clangd::SymbolDetails::name
std::string name
Definition: Protocol.h:740
clang::clangd::Symbol::ID
SymbolID ID
Definition: Index.h:162
clang::clangd::Hover::contents
MarkupContent contents
The hover&#39;s content.
Definition: Protocol.h:816
clang::clangd::DocumentHighlightKind::Read
clang::clangd::DocumentHighlight
A document highlight is a range inside a text document which deserves special attention.
Definition: Protocol.h:977
clang::clangd::typeDeclToString
static std::string typeDeclToString(const TypeDecl *TD)
Return a string representation (e.g.
Definition: XRefs.cpp:474
clang::clangd::Symbol::Definition
SymbolLocation Definition
Definition: Index.h:171
clang::clangd::SymbolDetails::ID
llvm::Optional< SymbolID > ID
Definition: Protocol.h:751
clang::clangd::getSymbolInfo
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
Definition: XRefs.cpp:765
clang::clangd::ParsedAST::getIncludeStructure
const IncludeStructure & getIncludeStructure() const
Definition: ClangdUnit.cpp:402
clang::clangd::SymbolOrigin::AST
clang::clangd::DocumentHighlightKind::Text
clang::clangd::URIForFile::fromURI
static llvm::Expected< URIForFile > fromURI(const URI &U, llvm::StringRef HintPath)
Definition: Protocol.cpp:45
clang::clangd::Ref::Location
SymbolLocation Location
Definition: Index.h:375
clang::clangd::namedDeclQualifiedName
static std::string namedDeclQualifiedName(const NamedDecl *ND, llvm::StringRef Prefix)
Return a string representation (e.g.
Definition: XRefs.cpp:489
clang::clangd::log
void log(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:63
Role
index::SymbolRoleSet Role
Definition: XRefs.cpp:375
clang::clangd::Path
std::string Path
A typedef to represent a file path.
Definition: Path.h:21
clang::clangd::URIForFile::canonicalize
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
Definition: Protocol.cpp:32
clang::clangd::SymbolDetails::containerName
std::string containerName
Definition: Protocol.h:742
clang::clangd::Symbol::CanonicalDeclaration
SymbolLocation CanonicalDeclaration
Definition: Index.h:180
clang::clangd::SymbolIndex::refs
virtual void refs(const RefsRequest &Req, llvm::function_ref< void(const Ref &)> Callback) const =0
Finds all occurrences (e.g.
D
const Decl * D
Definition: XRefs.cpp:79
Result
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
Definition: ClangdServer.cpp:60
clang::clangd::findDocumentHighlights
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
Definition: XRefs.cpp:434
Loc
SourceLocation Loc
Definition: XRefs.cpp:374
clang::clangd::DocumentHighlightKind::Write
clang::clangd::sourceLocToPosition
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
Definition: SourceCode.cpp:128
Pos
Position Pos
Definition: CodeComplete.cpp:1008
Macros
std::vector< MacroDecl > Macros
Definition: XRefs.cpp:201
clang::clangd::ParsedAST
Stores and provides access to parsed AST.
Definition: ClangdUnit.h:71
clang::clangd::Position::line
int line
Line position in a document (zero-based).
Definition: Protocol.h:127
Logger.h
clang::clangd::RefKind::Reference
clang::clangd::findReferences
std::vector< Location > findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index)
Returns reference locations of the symbol at a specified Pos.
Definition: XRefs.cpp:706
clang::clangd::Symbol
Definition: Index.h:160
clang::clangd::IncludeStructure::MainFileIncludes
std::vector< Inclusion > MainFileIncludes
Definition: Headers.h:78
clang::clangd::getBeginningOfIdentifier
SourceLocation getBeginningOfIdentifier(ParsedAST &Unit, const Position &Pos, const FileID FID)
Get the beginning SourceLocation at a specified Pos.
Definition: ClangdUnit.cpp:545
clang::clangd::LookupRequest
Definition: Index.h:472
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ChangeNamespace.cpp:18
Info
const MacroInfo * Info
Definition: XRefs.cpp:75
clang::clangd::printingPolicyForDecls
static PrintingPolicy printingPolicyForDecls(PrintingPolicy Base)
Definition: XRefs.cpp:460
clang::clangd::RefsRequest::Limit
llvm::Optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
Definition: Index.h:482
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:38
clang::clangd::splitQualifiedName
std::pair< llvm::StringRef, llvm::StringRef > splitQualifiedName(llvm::StringRef QName)
From "a::b::c", return {"a::b::", "c"}.
Definition: SourceCode.cpp:164
clang::clangd::DocumentHighlight::kind
DocumentHighlightKind kind
The highlight kind, default is DocumentHighlightKind.Text.
Definition: Protocol.h:982
clang::clangd::getCanonicalPath
llvm::Optional< std::string > getCanonicalPath(const FileEntry *F, const SourceManager &SourceMgr)
Get the canonical path of F.
Definition: SourceCode.cpp:187
URI.h
clang::clangd::getDeducedType
llvm::Optional< QualType > getDeducedType(ParsedAST &AST, SourceLocation SourceLocationBeg)
Retrieves the deduced type at a given location (auto, decltype).
Definition: XRefs.cpp:666
clang::clangd::URI::parse
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
Definition: URI.cpp:166
Name
llvm::StringRef Name
Definition: XRefs.cpp:74
clang::clangd::CompletionItemKind::Value
clang::doc::SymbolID
std::array< uint8_t, 20 > SymbolID
Definition: Representation.h:31
clang::clangd::SymbolDetails
Represents information about identifier.
Definition: Protocol.h:739
XRefs.h
clang::clangd::Location
Definition: Protocol.h:180
Index
const SymbolIndex * Index
Definition: Dexp.cpp:85
clang::clangd::SymbolID
Definition: SymbolID.h:31
Location
Definition: Modularize.cpp:384