//===- ExtractAPI/DeclarationFragments.h ------------------------*- 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
 
//
 
//===----------------------------------------------------------------------===//
 
///
 
/// \file
 
/// This file defines the Declaration Fragments related classes.
 
///
 
/// Declaration Fragments represent parts of a symbol declaration tagged with
 
/// syntactic/semantic information.
 
/// See https://github.com/apple/swift-docc-symbolkit
 
///
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_EXTRACTAPI_DECLARATION_FRAGMENTS_H
 
#define LLVM_CLANG_EXTRACTAPI_DECLARATION_FRAGMENTS_H
 
 
 
#include "clang/AST/ASTContext.h"
 
#include "clang/AST/Decl.h"
 
#include "clang/AST/DeclCXX.h"
 
#include "clang/AST/DeclObjC.h"
 
#include "clang/Lex/MacroInfo.h"
 
#include "llvm/ADT/StringRef.h"
 
#include <vector>
 
 
 
namespace clang {
 
namespace extractapi {
 
 
 
/// DeclarationFragments is a vector of tagged important parts of a symbol's
 
/// declaration.
 
///
 
/// The fragments sequence can be joined to form spans of declaration text, with
 
/// attached information useful for purposes like syntax-highlighting etc.
 
/// For example:
 
/// \code
 
///   const -> keyword    "const"
 
///   int   -> type       "int"
 
///   pi;   -> identifier "pi"
 
/// \endcode
 
class DeclarationFragments {
 
public:
 
  DeclarationFragments() = default;
 
 
 
  /// The kind of a fragment.
 
  enum class FragmentKind {
 
    /// Unknown fragment kind.
 
    None,
 
 
 
    Keyword,
 
    Attribute,
 
    NumberLiteral,
 
    StringLiteral,
 
    Identifier,
 
 
 
    /// Identifier that refers to a type in the context.
 
    TypeIdentifier,
 
 
 
    /// Parameter that's used as generics in the context. For example template
 
    /// parameters.
 
    GenericParameter,
 
 
 
    /// External parameters in Objective-C methods.
 
    /// For example, \c forKey in
 
    /// \code{.m}
 
    ///   - (void) setValue:(Value)value forKey(Key)key
 
    /// \endcode
 
    ExternalParam,
 
 
 
    /// Internal/local parameters in Objective-C methods.
 
    /// For example, \c key in
 
    /// \code{.m}
 
    ///   - (void) setValue:(Value)value forKey(Key)key
 
    /// \endcode
 
    InternalParam,
 
 
 
    Text,
 
  };
 
 
 
  /// Fragment holds information of a single fragment.
 
  struct Fragment {
 
    std::string Spelling;
 
    FragmentKind Kind;
 
 
 
    /// The USR of the fragment symbol, if applicable.
 
    std::string PreciseIdentifier;
 
 
 
    /// The associated declaration, if applicable. This is not intended to be
 
    /// used outside of libclang.
 
    const Decl *Declaration;
 
 
 
    Fragment(StringRef Spelling, FragmentKind Kind, StringRef PreciseIdentifier,
 
             const Decl *Declaration)
 
        : Spelling(Spelling), Kind(Kind), PreciseIdentifier(PreciseIdentifier),
 
          Declaration(Declaration) {}
 
  };
 
 
 
  const std::vector<Fragment> &getFragments() const { return Fragments; }
 
 
 
  /// Append a new Fragment to the end of the Fragments.
 
  ///
 
  /// \returns a reference to the DeclarationFragments object itself after
 
  /// appending to chain up consecutive appends.
 
  DeclarationFragments &append(StringRef Spelling, FragmentKind Kind,
 
                               StringRef PreciseIdentifier = "",
 
                               const Decl *Declaration = nullptr) {
 
    if (Kind == FragmentKind::Text && !Fragments.empty() &&
 
        Fragments.back().Kind == FragmentKind::Text) {
 
      // If appending a text fragment, and the last fragment is also text,
 
      // merge into the last fragment.
 
      Fragments.back().Spelling.append(Spelling.data(), Spelling.size());
 
    } else {
 
      Fragments.emplace_back(Spelling, Kind, PreciseIdentifier, Declaration);
 
    }
 
    return *this;
 
  }
 
 
 
  /// Append another DeclarationFragments to the end.
 
  ///
 
  /// Note: \p Other is moved from and cannot be used after a call to this
 
  /// method.
 
  ///
 
  /// \returns a reference to the DeclarationFragments object itself after
 
  /// appending to chain up consecutive appends.
 
  DeclarationFragments &append(DeclarationFragments &&Other) {
 
    Fragments.insert(Fragments.end(),
 
                     std::make_move_iterator(Other.Fragments.begin()),
 
                     std::make_move_iterator(Other.Fragments.end()));
 
    Other.Fragments.clear();
 
    return *this;
 
  }
 
 
 
  /// Append a text Fragment of a space character.
 
  ///
 
  /// \returns a reference to the DeclarationFragments object itself after
 
  /// appending to chain up consecutive appends.
 
  DeclarationFragments &appendSpace();
 
 
 
  /// Get the string description of a FragmentKind \p Kind.
 
  static StringRef getFragmentKindString(FragmentKind Kind);
 
 
 
  /// Get the corresponding FragmentKind from string \p S.
 
  static FragmentKind parseFragmentKindFromString(StringRef S);
 
 
 
private:
 
  std::vector<Fragment> Fragments;
 
};
 
 
 
/// Store function signature information with DeclarationFragments of the
 
/// return type and parameters.
 
class FunctionSignature {
 
public:
 
  FunctionSignature() = default;
 
 
 
  /// Parameter holds the name and DeclarationFragments of a single parameter.
 
  struct Parameter {
 
    std::string Name;
 
    DeclarationFragments Fragments;
 
 
 
    Parameter(StringRef Name, DeclarationFragments Fragments)
 
        : Name(Name), Fragments(Fragments) {}
 
  };
 
 
 
  const std::vector<Parameter> &getParameters() const { return Parameters; }
 
  const DeclarationFragments &getReturnType() const { return ReturnType; }
 
 
 
  FunctionSignature &addParameter(StringRef Name,
 
                                  DeclarationFragments Fragments) {
 
    Parameters.emplace_back(Name, Fragments);
 
    return *this;
 
  }
 
 
 
  void setReturnType(DeclarationFragments RT) { ReturnType = RT; }
 
 
 
  /// Determine if the FunctionSignature is empty.
 
  ///
 
  /// \returns true if the return type DeclarationFragments is empty and there
 
  /// is no parameter, otherwise false.
 
  bool empty() const {
 
    return Parameters.empty() && ReturnType.getFragments().empty();
 
  }
 
 
 
private:
 
  std::vector<Parameter> Parameters;
 
  DeclarationFragments ReturnType;
 
};
 
 
 
/// A factory class to build DeclarationFragments for different kinds of Decl.
 
class DeclarationFragmentsBuilder {
 
public:
 
  /// Build DeclarationFragments for a variable declaration VarDecl.
 
  static DeclarationFragments getFragmentsForVar(const VarDecl *);
 
 
 
  /// Build DeclarationFragments for a function declaration FunctionDecl.
 
  static DeclarationFragments getFragmentsForFunction(const FunctionDecl *);
 
 
 
  /// Build DeclarationFragments for an enum constant declaration
 
  /// EnumConstantDecl.
 
  static DeclarationFragments
 
  getFragmentsForEnumConstant(const EnumConstantDecl *);
 
 
 
  /// Build DeclarationFragments for an enum declaration EnumDecl.
 
  static DeclarationFragments getFragmentsForEnum(const EnumDecl *);
 
 
 
  /// Build DeclarationFragments for a field declaration FieldDecl.
 
  static DeclarationFragments getFragmentsForField(const FieldDecl *);
 
 
 
  /// Build DeclarationFragments for a struct record declaration RecordDecl.
 
  static DeclarationFragments getFragmentsForStruct(const RecordDecl *);
 
 
 
  /// Build DeclarationFragments for an Objective-C category declaration
 
  /// ObjCCategoryDecl.
 
  static DeclarationFragments
 
  getFragmentsForObjCCategory(const ObjCCategoryDecl *);
 
 
 
  /// Build DeclarationFragments for an Objective-C interface declaration
 
  /// ObjCInterfaceDecl.
 
  static DeclarationFragments
 
  getFragmentsForObjCInterface(const ObjCInterfaceDecl *);
 
 
 
  /// Build DeclarationFragments for an Objective-C method declaration
 
  /// ObjCMethodDecl.
 
  static DeclarationFragments getFragmentsForObjCMethod(const ObjCMethodDecl *);
 
 
 
  /// Build DeclarationFragments for an Objective-C property declaration
 
  /// ObjCPropertyDecl.
 
  static DeclarationFragments
 
  getFragmentsForObjCProperty(const ObjCPropertyDecl *);
 
 
 
  /// Build DeclarationFragments for an Objective-C protocol declaration
 
  /// ObjCProtocolDecl.
 
  static DeclarationFragments
 
  getFragmentsForObjCProtocol(const ObjCProtocolDecl *);
 
 
 
  /// Build DeclarationFragments for a macro.
 
  ///
 
  /// \param Name name of the macro.
 
  /// \param MD the associated MacroDirective.
 
  static DeclarationFragments getFragmentsForMacro(StringRef Name,
 
                                                   const MacroDirective *MD);
 
 
 
  /// Build DeclarationFragments for a typedef \p TypedefNameDecl.
 
  static DeclarationFragments
 
  getFragmentsForTypedef(const TypedefNameDecl *Decl);
 
 
 
  /// Build sub-heading fragments for a NamedDecl.
 
  static DeclarationFragments getSubHeading(const NamedDecl *);
 
 
 
  /// Build sub-heading fragments for an Objective-C method.
 
  static DeclarationFragments getSubHeading(const ObjCMethodDecl *);
 
 
 
  /// Build a sub-heading for macro \p Name.
 
  static DeclarationFragments getSubHeadingForMacro(StringRef Name);
 
 
 
  /// Build FunctionSignature for a function-like declaration \c FunctionT like
 
  /// FunctionDecl or ObjCMethodDecl.
 
  ///
 
  /// The logic and implementation of building a signature for a FunctionDecl
 
  /// and an ObjCMethodDecl are exactly the same, but they do not share a common
 
  /// base. This template helps reuse the code.
 
  template <typename FunctionT>
 
  static FunctionSignature getFunctionSignature(const FunctionT *);
 
 
 
private:
 
  DeclarationFragmentsBuilder() = delete;
 
 
 
  /// Build DeclarationFragments for a QualType.
 
  static DeclarationFragments getFragmentsForType(const QualType, ASTContext &,
 
                                                  DeclarationFragments &);
 
 
 
  /// Build DeclarationFragments for a Type.
 
  static DeclarationFragments getFragmentsForType(const Type *, ASTContext &,
 
                                                  DeclarationFragments &);
 
 
 
  /// Build DeclarationFragments for a NestedNameSpecifier.
 
  static DeclarationFragments getFragmentsForNNS(const NestedNameSpecifier *,
 
                                                 ASTContext &,
 
                                                 DeclarationFragments &);
 
 
 
  /// Build DeclarationFragments for Qualifiers.
 
  static DeclarationFragments getFragmentsForQualifiers(const Qualifiers quals);
 
 
 
  /// Build DeclarationFragments for a parameter variable declaration
 
  /// ParmVarDecl.
 
  static DeclarationFragments getFragmentsForParam(const ParmVarDecl *);
 
};
 
 
 
} // namespace extractapi
 
} // namespace clang
 
 
 
#endif // LLVM_CLANG_EXTRACTAPI_DECLARATION_FRAGMENTS_H