blob: a185a6d8270b16045910654a3ac7373c3f956393 [file] [log] [blame]
Haojian Wu5f100262018-03-09 14:00:34 +00001//===--- 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"
Ilya Biryukov19d75602018-11-23 15:21:19 +000014#include "clang/AST/DeclTemplate.h"
Eric Liu48597382018-10-18 12:23:05 +000015#include "clang/Basic/SourceLocation.h"
Haojian Wu5f100262018-03-09 14:00:34 +000016#include "clang/Basic/SourceManager.h"
Haojian Wuc6ddb462018-08-07 08:57:52 +000017#include "clang/Index/USRGeneration.h"
Ilya Biryukov19d75602018-11-23 15:21:19 +000018#include "llvm/Support/Casting.h"
19#include "llvm/Support/ScopedPrinter.h"
Haojian Wu5f100262018-03-09 14:00:34 +000020
21namespace clang {
22namespace clangd {
Haojian Wu5f100262018-03-09 14:00:34 +000023
Eric Liu48597382018-10-18 12:23:05 +000024// Returns true if the complete name of decl \p D is spelled in the source code.
Kadir Cetinkaya6f9b2042018-12-05 11:57:15 +000025// 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>".
Eric Liu48597382018-10-18 12:23:05 +000030bool isSpelledInSourceCode(const Decl *D) {
31 const auto &SM = D->getASTContext().getSourceManager();
32 auto Loc = D->getLocation();
Haojian Wu5f100262018-03-09 14:00:34 +000033 // FIXME: Revisit the strategy, the heuristic is limitted when handling
34 // macros, we should use the location where the whole definition occurs.
Eric Liu48597382018-10-18 12:23:05 +000035 if (Loc.isMacroID()) {
36 std::string PrintLoc = SM.getSpellingLoc(Loc).printToString(SM);
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000037 if (llvm::StringRef(PrintLoc).startswith("<scratch") ||
38 llvm::StringRef(PrintLoc).startswith("<command line>"))
Eric Liu48597382018-10-18 12:23:05 +000039 return false;
Haojian Wu5f100262018-03-09 14:00:34 +000040 }
Eric Liu48597382018-10-18 12:23:05 +000041 return true;
42}
43
44bool isImplementationDetail(const Decl *D) { return !isSpelledInSourceCode(D); }
45
Ilya Biryukov22fa4652019-01-03 13:28:05 +000046SourceLocation findNameLoc(const clang::Decl *D) {
Eric Liu48597382018-10-18 12:23:05 +000047 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());
Haojian Wu5f100262018-03-09 14:00:34 +000052}
53
Eric Liu7ad16962018-06-22 10:46:59 +000054std::string printQualifiedName(const NamedDecl &ND) {
55 std::string QName;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000056 llvm::raw_string_ostream OS(QName);
Eric Liu7ad16962018-06-22 10:46:59 +000057 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
Ilya Biryukov19d75602018-11-23 15:21:19 +000069static const TemplateArgumentList *
70getTemplateSpecializationArgs(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
80std::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.
Henry Wong1a1fbdc2018-11-27 04:27:00 +0000100 if (isa<NamespaceDecl>(ND))
Ilya Biryukov19d75602018-11-23 15:21:19 +0000101 return "(anonymous namespace)";
102 if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND))
103 return ("(anonymous " + Cls->getKindName() + ")").str();
Henry Wong1a1fbdc2018-11-27 04:27:00 +0000104 if (isa<EnumDecl>(ND))
Ilya Biryukov19d75602018-11-23 15:21:19 +0000105 return "(anonymous enum)";
106 return "(anonymous)";
107}
108
Eric Liu3fac4ef2018-10-17 11:19:02 +0000109std::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
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000117llvm::Optional<SymbolID> getSymbolID(const Decl *D) {
118 llvm::SmallString<128> USR;
Haojian Wuc6ddb462018-08-07 08:57:52 +0000119 if (index::generateUSRForDecl(D, USR))
120 return None;
121 return SymbolID(USR);
122}
123
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000124llvm::Optional<SymbolID> getSymbolID(const IdentifierInfo &II,
125 const MacroInfo *MI,
126 const SourceManager &SM) {
Eric Liud25f1212018-09-06 09:59:37 +0000127 if (MI == nullptr)
128 return None;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000129 llvm::SmallString<128> USR;
Eric Liud25f1212018-09-06 09:59:37 +0000130 if (index::generateUSRForMacro(II.getName(), MI->getDefinitionLoc(), SM, USR))
131 return None;
132 return SymbolID(USR);
133}
134
Haojian Wu5f100262018-03-09 14:00:34 +0000135} // namespace clangd
136} // namespace clang