Clang: turn off delayed template parsing

Fix templates highlight and completion on Windows
Add UI to turn on/off delayed parsing (off by default)

Task-number: QTCREATORBUG-17222
Change-Id: I0cd5e0bcfff2789cd938e4096829f777ff15957a
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
Ivan Donchevskii
2017-05-23 09:49:22 +02:00
parent 0784dd20fe
commit 78db7d7ed2
23 changed files with 255 additions and 139 deletions

View File

@@ -419,16 +419,24 @@ static QStringList warningOptions(CppTools::ProjectPart *projectPart)
{
if (projectPart && projectPart->project) {
ClangProjectSettings projectSettings(projectPart->project);
if (!projectSettings.useGlobalWarningConfig()) {
if (!projectSettings.useGlobalConfig()) {
const Core::Id warningConfigId = projectSettings.warningConfigId();
const CppTools::ClangDiagnosticConfigsModel configsModel(
CppTools::codeModelSettings()->clangCustomDiagnosticConfigs());
if (configsModel.hasConfigWithId(warningConfigId))
return configsModel.configWithId(warningConfigId).commandLineOptions();
return configsModel.configWithId(warningConfigId).commandLineWarnings();
}
}
return CppTools::codeModelSettings()->clangDiagnosticConfig().commandLineOptions();
return CppTools::codeModelSettings()->clangDiagnosticConfig().commandLineWarnings();
}
static QStringList commandLineOptions(CppTools::ProjectPart *projectPart)
{
if (!projectPart || !projectPart->project)
return ClangProjectSettings::globalCommandLineOptions();
return ClangProjectSettings{projectPart->project}.commandLineOptions();
}
static QStringList precompiledHeaderOptions(
@@ -454,6 +462,7 @@ static QStringList fileArguments(const QString &filePath, CppTools::ProjectPart
{
return languageOptions(filePath, projectPart)
+ warningOptions(projectPart)
+ commandLineOptions(projectPart)
+ precompiledHeaderOptions(filePath, projectPart);
}

View File

@@ -25,15 +25,23 @@
#include "clangprojectsettings.h"
#include <utils/qtcassert.h>
#include <utils/hostosinfo.h>
#include <QDebug>
namespace ClangCodeModel {
namespace Internal {
static QString useGlobalWarningConfigKey()
{ return QStringLiteral("ClangCodeModel.UseGlobalWarningConfig"); }
static QString useGlobalConfigKey()
{ return QStringLiteral("ClangCodeModel.UseGlobalConfig"); }
static QString warningConfigIdKey()
{ return QStringLiteral("ClangCodeModel.WarningConfigId"); }
static QString customCommandLineKey()
{ return QLatin1String("ClangCodeModel.CustomCommandLineKey"); }
ClangProjectSettings::ClangProjectSettings(ProjectExplorer::Project *project)
: m_project(project)
{
@@ -55,31 +63,55 @@ void ClangProjectSettings::setWarningConfigId(const Core::Id &customConfigId)
m_warningConfigId = customConfigId;
}
bool ClangProjectSettings::useGlobalWarningConfig() const
bool ClangProjectSettings::useGlobalConfig() const
{
return m_useGlobalWarningConfig;
return m_useGlobalConfig;
}
void ClangProjectSettings::setUseGlobalWarningConfig(bool useGlobalWarningConfig)
void ClangProjectSettings::setUseGlobalConfig(bool useGlobalConfig)
{
m_useGlobalWarningConfig = useGlobalWarningConfig;
m_useGlobalConfig = useGlobalConfig;
}
QStringList ClangProjectSettings::commandLineOptions() const
{
return m_useGlobalConfig ? globalCommandLineOptions()
: m_customCommandLineOptions;
}
void ClangProjectSettings::setCommandLineOptions(const QStringList &options)
{
QTC_ASSERT(!m_useGlobalConfig, qDebug()
<< "setCommandLineOptions was called while using global project config");
m_customCommandLineOptions = options;
}
void ClangProjectSettings::load()
{
const QVariant useGlobalConfigVariant = m_project->namedSettings(useGlobalWarningConfigKey());
const QVariant useGlobalConfigVariant = m_project->namedSettings(useGlobalConfigKey());
const bool useGlobalConfig = useGlobalConfigVariant.isValid()
? useGlobalConfigVariant.toBool()
: true;
setUseGlobalWarningConfig(useGlobalConfig);
setUseGlobalConfig(useGlobalConfig);
setWarningConfigId(Core::Id::fromSetting(m_project->namedSettings(warningConfigIdKey())));
m_customCommandLineOptions = m_project->namedSettings(customCommandLineKey()).toStringList();
if (m_customCommandLineOptions.empty())
m_customCommandLineOptions = globalCommandLineOptions();
}
void ClangProjectSettings::store()
{
m_project->setNamedSettings(useGlobalWarningConfigKey(), useGlobalWarningConfig());
m_project->setNamedSettings(useGlobalConfigKey(), useGlobalConfig());
m_project->setNamedSettings(warningConfigIdKey(), warningConfigId().toSetting());
m_project->setNamedSettings(customCommandLineKey(), m_customCommandLineOptions);
}
QStringList ClangProjectSettings::globalCommandLineOptions()
{
if (Utils::HostOsInfo::isWindowsHost())
return {QLatin1String{GlobalWindowsCmdOptions}};
return {};
}
} // namespace Internal

View File

@@ -39,21 +39,32 @@ class ClangProjectSettings: public QObject
Q_OBJECT
public:
constexpr static const char* DelayedTemplateParsing = "-fdelayed-template-parsing";
constexpr static const char* NoDelayedTemplateParsing = "-fno-delayed-template-parsing";
constexpr static const char* GlobalWindowsCmdOptions = NoDelayedTemplateParsing;
ClangProjectSettings(ProjectExplorer::Project *project);
bool useGlobalWarningConfig() const;
void setUseGlobalWarningConfig(bool useGlobalWarningConfig);
bool useGlobalConfig() const;
void setUseGlobalConfig(bool useGlobalConfig);
Core::Id warningConfigId() const;
void setWarningConfigId(const Core::Id &warningConfigId);
QStringList commandLineOptions() const;
void setCommandLineOptions(const QStringList &options);
void load();
void store();
static QStringList globalCommandLineOptions();
private:
ProjectExplorer::Project *m_project;
bool m_useGlobalWarningConfig = true;
bool m_useGlobalConfig = true;
Core::Id m_warningConfigId;
QStringList m_customCommandLineOptions;
};
} // namespace Internal

View File

@@ -34,60 +34,21 @@
#include <cpptools/cppcodemodelsettings.h>
#include <cpptools/cpptoolsreuse.h>
static const char GLOBAL_PROXY_CONFIG_ID[] = "globalProxyConfig";
#include <utils/hostosinfo.h>
namespace ClangCodeModel {
namespace Internal {
static CppTools::ClangDiagnosticConfig
createConfigRepresentingGlobalSetting(const CppTools::ClangDiagnosticConfig &baseConfig)
static Core::Id configIdForProject(ClangProjectSettings &projectSettings)
{
CppTools::ClangDiagnosticConfig config = baseConfig;
config.setId(GLOBAL_PROXY_CONFIG_ID);
QString displayName = config.displayName();
if (config.isReadOnly())
displayName = CppTools::ClangDiagnosticConfigsModel::displayNameWithBuiltinIndication(config);
displayName = ClangProjectSettingsWidget::tr("Global setting (%1)").arg(displayName);
config.setDisplayName(displayName);
config.setIsReadOnly(true);
return config;
}
static Core::Id globalConfigId(const CppTools::CppCodeModelSettings &settings,
const CppTools::ClangDiagnosticConfigsModel &model)
{
const Core::Id configId = settings.clangDiagnosticConfigId();
if (model.hasConfigWithId(configId))
return configId;
return model.at(0).id(); // Config saved in the settings was removed, fallback to first.
}
static CppTools::ClangDiagnosticConfigsModel
createConfigsModelWithGlobalProxyConfig(const CppTools::CppCodeModelSettings &settings)
{
using namespace CppTools;
ClangDiagnosticConfigsModel configsModel(settings.clangCustomDiagnosticConfigs());
const Core::Id globalId = globalConfigId(settings, configsModel);
const ClangDiagnosticConfig globalConfig = configsModel.configWithId(globalId);
const ClangDiagnosticConfig globalProxy
= createConfigRepresentingGlobalSetting(globalConfig);
configsModel.prepend(globalProxy);
return configsModel;
}
static Core::Id configIdForProject(const ClangProjectSettings &projectSettings)
{
return projectSettings.useGlobalWarningConfig()
? Core::Id(GLOBAL_PROXY_CONFIG_ID)
: projectSettings.warningConfigId();
if (projectSettings.useGlobalConfig())
return CppTools::codeModelSettings()->clangDiagnosticConfigId();
Core::Id configId = projectSettings.warningConfigId();
if (!configId.isValid()) {
configId = CppTools::codeModelSettings()->clangDiagnosticConfigId();
projectSettings.setWarningConfigId(configId);
}
return configId;
}
ClangProjectSettingsWidget::ClangProjectSettingsWidget(ProjectExplorer::Project *project)
@@ -98,24 +59,33 @@ ClangProjectSettingsWidget::ClangProjectSettingsWidget(ProjectExplorer::Project
using namespace CppTools;
m_diagnosticConfigWidget = new ClangDiagnosticConfigsWidget;
m_diagnosticConfigWidget->setConfigWithUndecoratedDisplayName(Core::Id(GLOBAL_PROXY_CONFIG_ID));
refreshDiagnosticConfigsWidgetFromSettings();
m_ui.generalConfigurationGroupBox->setVisible(Utils::HostOsInfo::isWindowsHost());
m_ui.clangSettings->setCurrentIndex(m_projectSettings.useGlobalConfig() ? 0 : 1);
syncOtherWidgetsToComboBox();
connectToCppCodeModelSettingsChanged();
connect(m_diagnosticConfigWidget.data(), &ClangDiagnosticConfigsWidget::currentConfigChanged,
this, &ClangProjectSettingsWidget::onCurrentWarningConfigChanged);
connect(m_diagnosticConfigWidget.data(), &ClangDiagnosticConfigsWidget::customConfigsChanged,
this, &ClangProjectSettingsWidget::onCustomWarningConfigsChanged);
connect(m_ui.delayedTemplateParse, &QCheckBox::toggled,
this, &ClangProjectSettingsWidget::onDelayedTemplateParseClicked);
connect(m_ui.clangSettings,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &ClangProjectSettingsWidget::onClangSettingsChanged);
m_ui.diagnosticConfigurationGroupBox->layout()->addWidget(m_diagnosticConfigWidget);
}
void ClangProjectSettingsWidget::onCurrentWarningConfigChanged(const Core::Id &currentConfigId)
{
const bool useGlobalConfig = currentConfigId == Core::Id(GLOBAL_PROXY_CONFIG_ID);
m_projectSettings.setUseGlobalWarningConfig(useGlobalConfig);
// Don't save it when we reset the global config in code
if (m_projectSettings.useGlobalConfig())
return;
m_projectSettings.setWarningConfigId(currentConfigId);
m_projectSettings.store();
}
@@ -132,11 +102,48 @@ void ClangProjectSettingsWidget::onCustomWarningConfigsChanged(
connectToCppCodeModelSettingsChanged();
}
void ClangProjectSettingsWidget::onDelayedTemplateParseClicked(bool checked)
{
// Don't save it when we reset the global config in code
if (m_projectSettings.useGlobalConfig())
return;
const QLatin1String extraFlag{checked ? ClangProjectSettings::DelayedTemplateParsing
: ClangProjectSettings::NoDelayedTemplateParsing};
QStringList options = m_projectSettings.commandLineOptions();
options.removeAll(QLatin1String{ClangProjectSettings::DelayedTemplateParsing});
options.removeAll(QLatin1String{ClangProjectSettings::NoDelayedTemplateParsing});
options.append(extraFlag);
m_projectSettings.setCommandLineOptions(options);
m_projectSettings.store();
}
void ClangProjectSettingsWidget::onClangSettingsChanged(int index)
{
m_projectSettings.setUseGlobalConfig(index == 0 ? true : false);
m_projectSettings.store();
syncOtherWidgetsToComboBox();
}
void ClangProjectSettingsWidget::syncOtherWidgetsToComboBox()
{
const QStringList options = m_projectSettings.commandLineOptions();
m_ui.delayedTemplateParse->setChecked(
options.contains(QLatin1String{ClangProjectSettings::DelayedTemplateParsing}));
const bool isCustom = !m_projectSettings.useGlobalConfig();
m_ui.generalConfigurationGroupBox->setEnabled(isCustom);
m_ui.diagnosticConfigurationGroupBox->setEnabled(isCustom);
refreshDiagnosticConfigsWidgetFromSettings();
}
void ClangProjectSettingsWidget::refreshDiagnosticConfigsWidgetFromSettings()
{
m_diagnosticConfigWidget->refresh(
createConfigsModelWithGlobalProxyConfig(*CppTools::codeModelSettings()),
configIdForProject(m_projectSettings));
CppTools::ClangDiagnosticConfigsModel configsModel(
CppTools::codeModelSettings()->clangCustomDiagnosticConfigs());
m_diagnosticConfigWidget->refresh(configsModel,
configIdForProject(m_projectSettings));
}
void ClangProjectSettingsWidget::connectToCppCodeModelSettingsChanged()

View File

@@ -49,9 +49,12 @@ public:
private:
void onCurrentWarningConfigChanged(const Core::Id &currentConfigId);
void onCustomWarningConfigsChanged(const CppTools::ClangDiagnosticConfigs &customConfigs);
void onDelayedTemplateParseClicked(bool);
void onClangSettingsChanged(int index);
void refreshDiagnosticConfigsWidgetFromSettings();
void connectToCppCodeModelSettingsChanged();
void disconnectFromCppCodeModelSettingsChanged();
void syncOtherWidgetsToComboBox();
private:
Ui::ClangProjectSettingsWidget m_ui;

View File

@@ -14,6 +14,52 @@
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QComboBox" name="clangSettings">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Global</string>
</property>
</item>
<item>
<property name="text">
<string>Custom</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QGroupBox" name="generalConfigurationGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>General</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QCheckBox" name="delayedTemplateParse">
<property name="toolTip">
<string>Parse templates in a MSVC-compliant way. This helps to parse headers for example from Active Template Library (ATL) or Windows Runtime Library (WRL).
However, using the relaxed and extended rules means also that no highlighting/completion can be provided within template functions.</string>
</property>
<property name="text">
<string>Enable MSVC-compliant template parsing</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="diagnosticConfigurationGroupBox">
<property name="title">