Teach block rewriter to replace '^' with '*' in VarDecls.

Since we don't have DeclGroup's and location information for types, there is some fancy footwork to do this fairly reliably.

O.K...it's a kludge. One day, we can use this as motivation to do this more gracefully:-)


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@56499 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Steve Naroff 2008-09-23 19:24:41 +00:00
Родитель d1f5ff717d
Коммит eab5f63207
2 изменённых файлов: 91 добавлений и 12 удалений

Просмотреть файл

@ -131,6 +131,9 @@ public:
void RewriteCategoryDecl(ObjCCategoryDecl *CatDecl);
void RewriteProtocolDecl(ObjCProtocolDecl *PDecl);
void RewriteMethodDecl(ObjCMethodDecl *MDecl);
bool BlockPointerTypeTakesAnyBlockArguments(QualType QT);
void GetExtentOfArgList(const char *Name, char *&LParen, char *&RParen);
};
}
@ -455,9 +458,9 @@ std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i,
}
if (haveByRefDecls) {
// Remove |...|.
const char *firstBarPtr = strchr(BodyStartBuf, '|');
const char *secondBarPtr = strchr(firstBarPtr+1, '|');
BodyBuf.replace(firstBarPtr-BodyStartBuf, secondBarPtr-firstBarPtr+1, "");
//const char *firstBarPtr = strchr(BodyStartBuf, '|');
//const char *secondBarPtr = strchr(firstBarPtr+1, '|');
//BodyBuf.replace(firstBarPtr-BodyStartBuf, secondBarPtr-firstBarPtr+1, "");
}
S += " ";
S += BodyBuf;
@ -809,6 +812,40 @@ void RewriteBlocks::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
return;
}
bool RewriteBlocks::BlockPointerTypeTakesAnyBlockArguments(QualType QT) {
const BlockPointerType *BPT = QT->getAsBlockPointerType();
assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
const FunctionTypeProto *FTP = BPT->getPointeeType()->getAsFunctionTypeProto();
if (FTP) {
for (FunctionTypeProto::arg_type_iterator I = FTP->arg_type_begin(),
E = FTP->arg_type_end(); I != E; ++I)
if (isBlockPointerType(*I))
return true;
}
return false;
}
void RewriteBlocks::GetExtentOfArgList(const char *Name,
char *&LParen, char *&RParen) {
char *argPtr = strchr(Name, '(');
assert((*argPtr == '(') && "Rewriter fuzzy parser confused");
LParen = argPtr; // output the start.
argPtr++; // skip past the left paren.
unsigned parenCount = 1;
while (*argPtr && parenCount) {
switch (*argPtr) {
case '(': parenCount++; break;
case ')': parenCount--; break;
default: break;
}
if (parenCount) argPtr++;
}
assert((*argPtr == ')') && "Rewriter fuzzy parser confused");
RParen = argPtr; // output the end
}
void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) {
SourceLocation DeclLoc = ND->getLocation();
const char *startBuf, *endBuf;
@ -820,6 +857,29 @@ void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) {
DeclLoc = VD->getLocation();
startBuf = SM->getCharacterData(DeclLoc);
endBuf = startBuf;
// scan backward (from the decl location) for the end of the previous decl.
while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart)
startBuf--;
assert((*startBuf == '^') &&
"RewriteBlockPointerDecl() scan error: no caret");
// Replace the '^' with '*', computing a negative offset.
DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf);
ReplaceText(DeclLoc, 1, "*", 1);
if (BlockPointerTypeTakesAnyBlockArguments(VD->getType())) {
// Replace the '^' with '*' for arguments.
DeclLoc = VD->getLocation();
startBuf = SM->getCharacterData(DeclLoc);
char *argListBegin, *argListEnd;
GetExtentOfArgList(startBuf, argListBegin, argListEnd);
while (argListBegin < argListEnd) {
if (*argListBegin == '^') {
SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf);
ReplaceText(CaretLoc, 1, "*", 1);
}
argListBegin++;
}
}
} else if (TypedefDecl *TDD = dyn_cast<TypedefDecl>(ND)) {
DeclLoc = TDD->getLocation();
startBuf = SM->getCharacterData(DeclLoc);
@ -828,15 +888,7 @@ void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) {
DeclLoc = DeclLoc.getFileLocWithOffset(8);
}
endBuf = startBuf;
}
// FIXME: need to skip past the argument list...then check for ','.
while (*endBuf && *endBuf != '=' && *endBuf != ';')
endBuf++;
SourceLocation DeclEndLoc = DeclLoc.getFileLocWithOffset(endBuf-startBuf);
std::string Tag = "struct __closure_impl *" + std::string(ND->getName());
ReplaceText(DeclLoc, endBuf-startBuf, Tag.c_str(), Tag.size());
}
return;
}

Просмотреть файл

@ -0,0 +1,27 @@
// RUN: clang -rewrite-blocks %s -o -
typedef void (^test_block_t)();
int main(int argc, char **argv) {
int a;
void (^test_block_v)();
void (^test_block_v2)(int, float);
void (^test_block_v3)(void (^barg)(int));
a = 77;
test_block_v = ^(){ int local=1; printf("a=%d\n",a+local); };
test_block_v();
a++;
test_block_v();
__block int b;
b = 88;
test_block_v2 = ^(int x, float f){ printf("b=%d\n",b); };
test_block_v2(1,2.0);
b++;
test_block_v2(3,4.0);
return 7;
}