| 1 | //===--- AST.h - 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 | // Various code that examines C++ source code using AST. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_AST_H |
| 14 | #define |
| 15 | |
| 16 | #include "Headers.h" |
| 17 | #include "index/Symbol.h" |
| 18 | #include "index/SymbolID.h" |
| 19 | #include "clang/AST/Decl.h" |
| 20 | #include "clang/AST/DeclObjC.h" |
| 21 | #include "clang/AST/NestedNameSpecifier.h" |
| 22 | #include "clang/AST/TypeLoc.h" |
| 23 | #include "clang/Basic/SourceLocation.h" |
| 24 | #include "clang/Lex/MacroInfo.h" |
| 25 | #include "llvm/ADT/StringRef.h" |
| 26 | #include <optional> |
| 27 | #include <string> |
| 28 | #include <vector> |
| 29 | |
| 30 | namespace clang { |
| 31 | class SourceManager; |
| 32 | class Decl; |
| 33 | class DynTypedNode; |
| 34 | |
| 35 | namespace clangd { |
| 36 | |
| 37 | /// Returns true if the declaration is considered implementation detail based on |
| 38 | /// heuristics. For example, a declaration whose name is not explicitly spelled |
| 39 | /// in code is considered implementation detail. |
| 40 | bool isImplementationDetail(const Decl *D); |
| 41 | |
| 42 | /// Find the source location of the identifier for \p D. |
| 43 | /// Transforms macro locations to locations spelled inside files. All code |
| 44 | /// that needs locations of declaration names (e.g. the index) should go through |
| 45 | /// this function. |
| 46 | SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM); |
| 47 | |
| 48 | /// Returns the qualified name of ND. The scope doesn't contain unwritten scopes |
| 49 | /// like inline namespaces. |
| 50 | std::string printQualifiedName(const NamedDecl &ND); |
| 51 | |
| 52 | /// Returns the first enclosing namespace scope starting from \p DC. |
| 53 | std::string printNamespaceScope(const DeclContext &DC); |
| 54 | |
| 55 | /// Returns the name of the namespace inside the 'using namespace' directive, as |
| 56 | /// written in the code. E.g., passing 'using namespace ::std' will result in |
| 57 | /// '::std'. |
| 58 | std::string printUsingNamespaceName(const ASTContext &Ctx, |
| 59 | const UsingDirectiveDecl &D); |
| 60 | |
| 61 | /// Prints unqualified name of the decl for the purpose of displaying it to the |
| 62 | /// user. Anonymous decls return names of the form "(anonymous {kind})", e.g. |
| 63 | /// "(anonymous struct)" or "(anonymous namespace)". |
| 64 | std::string printName(const ASTContext &Ctx, const NamedDecl &ND); |
| 65 | |
| 66 | /// Prints template arguments of a decl as written in the source code, including |
| 67 | /// enclosing '<' and '>', e.g for a partial specialization like: template |
| 68 | /// <typename U> struct Foo<int, U> will return '<int, U>'. Returns an empty |
| 69 | /// string if decl is not a template specialization. |
| 70 | std::string printTemplateSpecializationArgs(const NamedDecl &ND); |
| 71 | |
| 72 | /// Print the Objective-C method name, including the full container name, e.g. |
| 73 | /// `-[MyClass(Category) method:]` |
| 74 | std::string printObjCMethod(const ObjCMethodDecl &Method); |
| 75 | |
| 76 | /// Print the Objective-C container name including categories, e.g. `MyClass`, |
| 77 | // `MyClass()`, `MyClass(Category)`, and `MyProtocol`. |
| 78 | std::string printObjCContainer(const ObjCContainerDecl &C); |
| 79 | |
| 80 | /// Returns true if this is a NamedDecl with a reserved name. |
| 81 | bool hasReservedName(const Decl &); |
| 82 | /// Returns true if this scope would be written with a reserved name. |
| 83 | /// This does not include unwritten scope elements like __1 in std::__1::vector. |
| 84 | bool hasReservedScope(const DeclContext &); |
| 85 | |
| 86 | /// Gets the symbol ID for a declaration. Returned SymbolID might be null. |
| 87 | SymbolID getSymbolID(const Decl *D); |
| 88 | |
| 89 | /// Gets the symbol ID for a macro. Returned SymbolID might be null. |
| 90 | /// Currently, this is an encoded USR of the macro, which incorporates macro |
| 91 | /// locations (e.g. file name, offset in file). |
| 92 | /// FIXME: the USR semantics might not be stable enough as the ID for index |
| 93 | /// macro (e.g. a change in definition offset can result in a different USR). We |
| 94 | /// could change these semantics in the future by reimplementing this funcure |
| 95 | /// (e.g. avoid USR for macros). |
| 96 | SymbolID getSymbolID(const llvm::StringRef MacroName, const MacroInfo *MI, |
| 97 | const SourceManager &SM); |
| 98 | |
| 99 | /// Return the corresponding implementation/definition for the given ObjC |
| 100 | /// container if it has one, otherwise, return nullptr. |
| 101 | /// |
| 102 | /// Objective-C classes can have three types of declarations: |
| 103 | /// |
| 104 | /// - forward declaration: "@class MyClass;" |
| 105 | /// - true declaration (interface definition): "@interface MyClass ... @end" |
| 106 | /// - true definition (implementation): "@implementation MyClass ... @end" |
| 107 | /// |
| 108 | /// Objective-C categories are extensions on classes: |
| 109 | /// |
| 110 | /// - declaration: "@interface MyClass (Ext) ... @end" |
| 111 | /// - definition: "@implementation MyClass (Ext) ... @end" |
| 112 | /// |
| 113 | /// With one special case, a class extension, which is normally used to keep |
| 114 | /// some declarations internal to a file without exposing them in a header. |
| 115 | /// |
| 116 | /// - class extension declaration: "@interface MyClass () ... @end" |
| 117 | /// - which really links to class definition: "@implementation MyClass ... @end" |
| 118 | /// |
| 119 | /// For Objective-C protocols, e.g. "@protocol MyProtocol ... @end" this will |
| 120 | /// return nullptr as protocols don't have an implementation. |
| 121 | const ObjCImplDecl *getCorrespondingObjCImpl(const ObjCContainerDecl *D); |
| 122 | |
| 123 | /// Infer the include directive to use for the given \p FileName. It aims for |
| 124 | /// #import for ObjC files and #include for the rest. |
| 125 | /// |
| 126 | /// - For source files we use LangOpts directly to infer ObjC-ness. |
| 127 | /// - For header files we also check for symbols declared by the file and |
| 128 | /// existing include directives, as the language can be set to ObjC++ as a |
| 129 | /// fallback in the absence of compile flags. |
| 130 | Symbol::IncludeDirective |
| 131 | preferredIncludeDirective(llvm::StringRef FileName, const LangOptions &LangOpts, |
| 132 | ArrayRef<Inclusion> MainFileIncludes, |
| 133 | ArrayRef<const Decl *> TopLevelDecls); |
| 134 | |
| 135 | /// Returns a QualType as string. The result doesn't contain unwritten scopes |
| 136 | /// like anonymous/inline namespace. |
| 137 | std::string printType(const QualType QT, const DeclContext &CurContext, |
| 138 | llvm::StringRef Placeholder = "" ); |
| 139 | |
| 140 | /// Indicates if \p D is a template instantiation implicitly generated by the |
| 141 | /// compiler, e.g. |
| 142 | /// template <class T> struct vector {}; |
| 143 | /// vector<int> v; // 'vector<int>' is an implicit instantiation |
| 144 | bool isImplicitTemplateInstantiation(const NamedDecl *D); |
| 145 | /// Indicates if \p D is an explicit template specialization, e.g. |
| 146 | /// template <class T> struct vector {}; |
| 147 | /// template <> struct vector<bool> {}; // <-- explicit specialization |
| 148 | /// |
| 149 | /// Note that explicit instantiations are NOT explicit specializations, albeit |
| 150 | /// they look similar. |
| 151 | /// template struct vector<bool>; // <-- explicit instantiation, NOT an |
| 152 | /// explicit specialization. |
| 153 | bool isExplicitTemplateSpecialization(const NamedDecl *D); |
| 154 | |
| 155 | /// Returns a nested name specifier loc of \p ND if it was present in the |
| 156 | /// source, e.g. |
| 157 | /// void ns::something::foo() -> returns 'ns::something' |
| 158 | /// void foo() -> returns null |
| 159 | NestedNameSpecifierLoc getQualifierLoc(const NamedDecl &ND); |
| 160 | |
| 161 | // Returns a type corresponding to a declaration of that type. |
| 162 | // Unlike the method on ASTContext, attempts to preserve the type as-written |
| 163 | // (i.e. vector<T*> rather than vector<type-parameter-0-0 *>. |
| 164 | QualType declaredType(const TypeDecl *D); |
| 165 | |
| 166 | /// Retrieves the deduced type at a given location (auto, decltype). |
| 167 | /// It will return the underlying type. |
| 168 | /// If the type is an undeduced auto, returns the type itself. |
| 169 | std::optional<QualType> getDeducedType(ASTContext &, SourceLocation Loc); |
| 170 | |
| 171 | // Find the abbreviated-function-template `auto` within a type, or returns null. |
| 172 | // Similar to getContainedAutoTypeLoc, but these `auto`s are |
| 173 | // TemplateTypeParmTypes for implicit TTPs, instead of AutoTypes. |
| 174 | // Also we don't look very hard, just stripping const, references, pointers. |
| 175 | // FIXME: handle more type patterns. |
| 176 | TemplateTypeParmTypeLoc getContainedAutoParamType(TypeLoc TL); |
| 177 | |
| 178 | // If TemplatedDecl is the generic body of a template, and the template has |
| 179 | // exactly one visible instantiation, return the instantiated body. |
| 180 | NamedDecl *getOnlyInstantiation(NamedDecl *TemplatedDecl); |
| 181 | |
| 182 | /// Return attributes attached directly to a node. |
| 183 | std::vector<const Attr *> getAttributes(const DynTypedNode &); |
| 184 | |
| 185 | /// Gets the nested name specifier necessary for spelling \p ND in \p |
| 186 | /// DestContext, at \p InsertionPoint. It selects the shortest suffix of \p ND |
| 187 | /// such that it is visible in \p DestContext. |
| 188 | /// Returns an empty string if no qualification is necessary. For example, if |
| 189 | /// you want to qualify clang::clangd::bar::foo in clang::clangd::x, this |
| 190 | /// function will return bar. Note that the result might be sub-optimal for |
| 191 | /// classes, e.g. when the \p ND is a member of the base class. |
| 192 | /// |
| 193 | /// This version considers all the using namespace directives before \p |
| 194 | /// InsertionPoint. i.e, if you have `using namespace |
| 195 | /// clang::clangd::bar`, this function will return an empty string for the |
| 196 | /// example above since no qualification is necessary in that case. |
| 197 | /// FIXME: Also take using directives and namespace aliases inside function body |
| 198 | /// into account. |
| 199 | std::string getQualification(ASTContext &Context, |
| 200 | const DeclContext *DestContext, |
| 201 | SourceLocation InsertionPoint, |
| 202 | const NamedDecl *ND); |
| 203 | |
| 204 | /// This function uses the \p VisibleNamespaces to figure out if a shorter |
| 205 | /// qualification is sufficient for \p ND, and ignores any using namespace |
| 206 | /// directives. It can be useful if there's no AST for the DestContext, but some |
| 207 | /// pseudo-parsing is done. i.e. if \p ND is ns1::ns2::X and \p DestContext is |
| 208 | /// ns1::, users can provide `ns2::` as visible to change the result to be |
| 209 | /// empty. |
| 210 | /// Elements in VisibleNamespaces should be in the form: `ns::`, with trailing |
| 211 | /// "::". |
| 212 | /// Note that this is just textual and might be incorrect. e.g. when there are |
| 213 | /// two namespaces ns1::a and ns2::a, the function will early exit if "a::" is |
| 214 | /// present in \p VisibleNamespaces, no matter whether it is from ns1:: or ns2:: |
| 215 | std::string getQualification(ASTContext &Context, |
| 216 | const DeclContext *DestContext, |
| 217 | const NamedDecl *ND, |
| 218 | llvm::ArrayRef<std::string> VisibleNamespaces); |
| 219 | |
| 220 | /// Whether we must avoid computing linkage for D during code completion. |
| 221 | /// Clang aggressively caches linkage computation, which is stable after the AST |
| 222 | /// is built. Unfortunately the AST is incomplete during code completion, so |
| 223 | /// linkage may still change. |
| 224 | /// |
| 225 | /// Example: `auto x = []{^}` at file scope. |
| 226 | /// During code completion, the initializer for x hasn't been parsed yet. |
| 227 | /// x has type `undeduced auto`, and external linkage. |
| 228 | /// If we compute linkage at this point, the external linkage will be cached. |
| 229 | /// |
| 230 | /// After code completion the initializer is attached, and x has a lambda type. |
| 231 | /// This means x has "unique external" linkage. If we computed linkage above, |
| 232 | /// the cached value is incorrect. (clang catches this with an assertion). |
| 233 | bool hasUnstableLinkage(const Decl *D); |
| 234 | |
| 235 | /// Checks whether \p D is more than \p MaxDepth away from translation unit |
| 236 | /// scope. |
| 237 | /// This is useful for limiting traversals to keep operation latencies |
| 238 | /// reasonable. |
| 239 | bool isDeeplyNested(const Decl *D, unsigned MaxDepth = 10); |
| 240 | |
| 241 | /// Recursively resolves the parameters of a FunctionDecl that forwards its |
| 242 | /// parameters to another function via variadic template parameters. This can |
| 243 | /// for example be used to retrieve the constructor parameter ParmVarDecl for a |
| 244 | /// make_unique or emplace_back call. |
| 245 | llvm::SmallVector<const ParmVarDecl *> |
| 246 | resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth = 10); |
| 247 | |
| 248 | /// Checks whether D is instantiated from a function parameter pack |
| 249 | /// whose type is a bare type parameter pack (e.g. `Args...`), or a |
| 250 | /// reference to one (e.g. `Args&...` or `Args&&...`). |
| 251 | bool isExpandedFromParameterPack(const ParmVarDecl *D); |
| 252 | |
| 253 | } // namespace clangd |
| 254 | } // namespace clang |
| 255 | |
| 256 | #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_AST_H |
| 257 | |