Clang: Show info bar for parse errors in header files

...because those errors can lead to a substantial performance/functional
regression.

The actual diagnostics (possibly with children) are shown as details in
the info bar.

The info bar can be hidden with the "Do Not Show Again" button.
Re-enabling the info bar is possible with the new editor tool bar
button.

Change-Id: I03394ff8e3c84127946b0b791930b28a385f5a46
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Nikolai Kosjar
2016-10-04 16:23:42 +02:00
parent cb24872f43
commit 9d55d8485c
25 changed files with 458 additions and 44 deletions

View File

@@ -182,7 +182,9 @@ void IpcReceiver::documentAnnotationsChanged(const DocumentAnnotationsChangedMes
const QString documentProjectPartId = CppTools::CppToolsBridge::projectPartIdForFile(filePath);
if (projectPartId == documentProjectPartId) {
const quint32 documentRevision = message.fileContainer().documentRevision();
processor->updateCodeWarnings(message.diagnostics(), documentRevision);
processor->updateCodeWarnings(message.diagnostics(),
message.firstHeaderErrorDiagnostic(),
documentRevision);
processor->updateHighlighting(message.highlightingMarks(),
message.skippedPreprocessorRanges(),
documentRevision);

View File

@@ -41,6 +41,7 @@
#include <utils/proxyaction.h>
#include <utils/qtcassert.h>
#include <QFileInfo>
#include <QTextBlock>
namespace {

View File

@@ -129,9 +129,10 @@ enum IndentType { IndentDiagnostic, DoNotIndentDiagnostic };
QWidget *createDiagnosticLabel(const ClangBackEnd::DiagnosticContainer &diagnostic,
const QString &mainFilePath,
IndentType indentType = DoNotIndentDiagnostic)
IndentType indentType = DoNotIndentDiagnostic,
bool enableClickableFixits = true)
{
const bool hasFixit = !diagnostic.fixIts().isEmpty();
const bool hasFixit = enableClickableFixits ? !diagnostic.fixIts().isEmpty() : false;
const QString diagnosticText = diagnostic.text().toString().toHtmlEscaped();
const QString text = clickableLocation(mainFilePath, diagnostic.location())
+ QStringLiteral(": ")
@@ -159,25 +160,35 @@ class MainDiagnosticWidget : public QWidget
{
Q_OBJECT
public:
MainDiagnosticWidget(const ClangBackEnd::DiagnosticContainer &diagnostic)
MainDiagnosticWidget(const ClangBackEnd::DiagnosticContainer &diagnostic,
const ClangCodeModel::Internal::DisplayHints &displayHints)
{
setContentsMargins(0, 0, 0, 0);
auto *mainLayout = createLayout<QVBoxLayout>();
// Set up header row: category + responsible option
const QString category = diagnostic.category();
const QString responsibleOption = diagnostic.enableOption();
const ClangBackEnd::SourceLocationContainer location = diagnostic.location();
auto *headerLayout = createLayout<QHBoxLayout>();
headerLayout->addWidget(new QLabel(wrapInBoldTags(category)), 1);
// Set up header row: category + responsible option
if (displayHints.showMainDiagnosticHeader) {
const QString category = diagnostic.category();
const QString responsibleOption = diagnostic.enableOption();
auto *responsibleOptionLabel = new QLabel(wrapInColor(responsibleOption, "gray"));
headerLayout->addWidget(responsibleOptionLabel, 0);
mainLayout->addLayout(headerLayout);
auto *headerLayout = createLayout<QHBoxLayout>();
headerLayout->addWidget(new QLabel(wrapInBoldTags(category)), 1);
auto *responsibleOptionLabel = new QLabel(wrapInColor(responsibleOption, "gray"));
headerLayout->addWidget(responsibleOptionLabel, 0);
mainLayout->addLayout(headerLayout);
}
// Set up main row: diagnostic text
mainLayout->addWidget(createDiagnosticLabel(diagnostic, location.filePath()));
const Utf8String mainFilePath = displayHints.showFileNameInMainDiagnostic
? Utf8String()
: location.filePath();
mainLayout->addWidget(createDiagnosticLabel(diagnostic,
mainFilePath,
DoNotIndentDiagnostic,
displayHints.enableClickableFixits));
setLayout(mainLayout);
}
@@ -186,26 +197,35 @@ public:
void addChildrenToLayout(const QString &mainFilePath,
const QVector<ClangBackEnd::DiagnosticContainer>::const_iterator first,
const QVector<ClangBackEnd::DiagnosticContainer>::const_iterator last,
bool enableClickableFixits,
QLayout &boxLayout)
{
for (auto it = first; it != last; ++it)
boxLayout.addWidget(createDiagnosticLabel(*it, mainFilePath, IndentDiagnostic));
for (auto it = first; it != last; ++it) {
boxLayout.addWidget(createDiagnosticLabel(*it,
mainFilePath,
IndentDiagnostic,
enableClickableFixits));
}
}
void setupChildDiagnostics(const QString &mainFilePath,
const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
bool enableClickableFixits,
QLayout &boxLayout)
{
if (diagnostics.size() <= 10) {
addChildrenToLayout(mainFilePath, diagnostics.begin(), diagnostics.end(), boxLayout);
addChildrenToLayout(mainFilePath, diagnostics.begin(), diagnostics.end(),
enableClickableFixits, boxLayout);
} else {
addChildrenToLayout(mainFilePath, diagnostics.begin(), diagnostics.begin() + 7, boxLayout);
addChildrenToLayout(mainFilePath, diagnostics.begin(), diagnostics.begin() + 7,
enableClickableFixits, boxLayout);
auto ellipsisLabel = new QLabel(QStringLiteral("..."));
ellipsisLabel->setContentsMargins(childIndentationOnTheLeftInPixel, 0, 0, 0);
boxLayout.addWidget(ellipsisLabel);
addChildrenToLayout(mainFilePath, diagnostics.end() - 3, diagnostics.end(), boxLayout);
addChildrenToLayout(mainFilePath, diagnostics.end() - 3, diagnostics.end(),
enableClickableFixits, boxLayout);
}
}
@@ -214,13 +234,18 @@ void setupChildDiagnostics(const QString &mainFilePath,
namespace ClangCodeModel {
namespace Internal {
void addToolTipToLayout(const ClangBackEnd::DiagnosticContainer &diagnostic, QLayout *target)
void addToolTipToLayout(const ClangBackEnd::DiagnosticContainer &diagnostic,
QLayout *target,
const DisplayHints &displayHints)
{
// Set up header and text row for main diagnostic
target->addWidget(new MainDiagnosticWidget(diagnostic));
target->addWidget(new MainDiagnosticWidget(diagnostic, displayHints));
// Set up child rows for notes
setupChildDiagnostics(diagnostic.location().filePath(), diagnostic.children(), *target);
setupChildDiagnostics(diagnostic.location().filePath(),
diagnostic.children(),
displayHints.enableClickableFixits,
*target);
}
} // namespace Internal

View File

@@ -34,7 +34,15 @@ QT_END_NAMESPACE
namespace ClangCodeModel {
namespace Internal {
void addToolTipToLayout(const ClangBackEnd::DiagnosticContainer &diagnostic, QLayout *target);
struct DisplayHints {
bool showMainDiagnosticHeader = true;
bool showFileNameInMainDiagnostic = false;
bool enableClickableFixits = true;
};
void addToolTipToLayout(const ClangBackEnd::DiagnosticContainer &diagnostic,
QLayout *target,
const DisplayHints &displayHints = DisplayHints());
} // namespace Internal
} // namespace ClangCodeModel

View File

@@ -57,6 +57,8 @@
#include <utils/runextensions.h>
#include <QTextBlock>
#include <QVBoxLayout>
#include <QWidget>
namespace ClangCodeModel {
namespace Internal {
@@ -167,14 +169,21 @@ void ClangEditorDocumentProcessor::clearProjectPart()
m_projectPart.clear();
}
void ClangEditorDocumentProcessor::updateCodeWarnings(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
uint documentRevision)
void ClangEditorDocumentProcessor::updateCodeWarnings(
const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic,
uint documentRevision)
{
if (documentRevision == revision()) {
m_diagnosticManager.processNewDiagnostics(diagnostics);
const auto codeWarnings = m_diagnosticManager.takeExtraSelections();
const auto fixitAvailableMarkers = m_diagnosticManager.takeFixItAvailableMarkers();
emit codeWarningsUpdated(revision(), codeWarnings, fixitAvailableMarkers);
const auto creator = creatorForHeaderErrorDiagnosticWidget(firstHeaderErrorDiagnostic);
emit codeWarningsUpdated(revision(),
codeWarnings,
creator,
fixitAvailableMarkers);
}
}
namespace {
@@ -333,6 +342,38 @@ void ClangEditorDocumentProcessor::requestDocumentAnnotations(const QString &pro
m_ipcCommunicator.requestDocumentAnnotations(fileContainer);
}
static Internal::DisplayHints displayHintsForInfoBar()
{
Internal::DisplayHints displayHints;
displayHints.showMainDiagnosticHeader = false;
displayHints.showFileNameInMainDiagnostic = true;
displayHints.enableClickableFixits = false; // Tool chain headers might be changed, so disable.
return displayHints;
}
CppTools::BaseEditorDocumentProcessor::HeaderErrorDiagnosticWidgetCreator
ClangEditorDocumentProcessor::creatorForHeaderErrorDiagnosticWidget(
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic)
{
if (firstHeaderErrorDiagnostic.text().isEmpty())
return CppTools::BaseEditorDocumentProcessor::HeaderErrorDiagnosticWidgetCreator();
return [firstHeaderErrorDiagnostic]() {
auto vbox = new QVBoxLayout;
vbox->setMargin(0);
vbox->setContentsMargins(10, 0, 0, 2);
vbox->setSpacing(2);
addToolTipToLayout(firstHeaderErrorDiagnostic, vbox, displayHintsForInfoBar());
auto widget = new QWidget;
widget->setLayout(vbox);
return widget;
};
}
static CppTools::ProjectPart projectPartForLanguageOption(CppTools::ProjectPart *projectPart)
{
if (projectPart)

View File

@@ -68,6 +68,7 @@ public:
void clearProjectPart();
void updateCodeWarnings(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic,
uint documentRevision);
void updateHighlighting(const QVector<ClangBackEnd::HighlightingMarkContainer> &highlightingMarks,
const QVector<ClangBackEnd::SourceRangeContainer> &skippedPreprocessorRanges,
@@ -96,6 +97,8 @@ private:
void registerTranslationUnitForEditor(CppTools::ProjectPart *projectPart);
void updateTranslationUnitIfProjectPartExists();
void requestDocumentAnnotations(const QString &projectpartId);
HeaderErrorDiagnosticWidgetCreator creatorForHeaderErrorDiagnosticWidget(
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic);
ClangBackEnd::FileContainer fileContainerWithArguments(CppTools::ProjectPart *projectPart) const;
ClangBackEnd::FileContainer fileContainerWithDocumentContent(const QString &projectpartId) const;

View File

@@ -84,7 +84,7 @@ void ClangTextMark::setIcon(ClangBackEnd::DiagnosticSeverity severity)
bool ClangTextMark::addToolTipContent(QLayout *target)
{
Internal::addToolTipToLayout(m_diagnostic, target);
Internal::addToolTipToLayout(m_diagnostic, target, Internal::DisplayHints());
return true;
}