From beac7b9539457fe721de1709b9a406cac2379851 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Wed, 19 Nov 2014 12:07:29 +0100 Subject: [PATCH] C++: Fix highlighting after "invalid code" For the semantic info document we do not expand function like macros and because of that certain macro invocations lead to invalid code that we need to handle, e.g.: Q_GLOBAL_STATIC(CppTools::SymbolFinder, symbolFinder) class Foo {}; This change makes parsing Foo in the semantic info document successfully again, which affects highlighting of that class. Change-Id: I389265ac64d3f0b8b8f406d38fa58d78820b14ba Reviewed-by: Erik Verbruggen --- src/libs/3rdparty/cplusplus/Parser.cpp | 9 +++---- src/libs/3rdparty/cplusplus/Parser.h | 3 ++- .../3rdparty/cplusplus/TranslationUnit.cpp | 5 ++-- src/libs/3rdparty/cplusplus/TranslationUnit.h | 5 ++++ src/libs/cplusplus/CppDocument.cpp | 7 +++++ src/libs/cplusplus/CppDocument.h | 1 + .../cpptools/cppsemanticinfoupdater.cpp | 1 + tests/auto/cplusplus/ast/tst_ast.cpp | 27 ++++++++++++++++++- 8 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index 11656bd47f1..c98f92cc37b 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -66,8 +66,6 @@ public: int DebugRule::depth = 0; -const int declarationsInRowAllowedToFail = 2; - inline bool lookAtAssignmentOperator(int tokenKind) { switch (tokenKind) { @@ -267,12 +265,13 @@ inline void debugPrintCheckCache(bool) {} return true; \ } -Parser::Parser(TranslationUnit *unit) +Parser::Parser(TranslationUnit *unit, int retryParseDeclarationLimit) : _translationUnit(unit), _control(unit->control()), _pool(unit->memoryPool()), _languageFeatures(unit->languageFeatures()), _tokenIndex(1), + _retryParseDeclarationLimit(retryParseDeclarationLimit), _templateArguments(0), _inFunctionBody(false), _inExpressionStatement(false), @@ -657,7 +656,7 @@ bool Parser::parseTranslationUnit(TranslationUnitAST *&node) } else { error(start_declaration, "expected a declaration"); rewind(start_declaration + 1); - if (++declarationsInRowFailedToParse == declarationsInRowAllowedToFail) + if (++declarationsInRowFailedToParse == _retryParseDeclarationLimit) skipUntilAfterSemicolonOrRightBrace(); else skipUntilDeclaration(); @@ -825,7 +824,7 @@ bool Parser::parseLinkageBody(DeclarationAST *&node) } else { error(start_declaration, "expected a declaration"); rewind(start_declaration + 1); - if (++declarationsInRowFailedToParse == declarationsInRowAllowedToFail) + if (++declarationsInRowFailedToParse == _retryParseDeclarationLimit) skipUntilAfterSemicolonOrRightBrace(); else skipUntilDeclaration(); diff --git a/src/libs/3rdparty/cplusplus/Parser.h b/src/libs/3rdparty/cplusplus/Parser.h index 923b0c4dc82..5f0a182bd12 100644 --- a/src/libs/3rdparty/cplusplus/Parser.h +++ b/src/libs/3rdparty/cplusplus/Parser.h @@ -33,7 +33,7 @@ namespace CPlusPlus { class CPLUSPLUS_EXPORT Parser { public: - Parser(TranslationUnit *translationUnit); + Parser(TranslationUnit *translationUnit, int retryParseDeclarationLimit); ~Parser(); bool parseTranslationUnit(TranslationUnitAST *&node); @@ -317,6 +317,7 @@ private: MemoryPool *_pool; LanguageFeatures _languageFeatures; unsigned _tokenIndex; + int _retryParseDeclarationLimit; bool _templateArguments: 1; bool _inFunctionBody: 1; bool _inExpressionStatement: 1; diff --git a/src/libs/3rdparty/cplusplus/TranslationUnit.cpp b/src/libs/3rdparty/cplusplus/TranslationUnit.cpp index ace6eda549a..86eb25f1e35 100644 --- a/src/libs/3rdparty/cplusplus/TranslationUnit.cpp +++ b/src/libs/3rdparty/cplusplus/TranslationUnit.cpp @@ -49,7 +49,8 @@ TranslationUnit::TranslationUnit(Control *control, const StringLiteral *fileId) _lastSourceChar(0), _pool(0), _ast(0), - _flags(0) + _flags(0), + _retryParseDeclarationLimit(defaultRetryParseDeclarationLimit()) { _tokens = new std::vector(); _comments = new std::vector(); @@ -299,7 +300,7 @@ bool TranslationUnit::parse(ParseMode mode) f._parsed = true; - Parser parser(this); + Parser parser(this, _retryParseDeclarationLimit); bool parsed = false; switch (mode) { diff --git a/src/libs/3rdparty/cplusplus/TranslationUnit.h b/src/libs/3rdparty/cplusplus/TranslationUnit.h index 94eb81666be..eb4e1f2e3a5 100644 --- a/src/libs/3rdparty/cplusplus/TranslationUnit.h +++ b/src/libs/3rdparty/cplusplus/TranslationUnit.h @@ -149,6 +149,9 @@ public: LanguageFeatures languageFeatures() const { return _languageFeatures; } void setLanguageFeatures(LanguageFeatures features) { _languageFeatures = features; } + static int defaultRetryParseDeclarationLimit() { return 2; } + void setRetryParseDeclarationLimit(int limit) { _retryParseDeclarationLimit = limit; } + private: struct PPLine { unsigned utf16charOffset; @@ -210,6 +213,8 @@ private: Flags f; }; LanguageFeatures _languageFeatures; + + int _retryParseDeclarationLimit; }; } // namespace CPlusPlus diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index 6c51ff5f3b0..3eea3c80c16 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -623,6 +623,13 @@ void Document::tokenize() _translationUnit->tokenize(); } +void Document::setRetryHarderToParseDeclarations(bool yesno) +{ + _translationUnit->setRetryParseDeclarationLimit( + yesno ? 1000 + : TranslationUnit::defaultRetryParseDeclarationLimit()); +} + bool Document::isParsed() const { return _translationUnit->isParsed(); diff --git a/src/libs/cplusplus/CppDocument.h b/src/libs/cplusplus/CppDocument.h index c680a0751e9..f840737d474 100644 --- a/src/libs/cplusplus/CppDocument.h +++ b/src/libs/cplusplus/CppDocument.h @@ -127,6 +127,7 @@ public: bool isTokenized() const; void tokenize(); + void setRetryHarderToParseDeclarations(bool yesno); bool isParsed() const; bool parse(ParseMode mode = ParseTranlationUnit); diff --git a/src/plugins/cpptools/cppsemanticinfoupdater.cpp b/src/plugins/cpptools/cppsemanticinfoupdater.cpp index 2ee0501aa72..9c9d87ac6a2 100644 --- a/src/plugins/cpptools/cppsemanticinfoupdater.cpp +++ b/src/plugins/cpptools/cppsemanticinfoupdater.cpp @@ -125,6 +125,7 @@ SemanticInfo SemanticInfoUpdaterPrivate::update(const SemanticInfo::Source &sour Document::Ptr doc = newSemanticInfo.snapshot.preprocessedDocument(source.code, source.fileName); if (processor) doc->control()->setTopLevelDeclarationProcessor(processor); + doc->setRetryHarderToParseDeclarations(true); doc->check(); if (processor && processor->isCanceled()) newSemanticInfo.complete = false; diff --git a/tests/auto/cplusplus/ast/tst_ast.cpp b/tests/auto/cplusplus/ast/tst_ast.cpp index 1691919012f..30e56b2350c 100644 --- a/tests/auto/cplusplus/ast/tst_ast.cpp +++ b/tests/auto/cplusplus/ast/tst_ast.cpp @@ -51,7 +51,9 @@ public: TranslationUnit::ParseMode mode, bool blockErrors = false, bool qtMocRun = false, - bool cxx11Enabled = false) + bool cxx11Enabled = false, + int retryParseDeclarationLimit + = TranslationUnit::defaultRetryParseDeclarationLimit()) { const StringLiteral *fileId = control.stringLiteral(""); LanguageFeatures features; @@ -62,6 +64,7 @@ public: features.qtMocRunEnabled = qtMocRun; TranslationUnit *unit = new TranslationUnit(&control, fileId); unit->setLanguageFeatures(features); + unit->setRetryParseDeclarationLimit(retryParseDeclarationLimit); unit->setSource(source.constData(), source.length()); unit->blockErrors(blockErrors); unit->parse(mode); @@ -199,6 +202,7 @@ private slots: void unnamed_class(); void unnamed_class_data(); void expensiveExpression(); + void invalidCode(); }; void tst_AST::gcc_attributes_1() @@ -1856,6 +1860,27 @@ void tst_AST::expensiveExpression() QVERIFY(unit->ast()); } +void tst_AST::invalidCode() +{ + const QByteArray invalidCode = "static inValidLine()\n" + "class Foo {};\n"; + + QSharedPointer unit(parse(invalidCode, TranslationUnit::ParseTranlationUnit, + false, false, false, 1000)); + QVERIFY(unit->ast()); + TranslationUnitAST *unitAST = unit->ast()->asTranslationUnit(); + QVERIFY(unitAST->declaration_list); + QVERIFY(unitAST->declaration_list->value); + SimpleDeclarationAST *simpleDecl = unitAST->declaration_list->value->asSimpleDeclaration(); + QVERIFY(simpleDecl); + QVERIFY(simpleDecl->decl_specifier_list); + QVERIFY(simpleDecl->decl_specifier_list->value); + ClassSpecifierAST *classSpecifier = simpleDecl->decl_specifier_list->value->asClassSpecifier(); + QVERIFY(classSpecifier); + + QVERIFY(diag.errorCount != 0); +} + void tst_AST::initTestCase() { control.setDiagnosticClient(&diag);