text: //===--- AST.h - Utility AST functions  -------------------------*- C++ -*-===//
  //
  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  // See https://llvm.org/LICENSE.txt for license information.
  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  //
  //===----------------------------------------------------------------------===//
  //
  // Various code that examines C++ source code using AST.
  //
  //===----------------------------------------------------------------------===//
  
  #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_AST_H_
  #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_AST_H_
  
  #include "index/SymbolID.h"
  #include "clang/AST/Decl.h"
  #include "clang/AST/NestedNameSpecifier.h"
  #include "clang/Basic/SourceLocation.h"
  #include "clang/Lex/MacroInfo.h"
  #include "llvm/ADT/DenseSet.h"
  #include "llvm/ADT/StringRef.h"
  #include <string>
  #include <vector>
  
  namespace clang {
  class SourceManager;
  class Decl;
  
  namespace clangd {
  
  /// Returns true if the declaration is considered implementation detail based on
  /// heuristics. For example, a declaration whose name is not explicitly spelled
  /// in code is considered implementation detail.
  bool isImplementationDetail(const Decl *D);
  
  /// Find the source location of the identifier for \p D.
  /// Transforms macro locations to locations spelled inside files. All code
  /// that needs locations of declaration names (e.g. the index) should go through
  /// this function.
  SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM);
  
  /// Returns the qualified name of ND. The scope doesn't contain unwritten scopes
  /// like inline namespaces.
  std::string printQualifiedName(const NamedDecl &ND);
  
  /// Returns the first enclosing namespace scope starting from \p DC.
  std::string printNamespaceScope(const DeclContext &DC);
  
  /// Returns the name of the namespace inside the 'using namespace' directive, as
  /// written in the code. E.g., passing 'using namespace ::std' will result in
  /// '::std'.
  std::string printUsingNamespaceName(const ASTContext &Ctx,
                                      const UsingDirectiveDecl &D);
  
  /// Prints unqualified name of the decl for the purpose of displaying it to the
  /// user. Anonymous decls return names of the form "(anonymous {kind})", e.g.
  /// "(anonymous struct)" or "(anonymous namespace)".
  std::string printName(const ASTContext &Ctx, const NamedDecl &ND);
  
  /// Prints template arguments of a decl as written in the source code, including
  /// enclosing '<' and '>', e.g for a partial specialization like: template
  /// <typename U> struct Foo<int, U> will return '<int, U>'. Returns an empty
  /// string if decl is not a template specialization.
  std::string printTemplateSpecializationArgs(const NamedDecl &ND);
  
  /// Gets the symbol ID for a declaration, if possible.
  llvm::Optional<SymbolID> getSymbolID(const Decl *D);
  
  /// Gets the symbol ID for a macro, if possible.
  /// Currently, this is an encoded USR of the macro, which incorporates macro
  /// locations (e.g. file name, offset in file).
  /// FIXME: the USR semantics might not be stable enough as the ID for index
  /// macro (e.g. a change in definition offset can result in a different USR). We
  /// could change these semantics in the future by reimplementing this funcure
  /// (e.g. avoid USR for macros).
  llvm::Optional<SymbolID> getSymbolID(const llvm::StringRef MacroName,
                                       const MacroInfo *MI,
                                       const SourceManager &SM);
  
  /// Returns a QualType as string. The result doesn't contain unwritten scopes
  /// like annoymous/inline namespace.
  std::string printType(const QualType QT, const DeclContext &Context);
  
  /// Try to shorten the OriginalName by removing namespaces from the left of
  /// the string that are redundant in the CurrentNamespace. This way the type
  /// idenfier become shorter and easier to read.
  /// Limitation: It only handles the qualifier of the type itself, not that of
  /// templates.
  /// FIXME: change type of parameter CurrentNamespace to DeclContext ,
  /// take in to account using directives etc
  /// Example: shortenNamespace("ns1::MyClass<ns1::OtherClass>", "ns1")
  ///    --> "MyClass<ns1::OtherClass>"
  std::string shortenNamespace(const llvm::StringRef OriginalName,
                               const llvm::StringRef CurrentNamespace);
  
  /// Indicates if \p D is a template instantiation implicitly generated by the
  /// compiler, e.g.
  ///     template <class T> struct vector {};
  ///     vector<int> v; // 'vector<int>' is an implicit instantiation
  bool isImplicitTemplateInstantiation(const NamedDecl *D);
  /// Indicates if \p D is an explicit template specialization, e.g.
  ///   template <class T> struct vector {};
  ///   template <> struct vector<bool> {}; // <-- explicit specialization
  ///
  /// Note that explicit instantiations are NOT explicit specializations, albeit
  /// they look similar.
  ///   template struct vector<bool>; // <-- explicit instantiation, NOT an
  ///   explicit specialization.
  bool isExplicitTemplateSpecialization(const NamedDecl *D);
  
  /// Returns a nested name specifier loc of \p ND if it was present in the
  /// source, e.g.
  ///     void ns::something::foo() -> returns 'ns::something'
  ///     void foo() -> returns null
  NestedNameSpecifierLoc getQualifierLoc(const NamedDecl &ND);
  
  // Returns a type corresponding to a declaration of that type.
  // Unlike the method on ASTContext, attempts to preserve the type as-written
  // (i.e. vector<T*> rather than vector<type-parameter-0-0 *>.
  QualType declaredType(const TypeDecl *D);
  
  /// Retrieves the deduced type at a given location (auto, decltype).
  /// Retuns None unless Loc starts an auto/decltype token.
  /// It will return the underlying type.
  llvm::Optional<QualType> getDeducedType(ASTContext &, SourceLocation Loc);
  
  /// Gets the nested name specifier necessary for spelling \p ND in \p
  /// DestContext, at \p InsertionPoint. It selects the shortest suffix of \p ND
  /// such that it is visible in \p DestContext.
  /// Returns an empty string if no qualification is necessary. For example, if
  /// you want to qualify clang::clangd::bar::foo in clang::clangd::x, this
  /// function will return bar. Note that the result might be sub-optimal for
  /// classes, e.g. when the \p ND is a member of the base class.
  ///
  /// This version considers all the using namespace directives before \p
  /// InsertionPoint. i.e, if you have `using namespace
  /// clang::clangd::bar`, this function will return an empty string for the
  /// example above since no qualification is necessary in that case.
  /// FIXME: Also take using directives and namespace aliases inside function body
  /// into account.
  std::string getQualification(ASTContext &Context,
                               const DeclContext *DestContext,
                               SourceLocation InsertionPoint,
                               const NamedDecl *ND);
  
  /// This function uses the \p VisibleNamespaces to figure out if a shorter
  /// qualification is sufficient for \p ND, and ignores any using namespace
  /// directives. It can be useful if there's no AST for the DestContext, but some
  /// pseudo-parsing is done. i.e. if \p ND is ns1::ns2::X and \p DestContext is
  /// ns1::, users can provide `ns2::` as visible to change the result to be
  /// empty.
  /// Elements in VisibleNamespaces should be in the form: `ns::`, with trailing
  /// "::".
  /// Note that this is just textual and might be incorrect. e.g. when there are
  /// two namespaces ns1::a and ns2::a, the function will early exit if "a::" is
  /// present in \p VisibleNamespaces, no matter whether it is from ns1:: or ns2::
  std::string getQualification(ASTContext &Context,
                               const DeclContext *DestContext,
                               SourceLocation InsertionPoint, const NamedDecl *ND,
                               llvm::ArrayRef<std::string> VisibleNamespaces);
  
  } // namespace clangd
  } // namespace clang
  
  #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_AST_H_
  