From: Steve Naroff Date: Sat, 31 May 2008 14:15:04 +0000 (+0000) Subject: Fix clang ObjC rewriter: #end from #if statement lost in... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=baf58c3f1fb13eec46fe339287662f180bb566da;p=clang Fix clang ObjC rewriter: #end from #if statement lost in translation. Some fancy footwork to accommodate embedded preprocessor directives within an interface. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@51815 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Driver/RewriteObjC.cpp b/Driver/RewriteObjC.cpp index 4d524a4a6d..c523b03d56 100644 --- a/Driver/RewriteObjC.cpp +++ b/Driver/RewriteObjC.cpp @@ -161,6 +161,7 @@ namespace { ObjCInterfaceDecl *isSuperReceiver(Expr *recExpr); QualType getSuperStructType(); QualType getConstantStringStructType(); + bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf); // Expression Rewriting. Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S); @@ -2247,6 +2248,32 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { } +bool RewriteObjC::BufferContainsPPDirectives(const char *startBuf, + const char *endBuf) { + while (startBuf < endBuf) { + if (*startBuf == '#') { + // Skip whitespace. + for (++startBuf; startBuf[0] == ' ' || startBuf[0] == '\t'; ++startBuf) + ; + if (!strncmp(startBuf, "if", strlen("if")) || + !strncmp(startBuf, "ifdef", strlen("ifdef")) || + !strncmp(startBuf, "ifndef", strlen("ifndef")) || + !strncmp(startBuf, "define", strlen("define")) || + !strncmp(startBuf, "undef", strlen("undef")) || + !strncmp(startBuf, "else", strlen("else")) || + !strncmp(startBuf, "elif", strlen("elif")) || + !strncmp(startBuf, "endif", strlen("endif")) || + !strncmp(startBuf, "pragma", strlen("pragma")) || + !strncmp(startBuf, "include", strlen("include")) || + !strncmp(startBuf, "import", strlen("import")) || + !strncmp(startBuf, "include_next", strlen("include_next"))) + return true; + } + startBuf++; + } + return false; +} + /// SynthesizeObjCInternalStruct - Rewrite one internal struct corresponding to /// an objective-c class with ivars. void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, @@ -2263,6 +2290,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, const char *startBuf = SM->getCharacterData(LocStart); const char *endBuf = SM->getCharacterData(LocEnd); + // If no ivars and no root or if its root, directly or indirectly, // have no ivars (thus not synthesized) then no need to synthesize this class. if ((CDecl->isForwardDecl() || NumIvars == 0) && @@ -2283,9 +2311,38 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, const char *cursor = strchr(startBuf, '{'); assert((cursor && endBuf) && "SynthesizeObjCInternalStruct - malformed @interface"); - - // rewrite the original header *without* disturbing the '{' - ReplaceText(LocStart, cursor-startBuf-1, Result.c_str(), Result.size()); + // If the buffer contains preprocessor directives, we do more fine-grained + // rewrites. This is intended to fix code that looks like (which occurs in + // NSURL.h, for example): + // + // #ifdef XYZ + // @interface Foo : NSObject + // #else + // @interface FooBar : NSObject + // #endif + // { + // int i; + // } + // @end + // + // This clause is segregated to avoid breaking the common case. + if (BufferContainsPPDirectives(startBuf, cursor)) { + SourceLocation L = RCDecl ? CDecl->getSuperClassLoc() : + CDecl->getClassLoc(); + const char *endHeader = SM->getCharacterData(L); + endHeader += Lexer::MeasureTokenLength(L, *SM); + + if (CDecl->getNumIntfRefProtocols()) { + // advance to the end of the referenced protocols. + while (endHeader < cursor && *endHeader != '>') endHeader++; + endHeader++; + } + // rewrite the original header + ReplaceText(LocStart, endHeader-startBuf, Result.c_str(), Result.size()); + } else { + // rewrite the original header *without* disturbing the '{' + ReplaceText(LocStart, cursor-startBuf-1, Result.c_str(), Result.size()); + } if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) { Result = "\n struct "; Result += RCDecl->getName();