Implement rewrite rules for ObjC string constants.

llvm-svn: 43665
This commit is contained in:
Steve Naroff 2007-11-03 11:27:19 +00:00
parent dfcc3f26ae
commit a397efd915
9 changed files with 98 additions and 32 deletions

View File

@ -861,23 +861,20 @@ QualType ASTContext::maxIntegerType(QualType lhs, QualType rhs) {
QualType ASTContext::getCFConstantStringType() {
if (!CFConstantStringTypeDecl) {
CFConstantStringTypeDecl = new RecordDecl(Decl::Struct, SourceLocation(),
&Idents.get("__builtin_CFString"),
&Idents.get("NSConstantString"),
0);
QualType FieldTypes[4];
QualType FieldTypes[3];
// const int *isa;
FieldTypes[0] = getPointerType(IntTy.getQualifiedType(QualType::Const));
// int flags;
FieldTypes[1] = IntTy;
// const char *str;
FieldTypes[2] = getPointerType(CharTy.getQualifiedType(QualType::Const));
FieldTypes[1] = getPointerType(CharTy.getQualifiedType(QualType::Const));
// long length;
FieldTypes[3] = LongTy;
FieldTypes[2] = LongTy;
// Create fields
FieldDecl *FieldDecls[4];
FieldDecl *FieldDecls[3];
for (unsigned i = 0; i < 4; ++i)
for (unsigned i = 0; i < 3; ++i)
FieldDecls[i] = new FieldDecl(SourceLocation(), 0, FieldTypes[i]);
CFConstantStringTypeDecl->defineBody(FieldDecls, 4);

View File

@ -39,6 +39,10 @@ namespace {
FunctionDecl *GetClassFunctionDecl;
FunctionDecl *SelGetUidFunctionDecl;
// ObjC string constant support.
FileVarDecl *ConstantStringClassReference;
RecordDecl *NSStringRecord;
static const int OBJC_ABI_VERSION =7 ;
public:
void Initialize(ASTContext &context, unsigned mainFileID) {
@ -48,6 +52,8 @@ namespace {
MsgSendFunctionDecl = 0;
GetClassFunctionDecl = 0;
SelGetUidFunctionDecl = 0;
ConstantStringClassReference = 0;
NSStringRecord = 0;
Rewrite.setSourceMgr(Context->SourceMgr);
}
@ -73,12 +79,14 @@ namespace {
Stmt *RewriteFunctionBody(Stmt *S);
Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
Expr **args, unsigned nargs);
void SynthMsgSendFunctionDecl();
void SynthGetClassFunctionDecl();
// Metadata emission.
void HandleObjcMetaDataEmission();
void RewriteObjcClassMetaData(ObjcImplementationDecl *IDecl,
std::string &Result);
@ -125,6 +133,12 @@ void RewriteTest::HandleTopLevelDecl(Decl *D) {
// Look for built-in declarations that we need to refer during the rewrite.
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
RewriteFunctionDecl(FD);
} else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
// declared in <Foundation/NSString.h>
if (strcmp(FVD->getName(), "_NSConstantStringClassReference") == 0) {
ConstantStringClassReference = FVD;
return;
}
} else if (ObjcInterfaceDecl *MD = dyn_cast<ObjcInterfaceDecl>(D)) {
RewriteInterfaceDecl(MD);
} else if (ObjcCategoryDecl *CD = dyn_cast<ObjcCategoryDecl>(D)) {
@ -161,17 +175,11 @@ RewriteTest::~RewriteTest() {
// Get the top-level buffer that this corresponds to.
RewriteTabs();
// Rewrite Objective-c meta data*
std::string ResultStr;
WriteObjcMetaData(ResultStr);
// For now just print the string out.
printf("%s", ResultStr.c_str());
// Get the buffer corresponding to MainFileID. If we haven't changed it, then
// we are done.
if (const RewriteBuffer *RewriteBuf =
Rewrite.getRewriteBufferFor(MainFileID)) {
printf("Changed:\n");
//printf("Changed:\n");
std::string S(RewriteBuf->begin(), RewriteBuf->end());
printf("%s\n", S.c_str());
} else {
@ -180,6 +188,16 @@ RewriteTest::~RewriteTest() {
}
/// HandleObjcMetaDataEmission - main routine to generate objective-c's
/// metadata.
void RewriteTest::HandleObjcMetaDataEmission() {
// Rewrite Objective-c meta data*
std::string ResultStr;
WriteObjcMetaData(ResultStr);
// For now just print the string out.
printf("%s", ResultStr.c_str());
}
//===----------------------------------------------------------------------===//
// Syntactic (non-AST) Rewriting Code
//===----------------------------------------------------------------------===//
@ -364,6 +382,9 @@ Stmt *RewriteTest::RewriteFunctionBody(Stmt *S) {
// Handle specific things.
if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
return RewriteAtEncode(AtEncode);
if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))
return RewriteObjCStringLiteral(AtString);
if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
// Before we rewrite it, put the original message expression in a comment.
@ -492,7 +513,7 @@ void RewriteTest::RewriteObjcQualifiedInterfaceTypes(
void RewriteTest::RewriteFunctionDecl(FunctionDecl *FD) {
// declared in <objc/objc.h>
if (strcmp(FD->getName(), "sel_getUid") == 0) {
if (strcmp(FD->getName(), "sel_registerName") == 0) {
SelGetUidFunctionDecl = FD;
return;
}
@ -536,8 +557,52 @@ void RewriteTest::SynthGetClassFunctionDecl() {
FunctionDecl::Extern, false, 0);
}
Stmt *RewriteTest::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
assert(ConstantStringClassReference && "Can't find constant string reference");
llvm::SmallVector<Expr*, 4> InitExprs;
// Synthesize "(Class)&_NSConstantStringClassReference"
DeclRefExpr *ClsRef = new DeclRefExpr(ConstantStringClassReference,
ConstantStringClassReference->getType(),
SourceLocation());
QualType expType = Context->getPointerType(ClsRef->getType());
UnaryOperator *Unop = new UnaryOperator(ClsRef, UnaryOperator::AddrOf,
expType, SourceLocation());
CastExpr *cast = new CastExpr(Context->getObjcClassType(), Unop,
SourceLocation());
InitExprs.push_back(cast); // set the 'isa'.
InitExprs.push_back(Exp->getString()); // set "char *bytes".
unsigned IntSize = static_cast<unsigned>(
Context->getTypeSize(Context->IntTy, Exp->getLocStart()));
llvm::APInt IntVal(IntSize, Exp->getString()->getByteLength());
IntegerLiteral *len = new IntegerLiteral(IntVal, Context->IntTy,
Exp->getLocStart());
InitExprs.push_back(len); // set "int numBytes".
// struct NSConstantString
QualType CFConstantStrType = Context->getCFConstantStringType();
// (struct NSConstantString) { <exprs from above> }
InitListExpr *ILE = new InitListExpr(SourceLocation(),
&InitExprs[0], InitExprs.size(),
SourceLocation());
CompoundLiteralExpr *StrRep = new CompoundLiteralExpr(CFConstantStrType, ILE);
// struct NSConstantString *
expType = Context->getPointerType(StrRep->getType());
Unop = new UnaryOperator(StrRep, UnaryOperator::AddrOf, expType,
SourceLocation());
// struct NSString *
if (!NSStringRecord)
NSStringRecord = new RecordDecl(Decl::Struct, SourceLocation(),
&Context->Idents.get("NSString"), 0);
expType = Context->getPointerType(Context->getTagDeclType(NSStringRecord));
cast = new CastExpr(expType, Unop, SourceLocation());
Rewrite.ReplaceStmt(Exp, cast);
delete Exp;
return StrRep;
}
Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
assert(SelGetUidFunctionDecl && "Can't find sel_getUid() decl");
assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
if (!MsgSendFunctionDecl)
SynthMsgSendFunctionDecl();
if (!GetClassFunctionDecl)
@ -561,7 +626,7 @@ Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
} else // instance message.
MsgExprs.push_back(Exp->getReceiver());
// Create a call to sel_getUid("selName"), it will be the 2nd argument.
// Create a call to sel_registerName("selName"), it will be the 2nd argument.
llvm::SmallVector<Expr*, 8> SelExprs;
QualType argType = Context->getPointerType(Context->CharTy);
SelExprs.push_back(new StringLiteral(Exp->getSelector().getName().c_str(),

View File

@ -1155,7 +1155,7 @@ Parser::ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
switch (Tok.getKind()) {
case tok::string_literal: // primary-expression: string-literal
case tok::wide_string_literal:
return ParsePostfixExpressionSuffix(ParseObjCStringLiteral());
return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
default:
break;
}
@ -1285,12 +1285,12 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() {
&KeyExprs[0]);
}
Parser::ExprResult Parser::ParseObjCStringLiteral() {
Parser::ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
ExprResult Res = ParseStringLiteralExpression();
if (Res.isInvalid) return Res;
return Actions.ParseObjCStringLiteral(Res.Val);
return Actions.ParseObjCStringLiteral(AtLoc, Res.Val);
}
/// objc-encode-expression:

View File

@ -454,7 +454,8 @@ public:
tok::TokenKind Kind);
// ParseObjCStringLiteral - Parse Objective-C string literals.
virtual ExprResult ParseObjCStringLiteral(ExprTy *string);
virtual ExprResult ParseObjCStringLiteral(SourceLocation AtLoc,
ExprTy *string);
virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc,
SourceLocation EncodeLoc,
SourceLocation LParenLoc,

View File

@ -1929,7 +1929,8 @@ Sema::ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
}
// TODO: Move this to SemaObjC.cpp
Sema::ExprResult Sema::ParseObjCStringLiteral(ExprTy *string) {
Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation AtLoc,
ExprTy *string) {
StringLiteral* S = static_cast<StringLiteral *>(string);
if (CheckBuiltinCFStringArgument(S))
@ -1949,7 +1950,7 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(ExprTy *string) {
}
QualType t = Context.getObjcConstantStringInterface();
t = Context.getPointerType(t);
return new ObjCStringLiteral(S, t);
return new ObjCStringLiteral(S, t, AtLoc);
}
Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,

View File

@ -178,8 +178,8 @@ public:
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType getPointerDiffType() const;
// getCFConstantStringType - Return the type used for constant CFStrings.
// CURRENTLY UNUSED (10/15/07). ObjCStringLiteral now uses the hook below.
// getCFConstantStringType - Return the C structure type used to represent
// constant CFStrings.
QualType getCFConstantStringType();
// This setter/getter represents the ObjC type for an NSConstantString.

View File

@ -1062,16 +1062,17 @@ public:
/// i.e. @"foo".
class ObjCStringLiteral : public Expr {
StringLiteral *String;
SourceLocation AtLoc;
public:
ObjCStringLiteral(StringLiteral *SL, QualType T)
: Expr(ObjCStringLiteralClass, T), String(SL) {}
ObjCStringLiteral(StringLiteral *SL, QualType T, SourceLocation L)
: Expr(ObjCStringLiteralClass, T), String(SL), AtLoc(L) {}
StringLiteral* getString() { return String; }
const StringLiteral* getString() const { return String; }
virtual SourceRange getSourceRange() const {
return String->getSourceRange();
return SourceRange(AtLoc, String->getLocEnd());
}
static bool classof(const Stmt *T) {

View File

@ -612,7 +612,8 @@ public:
//===----------------------- Obj-C Expressions --------------------------===//
virtual ExprResult ParseObjCStringLiteral(ExprTy *string) {
virtual ExprResult ParseObjCStringLiteral(SourceLocation AtLoc,
ExprTy *string) {
return 0;
}

View File

@ -362,7 +362,7 @@ private:
//===--------------------------------------------------------------------===//
// Objective-C Expressions
ExprResult ParseObjCAtExpression(SourceLocation AtLocation);
ExprResult ParseObjCStringLiteral();
ExprResult ParseObjCStringLiteral(SourceLocation AtLoc);
ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc);
ExprResult ParseObjCSelectorExpression(SourceLocation AtLoc);
ExprResult ParseObjCProtocolExpression(SourceLocation AtLoc);