forked from OSchip/llvm-project
[objcmt] Rewrite messages to NSString's stringWithUTF8String:/stringWithCString:
to use the @() boxing syntax. It will also rewrite uses of stringWithCString:encoding: where the encoding that is used is NSASCIIStringEncoding or NSUTF8StringEncoding. rdar://11438360 llvm-svn: 156868
This commit is contained in:
parent
385970f290
commit
7bd957c12a
|
@ -16,6 +16,7 @@
|
|||
namespace clang {
|
||||
class ASTContext;
|
||||
class QualType;
|
||||
class Expr;
|
||||
|
||||
// \brief Provides info and caches identifiers/selectors for NSFoundation API.
|
||||
class NSAPI {
|
||||
|
@ -37,15 +38,33 @@ public:
|
|||
|
||||
enum NSStringMethodKind {
|
||||
NSStr_stringWithString,
|
||||
NSStr_stringWithUTF8String,
|
||||
NSStr_stringWithCStringEncoding,
|
||||
NSStr_stringWithCString,
|
||||
NSStr_initWithString
|
||||
};
|
||||
static const unsigned NumNSStringMethods = 2;
|
||||
static const unsigned NumNSStringMethods = 5;
|
||||
|
||||
IdentifierInfo *getNSClassId(NSClassIdKindKind K) const;
|
||||
|
||||
/// \brief The Objective-C NSString selectors.
|
||||
Selector getNSStringSelector(NSStringMethodKind MK) const;
|
||||
|
||||
/// \brief Return NSStringMethodKind if \param Sel is such a selector.
|
||||
llvm::Optional<NSStringMethodKind> getNSStringMethodKind(Selector Sel) const;
|
||||
|
||||
/// \brief Returns true if the expression \param E is a reference of
|
||||
/// "NSUTF8StringEncoding" enum constant.
|
||||
bool isNSUTF8StringEncodingConstant(const Expr *E) const {
|
||||
return isObjCEnumerator(E, "NSUTF8StringEncoding", NSUTF8StringEncodingId);
|
||||
}
|
||||
|
||||
/// \brief Returns true if the expression \param E is a reference of
|
||||
/// "NSASCIIStringEncoding" enum constant.
|
||||
bool isNSASCIIStringEncodingConstant(const Expr *E) const {
|
||||
return isObjCEnumerator(E, "NSASCIIStringEncoding",NSASCIIStringEncodingId);
|
||||
}
|
||||
|
||||
/// \brief Enumerates the NSArray methods used to generate literals.
|
||||
enum NSArrayMethodKind {
|
||||
NSArr_array,
|
||||
|
@ -138,6 +157,8 @@ public:
|
|||
|
||||
private:
|
||||
bool isObjCTypedef(QualType T, StringRef name, IdentifierInfo *&II) const;
|
||||
bool isObjCEnumerator(const Expr *E,
|
||||
StringRef name, IdentifierInfo *&II) const;
|
||||
|
||||
ASTContext &Ctx;
|
||||
|
||||
|
@ -156,6 +177,7 @@ private:
|
|||
mutable Selector NSNumberInstanceSelectors[NumNSNumberLiteralMethods];
|
||||
|
||||
mutable IdentifierInfo *BOOLId, *NSIntegerId, *NSUIntegerId;
|
||||
mutable IdentifierInfo *NSASCIIStringEncodingId, *NSUTF8StringEncodingId;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -9,11 +9,13 @@
|
|||
|
||||
#include "clang/AST/NSAPI.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
NSAPI::NSAPI(ASTContext &ctx)
|
||||
: Ctx(ctx), ClassIds(), BOOLId(0), NSIntegerId(0), NSUIntegerId(0) {
|
||||
: Ctx(ctx), ClassIds(), BOOLId(0), NSIntegerId(0), NSUIntegerId(0),
|
||||
NSASCIIStringEncodingId(0), NSUTF8StringEncodingId(0) {
|
||||
}
|
||||
|
||||
IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const {
|
||||
|
@ -40,6 +42,21 @@ Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {
|
|||
case NSStr_stringWithString:
|
||||
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithString"));
|
||||
break;
|
||||
case NSStr_stringWithUTF8String:
|
||||
Sel = Ctx.Selectors.getUnarySelector(
|
||||
&Ctx.Idents.get("stringWithUTF8String"));
|
||||
break;
|
||||
case NSStr_stringWithCStringEncoding: {
|
||||
IdentifierInfo *KeyIdents[] = {
|
||||
&Ctx.Idents.get("stringWithCString"),
|
||||
&Ctx.Idents.get("encoding")
|
||||
};
|
||||
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
|
||||
break;
|
||||
}
|
||||
case NSStr_stringWithCString:
|
||||
Sel= Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithCString"));
|
||||
break;
|
||||
case NSStr_initWithString:
|
||||
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithString"));
|
||||
break;
|
||||
|
@ -50,6 +67,17 @@ Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {
|
|||
return NSStringSelectors[MK];
|
||||
}
|
||||
|
||||
llvm::Optional<NSAPI::NSStringMethodKind>
|
||||
NSAPI::getNSStringMethodKind(Selector Sel) const {
|
||||
for (unsigned i = 0; i != NumNSStringMethods; ++i) {
|
||||
NSStringMethodKind MK = NSStringMethodKind(i);
|
||||
if (Sel == getNSStringSelector(MK))
|
||||
return MK;
|
||||
}
|
||||
|
||||
return llvm::Optional<NSStringMethodKind>();
|
||||
}
|
||||
|
||||
Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
|
||||
if (NSArraySelectors[MK].isNull()) {
|
||||
Selector Sel;
|
||||
|
@ -353,3 +381,21 @@ bool NSAPI::isObjCTypedef(QualType T,
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NSAPI::isObjCEnumerator(const Expr *E,
|
||||
StringRef name, IdentifierInfo *&II) const {
|
||||
if (!Ctx.getLangOpts().ObjC1)
|
||||
return false;
|
||||
if (!E)
|
||||
return false;
|
||||
|
||||
if (!II)
|
||||
II = &Ctx.Idents.get(name);
|
||||
|
||||
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
|
||||
if (const EnumConstantDecl *
|
||||
EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl()))
|
||||
return EnumD->getIdentifier() == II;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -211,6 +211,8 @@ static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
|
|||
const NSAPI &NS, Commit &commit);
|
||||
static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
|
||||
const NSAPI &NS, Commit &commit);
|
||||
static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
|
||||
const NSAPI &NS, Commit &commit);
|
||||
|
||||
bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
|
||||
const NSAPI &NS, Commit &commit) {
|
||||
|
@ -224,6 +226,8 @@ bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
|
|||
return rewriteToDictionaryLiteral(Msg, NS, commit);
|
||||
if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
|
||||
return rewriteToNumberLiteral(Msg, NS, commit);
|
||||
if (II == NS.getNSClassId(NSAPI::ClassId_NSString))
|
||||
return rewriteToStringBoxedExpression(Msg, NS, commit);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -791,7 +795,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
|
|||
return false;
|
||||
|
||||
SourceRange ArgRange = OrigArg->getSourceRange();
|
||||
commit.replaceWithInner(Msg->getSourceRange(), OrigArg->getSourceRange());
|
||||
commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
|
||||
|
||||
if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
|
||||
commit.insertBefore(ArgRange.getBegin(), "@");
|
||||
|
@ -800,3 +804,68 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// rewriteToStringBoxedExpression.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static bool doRewriteToUTF8StringBoxedExpressionHelper(
|
||||
const ObjCMessageExpr *Msg,
|
||||
const NSAPI &NS, Commit &commit) {
|
||||
const Expr *Arg = Msg->getArg(0);
|
||||
if (Arg->isTypeDependent())
|
||||
return false;
|
||||
|
||||
const Expr *OrigArg = Arg->IgnoreImpCasts();
|
||||
QualType OrigTy = OrigArg->getType();
|
||||
|
||||
if (const StringLiteral *
|
||||
StrE = dyn_cast<StringLiteral>(OrigArg->IgnoreParens())) {
|
||||
commit.replaceWithInner(Msg->getSourceRange(), StrE->getSourceRange());
|
||||
commit.insert(StrE->getLocStart(), "@");
|
||||
return true;
|
||||
}
|
||||
|
||||
ASTContext &Ctx = NS.getASTContext();
|
||||
|
||||
if (const PointerType *PT = OrigTy->getAs<PointerType>()) {
|
||||
QualType PointeeType = PT->getPointeeType();
|
||||
if (Ctx.hasSameUnqualifiedType(PointeeType, Ctx.CharTy)) {
|
||||
SourceRange ArgRange = OrigArg->getSourceRange();
|
||||
commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
|
||||
|
||||
if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
|
||||
commit.insertBefore(ArgRange.getBegin(), "@");
|
||||
else
|
||||
commit.insertWrap("@(", ArgRange, ")");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
|
||||
const NSAPI &NS, Commit &commit) {
|
||||
Selector Sel = Msg->getSelector();
|
||||
|
||||
if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithUTF8String) ||
|
||||
Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCString)) {
|
||||
if (Msg->getNumArgs() != 1)
|
||||
return false;
|
||||
return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
|
||||
}
|
||||
|
||||
if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCStringEncoding)) {
|
||||
if (Msg->getNumArgs() != 2)
|
||||
return false;
|
||||
|
||||
const Expr *encodingArg = Msg->getArg(1);
|
||||
if (NS.isNSUTF8StringEncodingConstant(encodingArg) ||
|
||||
NS.isNSASCIIStringEncodingConstant(encodingArg))
|
||||
return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,22 @@ typedef signed char BOOL;
|
|||
+ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value;
|
||||
@end
|
||||
|
||||
enum {
|
||||
NSASCIIStringEncoding = 1,
|
||||
NSUTF8StringEncoding = 4,
|
||||
NSUnicodeStringEncoding = 10
|
||||
};
|
||||
typedef NSUInteger NSStringEncoding;
|
||||
|
||||
@interface NSString : NSObject
|
||||
@end
|
||||
|
||||
@interface NSString (NSStringExtensionMethods)
|
||||
+ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
|
||||
+ (id)stringWithCString:(const char *)cString encoding:(NSStringEncoding)enc;
|
||||
+ (id)stringWithCString:(const char *)bytes;
|
||||
@end
|
||||
|
||||
enum MyEnm {
|
||||
ME_foo
|
||||
};
|
||||
|
@ -66,3 +82,17 @@ void foo() {
|
|||
[NSNumber numberWithInteger:myenum];
|
||||
[NSNumber numberWithInteger:ME_foo];
|
||||
}
|
||||
|
||||
void boxString() {
|
||||
NSString *s = [NSString stringWithUTF8String:"box"];
|
||||
const char *cstr1;
|
||||
char *cstr2;
|
||||
s = [NSString stringWithUTF8String:cstr1];
|
||||
s = [NSString stringWithUTF8String:cstr2];
|
||||
s = [NSString stringWithCString:cstr1 encoding:NSASCIIStringEncoding];
|
||||
s = [NSString stringWithCString:cstr1 encoding:NSUTF8StringEncoding];
|
||||
s = [NSString stringWithCString:cstr1 encoding: NSUnicodeStringEncoding];
|
||||
NSStringEncoding encode;
|
||||
s = [NSString stringWithCString:cstr1 encoding:encode];
|
||||
s = [NSString stringWithCString:cstr1];
|
||||
}
|
||||
|
|
|
@ -54,6 +54,22 @@ typedef signed char BOOL;
|
|||
+ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value;
|
||||
@end
|
||||
|
||||
enum {
|
||||
NSASCIIStringEncoding = 1,
|
||||
NSUTF8StringEncoding = 4,
|
||||
NSUnicodeStringEncoding = 10
|
||||
};
|
||||
typedef NSUInteger NSStringEncoding;
|
||||
|
||||
@interface NSString : NSObject
|
||||
@end
|
||||
|
||||
@interface NSString (NSStringExtensionMethods)
|
||||
+ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
|
||||
+ (id)stringWithCString:(const char *)cString encoding:(NSStringEncoding)enc;
|
||||
+ (id)stringWithCString:(const char *)bytes;
|
||||
@end
|
||||
|
||||
enum MyEnm {
|
||||
ME_foo
|
||||
};
|
||||
|
@ -66,3 +82,17 @@ void foo() {
|
|||
@(myenum);
|
||||
@(ME_foo);
|
||||
}
|
||||
|
||||
void boxString() {
|
||||
NSString *s = @"box";
|
||||
const char *cstr1;
|
||||
char *cstr2;
|
||||
s = @(cstr1);
|
||||
s = @(cstr2);
|
||||
s = @(cstr1);
|
||||
s = @(cstr1);
|
||||
s = [NSString stringWithCString:cstr1 encoding: NSUnicodeStringEncoding];
|
||||
NSStringEncoding encode;
|
||||
s = [NSString stringWithCString:cstr1 encoding:encode];
|
||||
s = @(cstr1);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue