blob: 47559c10d36d5ad3939f1f7f2dd84922bd4d6bba [file] [log] [blame]
Haojian Wu5f100262018-03-09 14:00:34 +00001//===--- AST.cpp - Utility AST functions -----------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Haojian Wu5f100262018-03-09 14:00:34 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "AST.h"
10
11#include "clang/AST/ASTContext.h"
12#include "clang/AST/Decl.h"
Ilya Biryukov19d75602018-11-23 15:21:19 +000013#include "clang/AST/DeclTemplate.h"
Eric Liu48597382018-10-18 12:23:05 +000014#include "clang/Basic/SourceLocation.h"
Haojian Wu5f100262018-03-09 14:00:34 +000015#include "clang/Basic/SourceManager.h"
Haojian Wuc6ddb462018-08-07 08:57:52 +000016#include "clang/Index/USRGeneration.h"
Ilya Biryukov19d75602018-11-23 15:21:19 +000017#include "llvm/Support/Casting.h"
18#include "llvm/Support/ScopedPrinter.h"
Haojian Wu5f100262018-03-09 14:00:34 +000019
20namespace clang {
21namespace clangd {
Haojian Wu5f100262018-03-09 14:00:34 +000022
Eric Liu48597382018-10-18 12:23:05 +000023// Returns true if the complete name of decl \p D is spelled in the source code.
Kadir Cetinkaya6f9b2042018-12-05 11:57:15 +000024// 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>".
Eric Liu48597382018-10-18 12:23:05 +000029bool isSpelledInSourceCode(const Decl *D) {
30 const auto &SM = D->getASTContext().getSourceManager();
31 auto Loc = D->getLocation();
Haojian Wu5f100262018-03-09 14:00:34 +000032 // FIXME: Revisit the strategy, the heuristic is limitted when handling
33 // macros, we should use the location where the whole definition occurs.
Eric Liu48597382018-10-18 12:23:05 +000034 if (Loc.isMacroID()) {
35 std::string PrintLoc = SM.getSpellingLoc(Loc).printToString(SM);
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000036 if (llvm::StringRef(PrintLoc).startswith("<scratch") ||
37 llvm::StringRef(PrintLoc).startswith("<command line>"))
Eric Liu48597382018-10-18 12:23:05 +000038 return false;
Haojian Wu5f100262018-03-09 14:00:34 +000039 }
Eric Liu48597382018-10-18 12:23:05 +000040 return true;
41}
42
43bool isImplementationDetail(const Decl *D) { return !isSpelledInSourceCode(D); }
44
Ilya Biryukov22fa4652019-01-03 13:28:05 +000045SourceLocation findNameLoc(const clang::Decl *D) {
Eric Liu48597382018-10-18 12:23:05 +000046 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());
Haojian Wu5f100262018-03-09 14:00:34 +000051}
52
Eric Liu7ad16962018-06-22 10:46:59 +000053std::string printQualifiedName(const NamedDecl &ND) {
54 std::string QName;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000055 llvm::raw_string_ostream OS(QName);
Eric Liu7ad16962018-06-22 10:46:59 +000056 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
Ilya Biryukov19d75602018-11-23 15:21:19 +000068static const TemplateArgumentList *
69getTemplateSpecializationArgs(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
79std::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.
Henry Wong1a1fbdc2018-11-27 04:27:00 +000099 if (isa<NamespaceDecl>(ND))
Ilya Biryukov19d75602018-11-23 15:21:19 +0000100 return "(anonymous namespace)";
101 if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND))
102 return ("(anonymous " + Cls->getKindName() + ")").str();
Henry Wong1a1fbdc2018-11-27 04:27:00 +0000103 if (isa<EnumDecl>(ND))
Ilya Biryukov19d75602018-11-23 15:21:19 +0000104 return "(anonymous enum)";
105 return "(anonymous)";
106}
107
Eric Liu3fac4ef2018-10-17 11:19:02 +0000108std::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
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000116llvm::Optional<SymbolID> getSymbolID(const Decl *D) {
117 llvm::SmallString<128> USR;
Haojian Wuc6ddb462018-08-07 08:57:52 +0000118 if (index::generateUSRForDecl(D, USR))
119 return None;
120 return SymbolID(USR);
121}
122
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000123llvm::Optional<SymbolID> getSymbolID(const IdentifierInfo &II,
124 const MacroInfo *MI,
125 const SourceManager &SM) {
Eric Liud25f1212018-09-06 09:59:37 +0000126 if (MI == nullptr)
127 return None;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000128 llvm::SmallString<128> USR;
Eric Liud25f1212018-09-06 09:59:37 +0000129 if (index::generateUSRForMacro(II.getName(), MI->getDefinitionLoc(), SM, USR))
130 return None;
131 return SymbolID(USR);
132}
133
Haojian Wu5f100262018-03-09 14:00:34 +0000134} // namespace clangd
135} // namespace clang