clang-1/lib/Sema/TreeTransform.h

1349 строки
54 KiB
C
Исходник Обычный вид История

//===------- TreeTransform.h - Semantic Tree Transformation ---------------===/
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//===----------------------------------------------------------------------===/
//
// This file implements a semantic tree transformation that takes a given
// AST and rebuilds it, possibly transforming some nodes in the process.
//
//===----------------------------------------------------------------------===/
#ifndef LLVM_CLANG_SEMA_TREETRANSFORM_H
#define LLVM_CLANG_SEMA_TREETRANSFORM_H
#include "Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
#include <algorithm>
namespace clang {
/// \brief A semantic tree transformation that allows one to transform one
/// abstract syntax tree into another.
///
/// A new tree transformation is defined by creating a new subclass \c X of
/// \c TreeTransform<X> and then overriding certain operations to provide
/// behavior specific to that transformation. For example, template
/// instantiation is implemented as a tree transformation where the
/// transformation of TemplateTypeParmType nodes involves substituting the
/// template arguments for their corresponding template parameters; a similar
/// transformation is performed for non-type template parameters and
/// template template parameters.
///
/// This tree-transformation template uses static polymorphism to allow
/// subclasses to customize any of its operations. Thus, a subclass can
/// override any of the transformation or rebuild operators by providing an
/// operation with the same signature as the default implementation. The
/// overridding function should not be virtual.
///
/// Semantic tree transformations are split into two stages, either of which
/// can be replaced by a subclass. The "transform" step transforms an AST node
/// or the parts of an AST node using the various transformation functions,
/// then passes the pieces on to the "rebuild" step, which constructs a new AST
/// node of the appropriate kind from the pieces. The default transformation
/// routines recursively transform the operands to composite AST nodes (e.g.,
/// the pointee type of a PointerType node) and, if any of those operand nodes
/// were changed by the transformation, invokes the rebuild operation to create
/// a new AST node.
///
/// Subclasses can customize the transformation at various levels. The
/// most coarse-grained transformations involve replacing TransformType(),
/// TransformExpr(), TransformDecl(), TransformNestedNameSpecifier(),
/// TransformTemplateName(), or TransformTemplateArgument() with entirely
/// new implementations.
///
/// For more fine-grained transformations, subclasses can replace any of the
/// \c TransformXXX functions (where XXX is the name of an AST node, e.g.,
/// PointerType) to alter the transformation. As mentioned previously,
/// replacing TransformTemplateTypeParmType() allows template instantiation
/// to substitute template arguments for their corresponding template
/// parameters. Additionally, subclasses can override the \c RebuildXXX
/// functions to control how AST nodes are rebuilt when their operands change.
/// By default, \c TreeTransform will invoke semantic analysis to rebuild
/// AST nodes. However, certain other tree transformations (e.g, cloning) may
/// be able to use more efficient rebuild steps.
///
/// There are a handful of other functions that can be overridden, allowing one
/// to avoid traversing nodes that don't need any transformation
/// (\c AlreadyTransformed()), force rebuilding AST nodes even when their
/// operands have not changed (\c AlwaysRebuild()), and customize the
/// default locations and entity names used for type-checking
/// (\c getBaseLocation(), \c getBaseEntity()).
///
/// FIXME: In the future, TreeTransform will support transformation of
/// statements and expressions as well as types.
template<typename Derived>
class TreeTransform {
protected:
Sema &SemaRef;
public:
/// \brief Initializes a new tree transformer.
TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { }
/// \brief Retrieves a reference to the derived class.
Derived &getDerived() { return static_cast<Derived&>(*this); }
/// \brief Retrieves a reference to the derived class.
const Derived &getDerived() const {
return static_cast<const Derived&>(*this);
}
/// \brief Retrieves a reference to the semantic analysis object used for
/// this tree transform.
Sema &getSema() const { return SemaRef; }
/// \brief Whether the transformation should always rebuild AST nodes, even
/// if none of the children have changed.
///
/// Subclasses may override this function to specify when the transformation
/// should rebuild all AST nodes.
bool AlwaysRebuild() { return false; }
/// \brief Returns the location of the entity being transformed, if that
/// information was not available elsewhere in the AST.
///
/// By default, returns no source-location information. Subclasses can
/// provide an alternative implementation that provides better location
/// information.
SourceLocation getBaseLocation() { return SourceLocation(); }
/// \brief Returns the name of the entity being transformed, if that
/// information was not available elsewhere in the AST.
///
/// By default, returns an empty name. Subclasses can provide an alternative
/// implementation with a more precise name.
DeclarationName getBaseEntity() { return DeclarationName(); }
/// \brief Determine whether the given type \p T has already been
/// transformed.
///
/// Subclasses can provide an alternative implementation of this routine
/// to short-circuit evaluation when it is known that a given type will
/// not change. For example, template instantiation need not traverse
/// non-dependent types.
bool AlreadyTransformed(QualType T) {
return T.isNull();
}
/// \brief Transforms the given type into another type.
///
/// By default, this routine transforms a type by delegating to the
/// appropriate TransformXXXType to build a new type, then applying
/// the qualifiers on \p T to the resulting type with AddTypeQualifiers.
/// Subclasses may override this function (to take over all type
/// transformations), some set of the TransformXXXType functions, or
/// the AddTypeQualifiers function to alter the transformation.
///
/// \returns the transformed type.
QualType TransformType(QualType T);
/// \brief Transform the given type by adding the given set of qualifiers
/// and returning the result.
///
/// FIXME: By default, this routine adds type qualifiers only to types that
/// can have qualifiers, and silently suppresses those qualifiers that are
/// not permitted (e.g., qualifiers on reference or function types). This
/// is the right thing for template instantiation, but probably not for
/// other clients.
QualType AddTypeQualifiers(QualType T, unsigned CVRQualifiers);
/// \brief Transform the given expression.
///
/// FIXME: At the moment, subclasses must override this.
Sema::OwningExprResult TransformExpr(Expr *E);
/// \brief Transform the given declaration, which is referenced from a type
/// or expression.
///
/// By default, acts as the identity function on declarations. Subclasses
/// may override this function to provide alternate behavior.
Decl *TransformDecl(Decl *D) { return D; }
/// \brief Transform the given nested-name-specifier.
///
/// By default, transforms all of the types and declarations within the
/// nested-name-specifier. Subclasses may override this function to provide
/// alternate behavior.
NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
SourceRange Range);
/// \brief Transform the given template name.
///
/// FIXME: At the moment, subclasses must override this.
TemplateName TransformTemplateName(TemplateName Template);
/// \brief Transform the given template argument.
///
/// By default, this operation transforms the type, expression, or
/// declaration stored within the template argument and constructs a
/// new template argument from the transformed result. Subclasses may
/// override this function to provide alternate behavior.
TemplateArgument TransformTemplateArgument(const TemplateArgument &Arg);
#define ABSTRACT_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) \
QualType Transform##CLASS##Type(const CLASS##Type *T);
#include "clang/AST/TypeNodes.def"
/// \brief Build a new pointer type given its pointee type.
///
/// By default, performs semantic analysis when building the pointer type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildPointerType(QualType PointeeType);
/// \brief Build a new block pointer type given its pointee type.
///
/// By default, performs semantic analysis when building the block pointer
/// type. Subclasses may override this routine to provide different behavior.
QualType RebuildBlockPointerType(QualType PointeeType);
/// \brief Build a new lvalue reference type given the type it references.
///
/// By default, performs semantic analysis when building the lvalue reference
/// type. Subclasses may override this routine to provide different behavior.
QualType RebuildLValueReferenceType(QualType ReferentType);
/// \brief Build a new rvalue reference type given the type it references.
///
/// By default, performs semantic analysis when building the rvalue reference
/// type. Subclasses may override this routine to provide different behavior.
QualType RebuildRValueReferenceType(QualType ReferentType);
/// \brief Build a new member pointer type given the pointee type and the
/// class type it refers into.
///
/// By default, performs semantic analysis when building the member pointer
/// type. Subclasses may override this routine to provide different behavior.
QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType);
/// \brief Build a new array type given the element type, size
/// modifier, size of the array (if known), size expression, and index type
/// qualifiers.
///
/// By default, performs semantic analysis when building the array type.
/// Subclasses may override this routine to provide different behavior.
/// Also by default, all of the other Rebuild*Array
QualType RebuildArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt *Size,
Expr *SizeExpr,
unsigned IndexTypeQuals,
SourceRange BracketsRange);
/// \brief Build a new constant array type given the element type, size
/// modifier, (known) size of the array, and index type qualifiers.
///
/// By default, performs semantic analysis when building the array type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildConstantArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt &Size,
unsigned IndexTypeQuals);
/// \brief Build a new constant array type given the element type, size
/// modifier, (known) size of the array, size expression, and index type
/// qualifiers.
///
/// By default, performs semantic analysis when building the array type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildConstantArrayWithExprType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt &Size,
Expr *SizeExpr,
unsigned IndexTypeQuals,
SourceRange BracketsRange);
/// \brief Build a new constant array type given the element type, size
/// modifier, (known) size of the array, and index type qualifiers.
///
/// By default, performs semantic analysis when building the array type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildConstantArrayWithoutExprType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt &Size,
unsigned IndexTypeQuals);
/// \brief Build a new incomplete array type given the element type, size
/// modifier, and index type qualifiers.
///
/// By default, performs semantic analysis when building the array type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildIncompleteArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
unsigned IndexTypeQuals);
/// \brief Build a new variable-length array type given the element type,
/// size modifier, size expression, and index type qualifiers.
///
/// By default, performs semantic analysis when building the array type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildVariableArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
Sema::ExprArg SizeExpr,
unsigned IndexTypeQuals,
SourceRange BracketsRange);
/// \brief Build a new dependent-sized array type given the element type,
/// size modifier, size expression, and index type qualifiers.
///
/// By default, performs semantic analysis when building the array type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildDependentSizedArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
Sema::ExprArg SizeExpr,
unsigned IndexTypeQuals,
SourceRange BracketsRange);
/// \brief Build a new vector type given the element type and
/// number of elements.
///
/// By default, performs semantic analysis when building the vector type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildVectorType(QualType ElementType, unsigned NumElements);
/// \brief Build a new extended vector type given the element type and
/// number of elements.
///
/// By default, performs semantic analysis when building the vector type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildExtVectorType(QualType ElementType, unsigned NumElements,
SourceLocation AttributeLoc);
/// \brief Build a new potentially dependently-sized extended vector type
/// given the element type and number of elements.
///
/// By default, performs semantic analysis when building the vector type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildDependentSizedExtVectorType(QualType ElementType,
Sema::ExprArg SizeExpr,
SourceLocation AttributeLoc);
/// \brief Build a new function type.
///
/// By default, performs semantic analysis when building the function type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildFunctionProtoType(QualType T,
QualType *ParamTypes,
unsigned NumParamTypes,
bool Variadic, unsigned Quals);
/// \brief Build a new typedef type.
QualType RebuildTypedefType(TypedefDecl *Typedef) {
return SemaRef.Context.getTypeDeclType(Typedef);
}
/// \brief Build a new class/struct/union type.
QualType RebuildRecordType(RecordDecl *Record) {
return SemaRef.Context.getTypeDeclType(Record);
}
/// \brief Build a new Enum type.
QualType RebuildEnumType(EnumDecl *Enum) {
return SemaRef.Context.getTypeDeclType(Enum);
}
/// \brief Build a new typeof(expr) type.
///
/// By default, performs semantic analysis when building the typeof type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildTypeOfExprType(Sema::ExprArg Underlying);
/// \brief Build a new typeof(type) type.
///
/// By default, builds a new TypeOfType with the given underlying type.
QualType RebuildTypeOfType(QualType Underlying);
/// \brief Build a new C++0x decltype type.
///
/// By default, performs semantic analysis when building the decltype type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildDecltypeType(Sema::ExprArg Underlying);
/// \brief Build a new template specialization type.
///
/// By default, performs semantic analysis when building the template
/// specialization type. Subclasses may override this routine to provide
/// different behavior.
QualType RebuildTemplateSpecializationType(TemplateName Template,
const TemplateArgument *Args,
unsigned NumArgs);
/// \brief Build a new qualified name type.
///
/// By default, builds a new QualifiedNameType type from the
/// nested-name-specifier and the named type. Subclasses may override
/// this routine to provide different behavior.
QualType RebuildQualifiedNameType(NestedNameSpecifier *NNS, QualType Named) {
return SemaRef.Context.getQualifiedNameType(NNS, Named);
}
/// \brief Build a new typename type that refers to a template-id.
///
/// By default, builds a new TypenameType type from the nested-name-specifier
/// and the given type. Subclasses may override this routine to provide
/// different behavior.
QualType RebuildTypenameType(NestedNameSpecifier *NNS, QualType T) {
if (NNS->isDependent())
return SemaRef.Context.getTypenameType(NNS,
cast<TemplateSpecializationType>(T));
return SemaRef.Context.getQualifiedNameType(NNS, T);
}
/// \brief Build a new typename type that refers to an identifier.
///
/// By default, performs semantic analysis when building the typename type
/// (or qualified name type). Subclasses may override this routine to provide
/// different behavior.
QualType RebuildTypenameType(NestedNameSpecifier *NNS,
const IdentifierInfo *Id) {
return SemaRef.CheckTypenameType(NNS, *Id,
SourceRange(getDerived().getBaseLocation()));
}
/// \brief Build a new nested-name-specifier given the prefix and an
/// identifier that names the next step in the nested-name-specifier.
///
/// By default, performs semantic analysis when building the new
/// nested-name-specifier. Subclasses may override this routine to provide
/// different behavior.
NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
SourceRange Range,
IdentifierInfo &II);
/// \brief Build a new nested-name-specifier given the prefix and the
/// namespace named in the next step in the nested-name-specifier.
///
/// By default, performs semantic analysis when building the new
/// nested-name-specifier. Subclasses may override this routine to provide
/// different behavior.
NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
SourceRange Range,
NamespaceDecl *NS);
/// \brief Build a new nested-name-specifier given the prefix and the
/// type named in the next step in the nested-name-specifier.
///
/// By default, performs semantic analysis when building the new
/// nested-name-specifier. Subclasses may override this routine to provide
/// different behavior.
NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
SourceRange Range,
bool TemplateKW,
QualType T);
};
template<typename Derived>
NestedNameSpecifier *
TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
SourceRange Range) {
// Instantiate the prefix of this nested name specifier.
NestedNameSpecifier *Prefix = NNS->getPrefix();
if (Prefix) {
Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range);
if (!Prefix)
return 0;
}
switch (NNS->getKind()) {
case NestedNameSpecifier::Identifier:
assert(Prefix &&
"Can't have an identifier nested-name-specifier with no prefix");
if (!getDerived().AlwaysRebuild() && Prefix == NNS->getPrefix())
return NNS;
return getDerived().RebuildNestedNameSpecifier(Prefix, Range,
*NNS->getAsIdentifier());
case NestedNameSpecifier::Namespace: {
NamespaceDecl *NS
= cast_or_null<NamespaceDecl>(
getDerived().TransformDecl(NNS->getAsNamespace()));
if (!getDerived().AlwaysRebuild() &&
Prefix == NNS->getPrefix() &&
NS == NNS->getAsNamespace())
return NNS;
return getDerived().RebuildNestedNameSpecifier(Prefix, Range, NS);
}
case NestedNameSpecifier::Global:
// There is no meaningful transformation that one could perform on the
// global scope.
return NNS;
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::TypeSpec: {
QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0));
if (!getDerived().AlwaysRebuild() &&
Prefix == NNS->getPrefix() &&
T == QualType(NNS->getAsType(), 0))
return NNS;
return getDerived().RebuildNestedNameSpecifier(Prefix, Range,
NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate,
T);
}
}
// Required to silence a GCC warning
return 0;
}
template<typename Derived>
TemplateArgument
TreeTransform<Derived>::TransformTemplateArgument(const TemplateArgument &Arg) {
switch (Arg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Integral:
return Arg;
case TemplateArgument::Type: {
QualType T = getDerived().TransformType(Arg.getAsType());
if (T.isNull())
return TemplateArgument();
return TemplateArgument(Arg.getLocation(), T);
}
case TemplateArgument::Declaration: {
Decl *D = getDerived().TransformDecl(Arg.getAsDecl());
if (!D)
return TemplateArgument();
return TemplateArgument(Arg.getLocation(), D);
}
case TemplateArgument::Expression: {
// Template argument expressions are not potentially evaluated.
EnterExpressionEvaluationContext Unevaluated(getSema(),
Action::Unevaluated);
Sema::OwningExprResult E = getDerived().TransformExpr(Arg.getAsExpr());
if (E.isInvalid())
return TemplateArgument();
return TemplateArgument(E.takeAs<Expr>());
}
case TemplateArgument::Pack: {
llvm::SmallVector<TemplateArgument, 4> TransformedArgs;
TransformedArgs.reserve(Arg.pack_size());
for (TemplateArgument::pack_iterator A = Arg.pack_begin(),
AEnd = Arg.pack_end();
A != AEnd; ++A) {
TemplateArgument TA = getDerived().TransformTemplateArgument(*A);
if (TA.isNull())
return TA;
TransformedArgs.push_back(TA);
}
TemplateArgument Result;
Result.setArgumentPack(TransformedArgs.data(), TransformedArgs.size(),
true);
return Result;
}
}
// Work around bogus GCC warning
return TemplateArgument();
}
//===----------------------------------------------------------------------===//
// Type transformation
//===----------------------------------------------------------------------===//
template<typename Derived>
QualType TreeTransform<Derived>::TransformType(QualType T) {
if (getDerived().AlreadyTransformed(T))
return T;
QualType Result;
switch (T->getTypeClass()) {
#define ABSTRACT_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) \
case Type::CLASS: \
Result = getDerived().Transform##CLASS##Type( \
static_cast<CLASS##Type*>(T.getTypePtr())); \
break;
#include "clang/AST/TypeNodes.def"
}
if (Result.isNull() || T == Result)
return Result;
return getDerived().AddTypeQualifiers(Result, T.getCVRQualifiers());
}
template<typename Derived>
QualType
TreeTransform<Derived>::AddTypeQualifiers(QualType T, unsigned CVRQualifiers) {
if (CVRQualifiers && !T->isFunctionType() && !T->isReferenceType())
return T.getWithAdditionalQualifiers(CVRQualifiers);
return T;
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformExtQualType(const ExtQualType *T) {
// FIXME: Implement
return QualType(T, 0);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformBuiltinType(const BuiltinType *T) {
// Nothing to do
return QualType(T, 0);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformFixedWidthIntType(
const FixedWidthIntType *T) {
// FIXME: Implement
return QualType(T, 0);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformComplexType(const ComplexType *T) {
// FIXME: Implement
return QualType(T, 0);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformPointerType(const PointerType *T) {
QualType PointeeType = getDerived().TransformType(T->getPointeeType());
if (PointeeType.isNull())
return QualType();
if (!getDerived().AlwaysRebuild() &&
PointeeType == T->getPointeeType())
return QualType(T, 0);
return getDerived().RebuildPointerType(PointeeType);
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformBlockPointerType(const BlockPointerType *T) {
QualType PointeeType = getDerived().TransformType(T->getPointeeType());
if (PointeeType.isNull())
return QualType();
if (!getDerived().AlwaysRebuild() &&
PointeeType == T->getPointeeType())
return QualType(T, 0);
return getDerived().RebuildBlockPointerType(PointeeType);
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformLValueReferenceType(
const LValueReferenceType *T) {
QualType PointeeType = getDerived().TransformType(T->getPointeeType());
if (PointeeType.isNull())
return QualType();
if (!getDerived().AlwaysRebuild() &&
PointeeType == T->getPointeeType())
return QualType(T, 0);
return getDerived().RebuildLValueReferenceType(PointeeType);
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformRValueReferenceType(
const RValueReferenceType *T) {
QualType PointeeType = getDerived().TransformType(T->getPointeeType());
if (PointeeType.isNull())
return QualType();
if (!getDerived().AlwaysRebuild() &&
PointeeType == T->getPointeeType())
return QualType(T, 0);
return getDerived().RebuildRValueReferenceType(PointeeType);
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformMemberPointerType(const MemberPointerType *T) {
QualType PointeeType = getDerived().TransformType(T->getPointeeType());
if (PointeeType.isNull())
return QualType();
QualType ClassType = getDerived().TransformType(QualType(T->getClass(), 0));
if (ClassType.isNull())
return QualType();
if (!getDerived().AlwaysRebuild() &&
PointeeType == T->getPointeeType() &&
ClassType == QualType(T->getClass(), 0))
return QualType(T, 0);
return getDerived().RebuildMemberPointerType(PointeeType, ClassType);
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformConstantArrayType(const ConstantArrayType *T) {
QualType ElementType = getDerived().TransformType(T->getElementType());
if (ElementType.isNull())
return QualType();
if (!getDerived().AlwaysRebuild() &&
ElementType == T->getElementType())
return QualType(T, 0);
return getDerived().RebuildConstantArrayType(ElementType,
T->getSizeModifier(),
T->getSize(),
T->getIndexTypeQualifier());
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformConstantArrayWithExprType(
const ConstantArrayWithExprType *T) {
QualType ElementType = getDerived().TransformType(T->getElementType());
if (ElementType.isNull())
return QualType();
// Array bounds are not potentially evaluated contexts
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr());
if (Size.isInvalid())
return QualType();
if (!getDerived().AlwaysRebuild() &&
ElementType == T->getElementType() &&
Size.get() == T->getSizeExpr())
return QualType(T, 0);
return getDerived().RebuildConstantArrayWithExprType(ElementType,
T->getSizeModifier(),
T->getSize(),
Size.takeAs<Expr>(),
T->getIndexTypeQualifier(),
T->getBracketsRange());
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformConstantArrayWithoutExprType(
const ConstantArrayWithoutExprType *T) {
QualType ElementType = getDerived().TransformType(T->getElementType());
if (ElementType.isNull())
return QualType();
if (!getDerived().AlwaysRebuild() &&
ElementType == T->getElementType())
return QualType(T, 0);
return getDerived().RebuildConstantArrayWithoutExprType(ElementType,
T->getSizeModifier(),
T->getSize(),
T->getIndexTypeQualifier());
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformIncompleteArrayType(
const IncompleteArrayType *T) {
QualType ElementType = getDerived().TransformType(T->getElementType());
if (ElementType.isNull())
return QualType();
if (!getDerived().AlwaysRebuild() &&
ElementType == T->getElementType())
return QualType(T, 0);
return getDerived().RebuildIncompleteArrayType(ElementType,
T->getSizeModifier(),
T->getIndexTypeQualifier());
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformVariableArrayType(
const VariableArrayType *T) {
QualType ElementType = getDerived().TransformType(T->getElementType());
if (ElementType.isNull())
return QualType();
// Array bounds are not potentially evaluated contexts
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr());
if (Size.isInvalid())
return QualType();
if (!getDerived().AlwaysRebuild() &&
ElementType == T->getElementType() &&
Size.get() == T->getSizeExpr()) {
Size.take();
return QualType(T, 0);
}
return getDerived().RebuildVariableArrayType(ElementType,
T->getSizeModifier(),
move(Size),
T->getIndexTypeQualifier(),
T->getBracketsRange());
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformDependentSizedArrayType(
const DependentSizedArrayType *T) {
QualType ElementType = getDerived().TransformType(T->getElementType());
if (ElementType.isNull())
return QualType();
// Array bounds are not potentially evaluated contexts
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr());
if (Size.isInvalid())
return QualType();
if (!getDerived().AlwaysRebuild() &&
ElementType == T->getElementType() &&
Size.get() == T->getSizeExpr()) {
Size.take();
return QualType(T, 0);
}
return getDerived().RebuildDependentSizedArrayType(ElementType,
T->getSizeModifier(),
move(Size),
T->getIndexTypeQualifier(),
T->getBracketsRange());
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType(
const DependentSizedExtVectorType *T) {
QualType ElementType = getDerived().TransformType(T->getElementType());
if (ElementType.isNull())
return QualType();
// Vector sizes are not potentially evaluated contexts
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr());
if (Size.isInvalid())
return QualType();
if (!getDerived().AlwaysRebuild() &&
ElementType == T->getElementType() &&
Size.get() == T->getSizeExpr()) {
Size.take();
return QualType(T, 0);
}
return getDerived().RebuildDependentSizedExtVectorType(ElementType,
move(Size),
T->getAttributeLoc());
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformVectorType(const VectorType *T) {
QualType ElementType = getDerived().TransformType(T->getElementType());
if (ElementType.isNull())
return QualType();
if (!getDerived().AlwaysRebuild() &&
ElementType == T->getElementType())
return QualType(T, 0);
return getDerived().RebuildVectorType(ElementType, T->getNumElements());
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformExtVectorType(const ExtVectorType *T) {
QualType ElementType = getDerived().TransformType(T->getElementType());
if (ElementType.isNull())
return QualType();
if (!getDerived().AlwaysRebuild() &&
ElementType == T->getElementType())
return QualType(T, 0);
return getDerived().RebuildExtVectorType(ElementType, T->getNumElements(),
/*FIXME*/SourceLocation());
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformFunctionProtoType(
const FunctionProtoType *T) {
QualType ResultType = getDerived().TransformType(T->getResultType());
if (ResultType.isNull())
return QualType();
llvm::SmallVector<QualType, 4> ParamTypes;
for (FunctionProtoType::arg_type_iterator Param = T->arg_type_begin(),
ParamEnd = T->arg_type_end();
Param != ParamEnd; ++Param) {
QualType P = getDerived().TransformType(*Param);
if (P.isNull())
return QualType();
ParamTypes.push_back(P);
}
if (!getDerived().AlwaysRebuild() &&
ResultType == T->getResultType() &&
std::equal(T->arg_type_begin(), T->arg_type_end(), ParamTypes.begin()))
return QualType(T, 0);
return getDerived().RebuildFunctionProtoType(ResultType, ParamTypes.data(),
ParamTypes.size(), T->isVariadic(),
T->getTypeQuals());
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformFunctionNoProtoType(
const FunctionNoProtoType *T) {
// FIXME: Implement
return QualType(T, 0);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformTypedefType(const TypedefType *T) {
TypedefDecl *Typedef
= cast_or_null<TypedefDecl>(getDerived().TransformDecl(T->getDecl()));
if (!Typedef)
return QualType();
if (!getDerived().AlwaysRebuild() &&
Typedef == T->getDecl())
return QualType(T, 0);
return getDerived().RebuildTypedefType(Typedef);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformTypeOfExprType(
const TypeOfExprType *T) {
// typeof expressions are not potentially evaluated contexts
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
Sema::OwningExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr());
if (E.isInvalid())
return QualType();
if (!getDerived().AlwaysRebuild() &&
E.get() == T->getUnderlyingExpr()) {
E.take();
return QualType(T, 0);
}
return getDerived().RebuildTypeOfExprType(move(E));
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformTypeOfType(const TypeOfType *T) {
QualType Underlying = getDerived().TransformType(T->getUnderlyingType());
if (Underlying.isNull())
return QualType();
if (!getDerived().AlwaysRebuild() &&
Underlying == T->getUnderlyingType())
return QualType(T, 0);
return getDerived().RebuildTypeOfType(Underlying);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformDecltypeType(const DecltypeType *T) {
// decltype expressions are not potentially evaluated contexts
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
Sema::OwningExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr());
if (E.isInvalid())
return QualType();
if (!getDerived().AlwaysRebuild() &&
E.get() == T->getUnderlyingExpr()) {
E.take();
return QualType(T, 0);
}
return getDerived().RebuildDecltypeType(move(E));
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformRecordType(const RecordType *T) {
RecordDecl *Record
= cast_or_null<RecordDecl>(getDerived().TransformDecl(T->getDecl()));
if (!Record)
return QualType();
if (!getDerived().AlwaysRebuild() &&
Record == T->getDecl())
return QualType(T, 0);
return getDerived().RebuildRecordType(Record);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformEnumType(const EnumType *T) {
EnumDecl *Enum
= cast_or_null<EnumDecl>(getDerived().TransformDecl(T->getDecl()));
if (!Enum)
return QualType();
if (!getDerived().AlwaysRebuild() &&
Enum == T->getDecl())
return QualType(T, 0);
return getDerived().RebuildEnumType(Enum);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformTemplateTypeParmType(
const TemplateTypeParmType *T) {
// Nothing to do
return QualType(T, 0);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
const TemplateSpecializationType *T) {
TemplateName Template
= getDerived().TransformTemplateName(T->getTemplateName());
if (Template.isNull())
return QualType();
llvm::SmallVector<TemplateArgument, 4> NewTemplateArgs;
NewTemplateArgs.reserve(T->getNumArgs());
for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end();
Arg != ArgEnd; ++Arg) {
TemplateArgument NewArg = getDerived().TransformTemplateArgument(*Arg);
if (NewArg.isNull())
return QualType();
NewTemplateArgs.push_back(NewArg);
}
// FIXME: early abort if all of the template arguments and such are the
// same.
// FIXME: We're missing the locations of the template name, '<', and '>'.
return getDerived().RebuildTemplateSpecializationType(Template,
NewTemplateArgs.data(),
NewTemplateArgs.size());
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformQualifiedNameType(
const QualifiedNameType *T) {
NestedNameSpecifier *NNS
= getDerived().TransformNestedNameSpecifier(T->getQualifier(),
SourceRange());
if (!NNS)
return QualType();
QualType Named = getDerived().TransformType(T->getNamedType());
if (Named.isNull())
return QualType();
if (!getDerived().AlwaysRebuild() &&
NNS == T->getQualifier() &&
Named == T->getNamedType())
return QualType(T, 0);
return getDerived().RebuildQualifiedNameType(NNS, Named);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformTypenameType(const TypenameType *T) {
NestedNameSpecifier *NNS
= getDerived().TransformNestedNameSpecifier(T->getQualifier(),
SourceRange(getDerived().getBaseLocation()));
if (!NNS)
return QualType();
if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) {
QualType NewTemplateId
= getDerived().TransformType(QualType(TemplateId, 0));
if (NewTemplateId.isNull())
return QualType();
if (!getDerived().AlwaysRebuild() &&
NNS == T->getQualifier() &&
NewTemplateId == QualType(TemplateId, 0))
return QualType(T, 0);
return getDerived().RebuildTypenameType(NNS, NewTemplateId);
}
return getDerived().RebuildTypenameType(NNS, T->getIdentifier());
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformObjCInterfaceType(
const ObjCInterfaceType *T) {
// FIXME: Implement
return QualType(T, 0);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformObjCObjectPointerType(
const ObjCObjectPointerType *T) {
// FIXME: Implement
return QualType(T, 0);
}
//===----------------------------------------------------------------------===//
// Type reconstruction
//===----------------------------------------------------------------------===//
template<typename Derived>
QualType TreeTransform<Derived>::RebuildPointerType(QualType PointeeType) {
return SemaRef.BuildPointerType(PointeeType, 0,
getDerived().getBaseLocation(),
getDerived().getBaseEntity());
}
template<typename Derived>
QualType TreeTransform<Derived>::RebuildBlockPointerType(QualType PointeeType) {
return SemaRef.BuildBlockPointerType(PointeeType, 0,
getDerived().getBaseLocation(),
getDerived().getBaseEntity());
}
template<typename Derived>
QualType
TreeTransform<Derived>::RebuildLValueReferenceType(QualType ReferentType) {
return SemaRef.BuildReferenceType(ReferentType, true, 0,
getDerived().getBaseLocation(),
getDerived().getBaseEntity());
}
template<typename Derived>
QualType
TreeTransform<Derived>::RebuildRValueReferenceType(QualType ReferentType) {
return SemaRef.BuildReferenceType(ReferentType, false, 0,
getDerived().getBaseLocation(),
getDerived().getBaseEntity());
}
template<typename Derived>
QualType TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType,
QualType ClassType) {
return SemaRef.BuildMemberPointerType(PointeeType, ClassType, 0,
getDerived().getBaseLocation(),
getDerived().getBaseEntity());
}
template<typename Derived>
QualType
TreeTransform<Derived>::RebuildArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt *Size,
Expr *SizeExpr,
unsigned IndexTypeQuals,
SourceRange BracketsRange) {
if (SizeExpr || !Size)
return SemaRef.BuildArrayType(ElementType, SizeMod, SizeExpr,
IndexTypeQuals, BracketsRange,
getDerived().getBaseEntity());
QualType Types[] = {
SemaRef.Context.UnsignedCharTy, SemaRef.Context.UnsignedShortTy,
SemaRef.Context.UnsignedIntTy, SemaRef.Context.UnsignedLongTy,
SemaRef.Context.UnsignedLongLongTy, SemaRef.Context.UnsignedInt128Ty
};
const unsigned NumTypes = sizeof(Types) / sizeof(QualType);
QualType SizeType;
for (unsigned I = 0; I != NumTypes; ++I)
if (Size->getBitWidth() == SemaRef.Context.getIntWidth(Types[I])) {
SizeType = Types[I];
break;
}
if (SizeType.isNull())
SizeType = SemaRef.Context.getFixedWidthIntType(Size->getBitWidth(), false);
IntegerLiteral ArraySize(*Size, SizeType, /*FIXME*/BracketsRange.getBegin());
return SemaRef.BuildArrayType(ElementType, SizeMod, &ArraySize,
IndexTypeQuals, BracketsRange,
getDerived().getBaseEntity());
}
template<typename Derived>
QualType
TreeTransform<Derived>::RebuildConstantArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt &Size,
unsigned IndexTypeQuals) {
return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0,
IndexTypeQuals, SourceRange());
}
template<typename Derived>
QualType
TreeTransform<Derived>::RebuildConstantArrayWithExprType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt &Size,
Expr *SizeExpr,
unsigned IndexTypeQuals,
SourceRange BracketsRange) {
return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, SizeExpr,
IndexTypeQuals, BracketsRange);
}
template<typename Derived>
QualType
TreeTransform<Derived>::RebuildConstantArrayWithoutExprType(
QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt &Size,
unsigned IndexTypeQuals) {
return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0,
IndexTypeQuals, SourceRange());
}
template<typename Derived>
QualType
TreeTransform<Derived>::RebuildIncompleteArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
unsigned IndexTypeQuals) {
return getDerived().RebuildArrayType(ElementType, SizeMod, 0, 0,
IndexTypeQuals, SourceRange());
}
template<typename Derived>
QualType
TreeTransform<Derived>::RebuildVariableArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
Sema::ExprArg SizeExpr,
unsigned IndexTypeQuals,
SourceRange BracketsRange) {
return getDerived().RebuildArrayType(ElementType, SizeMod, 0,
SizeExpr.takeAs<Expr>(),
IndexTypeQuals, BracketsRange);
}
template<typename Derived>
QualType
TreeTransform<Derived>::RebuildDependentSizedArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
Sema::ExprArg SizeExpr,
unsigned IndexTypeQuals,
SourceRange BracketsRange) {
return getDerived().RebuildArrayType(ElementType, SizeMod, 0,
SizeExpr.takeAs<Expr>(),
IndexTypeQuals, BracketsRange);
}
template<typename Derived>
QualType TreeTransform<Derived>::RebuildVectorType(QualType ElementType,
unsigned NumElements) {
// FIXME: semantic checking!
return SemaRef.Context.getVectorType(ElementType, NumElements);
}
template<typename Derived>
QualType TreeTransform<Derived>::RebuildExtVectorType(QualType ElementType,
unsigned NumElements,
SourceLocation AttributeLoc) {
llvm::APInt numElements(SemaRef.Context.getIntWidth(SemaRef.Context.IntTy),
NumElements, true);
IntegerLiteral *VectorSize
= new (SemaRef.Context) IntegerLiteral(numElements, SemaRef.Context.IntTy,
AttributeLoc);
return SemaRef.BuildExtVectorType(ElementType, SemaRef.Owned(VectorSize),
AttributeLoc);
}
template<typename Derived>
QualType
TreeTransform<Derived>::RebuildDependentSizedExtVectorType(QualType ElementType,
Sema::ExprArg SizeExpr,
SourceLocation AttributeLoc) {
return SemaRef.BuildExtVectorType(ElementType, move(SizeExpr), AttributeLoc);
}
template<typename Derived>
QualType TreeTransform<Derived>::RebuildFunctionProtoType(QualType T,
QualType *ParamTypes,
unsigned NumParamTypes,
bool Variadic,
unsigned Quals) {
return SemaRef.BuildFunctionType(T, ParamTypes, NumParamTypes, Variadic,
Quals,
getDerived().getBaseLocation(),
getDerived().getBaseEntity());
}
template<typename Derived>
QualType TreeTransform<Derived>::RebuildTypeOfExprType(Sema::ExprArg E) {
return SemaRef.BuildTypeofExprType(E.takeAs<Expr>());
}
template<typename Derived>
QualType TreeTransform<Derived>::RebuildTypeOfType(QualType Underlying) {
return SemaRef.Context.getTypeOfType(Underlying);
}
template<typename Derived>
QualType TreeTransform<Derived>::RebuildDecltypeType(Sema::ExprArg E) {
return SemaRef.BuildDecltypeType(E.takeAs<Expr>());
}
template<typename Derived>
QualType TreeTransform<Derived>::RebuildTemplateSpecializationType(
TemplateName Template,
const TemplateArgument *Args,
unsigned NumArgs) {
// FIXME: Missing source locations for the template name, <, >.
return SemaRef.CheckTemplateIdType(Template, getDerived().getBaseLocation(),
SourceLocation(), Args, NumArgs,
SourceLocation());
}
template<typename Derived>
NestedNameSpecifier *
TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
SourceRange Range,
IdentifierInfo &II) {
CXXScopeSpec SS;
// FIXME: The source location information is all wrong.
SS.setRange(Range);
SS.setScopeRep(Prefix);
return static_cast<NestedNameSpecifier *>(
SemaRef.ActOnCXXNestedNameSpecifier(0, SS, Range.getEnd(),
Range.getEnd(), II));
}
template<typename Derived>
NestedNameSpecifier *
TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
SourceRange Range,
NamespaceDecl *NS) {
return NestedNameSpecifier::Create(SemaRef.Context, Prefix, NS);
}
template<typename Derived>
NestedNameSpecifier *
TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
SourceRange Range,
bool TemplateKW,
QualType T) {
if (T->isDependentType() || T->isRecordType() ||
(SemaRef.getLangOptions().CPlusPlus0x && T->isEnumeralType())) {
assert(T.getCVRQualifiers() == 0 && "Can't get cv-qualifiers here");
return NestedNameSpecifier::Create(SemaRef.Context, Prefix, TemplateKW,
T.getTypePtr());
}
SemaRef.Diag(Range.getBegin(), diag::err_nested_name_spec_non_tag) << T;
return 0;
}
} // end namespace clang
#endif // LLVM_CLANG_SEMA_TREETRANSFORM_H