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
#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"
}
} 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(), ")");
}
}
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.
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()),
")"));
// 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);
// 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"
}