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 "SourceCode.h" 12 #include "clang/AST/ASTContext.h" 13 #include "clang/AST/Decl.h" 14 #include "clang/AST/DeclTemplate.h" 15 #include "clang/AST/DeclarationName.h" 16 #include "clang/AST/NestedNameSpecifier.h" 17 #include "clang/AST/PrettyPrinter.h" 18 #include "clang/AST/TemplateBase.h" 19 #include "clang/Basic/SourceLocation.h" 20 #include "clang/Basic/SourceManager.h" 21 #include "clang/Basic/Specifiers.h" 22 #include "clang/Index/USRGeneration.h" 23 #include "llvm/ADT/Optional.h" 24 #include "llvm/Support/Casting.h" 25 #include "llvm/Support/ScopedPrinter.h" 26 #include "llvm/Support/raw_ostream.h" 27 28 namespace clang { 29 namespace clangd { 30 31 namespace { 32 llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>> 33 getTemplateSpecializationArgLocs(const NamedDecl &ND) { 34 if (auto *Func = llvm::dyn_cast<FunctionDecl>(&ND)) { 35 if (const ASTTemplateArgumentListInfo *Args = 36 Func->getTemplateSpecializationArgsAsWritten()) 37 return Args->arguments(); 38 } else if (auto *Cls = 39 llvm::dyn_cast<ClassTemplatePartialSpecializationDecl>(&ND)) { 40 if (auto *Args = Cls->getTemplateArgsAsWritten()) 41 return Args->arguments(); 42 } else if (auto *Var = 43 llvm::dyn_cast<VarTemplatePartialSpecializationDecl>(&ND)) { 44 if (auto *Args = Var->getTemplateArgsAsWritten()) 45 return Args->arguments(); 46 } else if (auto *Var = llvm::dyn_cast<VarTemplateSpecializationDecl>(&ND)) 47 return Var->getTemplateArgsInfo().arguments(); 48 // We return None for ClassTemplateSpecializationDecls because it does not 49 // contain TemplateArgumentLoc information. 50 return llvm::None; 51 } 52 53 template <class T> 54 bool isTemplateSpecializationKind(const NamedDecl *D, 55 TemplateSpecializationKind Kind) { 56 if (const auto *TD = dyn_cast<T>(D)) 57 return TD->getTemplateSpecializationKind() == Kind; 58 return false; 59 } 60 61 bool isTemplateSpecializationKind(const NamedDecl *D, 62 TemplateSpecializationKind Kind) { 63 return isTemplateSpecializationKind<FunctionDecl>(D, Kind) || 64 isTemplateSpecializationKind<CXXRecordDecl>(D, Kind) || 65 isTemplateSpecializationKind<VarDecl>(D, Kind); 66 } 67 68 } // namespace 69 70 bool isImplicitTemplateInstantiation(const NamedDecl *D) { 71 return isTemplateSpecializationKind(D, TSK_ImplicitInstantiation); 72 } 73 74 bool isExplicitTemplateSpecialization(const NamedDecl *D) { 75 return isTemplateSpecializationKind(D, TSK_ExplicitSpecialization); 76 } 77 78 bool isImplementationDetail(const Decl *D) { 79 return !isSpelledInSource(D->getLocation(), 80 D->getASTContext().getSourceManager()); 81 } 82 83 SourceLocation findName(const clang::Decl *D) { 84 return D->getLocation(); 85 } 86 87 std::string printQualifiedName(const NamedDecl &ND) { 88 std::string QName; 89 llvm::raw_string_ostream OS(QName); 90 PrintingPolicy Policy(ND.getASTContext().getLangOpts()); 91 // Note that inline namespaces are treated as transparent scopes. This 92 // reflects the way they're most commonly used for lookup. Ideally we'd 93 // include them, but at query time it's hard to find all the inline 94 // namespaces to query: the preamble doesn't have a dedicated list. 95 Policy.SuppressUnwrittenScope = true; 96 ND.printQualifiedName(OS, Policy); 97 OS.flush(); 98 assert(!StringRef(QName).startswith("::")); 99 return QName; 100 } 101 102 static bool isAnonymous(const DeclarationName &N) { 103 return N.isIdentifier() && !N.getAsIdentifierInfo(); 104 } 105 106 NestedNameSpecifierLoc getQualifierLoc(const NamedDecl &ND) { 107 if (auto *V = llvm::dyn_cast<DeclaratorDecl>(&ND)) 108 return V->getQualifierLoc(); 109 if (auto *T = llvm::dyn_cast<TagDecl>(&ND)) 110 return T->getQualifierLoc(); 111 return NestedNameSpecifierLoc(); 112 } 113 114 std::string printUsingNamespaceName(const ASTContext &Ctx, 115 const UsingDirectiveDecl &D) { 116 PrintingPolicy PP(Ctx.getLangOpts()); 117 std::string Name; 118 llvm::raw_string_ostream Out(Name); 119 120 if (auto *Qual = D.getQualifier()) 121 Qual->print(Out, PP); 122 D.getNominatedNamespaceAsWritten()->printName(Out); 123 return Out.str(); 124 } 125 126 std::string printName(const ASTContext &Ctx, const NamedDecl &ND) { 127 std::string Name; 128 llvm::raw_string_ostream Out(Name); 129 PrintingPolicy PP(Ctx.getLangOpts()); 130 131 // Handle 'using namespace'. They all have the same name - <using-directive>. 132 if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) { 133 Out << "using namespace "; 134 if (auto *Qual = UD->getQualifier()) 135 Qual->print(Out, PP); 136 UD->getNominatedNamespaceAsWritten()->printName(Out); 137 return Out.str(); 138 } 139 140 if (isAnonymous(ND.getDeclName())) { 141 // Come up with a presentation for an anonymous entity. 142 if (isa<NamespaceDecl>(ND)) 143 return "(anonymous namespace)"; 144 if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND)) 145 return ("(anonymous " + Cls->getKindName() + ")").str(); 146 if (isa<EnumDecl>(ND)) 147 return "(anonymous enum)"; 148 return "(anonymous)"; 149 } 150 151 // Print nested name qualifier if it was written in the source code. 152 if (auto *Qualifier = getQualifierLoc(ND).getNestedNameSpecifier()) 153 Qualifier->print(Out, PP); 154 // Print the name itself. 155 ND.getDeclName().print(Out, PP); 156 // Print template arguments. 157 Out << printTemplateSpecializationArgs(ND); 158 159 return Out.str(); 160 } 161 162 std::string printTemplateSpecializationArgs(const NamedDecl &ND) { 163 std::string TemplateArgs; 164 llvm::raw_string_ostream OS(TemplateArgs); 165 PrintingPolicy Policy(ND.getASTContext().getLangOpts()); 166 if (llvm::Optional<llvm::ArrayRef<TemplateArgumentLoc>> Args = 167 getTemplateSpecializationArgLocs(ND)) { 168 printTemplateArgumentList(OS, *Args, Policy); 169 } else if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) { 170 if (const TypeSourceInfo *TSI = Cls->getTypeAsWritten()) { 171 // ClassTemplateSpecializationDecls do not contain 172 // TemplateArgumentTypeLocs, they only have TemplateArgumentTypes. So we 173 // create a new argument location list from TypeSourceInfo. 174 auto STL = TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>(); 175 llvm::SmallVector<TemplateArgumentLoc, 8> ArgLocs; 176 ArgLocs.reserve(STL.getNumArgs()); 177 for (unsigned I = 0; I < STL.getNumArgs(); ++I) 178 ArgLocs.push_back(STL.getArgLoc(I)); 179 printTemplateArgumentList(OS, ArgLocs, Policy); 180 } else { 181 // FIXME: Fix cases when getTypeAsWritten returns null inside clang AST, 182 // e.g. friend decls. Currently we fallback to Template Arguments without 183 // location information. 184 printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy); 185 } 186 } 187 OS.flush(); 188 return TemplateArgs; 189 } 190 191 std::string printNamespaceScope(const DeclContext &DC) { 192 for (const auto *Ctx = &DC; Ctx != nullptr; Ctx = Ctx->getParent()) 193 if (const auto *NS = dyn_cast<NamespaceDecl>(Ctx)) 194 if (!NS->isAnonymousNamespace() && !NS->isInlineNamespace()) 195 return printQualifiedName(*NS) + "::"; 196 return ""; 197 } 198 199 llvm::Optional<SymbolID> getSymbolID(const Decl *D) { 200 llvm::SmallString<128> USR; 201 if (index::generateUSRForDecl(D, USR)) 202 return None; 203 return SymbolID(USR); 204 } 205 206 llvm::Optional<SymbolID> getSymbolID(const IdentifierInfo &II, 207 const MacroInfo *MI, 208 const SourceManager &SM) { 209 if (MI == nullptr) 210 return None; 211 llvm::SmallString<128> USR; 212 if (index::generateUSRForMacro(II.getName(), MI->getDefinitionLoc(), SM, USR)) 213 return None; 214 return SymbolID(USR); 215 } 216 217 std::string shortenNamespace(const llvm::StringRef OriginalName, 218 const llvm::StringRef CurrentNamespace) { 219 llvm::SmallVector<llvm::StringRef, 8> OriginalParts; 220 llvm::SmallVector<llvm::StringRef, 8> CurrentParts; 221 llvm::SmallVector<llvm::StringRef, 8> Result; 222 OriginalName.split(OriginalParts, "::"); 223 CurrentNamespace.split(CurrentParts, "::"); 224 auto MinLength = std::min(CurrentParts.size(), OriginalParts.size()); 225 226 unsigned DifferentAt = 0; 227 while (DifferentAt < MinLength && 228 CurrentParts[DifferentAt] == OriginalParts[DifferentAt]) { 229 DifferentAt++; 230 } 231 232 for (unsigned i = DifferentAt; i < OriginalParts.size(); ++i) { 233 Result.push_back(OriginalParts[i]); 234 } 235 return join(Result, "::"); 236 } 237 238 std::string printType(const QualType QT, const DeclContext & Context){ 239 PrintingPolicy PP(Context.getParentASTContext().getPrintingPolicy()); 240 PP.SuppressUnwrittenScope = 1; 241 PP.SuppressTagKeyword = 1; 242 return shortenNamespace( 243 QT.getAsString(PP), 244 printNamespaceScope(Context) ); 245 } 246 247 248 } // namespace clangd 249 } // namespace clang 250