Run all functional logic of clang_annotateTokens() within a CrashRecoveryContext. Fixes <rdar://problem/9121698>.
llvm-svn: 127919
This commit is contained in:
parent
54140eb568
commit
21c7e6e298
|
@ -4566,9 +4566,192 @@ static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
|
||||||
return static_cast<AnnotateTokensWorker*>(client_data)->Visit(cursor, parent);
|
return static_cast<AnnotateTokensWorker*>(client_data)->Visit(cursor, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct clang_annotateTokens_Data {
|
||||||
|
CXTranslationUnit TU;
|
||||||
|
ASTUnit *CXXUnit;
|
||||||
|
CXToken *Tokens;
|
||||||
|
unsigned NumTokens;
|
||||||
|
CXCursor *Cursors;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// This gets run a separate thread to avoid stack blowout.
|
// This gets run a separate thread to avoid stack blowout.
|
||||||
static void runAnnotateTokensWorker(void *UserData) {
|
static void clang_annotateTokensImpl(void *UserData) {
|
||||||
((AnnotateTokensWorker*)UserData)->AnnotateTokens();
|
CXTranslationUnit TU = ((clang_annotateTokens_Data*)UserData)->TU;
|
||||||
|
ASTUnit *CXXUnit = ((clang_annotateTokens_Data*)UserData)->CXXUnit;
|
||||||
|
CXToken *Tokens = ((clang_annotateTokens_Data*)UserData)->Tokens;
|
||||||
|
const unsigned NumTokens = ((clang_annotateTokens_Data*)UserData)->NumTokens;
|
||||||
|
CXCursor *Cursors = ((clang_annotateTokens_Data*)UserData)->Cursors;
|
||||||
|
|
||||||
|
// Determine the region of interest, which contains all of the tokens.
|
||||||
|
SourceRange RegionOfInterest;
|
||||||
|
RegionOfInterest.setBegin(
|
||||||
|
cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[0])));
|
||||||
|
RegionOfInterest.setEnd(
|
||||||
|
cxloc::translateSourceLocation(clang_getTokenLocation(TU,
|
||||||
|
Tokens[NumTokens-1])));
|
||||||
|
|
||||||
|
// A mapping from the source locations found when re-lexing or traversing the
|
||||||
|
// region of interest to the corresponding cursors.
|
||||||
|
AnnotateTokensData Annotated;
|
||||||
|
|
||||||
|
// Relex the tokens within the source range to look for preprocessing
|
||||||
|
// directives.
|
||||||
|
SourceManager &SourceMgr = CXXUnit->getSourceManager();
|
||||||
|
std::pair<FileID, unsigned> BeginLocInfo
|
||||||
|
= SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin());
|
||||||
|
std::pair<FileID, unsigned> EndLocInfo
|
||||||
|
= SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd());
|
||||||
|
|
||||||
|
llvm::StringRef Buffer;
|
||||||
|
bool Invalid = false;
|
||||||
|
if (BeginLocInfo.first == EndLocInfo.first &&
|
||||||
|
((Buffer = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid)),true) &&
|
||||||
|
!Invalid) {
|
||||||
|
Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
|
||||||
|
CXXUnit->getASTContext().getLangOptions(),
|
||||||
|
Buffer.begin(), Buffer.data() + BeginLocInfo.second,
|
||||||
|
Buffer.end());
|
||||||
|
Lex.SetCommentRetentionState(true);
|
||||||
|
|
||||||
|
// Lex tokens in raw mode until we hit the end of the range, to avoid
|
||||||
|
// entering #includes or expanding macros.
|
||||||
|
while (true) {
|
||||||
|
Token Tok;
|
||||||
|
Lex.LexFromRawLexer(Tok);
|
||||||
|
|
||||||
|
reprocess:
|
||||||
|
if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) {
|
||||||
|
// We have found a preprocessing directive. Gobble it up so that we
|
||||||
|
// don't see it while preprocessing these tokens later, but keep track
|
||||||
|
// of all of the token locations inside this preprocessing directive so
|
||||||
|
// that we can annotate them appropriately.
|
||||||
|
//
|
||||||
|
// FIXME: Some simple tests here could identify macro definitions and
|
||||||
|
// #undefs, to provide specific cursor kinds for those.
|
||||||
|
llvm::SmallVector<SourceLocation, 32> Locations;
|
||||||
|
do {
|
||||||
|
Locations.push_back(Tok.getLocation());
|
||||||
|
Lex.LexFromRawLexer(Tok);
|
||||||
|
} while (!Tok.isAtStartOfLine() && !Tok.is(tok::eof));
|
||||||
|
|
||||||
|
using namespace cxcursor;
|
||||||
|
CXCursor Cursor
|
||||||
|
= MakePreprocessingDirectiveCursor(SourceRange(Locations.front(),
|
||||||
|
Locations.back()),
|
||||||
|
TU);
|
||||||
|
for (unsigned I = 0, N = Locations.size(); I != N; ++I) {
|
||||||
|
Annotated[Locations[I].getRawEncoding()] = Cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Tok.isAtStartOfLine())
|
||||||
|
goto reprocess;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Tok.is(tok::eof))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Annotate all of the source locations in the region of interest that map to
|
||||||
|
// a specific cursor.
|
||||||
|
AnnotateTokensWorker W(Annotated, Tokens, Cursors, NumTokens,
|
||||||
|
TU, RegionOfInterest);
|
||||||
|
|
||||||
|
// FIXME: We use a ridiculous stack size here because the data-recursion
|
||||||
|
// algorithm uses a large stack frame than the non-data recursive version,
|
||||||
|
// and AnnotationTokensWorker currently transforms the data-recursion
|
||||||
|
// algorithm back into a traditional recursion by explicitly calling
|
||||||
|
// VisitChildren(). We will need to remove this explicit recursive call.
|
||||||
|
W.AnnotateTokens();
|
||||||
|
|
||||||
|
// If we ran into any entities that involve context-sensitive keywords,
|
||||||
|
// take another pass through the tokens to mark them as such.
|
||||||
|
if (W.hasContextSensitiveKeywords()) {
|
||||||
|
for (unsigned I = 0; I != NumTokens; ++I) {
|
||||||
|
if (clang_getTokenKind(Tokens[I]) != CXToken_Identifier)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (Cursors[I].kind == CXCursor_ObjCPropertyDecl) {
|
||||||
|
IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
|
||||||
|
if (ObjCPropertyDecl *Property
|
||||||
|
= dyn_cast_or_null<ObjCPropertyDecl>(getCursorDecl(Cursors[I]))) {
|
||||||
|
if (Property->getPropertyAttributesAsWritten() != 0 &&
|
||||||
|
llvm::StringSwitch<bool>(II->getName())
|
||||||
|
.Case("readonly", true)
|
||||||
|
.Case("assign", true)
|
||||||
|
.Case("readwrite", true)
|
||||||
|
.Case("retain", true)
|
||||||
|
.Case("copy", true)
|
||||||
|
.Case("nonatomic", true)
|
||||||
|
.Case("atomic", true)
|
||||||
|
.Case("getter", true)
|
||||||
|
.Case("setter", true)
|
||||||
|
.Default(false))
|
||||||
|
Tokens[I].int_data[0] = CXToken_Keyword;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Cursors[I].kind == CXCursor_ObjCInstanceMethodDecl ||
|
||||||
|
Cursors[I].kind == CXCursor_ObjCClassMethodDecl) {
|
||||||
|
IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
|
||||||
|
if (llvm::StringSwitch<bool>(II->getName())
|
||||||
|
.Case("in", true)
|
||||||
|
.Case("out", true)
|
||||||
|
.Case("inout", true)
|
||||||
|
.Case("oneway", true)
|
||||||
|
.Case("bycopy", true)
|
||||||
|
.Case("byref", true)
|
||||||
|
.Default(false))
|
||||||
|
Tokens[I].int_data[0] = CXToken_Keyword;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Cursors[I].kind == CXCursor_CXXMethod) {
|
||||||
|
IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
|
||||||
|
if (CXXMethodDecl *Method
|
||||||
|
= dyn_cast_or_null<CXXMethodDecl>(getCursorDecl(Cursors[I]))) {
|
||||||
|
if ((Method->hasAttr<FinalAttr>() ||
|
||||||
|
Method->hasAttr<OverrideAttr>()) &&
|
||||||
|
Method->getLocation().getRawEncoding() != Tokens[I].int_data[1] &&
|
||||||
|
llvm::StringSwitch<bool>(II->getName())
|
||||||
|
.Case("final", true)
|
||||||
|
.Case("override", true)
|
||||||
|
.Default(false))
|
||||||
|
Tokens[I].int_data[0] = CXToken_Keyword;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Cursors[I].kind == CXCursor_ClassDecl ||
|
||||||
|
Cursors[I].kind == CXCursor_StructDecl ||
|
||||||
|
Cursors[I].kind == CXCursor_ClassTemplate) {
|
||||||
|
IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
|
||||||
|
if (II->getName() == "final") {
|
||||||
|
// We have to be careful with 'final', since it could be the name
|
||||||
|
// of a member class rather than the context-sensitive keyword.
|
||||||
|
// So, check whether the cursor associated with this
|
||||||
|
Decl *D = getCursorDecl(Cursors[I]);
|
||||||
|
if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(D)) {
|
||||||
|
if ((Record->hasAttr<FinalAttr>()) &&
|
||||||
|
Record->getIdentifier() != II)
|
||||||
|
Tokens[I].int_data[0] = CXToken_Keyword;
|
||||||
|
} else if (ClassTemplateDecl *ClassTemplate
|
||||||
|
= dyn_cast_or_null<ClassTemplateDecl>(D)) {
|
||||||
|
CXXRecordDecl *Record = ClassTemplate->getTemplatedDecl();
|
||||||
|
if ((Record->hasAttr<FinalAttr>()) &&
|
||||||
|
Record->getIdentifier() != II)
|
||||||
|
Tokens[I].int_data[0] = CXToken_Keyword;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -4590,181 +4773,15 @@ void clang_annotateTokens(CXTranslationUnit TU,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
|
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
|
||||||
|
|
||||||
// Determine the region of interest, which contains all of the tokens.
|
clang_annotateTokens_Data data = { TU, CXXUnit, Tokens, NumTokens, Cursors };
|
||||||
SourceRange RegionOfInterest;
|
|
||||||
RegionOfInterest.setBegin(cxloc::translateSourceLocation(
|
|
||||||
clang_getTokenLocation(TU, Tokens[0])));
|
|
||||||
RegionOfInterest.setEnd(cxloc::translateSourceLocation(
|
|
||||||
clang_getTokenLocation(TU,
|
|
||||||
Tokens[NumTokens - 1])));
|
|
||||||
|
|
||||||
// A mapping from the source locations found when re-lexing or traversing the
|
|
||||||
// region of interest to the corresponding cursors.
|
|
||||||
AnnotateTokensData Annotated;
|
|
||||||
|
|
||||||
// Relex the tokens within the source range to look for preprocessing
|
|
||||||
// directives.
|
|
||||||
SourceManager &SourceMgr = CXXUnit->getSourceManager();
|
|
||||||
std::pair<FileID, unsigned> BeginLocInfo
|
|
||||||
= SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin());
|
|
||||||
std::pair<FileID, unsigned> EndLocInfo
|
|
||||||
= SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd());
|
|
||||||
|
|
||||||
llvm::StringRef Buffer;
|
|
||||||
bool Invalid = false;
|
|
||||||
if (BeginLocInfo.first == EndLocInfo.first &&
|
|
||||||
((Buffer = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid)),true) &&
|
|
||||||
!Invalid) {
|
|
||||||
Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
|
|
||||||
CXXUnit->getASTContext().getLangOptions(),
|
|
||||||
Buffer.begin(), Buffer.data() + BeginLocInfo.second,
|
|
||||||
Buffer.end());
|
|
||||||
Lex.SetCommentRetentionState(true);
|
|
||||||
|
|
||||||
// Lex tokens in raw mode until we hit the end of the range, to avoid
|
|
||||||
// entering #includes or expanding macros.
|
|
||||||
while (true) {
|
|
||||||
Token Tok;
|
|
||||||
Lex.LexFromRawLexer(Tok);
|
|
||||||
|
|
||||||
reprocess:
|
|
||||||
if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) {
|
|
||||||
// We have found a preprocessing directive. Gobble it up so that we
|
|
||||||
// don't see it while preprocessing these tokens later, but keep track
|
|
||||||
// of all of the token locations inside this preprocessing directive so
|
|
||||||
// that we can annotate them appropriately.
|
|
||||||
//
|
|
||||||
// FIXME: Some simple tests here could identify macro definitions and
|
|
||||||
// #undefs, to provide specific cursor kinds for those.
|
|
||||||
std::vector<SourceLocation> Locations;
|
|
||||||
do {
|
|
||||||
Locations.push_back(Tok.getLocation());
|
|
||||||
Lex.LexFromRawLexer(Tok);
|
|
||||||
} while (!Tok.isAtStartOfLine() && !Tok.is(tok::eof));
|
|
||||||
|
|
||||||
using namespace cxcursor;
|
|
||||||
CXCursor Cursor
|
|
||||||
= MakePreprocessingDirectiveCursor(SourceRange(Locations.front(),
|
|
||||||
Locations.back()),
|
|
||||||
TU);
|
|
||||||
for (unsigned I = 0, N = Locations.size(); I != N; ++I) {
|
|
||||||
Annotated[Locations[I].getRawEncoding()] = Cursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Tok.isAtStartOfLine())
|
|
||||||
goto reprocess;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Tok.is(tok::eof))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Annotate all of the source locations in the region of interest that map to
|
|
||||||
// a specific cursor.
|
|
||||||
AnnotateTokensWorker W(Annotated, Tokens, Cursors, NumTokens,
|
|
||||||
TU, RegionOfInterest);
|
|
||||||
|
|
||||||
// Run the worker within a CrashRecoveryContext.
|
|
||||||
// FIXME: We use a ridiculous stack size here because the data-recursion
|
|
||||||
// algorithm uses a large stack frame than the non-data recursive version,
|
|
||||||
// and AnnotationTokensWorker currently transforms the data-recursion
|
|
||||||
// algorithm back into a traditional recursion by explicitly calling
|
|
||||||
// VisitChildren(). We will need to remove this explicit recursive call.
|
|
||||||
llvm::CrashRecoveryContext CRC;
|
llvm::CrashRecoveryContext CRC;
|
||||||
if (!RunSafely(CRC, runAnnotateTokensWorker, &W,
|
if (!RunSafely(CRC, clang_annotateTokensImpl, &data,
|
||||||
GetSafetyThreadStackSize() * 2)) {
|
GetSafetyThreadStackSize() * 2)) {
|
||||||
fprintf(stderr, "libclang: crash detected while annotating tokens\n");
|
fprintf(stderr, "libclang: crash detected while annotating tokens\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we ran into any entities that involve context-sensitive keywords,
|
|
||||||
// take another pass through the tokens to mark them as such.
|
|
||||||
if (W.hasContextSensitiveKeywords()) {
|
|
||||||
for (unsigned I = 0; I != NumTokens; ++I) {
|
|
||||||
if (clang_getTokenKind(Tokens[I]) != CXToken_Identifier)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (Cursors[I].kind == CXCursor_ObjCPropertyDecl) {
|
|
||||||
IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
|
|
||||||
if (ObjCPropertyDecl *Property
|
|
||||||
= dyn_cast_or_null<ObjCPropertyDecl>(getCursorDecl(Cursors[I]))) {
|
|
||||||
if (Property->getPropertyAttributesAsWritten() != 0 &&
|
|
||||||
llvm::StringSwitch<bool>(II->getName())
|
|
||||||
.Case("readonly", true)
|
|
||||||
.Case("assign", true)
|
|
||||||
.Case("readwrite", true)
|
|
||||||
.Case("retain", true)
|
|
||||||
.Case("copy", true)
|
|
||||||
.Case("nonatomic", true)
|
|
||||||
.Case("atomic", true)
|
|
||||||
.Case("getter", true)
|
|
||||||
.Case("setter", true)
|
|
||||||
.Default(false))
|
|
||||||
Tokens[I].int_data[0] = CXToken_Keyword;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Cursors[I].kind == CXCursor_ObjCInstanceMethodDecl ||
|
|
||||||
Cursors[I].kind == CXCursor_ObjCClassMethodDecl) {
|
|
||||||
IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
|
|
||||||
if (llvm::StringSwitch<bool>(II->getName())
|
|
||||||
.Case("in", true)
|
|
||||||
.Case("out", true)
|
|
||||||
.Case("inout", true)
|
|
||||||
.Case("oneway", true)
|
|
||||||
.Case("bycopy", true)
|
|
||||||
.Case("byref", true)
|
|
||||||
.Default(false))
|
|
||||||
Tokens[I].int_data[0] = CXToken_Keyword;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Cursors[I].kind == CXCursor_CXXMethod) {
|
|
||||||
IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
|
|
||||||
if (CXXMethodDecl *Method
|
|
||||||
= dyn_cast_or_null<CXXMethodDecl>(getCursorDecl(Cursors[I]))) {
|
|
||||||
if ((Method->hasAttr<FinalAttr>() ||
|
|
||||||
Method->hasAttr<OverrideAttr>()) &&
|
|
||||||
Method->getLocation().getRawEncoding() != Tokens[I].int_data[1] &&
|
|
||||||
llvm::StringSwitch<bool>(II->getName())
|
|
||||||
.Case("final", true)
|
|
||||||
.Case("override", true)
|
|
||||||
.Default(false))
|
|
||||||
Tokens[I].int_data[0] = CXToken_Keyword;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Cursors[I].kind == CXCursor_ClassDecl ||
|
|
||||||
Cursors[I].kind == CXCursor_StructDecl ||
|
|
||||||
Cursors[I].kind == CXCursor_ClassTemplate) {
|
|
||||||
IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
|
|
||||||
if (II->getName() == "final") {
|
|
||||||
// We have to be careful with 'final', since it could be the name
|
|
||||||
// of a member class rather than the context-sensitive keyword.
|
|
||||||
// So, check whether the cursor associated with this
|
|
||||||
Decl *D = getCursorDecl(Cursors[I]);
|
|
||||||
if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(D)) {
|
|
||||||
if ((Record->hasAttr<FinalAttr>()) &&
|
|
||||||
Record->getIdentifier() != II)
|
|
||||||
Tokens[I].int_data[0] = CXToken_Keyword;
|
|
||||||
} else if (ClassTemplateDecl *ClassTemplate
|
|
||||||
= dyn_cast_or_null<ClassTemplateDecl>(D)) {
|
|
||||||
CXXRecordDecl *Record = ClassTemplate->getTemplatedDecl();
|
|
||||||
if ((Record->hasAttr<FinalAttr>()) &&
|
|
||||||
Record->getIdentifier() != II)
|
|
||||||
Tokens[I].int_data[0] = CXToken_Keyword;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end: extern "C"
|
} // end: extern "C"
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
Loading…
Reference in New Issue