r354180 - [ObjC] For type substitution in generics use a regular recursive type visitor.
Volodymyr Sapsai via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 15 14:14:58 PST 2019
Author: vsapsai
Date: Fri Feb 15 14:14:58 2019
New Revision: 354180
URL: http://llvm.org/viewvc/llvm-project?rev=354180&view=rev
Log:
[ObjC] For type substitution in generics use a regular recursive type visitor.
Switch to the inheritance-based visitor from the lambda-based visitor to
allow both preorder and postorder customizations during type
transformation. NFC intended.
Reviewers: ahatanak, erik.pilkington
Reviewed By: erik.pilkington
Subscribers: jkorous, dexonsmith, cfe-commits
Differential Revision: https://reviews.llvm.org/D57075
Modified:
cfe/trunk/lib/AST/Type.cpp
Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=354180&r1=354179&r2=354180&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Fri Feb 15 14:14:58 2019
@@ -723,25 +723,30 @@ const ObjCObjectPointerType *ObjCObjectP
return ctx.getObjCObjectPointerType(obj)->castAs<ObjCObjectPointerType>();
}
-template<typename F>
-static QualType simpleTransform(ASTContext &ctx, QualType type, F &&f);
-
namespace {
-/// Visitor used by simpleTransform() to perform the transformation.
-template<typename F>
-struct SimpleTransformVisitor
- : public TypeVisitor<SimpleTransformVisitor<F>, QualType> {
+/// Visitor used to perform a simple type transformation that does not change
+/// the semantics of the type.
+template <typename Derived>
+struct SimpleTransformVisitor : public TypeVisitor<Derived, QualType> {
ASTContext &Ctx;
- F &&TheFunc;
QualType recurse(QualType type) {
- return simpleTransform(Ctx, type, std::move(TheFunc));
+ // Split out the qualifiers from the type.
+ SplitQualType splitType = type.split();
+
+ // Visit the type itself.
+ QualType result = static_cast<Derived *>(this)->Visit(splitType.Ty);
+ if (result.isNull())
+ return result;
+
+ // Reconstruct the transformed type by applying the local qualifiers
+ // from the split type.
+ return Ctx.getQualifiedType(result, splitType.Quals);
}
public:
- SimpleTransformVisitor(ASTContext &ctx, F &&f)
- : Ctx(ctx), TheFunc(std::move(f)) {}
+ explicit SimpleTransformVisitor(ASTContext &ctx) : Ctx(ctx) {}
// None of the clients of this transformation can occur where
// there are dependent types, so skip dependent types.
@@ -1121,220 +1126,205 @@ public:
#undef SUGARED_TYPE_CLASS
};
-} // namespace
-
-/// Perform a simple type transformation that does not change the
-/// semantics of the type.
-template<typename F>
-static QualType simpleTransform(ASTContext &ctx, QualType type, F &&f) {
- // Transform the type. If it changed, return the transformed result.
- QualType transformed = f(type);
- if (transformed.getAsOpaquePtr() != type.getAsOpaquePtr())
- return transformed;
-
- // Split out the qualifiers from the type.
- SplitQualType splitType = type.split();
-
- // Visit the type itself.
- SimpleTransformVisitor<F> visitor(ctx, std::forward<F>(f));
- QualType result = visitor.Visit(splitType.Ty);
- if (result.isNull())
- return result;
-
- // Reconstruct the transformed type by applying the local qualifiers
- // from the split type.
- return ctx.getQualifiedType(result, splitType.Quals);
-}
-
-/// Substitute the given type arguments for Objective-C type
-/// parameters within the given type, recursively.
-QualType QualType::substObjCTypeArgs(
- ASTContext &ctx,
- ArrayRef<QualType> typeArgs,
- ObjCSubstitutionContext context) const {
- return simpleTransform(ctx, *this,
- [&](QualType type) -> QualType {
- SplitQualType splitType = type.split();
+struct SubstObjCTypeArgsVisitor
+ : public SimpleTransformVisitor<SubstObjCTypeArgsVisitor> {
+ using BaseType = SimpleTransformVisitor<SubstObjCTypeArgsVisitor>;
+
+ ArrayRef<QualType> TypeArgs;
+ ObjCSubstitutionContext SubstContext;
+
+ SubstObjCTypeArgsVisitor(ASTContext &ctx, ArrayRef<QualType> typeArgs,
+ ObjCSubstitutionContext context)
+ : BaseType(ctx), TypeArgs(typeArgs), SubstContext(context) {}
+ QualType VisitObjCTypeParamType(const ObjCTypeParamType *OTPTy) {
// Replace an Objective-C type parameter reference with the corresponding
// type argument.
- if (const auto *OTPTy = dyn_cast<ObjCTypeParamType>(splitType.Ty)) {
- ObjCTypeParamDecl *typeParam = OTPTy->getDecl();
- // If we have type arguments, use them.
- if (!typeArgs.empty()) {
- QualType argType = typeArgs[typeParam->getIndex()];
- if (OTPTy->qual_empty())
- return ctx.getQualifiedType(argType, splitType.Quals);
-
- // Apply protocol lists if exists.
- bool hasError;
- SmallVector<ObjCProtocolDecl*, 8> protocolsVec;
- protocolsVec.append(OTPTy->qual_begin(),
- OTPTy->qual_end());
- ArrayRef<ObjCProtocolDecl *> protocolsToApply = protocolsVec;
- QualType resultTy = ctx.applyObjCProtocolQualifiers(argType,
- protocolsToApply, hasError, true/*allowOnPointerType*/);
+ ObjCTypeParamDecl *typeParam = OTPTy->getDecl();
+ // If we have type arguments, use them.
+ if (!TypeArgs.empty()) {
+ QualType argType = TypeArgs[typeParam->getIndex()];
+ if (OTPTy->qual_empty())
+ return argType;
+
+ // Apply protocol lists if exists.
+ bool hasError;
+ SmallVector<ObjCProtocolDecl *, 8> protocolsVec;
+ protocolsVec.append(OTPTy->qual_begin(), OTPTy->qual_end());
+ ArrayRef<ObjCProtocolDecl *> protocolsToApply = protocolsVec;
+ return Ctx.applyObjCProtocolQualifiers(
+ argType, protocolsToApply, hasError, true/*allowOnPointerType*/);
+ }
- return ctx.getQualifiedType(resultTy, splitType.Quals);
- }
+ switch (SubstContext) {
+ case ObjCSubstitutionContext::Ordinary:
+ case ObjCSubstitutionContext::Parameter:
+ case ObjCSubstitutionContext::Superclass:
+ // Substitute the bound.
+ return typeParam->getUnderlyingType();
+
+ case ObjCSubstitutionContext::Result:
+ case ObjCSubstitutionContext::Property: {
+ // Substitute the __kindof form of the underlying type.
+ const auto *objPtr =
+ typeParam->getUnderlyingType()->castAs<ObjCObjectPointerType>();
+
+ // __kindof types, id, and Class don't need an additional
+ // __kindof.
+ if (objPtr->isKindOfType() || objPtr->isObjCIdOrClassType())
+ return typeParam->getUnderlyingType();
+
+ // Add __kindof.
+ const auto *obj = objPtr->getObjectType();
+ QualType resultTy = Ctx.getObjCObjectType(
+ obj->getBaseType(), obj->getTypeArgsAsWritten(), obj->getProtocols(),
+ /*isKindOf=*/true);
- switch (context) {
- case ObjCSubstitutionContext::Ordinary:
- case ObjCSubstitutionContext::Parameter:
- case ObjCSubstitutionContext::Superclass:
- // Substitute the bound.
- return ctx.getQualifiedType(typeParam->getUnderlyingType(),
- splitType.Quals);
-
- case ObjCSubstitutionContext::Result:
- case ObjCSubstitutionContext::Property: {
- // Substitute the __kindof form of the underlying type.
- const auto *objPtr = typeParam->getUnderlyingType()
- ->castAs<ObjCObjectPointerType>();
-
- // __kindof types, id, and Class don't need an additional
- // __kindof.
- if (objPtr->isKindOfType() || objPtr->isObjCIdOrClassType())
- return ctx.getQualifiedType(typeParam->getUnderlyingType(),
- splitType.Quals);
-
- // Add __kindof.
- const auto *obj = objPtr->getObjectType();
- QualType resultTy = ctx.getObjCObjectType(obj->getBaseType(),
- obj->getTypeArgsAsWritten(),
- obj->getProtocols(),
- /*isKindOf=*/true);
-
- // Rebuild object pointer type.
- resultTy = ctx.getObjCObjectPointerType(resultTy);
- return ctx.getQualifiedType(resultTy, splitType.Quals);
- }
+ // Rebuild object pointer type.
+ return Ctx.getObjCObjectPointerType(resultTy);
}
}
+ }
- // If we have a function type, update the context appropriately.
- if (const auto *funcType = dyn_cast<FunctionType>(splitType.Ty)) {
- // Substitute result type.
- QualType returnType = funcType->getReturnType().substObjCTypeArgs(
- ctx,
- typeArgs,
- ObjCSubstitutionContext::Result);
- if (returnType.isNull())
- return {};
+ QualType VisitFunctionType(const FunctionType *funcType) {
+ // If we have a function type, update the substitution context
+ // appropriately.
+
+ //Substitute result type.
+ QualType returnType = funcType->getReturnType().substObjCTypeArgs(
+ Ctx, TypeArgs, ObjCSubstitutionContext::Result);
+ if (returnType.isNull())
+ return {};
- // Handle non-prototyped functions, which only substitute into the result
- // type.
- if (isa<FunctionNoProtoType>(funcType)) {
- // If the return type was unchanged, do nothing.
- if (returnType.getAsOpaquePtr()
- == funcType->getReturnType().getAsOpaquePtr())
- return type;
+ // Handle non-prototyped functions, which only substitute into the result
+ // type.
+ if (isa<FunctionNoProtoType>(funcType)) {
+ // If the return type was unchanged, do nothing.
+ if (returnType.getAsOpaquePtr() ==
+ funcType->getReturnType().getAsOpaquePtr())
+ return BaseType::VisitFunctionType(funcType);
- // Otherwise, build a new type.
- return ctx.getFunctionNoProtoType(returnType, funcType->getExtInfo());
- }
+ // Otherwise, build a new type.
+ return Ctx.getFunctionNoProtoType(returnType, funcType->getExtInfo());
+ }
- const auto *funcProtoType = cast<FunctionProtoType>(funcType);
+ const auto *funcProtoType = cast<FunctionProtoType>(funcType);
- // Transform parameter types.
- SmallVector<QualType, 4> paramTypes;
- bool paramChanged = false;
- for (auto paramType : funcProtoType->getParamTypes()) {
- QualType newParamType = paramType.substObjCTypeArgs(
- ctx,
- typeArgs,
- ObjCSubstitutionContext::Parameter);
- if (newParamType.isNull())
- return {};
+ // Transform parameter types.
+ SmallVector<QualType, 4> paramTypes;
+ bool paramChanged = false;
+ for (auto paramType : funcProtoType->getParamTypes()) {
+ QualType newParamType = paramType.substObjCTypeArgs(
+ Ctx, TypeArgs, ObjCSubstitutionContext::Parameter);
+ if (newParamType.isNull())
+ return {};
- if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr())
- paramChanged = true;
+ if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr())
+ paramChanged = true;
- paramTypes.push_back(newParamType);
- }
+ paramTypes.push_back(newParamType);
+ }
- // Transform extended info.
- FunctionProtoType::ExtProtoInfo info = funcProtoType->getExtProtoInfo();
- bool exceptionChanged = false;
- if (info.ExceptionSpec.Type == EST_Dynamic) {
- SmallVector<QualType, 4> exceptionTypes;
- for (auto exceptionType : info.ExceptionSpec.Exceptions) {
- QualType newExceptionType = exceptionType.substObjCTypeArgs(
- ctx,
- typeArgs,
- ObjCSubstitutionContext::Ordinary);
- if (newExceptionType.isNull())
- return {};
-
- if (newExceptionType.getAsOpaquePtr()
- != exceptionType.getAsOpaquePtr())
- exceptionChanged = true;
+ // Transform extended info.
+ FunctionProtoType::ExtProtoInfo info = funcProtoType->getExtProtoInfo();
+ bool exceptionChanged = false;
+ if (info.ExceptionSpec.Type == EST_Dynamic) {
+ SmallVector<QualType, 4> exceptionTypes;
+ for (auto exceptionType : info.ExceptionSpec.Exceptions) {
+ QualType newExceptionType = exceptionType.substObjCTypeArgs(
+ Ctx, TypeArgs, ObjCSubstitutionContext::Ordinary);
+ if (newExceptionType.isNull())
+ return {};
- exceptionTypes.push_back(newExceptionType);
- }
+ if (newExceptionType.getAsOpaquePtr() != exceptionType.getAsOpaquePtr())
+ exceptionChanged = true;
- if (exceptionChanged) {
- info.ExceptionSpec.Exceptions =
- llvm::makeArrayRef(exceptionTypes).copy(ctx);
- }
+ exceptionTypes.push_back(newExceptionType);
}
- if (returnType.getAsOpaquePtr()
- == funcProtoType->getReturnType().getAsOpaquePtr() &&
- !paramChanged && !exceptionChanged)
- return type;
-
- return ctx.getFunctionType(returnType, paramTypes, info);
+ if (exceptionChanged) {
+ info.ExceptionSpec.Exceptions =
+ llvm::makeArrayRef(exceptionTypes).copy(Ctx);
+ }
}
+ if (returnType.getAsOpaquePtr() ==
+ funcProtoType->getReturnType().getAsOpaquePtr() &&
+ !paramChanged && !exceptionChanged)
+ return BaseType::VisitFunctionType(funcType);
+
+ return Ctx.getFunctionType(returnType, paramTypes, info);
+ }
+
+ QualType VisitObjCObjectType(const ObjCObjectType *objcObjectType) {
// Substitute into the type arguments of a specialized Objective-C object
// type.
- if (const auto *objcObjectType = dyn_cast<ObjCObjectType>(splitType.Ty)) {
- if (objcObjectType->isSpecializedAsWritten()) {
- SmallVector<QualType, 4> newTypeArgs;
- bool anyChanged = false;
- for (auto typeArg : objcObjectType->getTypeArgsAsWritten()) {
- QualType newTypeArg = typeArg.substObjCTypeArgs(
- ctx, typeArgs,
- ObjCSubstitutionContext::Ordinary);
- if (newTypeArg.isNull())
- return {};
-
- if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) {
- // If we're substituting based on an unspecialized context type,
- // produce an unspecialized type.
- ArrayRef<ObjCProtocolDecl *> protocols(
- objcObjectType->qual_begin(),
- objcObjectType->getNumProtocols());
- if (typeArgs.empty() &&
- context != ObjCSubstitutionContext::Superclass) {
- return ctx.getObjCObjectType(
- objcObjectType->getBaseType(), {},
- protocols,
- objcObjectType->isKindOfTypeAsWritten());
- }
+ if (objcObjectType->isSpecializedAsWritten()) {
+ SmallVector<QualType, 4> newTypeArgs;
+ bool anyChanged = false;
+ for (auto typeArg : objcObjectType->getTypeArgsAsWritten()) {
+ QualType newTypeArg = typeArg.substObjCTypeArgs(
+ Ctx, TypeArgs, ObjCSubstitutionContext::Ordinary);
+ if (newTypeArg.isNull())
+ return {};
- anyChanged = true;
+ if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) {
+ // If we're substituting based on an unspecialized context type,
+ // produce an unspecialized type.
+ ArrayRef<ObjCProtocolDecl *> protocols(
+ objcObjectType->qual_begin(), objcObjectType->getNumProtocols());
+ if (TypeArgs.empty() &&
+ SubstContext != ObjCSubstitutionContext::Superclass) {
+ return Ctx.getObjCObjectType(
+ objcObjectType->getBaseType(), {}, protocols,
+ objcObjectType->isKindOfTypeAsWritten());
}
- newTypeArgs.push_back(newTypeArg);
+ anyChanged = true;
}
- if (anyChanged) {
- ArrayRef<ObjCProtocolDecl *> protocols(
- objcObjectType->qual_begin(),
- objcObjectType->getNumProtocols());
- return ctx.getObjCObjectType(objcObjectType->getBaseType(),
- newTypeArgs, protocols,
- objcObjectType->isKindOfTypeAsWritten());
- }
+ newTypeArgs.push_back(newTypeArg);
}
- return type;
+ if (anyChanged) {
+ ArrayRef<ObjCProtocolDecl *> protocols(
+ objcObjectType->qual_begin(), objcObjectType->getNumProtocols());
+ return Ctx.getObjCObjectType(objcObjectType->getBaseType(), newTypeArgs,
+ protocols,
+ objcObjectType->isKindOfTypeAsWritten());
+ }
}
- return type;
- });
+ return BaseType::VisitObjCObjectType(objcObjectType);
+ }
+};
+
+struct StripObjCKindOfTypeVisitor
+ : public SimpleTransformVisitor<StripObjCKindOfTypeVisitor> {
+ using BaseType = SimpleTransformVisitor<StripObjCKindOfTypeVisitor>;
+
+ explicit StripObjCKindOfTypeVisitor(ASTContext &ctx) : BaseType(ctx) {}
+
+ QualType VisitObjCObjectType(const ObjCObjectType *objType) {
+ if (!objType->isKindOfType())
+ return BaseType::VisitObjCObjectType(objType);
+
+ QualType baseType = objType->getBaseType().stripObjCKindOfType(Ctx);
+ return Ctx.getObjCObjectType(baseType, objType->getTypeArgsAsWritten(),
+ objType->getProtocols(),
+ /*isKindOf=*/false);
+ }
+};
+
+} // namespace
+
+/// Substitute the given type arguments for Objective-C type
+/// parameters within the given type, recursively.
+QualType QualType::substObjCTypeArgs(ASTContext &ctx,
+ ArrayRef<QualType> typeArgs,
+ ObjCSubstitutionContext context) const {
+ SubstObjCTypeArgsVisitor visitor(ctx, typeArgs, context);
+ return visitor.recurse(*this);
}
QualType QualType::substObjCMemberType(QualType objectType,
@@ -1349,25 +1339,8 @@ QualType QualType::substObjCMemberType(Q
QualType QualType::stripObjCKindOfType(const ASTContext &constCtx) const {
// FIXME: Because ASTContext::getAttributedType() is non-const.
auto &ctx = const_cast<ASTContext &>(constCtx);
- return simpleTransform(ctx, *this,
- [&](QualType type) -> QualType {
- SplitQualType splitType = type.split();
- if (auto *objType = splitType.Ty->getAs<ObjCObjectType>()) {
- if (!objType->isKindOfType())
- return type;
-
- QualType baseType
- = objType->getBaseType().stripObjCKindOfType(ctx);
- return ctx.getQualifiedType(
- ctx.getObjCObjectType(baseType,
- objType->getTypeArgsAsWritten(),
- objType->getProtocols(),
- /*isKindOf=*/false),
- splitType.Quals);
- }
-
- return type;
- });
+ StripObjCKindOfTypeVisitor visitor(ctx);
+ return visitor.recurse(*this);
}
QualType QualType::getAtomicUnqualifiedType() const {
More information about the cfe-commits
mailing list