diff options
author | Nikolai Kosjar <nikolai.kosjar@qt.io> | 2016-04-22 15:31:49 +0200 |
---|---|---|
committer | Nikolai Kosjar <nikolai.kosjar@qt.io> | 2016-04-26 12:28:16 +0000 |
commit | 7b7b1823cbfbf95589bf1f8fc07253f3f5ad7477 (patch) | |
tree | 4968b0f66b944fa7e36e436d786818ed48262087 /src | |
parent | 66e9cb0a5446c043385ab84af1cc13539c7fbe45 (diff) | |
download | qt-creator-7b7b1823cbfbf95589bf1f8fc07253f3f5ad7477.tar.gz |
Clang: Avoid parse loop if libclang crashed or file vanished
Remember whether clang_parseTranslationUnit() or
clang_reparseTranslationUnit() failed the last time and do not trigger
parse/reparse again.
Also, check whether the main file exists before reparsing.
Task-number: QTCREATORBUG-16051
Task-number: QTCREATORBUG-16140
Change-Id: Ied39e66a18032854911229898573941fe2ada35b
Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
Diffstat (limited to 'src')
7 files changed, 201 insertions, 24 deletions
diff --git a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri index 344a037207..6140f1ca88 100644 --- a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri +++ b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri @@ -12,6 +12,7 @@ HEADERS += $$PWD/clangipcserver.h \ $$PWD/projects.h \ $$PWD/translationunits.h \ $$PWD/translationunitparseerrorexception.h \ + $$PWD/translationunitreparseerrorexception.h \ $$PWD/projectpart.h \ $$PWD/translationunitfilenotexitexception.h \ $$PWD/translationunitdoesnotexistexception.h \ @@ -46,6 +47,7 @@ SOURCES += $$PWD/clangipcserver.cpp \ $$PWD/projects.cpp \ $$PWD/translationunits.cpp \ $$PWD/translationunitparseerrorexception.cpp \ + $$PWD/translationunitreparseerrorexception.cpp \ $$PWD/projectpart.cpp \ $$PWD/translationunitfilenotexitexception.cpp \ $$PWD/translationunitdoesnotexistexception.cpp \ diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp b/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp index 3460e6ff46..0644c53e3f 100644 --- a/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp +++ b/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp @@ -39,6 +39,7 @@ #include "translationunitfilenotexitexception.h" #include "translationunitisnullexception.h" #include "translationunitparseerrorexception.h" +#include "translationunitreparseerrorexception.h" #include "translationunits.h" #include "unsavedfiles.h" @@ -76,6 +77,8 @@ public: Utf8StringVector fileArguments; Utf8String filePath; CXTranslationUnit translationUnit = nullptr; + CXErrorCode parseErrorCode = CXError_Success; + int reparseErrorCode = 0; CXIndex index = nullptr; uint documentRevision = 0; bool needsToBeReparsed = false; @@ -155,6 +158,16 @@ void TranslationUnit::reparse() const reparseTranslationUnit(); } +bool TranslationUnit::parseWasSuccessful() const +{ + return d->parseErrorCode == CXError_Success; +} + +bool TranslationUnit::reparseWasSuccessful() const +{ + return d->reparseErrorCode == 0; +} + CXIndex TranslationUnit::index() const { checkIfNull(); @@ -350,7 +363,7 @@ void TranslationUnit::checkIfNull() const void TranslationUnit::checkIfFileExists() const { - if (!QFileInfo::exists(d->filePath.toString())) + if (!fileExists()) throw TranslationUnitFileNotExitsException(d->filePath); } @@ -396,16 +409,16 @@ void TranslationUnit::createTranslationUnitIfNeeded() const if (isVerboseModeEnabled()) args.print(); - CXErrorCode errorCode = clang_parseTranslationUnit2(index(), - NULL, - args.data(), - args.count(), - unsavedFiles().cxUnsavedFiles(), - unsavedFiles().count(), - defaultOptions(), - &d->translationUnit); + d->parseErrorCode = clang_parseTranslationUnit2(index(), + NULL, + args.data(), + args.count(), + unsavedFiles().cxUnsavedFiles(), + unsavedFiles().count(), + defaultOptions(), + &d->translationUnit); - checkTranslationUnitErrorCode(errorCode); + checkParseErrorCode(); updateIncludeFilePaths(); @@ -413,22 +426,33 @@ void TranslationUnit::createTranslationUnitIfNeeded() const } } -void TranslationUnit::checkTranslationUnitErrorCode(CXErrorCode errorCode) const +void TranslationUnit::checkParseErrorCode() const { - switch (errorCode) { - case CXError_Success: break; - default: throw TranslationUnitParseErrorException(d->filePath, - d->projectPart.projectPartId(), - errorCode); + if (!parseWasSuccessful()) { + throw TranslationUnitParseErrorException(d->filePath, + d->projectPart.projectPartId(), + d->parseErrorCode); + } +} + +void TranslationUnit::checkReparseErrorCode() const +{ + if (!reparseWasSuccessful()) { + throw TranslationUnitReparseErrorException(d->filePath, + d->projectPart.projectPartId(), + d->reparseErrorCode); } } void TranslationUnit::reparseTranslationUnit() const { - clang_reparseTranslationUnit(d->translationUnit, - unsavedFiles().count(), - unsavedFiles().cxUnsavedFiles(), - clang_defaultReparseOptions(d->translationUnit)); + d->reparseErrorCode = clang_reparseTranslationUnit( + d->translationUnit, + unsavedFiles().count(), + unsavedFiles().cxUnsavedFiles(), + clang_defaultReparseOptions(d->translationUnit)); + + checkReparseErrorCode(); updateIncludeFilePaths(); @@ -474,6 +498,19 @@ void TranslationUnit::updateIncludeFilePaths() const d->translationUnits.addWatchedFiles(d->dependedFilePaths); } +bool TranslationUnit::fileExists() const +{ + return QFileInfo::exists(d->filePath.toString()); +} + +bool TranslationUnit::isIntact() const +{ + return !isNull() + && fileExists() + && parseWasSuccessful() + && reparseWasSuccessful(); +} + CommandLineArguments TranslationUnit::commandLineArguments() const { return CommandLineArguments(d->filePath.constData(), diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunit.h b/src/tools/clangbackend/ipcsource/clangtranslationunit.h index 9a311b62bf..553a3f28de 100644 --- a/src/tools/clangbackend/ipcsource/clangtranslationunit.h +++ b/src/tools/clangbackend/ipcsource/clangtranslationunit.h @@ -91,6 +91,8 @@ public: void reset(); void reparse() const; + bool isIntact() const; + CXIndex index() const; CXTranslationUnit cxTranslationUnit() const; CXTranslationUnit cxTranslationUnitWithoutReparsing() const; @@ -150,10 +152,14 @@ private: bool projectPartIsOutdated() const; bool isMainFileAndExistsOrIsOtherFile(const Utf8String &filePath) const; void createTranslationUnitIfNeeded() const; - void checkTranslationUnitErrorCode(CXErrorCode errorCode) const; + void checkParseErrorCode() const; + void checkReparseErrorCode() const; void reparseTranslationUnit() const; void reparseTranslationUnitIfFilesAreChanged() const; + bool parseWasSuccessful() const; + bool reparseWasSuccessful() const; void updateIncludeFilePaths() const; + bool fileExists() const; static void includeCallback(CXFile included_file, CXSourceLocation * /*inclusion_stack*/, unsigned /*include_len*/, diff --git a/src/tools/clangbackend/ipcsource/translationunitparseerrorexception.cpp b/src/tools/clangbackend/ipcsource/translationunitparseerrorexception.cpp index 3cd99c53e8..27f1799e09 100644 --- a/src/tools/clangbackend/ipcsource/translationunitparseerrorexception.cpp +++ b/src/tools/clangbackend/ipcsource/translationunitparseerrorexception.cpp @@ -65,12 +65,13 @@ static const char *errorCodeToText(CXErrorCode errorCode) const char *TranslationUnitParseErrorException::what() const Q_DECL_NOEXCEPT { if (what_.isEmpty()) { - what_ += Utf8StringLiteral("Parse error for file ") + what_ += Utf8StringLiteral("clang_parseTranslationUnit() failed for file ") + filePath() + Utf8StringLiteral(" in project ") + projectPartId() + Utf8StringLiteral(": ") - + Utf8String::fromUtf8(errorCodeToText(errorCode_)); + + Utf8String::fromUtf8(errorCodeToText(errorCode_)) + + Utf8StringLiteral("."); } return what_.constData(); diff --git a/src/tools/clangbackend/ipcsource/translationunitreparseerrorexception.cpp b/src/tools/clangbackend/ipcsource/translationunitreparseerrorexception.cpp new file mode 100644 index 0000000000..6f1e7f0d7d --- /dev/null +++ b/src/tools/clangbackend/ipcsource/translationunitreparseerrorexception.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "translationunitreparseerrorexception.h" + +#include <QString> + +namespace ClangBackEnd { + +TranslationUnitReparseErrorException::TranslationUnitReparseErrorException( + const Utf8String &filePath, + const Utf8String &projectPartId, + int errorCode) + : filePath_(filePath), + projectPartId_(projectPartId), + errorCode_(errorCode) +{ +} + +const Utf8String &TranslationUnitReparseErrorException::filePath() const +{ + return filePath_; +} + +const Utf8String &TranslationUnitReparseErrorException::projectPartId() const +{ + return projectPartId_; +} + +const char *TranslationUnitReparseErrorException::what() const Q_DECL_NOEXCEPT +{ + if (what_.isEmpty()) { + what_ += Utf8StringLiteral("clang_reparseTranslationUnit() failed for file ") + + filePath() + + Utf8StringLiteral(" in project ") + + projectPartId() + + Utf8StringLiteral(": ") + + Utf8String::fromString(QString::number(errorCode_)) + + Utf8StringLiteral("."); + } + + return what_.constData(); +} + +} // namespace ClangBackEnd + diff --git a/src/tools/clangbackend/ipcsource/translationunitreparseerrorexception.h b/src/tools/clangbackend/ipcsource/translationunitreparseerrorexception.h new file mode 100644 index 0000000000..126a24c7e9 --- /dev/null +++ b/src/tools/clangbackend/ipcsource/translationunitreparseerrorexception.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <utf8string.h> + +#include <clang-c/Index.h> + +#include <exception> + +namespace ClangBackEnd { + +class TranslationUnitReparseErrorException : public std::exception +{ +public: + TranslationUnitReparseErrorException(const Utf8String &filePath, + const Utf8String &projectPartId, + int errorCode); + + const Utf8String &filePath() const; + const Utf8String &projectPartId() const; + + const char *what() const Q_DECL_NOEXCEPT override; + +#if defined(__GNUC__) && !defined(__clang__) +# if !__GNUC_PREREQ(4,8) + ~TranslationUnitReparseErrorException() noexcept {} +# endif +#endif + +private: + Utf8String filePath_; + Utf8String projectPartId_; + int errorCode_; + mutable Utf8String what_; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/translationunits.cpp b/src/tools/clangbackend/ipcsource/translationunits.cpp index 5b118a9652..6f9defc356 100644 --- a/src/tools/clangbackend/ipcsource/translationunits.cpp +++ b/src/tools/clangbackend/ipcsource/translationunits.cpp @@ -199,7 +199,9 @@ namespace { bool translationUnitHasNewDocumentAnnotations(const TranslationUnit &translationUnit) { - return translationUnit.hasNewDiagnostics() || translationUnit.hasNewHighlightingInformations(); + return translationUnit.isIntact() + && (translationUnit.hasNewDiagnostics() + || translationUnit.hasNewHighlightingInformations()); } } |