blob: 642b30ceb80d2c5a16024ac3590e0b1fde4a6c87 [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"
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000014#include "clang/AST/TemplateBase.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"
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000018#include "llvm/ADT/Optional.h"
Ilya Biryukov19d75602018-11-23 15:21:19 +000019#include "llvm/Support/Casting.h"
20#include "llvm/Support/ScopedPrinter.h"
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000021#include "llvm/Support/raw_ostream.h"
Haojian Wu5f100262018-03-09 14:00:34 +000022
23namespace clang {
24namespace clangd {
Haojian Wu5f100262018-03-09 14:00:34 +000025
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +000026namespace {
27llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>>
28getTemplateSpecializationArgLocs(const NamedDecl &ND) {
29 if (auto *Func = llvm::dyn_cast<FunctionDecl>(&ND)) {
30 if (const ASTTemplateArgumentListInfo *Args =
31 Func->getTemplateSpecializationArgsAsWritten())
32 return Args->arguments();
33 } else if (auto *Cls =
34 llvm::dyn_cast<ClassTemplatePartialSpecializationDecl>(&ND)) {
35 if (auto *Args = Cls->getTemplateArgsAsWritten())
36 return Args->arguments();
37 } else if (auto *Var = llvm::dyn_cast<VarTemplateSpecializationDecl>(&ND))
38 return Var->getTemplateArgsInfo().arguments();
39 // We return None for ClassTemplateSpecializationDecls because it does not
40 // contain TemplateArgumentLoc information.
41 return llvm::None;
42}
43} // namespace
44
Eric Liu48597382018-10-18 12:23:05 +000045// Returns true if the complete name of decl \p D is spelled in the source code.
Kadir Cetinkaya6f9b2042018-12-05 11:57:15 +000046// This is not the case for:
47// * symbols formed via macro concatenation, the spelling location will
48// be "<scratch space>"
49// * symbols controlled and defined by a compile command-line option
50// `-DName=foo`, the spelling location will be "<command line>".
Eric Liu48597382018-10-18 12:23:05 +000051bool isSpelledInSourceCode(const Decl *D) {
52 const auto &SM = D->getASTContext().getSourceManager();
53 auto Loc = D->getLocation();
Haojian Wu5f100262018-03-09 14:00:34 +000054 // FIXME: Revisit the strategy, the heuristic is limitted when handling
55 // macros, we should use the location where the whole definition occurs.
Eric Liu48597382018-10-18 12:23:05 +000056 if (Loc.isMacroID()) {
57 std::string PrintLoc = SM.getSpellingLoc(Loc).printToString(SM);
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000058 if (llvm::StringRef(PrintLoc).startswith("<scratch") ||
59 llvm::StringRef(PrintLoc).startswith("<command line>"))
Eric Liu48597382018-10-18 12:23:05 +000060 return false;
Haojian Wu5f100262018-03-09 14:00:34 +000061 }
Eric Liu48597382018-10-18 12:23:05 +000062 return true;
63}
64
65bool isImplementationDetail(const Decl *D) { return !isSpelledInSourceCode(D); }
66
Ilya Biryukov22fa4652019-01-03 13:28:05 +000067SourceLocation findNameLoc(const clang::Decl *D) {
Eric Liu48597382018-10-18 12:23:05 +000068 const auto &SM = D->getASTContext().getSourceManager();
69 if (!isSpelledInSourceCode(D))
70 // Use the expansion location as spelling location is not interesting.
71 return SM.getExpansionRange(D->getLocation()).getBegin();
72 return SM.getSpellingLoc(D->getLocation());
Haojian Wu5f100262018-03-09 14:00:34 +000073}
74
Eric Liu7ad16962018-06-22 10:46:59 +000075std::string printQualifiedName(const NamedDecl &ND) {
76 std::string QName;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000077 llvm::raw_string_ostream OS(QName);
Eric Liu7ad16962018-06-22 10:46:59 +000078 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
79 // Note that inline namespaces are treated as transparent scopes. This
80 // reflects the way they're most commonly used for lookup. Ideally we'd
81 // include them, but at query time it's hard to find all the inline
82 // namespaces to query: the preamble doesn't have a dedicated list.
83 Policy.SuppressUnwrittenScope = true;
84 ND.printQualifiedName(OS, Policy);
85 OS.flush();
86 assert(!StringRef(QName).startswith("::"));
87 return QName;
88}
89
Ilya Biryukov19d75602018-11-23 15:21:19 +000090std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
91 std::string Name;
92 llvm::raw_string_ostream Out(Name);
93 PrintingPolicy PP(Ctx.getLangOpts());
94 // Handle 'using namespace'. They all have the same name - <using-directive>.
95 if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) {
96 Out << "using namespace ";
97 if (auto *Qual = UD->getQualifier())
98 Qual->print(Out, PP);
99 UD->getNominatedNamespaceAsWritten()->printName(Out);
100 return Out.str();
101 }
102 ND.getDeclName().print(Out, PP);
103 if (!Out.str().empty()) {
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +0000104 Out << printTemplateSpecializationArgs(ND);
Ilya Biryukov19d75602018-11-23 15:21:19 +0000105 return Out.str();
106 }
107 // The name was empty, so present an anonymous entity.
Henry Wong1a1fbdc2018-11-27 04:27:00 +0000108 if (isa<NamespaceDecl>(ND))
Ilya Biryukov19d75602018-11-23 15:21:19 +0000109 return "(anonymous namespace)";
110 if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND))
111 return ("(anonymous " + Cls->getKindName() + ")").str();
Henry Wong1a1fbdc2018-11-27 04:27:00 +0000112 if (isa<EnumDecl>(ND))
Ilya Biryukov19d75602018-11-23 15:21:19 +0000113 return "(anonymous enum)";
114 return "(anonymous)";
115}
116
Kadir Cetinkayaa80a5222019-04-12 10:09:14 +0000117std::string printTemplateSpecializationArgs(const NamedDecl &ND) {
118 std::string TemplateArgs;
119 llvm::raw_string_ostream OS(TemplateArgs);
120 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
121 if (llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>> Args =
122 getTemplateSpecializationArgLocs(ND)) {
123 printTemplateArgumentList(OS, *Args, Policy);
124 } else if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) {
125 if (const TypeSourceInfo *TSI = Cls->getTypeAsWritten()) {
126 // ClassTemplateSpecializationDecls do not contain
127 // TemplateArgumentTypeLocs, they only have TemplateArgumentTypes. So we
128 // create a new argument location list from TypeSourceInfo.
129 auto STL = TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
130 llvm::SmallVector<TemplateArgumentLoc, 8> ArgLocs;
131 ArgLocs.reserve(STL.getNumArgs());
132 for (unsigned I = 0; I < STL.getNumArgs(); ++I)
133 ArgLocs.push_back(STL.getArgLoc(I));
134 printTemplateArgumentList(OS, ArgLocs, Policy);
135 } else {
136 // FIXME: Fix cases when getTypeAsWritten returns null inside clang AST,
137 // e.g. friend decls. Currently we fallback to Template Arguments without
138 // location information.
139 printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy);
140 }
141 }
142 OS.flush();
143 return TemplateArgs;
144}
145
Eric Liu3fac4ef2018-10-17 11:19:02 +0000146std::string printNamespaceScope(const DeclContext &DC) {
147 for (const auto *Ctx = &DC; Ctx != nullptr; Ctx = Ctx->getParent())
148 if (const auto *NS = dyn_cast<NamespaceDecl>(Ctx))
149 if (!NS->isAnonymousNamespace() && !NS->isInlineNamespace())
150 return printQualifiedName(*NS) + "::";
151 return "";
152}
153
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000154llvm::Optional<SymbolID> getSymbolID(const Decl *D) {
155 llvm::SmallString<128> USR;
Haojian Wuc6ddb462018-08-07 08:57:52 +0000156 if (index::generateUSRForDecl(D, USR))
157 return None;
158 return SymbolID(USR);
159}
160
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000161llvm::Optional<SymbolID> getSymbolID(const IdentifierInfo &II,
162 const MacroInfo *MI,
163 const SourceManager &SM) {
Eric Liud25f1212018-09-06 09:59:37 +0000164 if (MI == nullptr)
165 return None;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000166 llvm::SmallString<128> USR;
Eric Liud25f1212018-09-06 09:59:37 +0000167 if (index::generateUSRForMacro(II.getName(), MI->getDefinitionLoc(), SM, USR))
168 return None;
169 return SymbolID(USR);
170}
171
Sam McCall94701422019-07-11 16:04:18 +0000172std::string shortenNamespace(const llvm::StringRef OriginalName,
173 const llvm::StringRef CurrentNamespace) {
174 llvm::SmallVector<llvm::StringRef, 8> OriginalParts;
175 llvm::SmallVector<llvm::StringRef, 8> CurrentParts;
176 llvm::SmallVector<llvm::StringRef, 8> Result;
177 OriginalName.split(OriginalParts, "::");
178 CurrentNamespace.split(CurrentParts, "::");
179 auto MinLength = std::min(CurrentParts.size(), OriginalParts.size());
180
181 unsigned DifferentAt = 0;
182 while (DifferentAt < MinLength &&
183 CurrentParts[DifferentAt] == OriginalParts[DifferentAt]) {
184 DifferentAt++;
185 }
186
Paul Robinson2cb5c462019-07-11 23:48:06 +0000187 for (unsigned i = DifferentAt; i < OriginalParts.size(); ++i) {
Sam McCall94701422019-07-11 16:04:18 +0000188 Result.push_back(OriginalParts[i]);
189 }
190 return join(Result, "::");
191}
192
193std::string printType(const QualType QT, const DeclContext & Context){
194 PrintingPolicy PP(Context.getParentASTContext().getPrintingPolicy());
195 PP.SuppressTagKeyword = 1;
196 return shortenNamespace(
197 QT.getAsString(PP),
198 printNamespaceScope(Context) );
199}
200
201
Haojian Wu5f100262018-03-09 14:00:34 +0000202} // namespace clangd
203} // namespace clang