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