From: Anders Carlsson Date: Tue, 10 Nov 2009 04:46:30 +0000 (+0000) Subject: When trying to assign a regular string literal to an Objective-C 'id' type or a point... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b76cd3d0c166b2162c4709f2ef5da8d67d9844b7;p=clang When trying to assign a regular string literal to an Objective-C 'id' type or a pointer to an NSString, emit a code insertion hint that turns it into an Objective-C string. For example: @class NSString; @interface Test + (void)test:(NSString *)string; @end void g(NSString *a); void f() { NSString *a = "Foo"; g("Foo"); [Test test:"Foo"]; } will produce t.m:10:17: warning: incompatible pointer types initializing 'char [4]', expected 'NSString *' NSString *a = "Foo"; ^~~~~ @ t.m:11:5: warning: incompatible pointer types passing 'char [4]', expected 'NSString *' g("Foo"); ^~~~~ @ t.m:12:14: warning: incompatible pointer types sending 'char [4]', expected 'NSString *' [Test test:"Foo"]; ^~~~~ @ 3 diagnostics generated. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86665 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 34b9eb843b..ec6ca2a9ac 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -6201,6 +6201,34 @@ Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { return Owned(new (Context) GNUNullExpr(Ty, TokenLoc)); } +static void +MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef, + QualType DstType, + Expr *SrcExpr, + CodeModificationHint &Hint) { + if (!SemaRef.getLangOptions().ObjC1) + return; + + const ObjCObjectPointerType *PT = DstType->getAs(); + if (!PT) + return; + + // Check if the destination is of type 'id'. + if (!PT->isObjCIdType()) { + // Check if the destination is the 'NSString' interface. + const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); + if (!ID || !ID->getIdentifier()->isStr("NSString")) + return; + } + + // Strip off any parens and casts. + StringLiteral *SL = dyn_cast(SrcExpr->IgnoreParenCasts()); + if (!SL || SL->isWide()) + return; + + Hint = CodeModificationHint::CreateInsertion(SL->getLocStart(), "@"); +} + bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, SourceLocation Loc, QualType DstType, QualType SrcType, @@ -6208,6 +6236,8 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, // Decode the result (notice that AST's are still created for extensions). bool isInvalid = false; unsigned DiagKind; + CodeModificationHint Hint; + switch (ConvTy) { default: assert(0 && "Unknown conversion type"); case Compatible: return false; @@ -6218,6 +6248,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, DiagKind = diag::ext_typecheck_convert_int_pointer; break; case IncompatiblePointer: + MakeObjCStringLiteralCodeModificationHint(*this, DstType, SrcExpr, Hint); DiagKind = diag::ext_typecheck_convert_incompatible_pointer; break; case IncompatiblePointerSign: @@ -6265,7 +6296,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, } Diag(Loc, DiagKind) << DstType << SrcType << Flavor - << SrcExpr->getSourceRange(); + << SrcExpr->getSourceRange() << Hint; return isInvalid; } diff --git a/test/FixIt/fixit-objc.m b/test/FixIt/fixit-objc.m index b732e2f973..687405c7ce 100644 --- a/test/FixIt/fixit-objc.m +++ b/test/FixIt/fixit-objc.m @@ -1,8 +1,36 @@ -// RUN: clang-cc -fsyntax-only -fixit-at=fixit-at.c:3:1 %s -o %t.m -// RUN: clang-cc -verify %t.m +// RUN: clang-cc -fsyntax-only -pedantic -fixit %s -o %t +// RUN: clang-cc -fsyntax-only -pedantic -x objective-c %t -verify + +/* This is a test of the various code modification hints that are + provided as part of warning or extension diagnostics. All of the + warnings will be fixed by -fixit, and the resulting file should + compile cleanly with -Werror -pedantic. */ @protocol X; void foo() { *P; // should be fixed to 'id'. } + +@class A; +@class NSString; + +@interface Test +- (void)test:(NSString *)string; + +@property (copy) NSString *property; +@end + +void g(NSString *a); +void h(id a); + +void f(Test *t) { + NSString *a = "Foo"; + id b = "Foo"; + A* c = "Foo"; // expected-warning {{incompatible pointer types initializing 'char [4]', expected 'A *'}} + g("Foo"); + h("Foo"); + h(("Foo")); + [t test:"Foo"]; + t.property = "Foo"; +}