namespace clang {
class ASTContext;
class QualType;
+ class Expr;
// \brief Provides info and caches identifiers/selectors for NSFoundation API.
class NSAPI {
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,
private:
bool isObjCTypedef(QualType T, StringRef name, IdentifierInfo *&II) const;
+ bool isObjCEnumerator(const Expr *E,
+ StringRef name, IdentifierInfo *&II) const;
ASTContext &Ctx;
mutable Selector NSNumberInstanceSelectors[NumNSNumberLiteralMethods];
mutable IdentifierInfo *BOOLId, *NSIntegerId, *NSUIntegerId;
+ mutable IdentifierInfo *NSASCIIStringEncodingId, *NSUTF8StringEncodingId;
};
} // end namespace clang
#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 {
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;
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;
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;
+}
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) {
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;
}
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(), "@");
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;
+}
+ (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
};
[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];
+}
+ (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
};
@(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);
+}