C++: Cache parsing of template ids

...in order to stop memory intensive parsing for invalid code.

Parsing the test data/snippet "hard" led to a memory consumption of
about 5.5MB and this could easily get up to hundreds/gigabytes by adding
some more "if_<bool_<true>,\n" lines. With the caching, we are at about
1.0MB, even if more lines are added.

The "memory consumption" was measured with valgrind-massif. The stated
numbers are the reported peaks.

Task-number: QTCREATORBUG-12890
Change-Id: Ie7eb00cfc7915552d29bb27410a6b13a486f486e
Reviewed-by: Erik Verbruggen <erik.verbruggen@theqtcompany.com>
This commit is contained in:
Nikolai Kosjar
2015-02-10 16:21:53 +01:00
parent ae3aa07c4d
commit 921ec6da5a
2 changed files with 66 additions and 7 deletions

View File

@@ -165,6 +165,7 @@ public:
Expression, Expression,
ExpressionList, ExpressionList,
ParameterDeclarationClause, ParameterDeclarationClause,
TemplateId,
TypeId TypeId
}; };
@@ -510,6 +511,7 @@ bool Parser::parseClassOrNamespaceName(NameAST *&node)
bool Parser::parseTemplateId(NameAST *&node, unsigned template_token) bool Parser::parseTemplateId(NameAST *&node, unsigned template_token)
{ {
DEBUG_THIS_RULE(); DEBUG_THIS_RULE();
CHECK_CACHE(ASTCache::TemplateId, NameAST);
const unsigned start = cursor(); const unsigned start = cursor();
@@ -523,14 +525,17 @@ bool Parser::parseTemplateId(NameAST *&node, unsigned template_token)
if (maybeSplitGreaterGreaterToken() || LA() == T_GREATER) { if (maybeSplitGreaterGreaterToken() || LA() == T_GREATER) {
ast->greater_token = consumeToken(); ast->greater_token = consumeToken();
node = ast; node = ast;
return true; const bool result = true;
_astCache->insert(ASTCache::TemplateId, start, node, cursor(), result);
return result;
} }
} }
} }
const bool result = false;
_astCache->insert(ASTCache::TemplateId, start, 0, cursor(), result);
rewind(start); rewind(start);
return result;
return false;
} }
bool Parser::parseNestedNameSpecifier(NestedNameSpecifierListAST *&node, bool Parser::parseNestedNameSpecifier(NestedNameSpecifierListAST *&node,

View File

@@ -199,6 +199,7 @@ private slots:
void unnamed_class(); void unnamed_class();
void unnamed_class_data(); void unnamed_class_data();
void expensiveExpression(); void expensiveExpression();
void invalidCode_data();
void invalidCode(); void invalidCode();
}; };
@@ -1857,13 +1858,66 @@ void tst_AST::expensiveExpression()
QVERIFY(unit->ast()); QVERIFY(unit->ast());
} }
void tst_AST::invalidCode_data()
{
QTest::addColumn<QByteArray>("source");
typedef QByteArray _;
QTest::newRow("simple") <<
_("static inValidLine()\n");
QTest::newRow("hard") <<
_("typedef\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true>,\n"
"if_<bool_<true {}\n");
}
void tst_AST::invalidCode() void tst_AST::invalidCode()
{ {
const QByteArray invalidCode = "static inValidLine()\n" QFETCH(QByteArray, source);
"class Foo {};\n";
QSharedPointer<TranslationUnit> unit(parse(invalidCode, TranslationUnit::ParseTranlationUnit, source += "\nclass Foo {};\n";
false, false, false)); const QSharedPointer<TranslationUnit> unit(parse(source, TranslationUnit::ParseTranlationUnit,
false, false, true));
// Check that we find the class coming after the invalid garbage.
QVERIFY(unit->ast()); QVERIFY(unit->ast());
TranslationUnitAST *unitAST = unit->ast()->asTranslationUnit(); TranslationUnitAST *unitAST = unit->ast()->asTranslationUnit();
QVERIFY(unitAST->declaration_list); QVERIFY(unitAST->declaration_list);