summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2012-06-07 01:10:31 +0000
committerJordan Rose <jordan_rose@apple.com>2012-06-07 01:10:31 +0000
commit288c421b3d9a9c84b310088ce54c11c050775b9f (patch)
tree22f81731b5b482ce8024786e62d937056908feab
parent161d5bb6f7c958738a9809efe408fb74f7adcafe (diff)
downloadbcm5719-llvm-288c421b3d9a9c84b310088ce54c11c050775b9f.tar.gz
bcm5719-llvm-288c421b3d9a9c84b310088ce54c11c050775b9f.zip
Insert a space if necessary when suggesting CFBridgingRetain/Release.
This was a problem for people who write 'return(result);' Also fix ARCMT's corresponding code, though there's no test case for this because implicit casts like this are rejected by the migrator for being ambiguous, and explicit casts have no problem. <rdar://problem/11577346> llvm-svn: 158130
-rw-r--r--clang/include/clang/Lex/Lexer.h3
-rw-r--r--clang/lib/ARCMigrate/TransUnbridgedCasts.cpp25
-rw-r--r--clang/lib/Lex/Lexer.cpp5
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp17
-rw-r--r--clang/test/SemaObjC/arc-bridged-cast.m25
5 files changed, 61 insertions, 14 deletions
diff --git a/clang/include/clang/Lex/Lexer.h b/clang/include/clang/Lex/Lexer.h
index e96e1d7cb79..4fbc858fef0 100644
--- a/clang/include/clang/Lex/Lexer.h
+++ b/clang/include/clang/Lex/Lexer.h
@@ -541,6 +541,9 @@ public:
const LangOptions &LangOpts,
bool SkipTrailingWhitespaceAndNewLine);
+ /// \brief Returns true if the given character could appear in an identifier.
+ static bool isIdentifierBodyChar(char c, const LangOptions &LangOpts);
+
private:
/// getCharAndSizeSlowNoWarn - Same as getCharAndSizeSlow, but never emits a
diff --git a/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp b/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp
index 72c0d8e7de3..f8bc5cf932c 100644
--- a/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp
+++ b/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp
@@ -37,6 +37,7 @@
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/AST/ParentMap.h"
+#include "clang/Lex/Lexer.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
@@ -229,20 +230,26 @@ private:
}
} else {
assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained);
- StringRef cfBridging;
+ SmallString<32> BridgeCall;
+
+ Expr *WrapE = E->getSubExpr();
+ SourceLocation InsertLoc = WrapE->getLocStart();
+
+ SourceManager &SM = Pass.Ctx.getSourceManager();
+ char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1));
+ if (Lexer::isIdentifierBodyChar(PrevChar, Pass.Ctx.getLangOpts()))
+ BridgeCall += ' ';
+
if (Kind == OBC_BridgeTransfer)
- cfBridging = "CFBridgingRelease";
+ BridgeCall += "CFBridgingRelease";
else
- cfBridging = "CFBridgingRetain";
+ BridgeCall += "CFBridgingRetain";
- Expr *WrapE = E->getSubExpr();
- SourceLocation insertLoc = WrapE->getLocStart();
if (isa<ParenExpr>(WrapE)) {
- TA.insert(insertLoc, cfBridging);
+ TA.insert(InsertLoc, BridgeCall);
} else {
- std::string withParens = cfBridging;
- withParens += '(';
- TA.insert(insertLoc, withParens);
+ BridgeCall += '(';
+ TA.insert(InsertLoc, BridgeCall);
TA.insertAfterToken(WrapE->getLocEnd(), ")");
}
}
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 4ab0dae1fa1..a806ce34e23 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -1124,6 +1124,11 @@ static inline bool isRawStringDelimBody(unsigned char c) {
true : false;
}
+// Allow external clients to make use of CharInfo.
+bool Lexer::isIdentifierBodyChar(char c, const LangOptions &LangOpts) {
+ return isIdentifierBody(c) || (c == '$' && LangOpts.DollarIdents);
+}
+
//===----------------------------------------------------------------------===//
// Diagnostics forwarding code.
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
index 1b0ba580841..ed1a112a7eb 100644
--- a/clang/lib/Sema/SemaExprObjC.cpp
+++ b/clang/lib/Sema/SemaExprObjC.cpp
@@ -2820,14 +2820,23 @@ static void addFixitForObjCARCConversion(Sema &S,
castedE = CCE->getSubExpr();
castedE = castedE->IgnoreImpCasts();
SourceRange range = castedE->getSourceRange();
+
+ SmallString<32> BridgeCall;
+
+ SourceManager &SM = S.getSourceManager();
+ char PrevChar = *SM.getCharacterData(range.getBegin().getLocWithOffset(-1));
+ if (Lexer::isIdentifierBodyChar(PrevChar, S.getLangOpts()))
+ BridgeCall += ' ';
+
+ BridgeCall += CFBridgeName;
+
if (isa<ParenExpr>(castedE)) {
DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
- CFBridgeName));
+ BridgeCall));
} else {
- std::string namePlusParen = CFBridgeName;
- namePlusParen += "(";
+ BridgeCall += '(';
DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
- namePlusParen));
+ BridgeCall));
DiagB.AddFixItHint(FixItHint::CreateInsertion(
S.PP.getLocForEndOfToken(range.getEnd()),
")"));
diff --git a/clang/test/SemaObjC/arc-bridged-cast.m b/clang/test/SemaObjC/arc-bridged-cast.m
index 56efe81d608..c8f4d0d1661 100644
--- a/clang/test/SemaObjC/arc-bridged-cast.m
+++ b/clang/test/SemaObjC/arc-bridged-cast.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
typedef const void *CFTypeRef;
CFTypeRef CFBridgingRetain(id X);
@@ -32,13 +33,35 @@ void to_cf(id obj) {
// rdar://problem/9629566 - temporary workaround
CFTypeRef cf5 = (__bridge_retain CFTypeRef)CreateSomething(); // expected-error {{unknown cast annotation __bridge_retain; did you mean __bridge_retained?}}
+ // CHECK: fix-it:"{{.*}}":{35:20-35:35}:"__bridge_retained"
}
-void fixits() {
+CFTypeRef fixits() {
id obj1 = (id)CFCreateSomething(); // expected-error{{cast of C pointer type 'CFTypeRef' (aka 'const void *') to Objective-C pointer type 'id' requires a bridged cast}} \
// expected-note{{use __bridge to convert directly (no change in ownership)}} \
// expected-note{{use CFBridgingRelease call to transfer ownership of a +1 'CFTypeRef' (aka 'const void *') into ARC}}
+ // CHECK: fix-it:"{{.*}}":{40:14-40:14}:"__bridge "
+ // CHECK: fix-it:"{{.*}}":{40:17-40:17}:"CFBridgingRelease("
+ // CHECK: fix-it:"{{.*}}":{40:36-40:36}:")"
+
CFTypeRef cf1 = (CFTypeRef)CreateSomething(); // expected-error{{cast of Objective-C pointer type 'id' to C pointer type 'CFTypeRef' (aka 'const void *') requires a bridged cast}} \
// expected-note{{use __bridge to convert directly (no change in ownership)}} \
// expected-note{{use CFBridgingRetain call to make an ARC object available as a +1 'CFTypeRef' (aka 'const void *')}}
+ // CHECK: fix-it:"{{.*}}":{47:20-47:20}:"__bridge "
+ // CHECK: fix-it:"{{.*}}":{47:30-47:30}:"CFBridgingRetain("
+ // CHECK: fix-it:"{{.*}}":{47:47-47:47}:")"
+
+ return (obj1); // expected-error{{implicit conversion of Objective-C pointer type 'id' to C pointer type 'CFTypeRef' (aka 'const void *') requires a bridged cast}} \
+ // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note{{use CFBridgingRetain call to make an ARC object available as a +1 'CFTypeRef' (aka 'const void *')}}
+ // CHECK: fix-it:"{{.*}}":{54:10-54:10}:"(__bridge CFTypeRef)"
+ // CHECK: fix-it:"{{.*}}":{54:10-54:10}:"CFBridgingRetain"
+}
+
+CFTypeRef fixitsWithSpace(id obj) {
+ return(obj); // expected-error{{implicit conversion of Objective-C pointer type 'id' to C pointer type 'CFTypeRef' (aka 'const void *') requires a bridged cast}} \
+ // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note{{use CFBridgingRetain call to make an ARC object available as a +1 'CFTypeRef' (aka 'const void *')}}
+ // CHECK: fix-it:"{{.*}}":{62:9-62:9}:"(__bridge CFTypeRef)"
+ // CHECK: fix-it:"{{.*}}":{62:9-62:9}:" CFBridgingRetain"
}
OpenPOWER on IntegriCloud