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