clang-tools  8.0.0
AST.cpp
Go to the documentation of this file.
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/AST/DeclTemplate.h"
15 #include "clang/Basic/SourceLocation.h"
16 #include "clang/Basic/SourceManager.h"
17 #include "clang/Index/USRGeneration.h"
18 #include "llvm/Support/Casting.h"
19 #include "llvm/Support/ScopedPrinter.h"
20 
21 namespace clang {
22 namespace clangd {
23 
24 // Returns true if the complete name of decl \p D is spelled in the source code.
25 // This is not the case for:
26 // * symbols formed via macro concatenation, the spelling location will
27 // be "<scratch space>"
28 // * symbols controlled and defined by a compile command-line option
29 // `-DName=foo`, the spelling location will be "<command line>".
30 bool isSpelledInSourceCode(const Decl *D) {
31  const auto &SM = D->getASTContext().getSourceManager();
32  auto Loc = D->getLocation();
33  // FIXME: Revisit the strategy, the heuristic is limitted when handling
34  // macros, we should use the location where the whole definition occurs.
35  if (Loc.isMacroID()) {
36  std::string PrintLoc = SM.getSpellingLoc(Loc).printToString(SM);
37  if (llvm::StringRef(PrintLoc).startswith("<scratch") ||
38  llvm::StringRef(PrintLoc).startswith("<command line>"))
39  return false;
40  }
41  return true;
42 }
43 
44 bool isImplementationDetail(const Decl *D) { return !isSpelledInSourceCode(D); }
45 
46 SourceLocation findNameLoc(const clang::Decl *D) {
47  const auto &SM = D->getASTContext().getSourceManager();
48  if (!isSpelledInSourceCode(D))
49  // Use the expansion location as spelling location is not interesting.
50  return SM.getExpansionRange(D->getLocation()).getBegin();
51  return SM.getSpellingLoc(D->getLocation());
52 }
53 
54 std::string printQualifiedName(const NamedDecl &ND) {
55  std::string QName;
56  llvm::raw_string_ostream OS(QName);
57  PrintingPolicy Policy(ND.getASTContext().getLangOpts());
58  // Note that inline namespaces are treated as transparent scopes. This
59  // reflects the way they're most commonly used for lookup. Ideally we'd
60  // include them, but at query time it's hard to find all the inline
61  // namespaces to query: the preamble doesn't have a dedicated list.
62  Policy.SuppressUnwrittenScope = true;
63  ND.printQualifiedName(OS, Policy);
64  OS.flush();
65  assert(!StringRef(QName).startswith("::"));
66  return QName;
67 }
68 
69 static const TemplateArgumentList *
70 getTemplateSpecializationArgs(const NamedDecl &ND) {
71  if (auto *Func = llvm::dyn_cast<FunctionDecl>(&ND))
72  return Func->getTemplateSpecializationArgs();
73  if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND))
74  return &Cls->getTemplateInstantiationArgs();
75  if (auto *Var = llvm::dyn_cast<VarTemplateSpecializationDecl>(&ND))
76  return &Var->getTemplateInstantiationArgs();
77  return nullptr;
78 }
79 
80 std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
81  std::string Name;
82  llvm::raw_string_ostream Out(Name);
83  PrintingPolicy PP(Ctx.getLangOpts());
84  // Handle 'using namespace'. They all have the same name - <using-directive>.
85  if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) {
86  Out << "using namespace ";
87  if (auto *Qual = UD->getQualifier())
88  Qual->print(Out, PP);
89  UD->getNominatedNamespaceAsWritten()->printName(Out);
90  return Out.str();
91  }
92  ND.getDeclName().print(Out, PP);
93  if (!Out.str().empty()) {
94  // FIXME(ibiryukov): do not show args not explicitly written by the user.
95  if (auto *ArgList = getTemplateSpecializationArgs(ND))
96  printTemplateArgumentList(Out, ArgList->asArray(), PP);
97  return Out.str();
98  }
99  // The name was empty, so present an anonymous entity.
100  if (isa<NamespaceDecl>(ND))
101  return "(anonymous namespace)";
102  if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND))
103  return ("(anonymous " + Cls->getKindName() + ")").str();
104  if (isa<EnumDecl>(ND))
105  return "(anonymous enum)";
106  return "(anonymous)";
107 }
108 
109 std::string printNamespaceScope(const DeclContext &DC) {
110  for (const auto *Ctx = &DC; Ctx != nullptr; Ctx = Ctx->getParent())
111  if (const auto *NS = dyn_cast<NamespaceDecl>(Ctx))
112  if (!NS->isAnonymousNamespace() && !NS->isInlineNamespace())
113  return printQualifiedName(*NS) + "::";
114  return "";
115 }
116 
117 llvm::Optional<SymbolID> getSymbolID(const Decl *D) {
118  llvm::SmallString<128> USR;
119  if (index::generateUSRForDecl(D, USR))
120  return None;
121  return SymbolID(USR);
122 }
123 
124 llvm::Optional<SymbolID> getSymbolID(const IdentifierInfo &II,
125  const MacroInfo *MI,
126  const SourceManager &SM) {
127  if (MI == nullptr)
128  return None;
129  llvm::SmallString<128> USR;
130  if (index::generateUSRForMacro(II.getName(), MI->getDefinitionLoc(), SM, USR))
131  return None;
132  return SymbolID(USR);
133 }
134 
135 } // namespace clangd
136 } // namespace clang
SourceLocation Loc
&#39;#&#39; location in the include directive
std::string printName(const ASTContext &Ctx, const NamedDecl &ND)
Prints unqualified name of the decl for the purpose of displaying it to the user. ...
Definition: AST.cpp:80
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
Definition: AST.cpp:54
llvm::Optional< SymbolID > getSymbolID(const Decl *D)
Gets the symbol ID for a declaration, if possible.
Definition: AST.cpp:117
std::string printNamespaceScope(const DeclContext &DC)
Returns the first enclosing namespace scope starting from DC.
Definition: AST.cpp:109
SourceLocation findNameLoc(const clang::Decl *D)
Find the identifier source location of the given D.
Definition: AST.cpp:46
bool isSpelledInSourceCode(const Decl *D)
Definition: AST.cpp:30
Context Ctx
static constexpr llvm::StringLiteral Name
const Decl * D
Definition: XRefs.cpp:79
static const TemplateArgumentList * getTemplateSpecializationArgs(const NamedDecl &ND)
Definition: AST.cpp:70
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
bool isImplementationDetail(const Decl *D)
Returns true if the declaration is considered implementation detail based on heuristics.
Definition: AST.cpp:44
std::array< uint8_t, 20 > SymbolID