forked from qt-creator/qt-creator
C++: Stop parsing a declaration after two tries
If we fail to parse a declaration, we rewind, eat the token and look for the next token that might be a good candidate for a declaration start (e.g. an identifier). This becomes cpu and memory expensive with super long and invalid expressions like typedef b:Ⓜ️:if_< b:Ⓜ️:bool_< (sizeof(fun((Dummy *) 0, (ThisT *) 0, (b:Ⓜ️:int_<70> *) 0)) == sizeof(defined_)) >, b:Ⓜ️:if_< b:Ⓜ️:bool_< (sizeof(fun((Dummy *) 0, (ThisT *) 0, (b:Ⓜ️:int_<71> *) 0)) == sizeof(defined_)) >, b:Ⓜ️:if_< b:Ⓜ️:bool_< (sizeof(fun((Dummy *) 0, (ThisT *) 0, (b:Ⓜ️:int_<72> *) 0)) == sizeof(defined_)) >, b:Ⓜ️:if_< b:Ⓜ️:bool_< (sizeof(fun((Dummy *) 0, (ThisT *) 0, (b:Ⓜ️:int_<73> *) 0)) == sizeof(defined_)) >, b:Ⓜ️:if_< b:Ⓜ️:bool_< (sizeof(fun((Dummy *) 0, (ThisT *) 0, (b:Ⓜ️:int_<74> *) 0)) == sizeof(defined_)) >, b:Ⓜ️:if_< b:Ⓜ️:bool_< (sizeof(fun((Dummy *) 0, (ThisT *) 0, (b:Ⓜ️:int_<75> *) 0)) == sizeof(defined_)) >, b:Ⓜ️:if_< b:Ⓜ️:bool_< // ...some more crazy lines like this Therefore, stop trying after two failures by looking for the next semicolon or closing curly brace. Task-number: QTCREATORBUG-12890 Change-Id: I6637daeb840dd549d669080775228fa91fc932eb Reviewed-by: Erik Verbruggen <erik.verbruggen@theqtcompany.com>
This commit is contained in:
28
src/libs/3rdparty/cplusplus/Parser.cpp
vendored
28
src/libs/3rdparty/cplusplus/Parser.cpp
vendored
@@ -66,6 +66,8 @@ public:
|
|||||||
|
|
||||||
int DebugRule::depth = 0;
|
int DebugRule::depth = 0;
|
||||||
|
|
||||||
|
const int declarationsInRowAllowedToFail = 2;
|
||||||
|
|
||||||
inline bool lookAtAssignmentOperator(int tokenKind)
|
inline bool lookAtAssignmentOperator(int tokenKind)
|
||||||
{
|
{
|
||||||
switch (tokenKind) {
|
switch (tokenKind) {
|
||||||
@@ -310,6 +312,20 @@ bool Parser::skipUntil(int token)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Parser::skipUntilAfterSemicolonOrRightBrace()
|
||||||
|
{
|
||||||
|
while (int tk = LA()) {
|
||||||
|
switch (tk) {
|
||||||
|
case T_SEMICOLON:
|
||||||
|
case T_RBRACE:
|
||||||
|
consumeToken();
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
consumeToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Parser::skipUntilDeclaration()
|
void Parser::skipUntilDeclaration()
|
||||||
{
|
{
|
||||||
for (; ; consumeToken()) {
|
for (; ; consumeToken()) {
|
||||||
@@ -626,18 +642,24 @@ bool Parser::parseTranslationUnit(TranslationUnitAST *&node)
|
|||||||
TranslationUnitAST *ast = new (_pool) TranslationUnitAST;
|
TranslationUnitAST *ast = new (_pool) TranslationUnitAST;
|
||||||
DeclarationListAST **decl = &ast->declaration_list;
|
DeclarationListAST **decl = &ast->declaration_list;
|
||||||
|
|
||||||
|
int declarationsInRowFailedToParse = 0;
|
||||||
|
|
||||||
while (LA()) {
|
while (LA()) {
|
||||||
unsigned start_declaration = cursor();
|
unsigned start_declaration = cursor();
|
||||||
|
|
||||||
DeclarationAST *declaration = 0;
|
DeclarationAST *declaration = 0;
|
||||||
|
|
||||||
if (parseDeclaration(declaration)) {
|
if (parseDeclaration(declaration)) {
|
||||||
|
declarationsInRowFailedToParse = 0;
|
||||||
*decl = new (_pool) DeclarationListAST;
|
*decl = new (_pool) DeclarationListAST;
|
||||||
(*decl)->value = declaration;
|
(*decl)->value = declaration;
|
||||||
decl = &(*decl)->next;
|
decl = &(*decl)->next;
|
||||||
} else {
|
} else {
|
||||||
error(start_declaration, "expected a declaration");
|
error(start_declaration, "expected a declaration");
|
||||||
rewind(start_declaration + 1);
|
rewind(start_declaration + 1);
|
||||||
|
if (++declarationsInRowFailedToParse == declarationsInRowAllowedToFail)
|
||||||
|
skipUntilAfterSemicolonOrRightBrace();
|
||||||
|
else
|
||||||
skipUntilDeclaration();
|
skipUntilDeclaration();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -787,6 +809,8 @@ bool Parser::parseLinkageBody(DeclarationAST *&node)
|
|||||||
ast->lbrace_token = consumeToken();
|
ast->lbrace_token = consumeToken();
|
||||||
DeclarationListAST **declaration_ptr = &ast->declaration_list;
|
DeclarationListAST **declaration_ptr = &ast->declaration_list;
|
||||||
|
|
||||||
|
int declarationsInRowFailedToParse = 0;
|
||||||
|
|
||||||
while (int tk = LA()) {
|
while (int tk = LA()) {
|
||||||
if (tk == T_RBRACE)
|
if (tk == T_RBRACE)
|
||||||
break;
|
break;
|
||||||
@@ -794,12 +818,16 @@ bool Parser::parseLinkageBody(DeclarationAST *&node)
|
|||||||
unsigned start_declaration = cursor();
|
unsigned start_declaration = cursor();
|
||||||
DeclarationAST *declaration = 0;
|
DeclarationAST *declaration = 0;
|
||||||
if (parseDeclaration(declaration)) {
|
if (parseDeclaration(declaration)) {
|
||||||
|
declarationsInRowFailedToParse = 0;
|
||||||
*declaration_ptr = new (_pool) DeclarationListAST;
|
*declaration_ptr = new (_pool) DeclarationListAST;
|
||||||
(*declaration_ptr)->value = declaration;
|
(*declaration_ptr)->value = declaration;
|
||||||
declaration_ptr = &(*declaration_ptr)->next;
|
declaration_ptr = &(*declaration_ptr)->next;
|
||||||
} else {
|
} else {
|
||||||
error(start_declaration, "expected a declaration");
|
error(start_declaration, "expected a declaration");
|
||||||
rewind(start_declaration + 1);
|
rewind(start_declaration + 1);
|
||||||
|
if (++declarationsInRowFailedToParse == declarationsInRowAllowedToFail)
|
||||||
|
skipUntilAfterSemicolonOrRightBrace();
|
||||||
|
else
|
||||||
skipUntilDeclaration();
|
skipUntilDeclaration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
src/libs/3rdparty/cplusplus/Parser.h
vendored
1
src/libs/3rdparty/cplusplus/Parser.h
vendored
@@ -254,6 +254,7 @@ public:
|
|||||||
bool parseDesignator(DesignatorAST *&node);
|
bool parseDesignator(DesignatorAST *&node);
|
||||||
|
|
||||||
bool skipUntil(int token);
|
bool skipUntil(int token);
|
||||||
|
void skipUntilAfterSemicolonOrRightBrace();
|
||||||
void skipUntilDeclaration();
|
void skipUntilDeclaration();
|
||||||
bool skipUntilStatement();
|
bool skipUntilStatement();
|
||||||
bool skip(int l, int r);
|
bool skip(int l, int r);
|
||||||
|
Reference in New Issue
Block a user