//===- 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;
Fragment(StringRef Spelling, FragmentKind Kind, StringRef PreciseIdentifier)
: Spelling(Spelling), Kind(Kind), PreciseIdentifier(PreciseIdentifier) {
}
};
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 = "") {
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);
}
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