1 //===--- AST.cpp - Utility AST functions  -----------------------*- 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 
10 #include "AST.h"
11 
12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/Decl.h"
14 #include "clang/Basic/SourceLocation.h"
15 #include "clang/Basic/SourceManager.h"
16 #include "clang/Index/USRGeneration.h"
17 
18 using namespace llvm;
19 namespace clang {
20 namespace clangd {
21 
22 // Returns true if the complete name of decl \p D is spelled in the source code.
23 // This is not the case for symbols formed via macro concatenation.
24 // (We used to attempt to treat names spelled on the command-line this way too,
25 // but the preamble doesn't preserve the required information).
26 bool isSpelledInSourceCode(const Decl *D) {
27   const auto &SM = D->getASTContext().getSourceManager();
28   auto Loc = D->getLocation();
29   // FIXME: Revisit the strategy, the heuristic is limitted when handling
30   // macros, we should use the location where the whole definition occurs.
31   if (Loc.isMacroID()) {
32     std::string PrintLoc = SM.getSpellingLoc(Loc).printToString(SM);
33     if (StringRef(PrintLoc).startswith("<scratch"))
34       return false;
35   }
36   return true;
37 }
38 
39 bool isImplementationDetail(const Decl *D) { return !isSpelledInSourceCode(D); }
40 
41 SourceLocation findNameLoc(const clang::Decl* D) {
42   const auto &SM = D->getASTContext().getSourceManager();
43   if (!isSpelledInSourceCode(D))
44     // Use the expansion location as spelling location is not interesting.
45     return SM.getExpansionRange(D->getLocation()).getBegin();
46   return SM.getSpellingLoc(D->getLocation());
47 }
48 
49 std::string printQualifiedName(const NamedDecl &ND) {
50   std::string QName;
51   raw_string_ostream OS(QName);
52   PrintingPolicy Policy(ND.getASTContext().getLangOpts());
53   // Note that inline namespaces are treated as transparent scopes. This
54   // reflects the way they're most commonly used for lookup. Ideally we'd
55   // include them, but at query time it's hard to find all the inline
56   // namespaces to query: the preamble doesn't have a dedicated list.
57   Policy.SuppressUnwrittenScope = true;
58   ND.printQualifiedName(OS, Policy);
59   OS.flush();
60   assert(!StringRef(QName).startswith("::"));
61   return QName;
62 }
63 
64 std::string printNamespaceScope(const DeclContext &DC) {
65   for (const auto *Ctx = &DC; Ctx != nullptr; Ctx = Ctx->getParent())
66     if (const auto *NS = dyn_cast<NamespaceDecl>(Ctx))
67       if (!NS->isAnonymousNamespace() && !NS->isInlineNamespace())
68         return printQualifiedName(*NS) + "::";
69   return "";
70 }
71 
72 Optional<SymbolID> getSymbolID(const Decl *D) {
73   SmallString<128> USR;
74   if (index::generateUSRForDecl(D, USR))
75     return None;
76   return SymbolID(USR);
77 }
78 
79 Optional<SymbolID> getSymbolID(const IdentifierInfo &II, const MacroInfo *MI,
80                                const SourceManager &SM) {
81   if (MI == nullptr)
82     return None;
83   SmallString<128> USR;
84   if (index::generateUSRForMacro(II.getName(), MI->getDefinitionLoc(), SM, USR))
85     return None;
86   return SymbolID(USR);
87 }
88 
89 } // namespace clangd
90 } // namespace clang
91