For ObjC type parameter, we used to have TypedefType that is canonicalized to
id or the bound type. We can't represent "T <protocol>" and thus will lose
the type information in the following example:
@interface MyMutableDictionary<KeyType, ObjectType> : NSObject
- (void)setObject:(ObjectType)obj forKeyedSubscript:(KeyType <NSCopying>)key;
@end
MyMutableDictionary<NSString *, NSString *> *stringsByString;
NSNumber *n1, *n2;
stringsByString[n1] = n2;
--> no warning on type mismatch of the key.
To fix the problem, we introduce a new type ObjCTypeParamType that supports
a list of protocol qualifiers.
We create ObjCTypeParamType for ObjCTypeParamDecl when we create
ObjCTypeParamDecl. We also substitute ObjCTypeParamType instead of TypedefType
on an ObjCTypeParamDecl.
rdar://
24619481
rdar://
25060179
Differential Revision: http://reviews.llvm.org/D23080
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@281358
91177308-0d34-0410-b5e6-
96231b3b80d8
bool allowOnPointerType) const {
hasError = false;
+ if (const ObjCTypeParamType *objT =
+ dyn_cast<ObjCTypeParamType>(type.getTypePtr())) {
+ return getObjCTypeParamType(objT->getDecl(), protocols);
+ }
+
// Apply protocol qualifiers to ObjCObjectPointerType.
if (allowOnPointerType) {
if (const ObjCObjectPointerType *objPtr =
IdentifierInfo *name,
SourceLocation colonLoc,
TypeSourceInfo *boundInfo) {
- return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, variance, varianceLoc, index,
- nameLoc, name, colonLoc, boundInfo);
+ auto *TPDecl =
+ new (ctx, dc) ObjCTypeParamDecl(ctx, dc, variance, varianceLoc, index,
+ nameLoc, name, colonLoc, boundInfo);
+ QualType TPType = ctx.getObjCTypeParamType(TPDecl, {});
+ TPDecl->setTypeForDecl(TPType.getTypePtr());
+ return TPDecl;
}
ObjCTypeParamDecl *ObjCTypeParamDecl::CreateDeserialized(ASTContext &ctx,
// Replace an Objective-C type parameter reference with the corresponding
// type argument.
- if (const auto *typedefTy = dyn_cast<TypedefType>(splitType.Ty)) {
- if (auto *typeParam = dyn_cast<ObjCTypeParamDecl>(typedefTy->getDecl())) {
+ if (const auto *OTPTy = dyn_cast<ObjCTypeParamType>(splitType.Ty)) {
+ if (auto *typeParam = dyn_cast<ObjCTypeParamDecl>(OTPTy->getDecl())) {
// If we have type arguments, use them.
if (!typeArgs.empty()) {
- // FIXME: Introduce SubstObjCTypeParamType ?
QualType argType = typeArgs[typeParam->getIndex()];
- return ctx.getQualifiedType(argType, splitType.Quals);
+ 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*/);
+
+ return ctx.getQualifiedType(resultTy, splitType.Quals);
}
switch (context) {
}
if (S.Context.hasSameUnqualifiedType(ImplTy, IfaceTy))
return true;
-
+
if (!Warn)
return false;
unsigned DiagID =
ResultTL = ObjCObjectPointerTL.getPointeeLoc();
}
+ if (auto OTPTL = ResultTL.getAs<ObjCTypeParamTypeLoc>()) {
+ // Protocol qualifier information.
+ if (OTPTL.getNumProtocols() > 0) {
+ assert(OTPTL.getNumProtocols() == Protocols.size());
+ OTPTL.setProtocolLAngleLoc(ProtocolLAngleLoc);
+ OTPTL.setProtocolRAngleLoc(ProtocolRAngleLoc);
+ for (unsigned i = 0, n = Protocols.size(); i != n; ++i)
+ OTPTL.setProtocolLoc(i, ProtocolLocs[i]);
+ }
+
+ // We're done. Return the completed type to the parser.
+ return CreateParsedType(Result, ResultTInfo);
+ }
+
auto ObjCObjectTL = ResultTL.castAs<ObjCObjectTypeLoc>();
// Type argument information.
// For the context-sensitive keywords/Objective-C property
// attributes, require that the type be a single-level pointer.
if (isContextSensitive) {
- // Make sure that the pointee isn't itself a pointer type.
QualType pointeeType = desugared->getPointeeType();
if (pointeeType->isAnyPointerType() ||
pointeeType->isObjCObjectPointerType() ||
}
bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) {
+ if (isa<ObjCTypeParamType>(type)) {
+ // Build the attributed type to record where __kindof occurred.
+ type = Context.getAttributedType(AttributedType::attr_objc_kindof,
+ type, type);
+ return false;
+ }
+
// Find out if it's an Objective-C object or object pointer type;
const ObjCObjectPointerType *ptrType = type->getAs<ObjCObjectPointerType>();
const ObjCObjectType *objType = ptrType ? ptrType->getObjectType()
: public RecursiveASTVisitor<IsObjCTypeParamDependentTypeVisitor> {
public:
IsObjCTypeParamDependentTypeVisitor() : Result(false) {}
- bool VisitTypedefType(const TypedefType *Type) {
+ bool VisitObjCTypeParamType(const ObjCTypeParamType *Type) {
if (isa<ObjCTypeParamDecl>(Type->getDecl())) {
Result = true;
return false;
@end
@interface NSGeneric<ObjectType> : NSObject
-- (void)test:(__kindof ObjectType)T;
+- (void)test:(__kindof ObjectType)T; // expected-note{{passing argument to parameter 'T' here}}
- (void)mapUsingBlock:(id (^)(__kindof ObjectType))block;
@end
@implementation NSGeneric
}
@end
+void testGeneric(NSGeneric<NSString*> *generic) {
+ NSObject *NSObject_obj;
+ // Assign from NSObject_obj to __kindof NSString*.
+ [generic test:NSObject_obj]; // expected-warning{{incompatible pointer types sending 'NSObject *' to parameter of type '__kindof NSString *'}}
+ NSString *NSString_str;
+ [generic test:NSString_str];
+}
+
// Check that clang doesn't crash when a type parameter is illegal.
@interface Array1<T> : NSObject
@end
// warning about likely protocol/class name typos.
// --------------------------------------------------------------------------
typedef NSArray<NSObject> ArrayOfNSObjectWarning; // expected-warning{{parameterized class 'NSArray' already conforms to the protocols listed; did you forget a '*'?}}
+
+// rdar://25060179
+@interface MyMutableDictionary<KeyType, ObjectType> : NSObject
+- (void)setObject:(ObjectType)obj forKeyedSubscript:(KeyType <NSCopying>)key; // expected-note{{passing argument to parameter 'obj' here}} \
+ // expected-note{{passing argument to parameter 'key' here}}
+@end
+
+void bar(MyMutableDictionary<NSString *, NSString *> *stringsByString,
+ NSNumber *n1, NSNumber *n2) {
+ // We warn here when the key types do not match.
+ stringsByString[n1] = n2; // expected-warning{{incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'}} \
+ // expected-warning{{incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString<NSCopying> *'}}
+}
+
+@interface MyTest<K, V> : NSObject <NSCopying>
+- (V)test:(K)key;
+- (V)test2:(K)key; // expected-note{{previous definition is here}}
+- (void)mapUsingBlock:(id (^)(V))block;
+- (void)mapUsingBlock2:(id (^)(V))block; // expected-note{{previous definition is here}}
+@end
+
+@implementation MyTest
+- (id)test:(id)key {
+ return key;
+}
+- (int)test2:(id)key{ // expected-warning{{conflicting return type in implementation}}
+ return 0;
+}
+- (void)mapUsingBlock:(id (^)(id))block {
+}
+- (void)mapUsingBlock2:(id)block { // expected-warning{{conflicting parameter types in implementation}}
+}
+@end