зеркало из https://github.com/microsoft/clang.git
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:
Родитель
d1f5ff717d
Коммит
eab5f63207
|
@ -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;
|
||||
}
|
Загрузка…
Ссылка в новой задаче