...
 
Commits (63)
......@@ -14,6 +14,11 @@ function readOutput(executable, args)
return output;
}
function readListOutput(executable, args)
{
return readOutput(executable, args).split(/\s+/);
}
function isSuitableLLVMConfig(llvmConfigCandidate, qtcFunctions)
{
if (File.exists(llvmConfigCandidate)) {
......@@ -75,3 +80,66 @@ function libraries(targetOS)
{
return targetOS.contains("windows") ? ["libclang.lib", "advapi32.lib", "shell32.lib"] : ["clang"]
}
function toolingLibs(llvmConfig, targetOS)
{
var fixedList = [
"clangTooling",
"clangFrontend",
"clangIndex",
"clangParse",
"clangSerialization",
"clangSema",
"clangEdit",
"clangAnalysis",
"clangDriver",
"clangDynamicASTMatchers",
"clangASTMatchers",
"clangToolingCore",
"clangAST",
"clangLex",
"clangBasic",
];
if (targetOS.contains("windows"))
fixedList.push("version");
var dynamicList = readListOutput(llvmConfig, ["--libs"])
.concat(readListOutput(llvmConfig, ["--system-libs"]));
return fixedList.concat(dynamicList.map(function(s) {
return s.startsWith("-l") ? s.slice(2) : s;
}));
}
function toolingParameters(llvmConfig)
{
var params = {
defines: [],
includes: [],
cxxFlags: [],
};
var allCxxFlags = readListOutput(llvmConfig, ["--cxxflags"]);
for (var i = 0; i < allCxxFlags.length; ++i) {
var flag = allCxxFlags[i];
if (flag.startsWith("-D") || flag.startsWith("/D")) {
params.defines.push(flag.slice(2));
continue;
}
if (flag.startsWith("-I") || flag.startsWith("/I")) {
params.includes.push(flag.slice(2));
continue;
}
if (!flag.startsWith("-std") && !flag.startsWith("-O") && !flag.startsWith("/O")
&& !flag.startsWith("-march")
&& !flag.startsWith("/EH") && flag !== "-fno-exceptions"
&& flag !== "/W4" && flag !== "-Werror=date-time"
&& flag !== "-Wcovered-switch-default" && flag !== "-fPIC" && flag !== "-pedantic"
&& flag !== "-Wstring-conversion" && flag !== "-gsplit-dwarf") {
params.cxxFlags.push(flag);
}
}
return params;
}
function buildMode(llvmConfig)
{
return readOutput(llvmConfig, ["--build-mode"]);
}
import qbs
import qbs.Environment
import qbs.File
import qbs.Utilities
import QtcFunctions
import "functions.js" as ClangFunctions
......@@ -12,6 +14,11 @@ Module {
property string llvmIncludeDir
property string llvmLibDir
property stringList llvmLibs
property stringList llvmToolingLibs
property stringList llvmToolingDefines
property stringList llvmToolingIncludes
property stringList llvmToolingCxxFlags
property string llvmBuildMode
configure: {
llvmConfig = ClangFunctions.llvmConfig(qbs, QtcFunctions);
......@@ -19,6 +26,12 @@ Module {
llvmIncludeDir = ClangFunctions.includeDir(llvmConfig);
llvmLibDir = ClangFunctions.libDir(llvmConfig);
llvmLibs = ClangFunctions.libraries(qbs.targetOS);
llvmToolingLibs = ClangFunctions.toolingLibs(llvmConfig, qbs.targetOS);
llvmBuildMode = ClangFunctions.buildMode(llvmConfig);
var toolingParams = ClangFunctions.toolingParameters(llvmConfig);
llvmToolingDefines = toolingParams.defines;
llvmToolingIncludes = toolingParams.includes;
llvmToolingCxxFlags = toolingParams.cxxFlags;
found = llvmConfig && File.exists(llvmIncludeDir.concat("/clang-c/Index.h"));
}
}
......@@ -28,6 +41,17 @@ Module {
property string llvmIncludeDir: clangProbe.llvmIncludeDir
property string llvmLibDir: clangProbe.llvmLibDir
property stringList llvmLibs: clangProbe.llvmLibs
property stringList llvmToolingLibs: clangProbe.llvmToolingLibs
property string llvmBuildMode: clangProbe.llvmBuildMode
property bool llvmBuildModeMatches: qbs.buildVariant === llvmBuildMode.toLowerCase()
property stringList llvmToolingDefines: clangProbe.llvmToolingDefines
property stringList llvmToolingIncludes: clangProbe.llvmToolingIncludes.filter(function(incl) {
return incl != llvmIncludeDir;
})
property stringList llvmToolingCxxFlags: clangProbe.llvmToolingCxxFlags
property bool toolingEnabled: !Environment.getEnv("QTC_NO_CLANG_LIBTOOLING")
&& Utilities.versionCompare(llvmVersion, "3.9") > 0
&& Utilities.versionCompare(llvmVersion, "4") < 0
validate: {
if (!clangProbe.found) {
......
#!/usr/bin/perl -w
############################################################################
#
# Copyright (C) 2017 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.
#
############################################################################
=head1 NAME
clazyweb2tasks.pl - Convert Clazy logs as displayed by the Web frontend into
Qt Creator task files.
Expected format:
Explanation for clazy-strict-iterators
./qtbase/src/tools/moc/preprocessor.cpp
line 995: for (Symbols::const_iterator j = mergeSymbol + 1; j != i; ++j)
=> Mixing iterators with const_iterators
=head1 SYNOPSIS
clazyweb2tasks.pl < logfile > taskfile
=cut
use strict;
my $message = '';
my $fileName = '';
while (my $line = <STDIN> ) {
chomp($line);
if ($line =~ /\s*Explanation for (.*)$/) {
$message = $1;
} elsif (index($line, './') == 0) {
$fileName = substr($line, 2);
} elsif ($line =~ /\s*line (\d+):/) {
my $lineNumber = $1;
print $fileName, "\t", $lineNumber, "\tclazy\t", $message,"\n";
}
}
......@@ -702,7 +702,7 @@ class Dumper(DumperBase):
self.typesToReport = {}
if self.forceQtNamespace:
self.qtNamepaceToReport = self.qtNamespace()
self.qtNamespaceToReport = self.qtNamespace()
if self.qtNamespaceToReport:
self.output += ',qtnamespace="%s"' % self.qtNamespaceToReport
......@@ -996,8 +996,13 @@ class Dumper(DumperBase):
name = objfile.filename
if self.isWindowsTarget():
isQtCoreObjFile = name.find('Qt5Cored.dll') >= 0 or name.find('Qt5Core.dll') >= 0
if not isQtCoreObjFile:
isQtCoreObjFile = name.find('QtCored.dll') >= 0 or name.find('QtCore.dll') >= 0
else:
isQtCoreObjFile = name.find('/libQt5Core') >= 0
if not isQtCoreObjFile:
isQtCoreObjFile = name.find('/libQtCore') >= 0
if isQtCoreObjFile:
self.handleQtCoreLoaded(objfile)
......@@ -1019,6 +1024,13 @@ class Dumper(DumperBase):
if len(ns):
ns += '::'
break
if line.find('currentThreadData ') >= 0:
# [ 0] b 0x7ffff67d3000 _ZN2UUL17currentThreadDataE
# section .tbss UU::currentThreadData qthread_unix.cpp\\n
ns = re.split('_ZN?(\d*)(\w*)L17currentThreadDataE? ', line)[2]
if len(ns):
ns += '::'
break
os.remove(tmppath)
lenns = len(ns)
......
......@@ -128,7 +128,7 @@
},
{
"name": "UseVirtualKeyboard",
"trDisplayName": "Use Qt Virtual Keyboard.",
"trDisplayName": "Use Qt Virtual Keyboard",
"type": "CheckBox",
"data":
{
......
......@@ -124,7 +124,7 @@
},
{
"name": "UseVirtualKeyboard",
"trDisplayName": "Use Qt Virtual Keyboard.",
"trDisplayName": "Use Qt Virtual Keyboard",
"type": "CheckBox",
"data":
{
......
......@@ -176,7 +176,7 @@
},
{
"name": "UseVirtualKeyboard",
"trDisplayName": "Use Qt Virtual Keyboard.",
"trDisplayName": "Use Qt Virtual Keyboard",
"type": "CheckBox",
"data":
{
......
......@@ -193,7 +193,7 @@
},
{
"name": "UseVirtualKeyboard",
"trDisplayName": "Use Qt Virtual Keyboard.",
"trDisplayName": "Use Qt Virtual Keyboard",
"type": "CheckBox",
"data":
{
......
......@@ -193,7 +193,7 @@
},
{
"name": "UseVirtualKeyboard",
"trDisplayName": "Use Qt Virtual Keyboard.",
"trDisplayName": "Use Qt Virtual Keyboard",
"type": "CheckBox",
"data":
{
......
......@@ -442,7 +442,7 @@ QString PluginManager::systemInformation() const
if (response.result == SynchronousProcessResponse::Finished)
result += response.allOutput() + "\n";
result += "Plugin information:\n\n";
auto longestSpec = std::max_element(plugins().cbegin(), plugins().cend(),
auto longestSpec = std::max_element(d->pluginSpecs.cbegin(), d->pluginSpecs.cend(),
[](const PluginSpec *left, const PluginSpec *right) {
return left->name().size() < right->name().size();
});
......
......@@ -421,8 +421,9 @@ void PluginView::updatePlugins()
QList<CollectionItem *> collections;
auto end = PluginManager::pluginCollections().cend();
for (auto it = PluginManager::pluginCollections().cbegin(); it != end; ++it) {
const QHash<QString, QList<PluginSpec *>> pluginCollections = PluginManager::pluginCollections();
const auto end = pluginCollections.cend();
for (auto it = pluginCollections.cbegin(); it != end; ++it) {
const QString name = it.key().isEmpty() ? tr("Utilities") : it.key();
collections.append(new CollectionItem(name, it.value(), this));
}
......
......@@ -40,13 +40,13 @@ int SavingRefMap::countDanglingReferences()
bool SavingRefMap::hasRef(const void *address, const char *typeName)
{
return m_references.find(KeyType(address, typeName)) != m_references.end();
return m_references.constFind(KeyType(address, typeName)) != m_references.constEnd();
}
bool SavingRefMap::hasDefinedRef(const void *address, const char *typeName)
{
MapType::const_iterator it = m_references.find(KeyType(address, typeName));
if (it == m_references.end())
const MapType::const_iterator it = m_references.constFind(KeyType(address, typeName));
if (it == m_references.constEnd())
return false;
return it.value().second;
}
......
......@@ -232,7 +232,8 @@ QString FileInProjectFinder::findFile(const QUrl &fileUrl, bool *success) const
// check if absolute path is found in sysroot
if (!m_sysroot.isEmpty()) {
const QString sysrootPath = m_sysroot + originalPath;
if (QFileInfo(sysrootPath).exists() && QFileInfo(sysrootPath).isFile()) {
QFileInfo sysrootInfo(sysrootPath);
if (sysrootInfo.exists() && sysrootInfo.isFile()) {
if (success)
*success = true;
m_cache.insert(originalPath, sysrootPath);
......
......@@ -258,13 +258,14 @@ void JsonSchema::enterNestedTypeSchema()
QStringList JsonSchema::properties(JsonObjectValue *v) const
{
typedef QHash<QString, JsonValue *>::ConstIterator MemberConstIterator;
using Members = QHash<QString, JsonValue *>;
QStringList all;
if (JsonObjectValue *ov = getObjectValue(kProperties(), v)) {
const MemberConstIterator cend = ov->members().constEnd();
for (MemberConstIterator it = ov->members().constBegin(); it != cend; ++it)
const Members members = ov->members();
const Members::ConstIterator cend = members.constEnd();
for (Members::ConstIterator it = members.constBegin(); it != cend; ++it)
if (hasPropertySchema(it.key()))
all.append(it.key());
}
......
......@@ -33,6 +33,8 @@ namespace Utils {
class QTCREATOR_UTILS_EXPORT SaveFile : public QTemporaryFile
{
Q_OBJECT
public:
explicit SaveFile(const QString &filename);
virtual ~SaveFile();
......
......@@ -107,6 +107,7 @@ IDevice::Ptr AndroidDevice::clone() const
QUrl AndroidDevice::toolControlChannel(const ControlChannelHint &) const
{
QUrl url;
url.setScheme(urlTcpScheme());
url.setHost("localhost");
return url;
}
......
......@@ -180,8 +180,8 @@ static void sdkManagerCommand(const AndroidConfig &config, const QStringList &ar
output.success = false;
output.stdOutput = response.stdOut();
output.stdError = QCoreApplication::translate("Android::Internal::AndroidSdkManager",
"Operation requires user interaction."
"Please use \"sdkmanager\" commandline tool");
"The operation requires user interaction. "
"Use the \"sdkmanager\" command-line tool.");
} else {
output.success = response.result == SynchronousProcessResponse::Finished;
}
......
......@@ -269,7 +269,7 @@ void AndroidSdkManagerWidget::onNativeSdkManager()
QProcess::startDetached(m_androidConfig.androidToolPath().toString());
} else {
QMessageBox::warning(this, tr("Native SDK Manager Not Available"),
tr("SDK manager UI tool is not available in the installed SDK tools"
tr("SDK manager UI tool is not available in the installed SDK tools "
"(version %1). Use the command line tool \"sdkmanager\" for "
"advanced SDK management.")
.arg(m_androidConfig.sdkToolsVersion().toString()));
......
......@@ -34,9 +34,9 @@
<item>
<widget class="QCheckBox" name="useXMLOutputCB">
<property name="toolTip">
<string>XML output recommended as it avoids parsing issues, while plain text is more human readable.
<string>XML output is recommended, because it avoids parsing issues, while plain text is more human readable.
Warning: Plain text output is missing some information (e.g. duration)</string>
Warning: Plain text misses some information, such as duration.</string>
</property>
<property name="text">
<string>Use XML output</string>
......
......@@ -33,6 +33,7 @@
#include <QAbstractItemView>
#include <QPainter>
#include <QTextLayout>
#include <QWindow>
namespace Autotest {
namespace Internal {
......@@ -57,20 +58,20 @@ void TestResultDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
painter->save();
QFontMetrics fm(opt.font);
QBrush background;
QColor foreground;
const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(opt.widget);
const bool selected = opt.state & QStyle::State_Selected;
if (selected) {
painter->setBrush(opt.palette.highlight().color());
background = opt.palette.highlight().color();
foreground = opt.palette.highlightedText().color();
} else {
painter->setBrush(opt.palette.window().color());
background = opt.palette.window().color();
foreground = opt.palette.text().color();
}
painter->setPen(Qt::NoPen);
painter->drawRect(opt.rect);
painter->fillRect(opt.rect, background);
painter->setPen(foreground);
TestResultFilterModel *resultFilterModel = static_cast<TestResultFilterModel *>(view->model());
......@@ -78,10 +79,13 @@ void TestResultDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
const TestResult *testResult = resultFilterModel->testResult(index);
QTC_ASSERT(testResult, painter->restore();return);
const QWidget *widget = dynamic_cast<const QWidget*>(painter->device());
QWindow *window = widget ? widget->window()->windowHandle() : nullptr;
QIcon icon = index.data(Qt::DecorationRole).value<QIcon>();
if (!icon.isNull())
painter->drawPixmap(positions.left(), positions.top(),
icon.pixmap(positions.iconSize(), positions.iconSize()));
icon.pixmap(window, QSize(positions.iconSize(), positions.iconSize())));
QString typeStr = TestResult::resultToString(testResult->result());
if (selected) {
......@@ -130,9 +134,10 @@ void TestResultDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
painter->drawText(positions.lineAreaLeft(), positions.top() + fm.ascent(), line);
}
painter->setClipRect(opt.rect);
painter->setClipping(false);
painter->setPen(opt.palette.mid().color());
painter->drawLine(0, opt.rect.bottom(), opt.rect.right(), opt.rect.bottom());
const QRectF adjustedRect(QRectF(opt.rect).adjusted(0.5, 0.5, -0.5, -0.5));
painter->drawLine(adjustedRect.bottomLeft(), adjustedRect.bottomRight());
painter->restore();
}
......
......@@ -278,8 +278,12 @@ void TestTreeModel::handleParseResult(const TestParseResult *result, TestTreeIte
void TestTreeModel::removeAllTestItems()
{
for (Utils::TreeItem *item : *rootItem())
for (Utils::TreeItem *item : *rootItem()) {
item->removeChildren();
TestTreeItem *testTreeItem = static_cast<TestTreeItem *>(item);
if (testTreeItem->checked() == Qt::PartiallyChecked)
testTreeItem->setChecked(Qt::Checked);
}
emit testTreeModelChanged();
}
......
import qbs
import qbs.FileInfo
QtcPlugin {
name: "ClangPchManager"
Depends { name: "libclang"; required: false }
condition: libclang.present && libclang.toolingEnabled
Depends { name: "ClangSupport" }
Depends { name: "Utils" }
Depends { name: "Core" }
Depends { name: "CppTools" }
Depends { name: "ProjectExplorer" }
cpp.defines: {
var defines = base;
defines.push("CLANGPCHMANAGER_LIB");
// The following defines are used to determine the clang include path for intrinsics.
defines.push('CLANG_VERSION="' + libclang.llvmVersion + '"');
var resourceDir = FileInfo.joinPaths(libclang.llvmLibDir, "clang", libclang.llvmVersion,
"include");
defines.push('CLANG_RESOURCE_DIR="' + resourceDir + '"');
return defines;
}
cpp.includePaths: ["."]
files: [
"clangpchmanagerplugin.cpp",
"clangpchmanagerplugin.h",
"clangpchmanager_global.h",
"pchmanagerclient.cpp",
"pchmanagerclient.h",
"pchmanagernotifierinterface.cpp",
"pchmanagernotifierinterface.h",
"pchmanagerconnectionclient.cpp",
"pchmanagerconnectionclient.h",
"pchmanagerprojectupdater.cpp",
"pchmanagerprojectupdater.h",
"projectupdater.cpp",
"projectupdater.h",
"qtcreatorprojectupdater.cpp",
"qtcreatorprojectupdater.h",
]
}
......@@ -50,6 +50,8 @@ class SearchInterface;
class ClangQueryProjectsFindFilter : public Core::IFindFilter
{
Q_OBJECT
public:
ClangQueryProjectsFindFilter(ClangBackEnd::RefactoringServerInterface &server,
SearchInterface &searchInterface,
......
import qbs
import qbs.FileInfo
QtcPlugin {
name: "ClangRefactoring"
Depends { name: "libclang"; required: false }
condition: libclang.present && libclang.toolingEnabled
Depends { name: "ClangSupport" }
Depends { name: "Utils" }
Depends { name: "ClangPchManager" }
Depends { name: "Core" }
Depends { name: "CppTools" }
Depends { name: "ProjectExplorer" }
Depends { name: "TextEditor" }
cpp.defines: {
var defines = base;
defines.push("CLANGPCHMANAGER_LIB");
// The following defines are used to determine the clang include path for intrinsics.
defines.push('CLANG_VERSION="' + libclang.llvmVersion + '"');
var resourceDir = FileInfo.joinPaths(libclang.llvmLibDir, "clang", libclang.llvmVersion,
"include");
defines.push('CLANG_RESOURCE_DIR="' + resourceDir + '"');
return defines;
}
cpp.includePaths: ["."]
files: [
"baseclangquerytexteditorwidget.cpp",
"baseclangquerytexteditorwidget.h",
"clangqueryexamplehighlighter.cpp",
"clangqueryexamplehighlighter.h",
"clangqueryexamplehighlightmarker.h",
"clangqueryexampletexteditorwidget.cpp",
"clangqueryexampletexteditorwidget.h",
"clangqueryhighlighter.cpp",
"clangqueryhighlighter.h",
"clangqueryhighlightmarker.h",
"clangqueryhoverhandler.cpp",
"clangqueryhoverhandler.h",
"clangqueryprojectsfindfilter.cpp",
"clangqueryprojectsfindfilter.h",
"clangqueryprojectsfindfilter.ui",
"clangqueryprojectsfindfilterwidget.cpp",
"clangqueryprojectsfindfilterwidget.h",
"clangquerytexteditorwidget.cpp",
"clangquerytexteditorwidget.h",
"clangrefactoringplugin.cpp",
"clangrefactoringplugin.h",
"projectpartutilities.cpp",
"projectpartutilities.h",
"qtcreatorclangqueryfindfilter.cpp",
"qtcreatorclangqueryfindfilter.h",
"qtcreatorsearch.cpp",
"qtcreatorsearch.h",
"qtcreatorsearchhandle.cpp",
"qtcreatorsearchhandle.h",
"querysqlitestatementfactory.h",
"refactoringclient.cpp",
"refactoringclient.h",
"refactoringconnectionclient.cpp",
"refactoringconnectionclient.h",
"refactoringengine.cpp",
"refactoringengine.h",
"refactoringprojectupdater.cpp",
"refactoringprojectupdater.h",
"searchhandle.cpp",
"searchhandle.h",
"searchinterface.cpp",
"searchinterface.h",
"sourcelocations.h",
"symbolquery.cpp",
"symbolquery.h",
]
}
......@@ -222,7 +222,7 @@ void ClangStaticAnalyzerTool::updateRunActions()
bool canRun = target && project->projectLanguages().contains(cxx)
&& ToolChainKitInformation::toolChain(target->kit(), cxx);
if (!canRun)
toolTip = tr("This is not C++ project");
toolTip = tr("This is not a C++ project.");
m_startAction->setToolTip(toolTip);
m_startAction->setEnabled(canRun);
......
......@@ -457,13 +457,13 @@ void Manager::gotoLocations(const QList<QVariant> &list)
int column;
textEditor->convertPosition(textEditor->position(), &line, &column);
SymbolLocation current(fileName, line, column);
QSet<SymbolLocation>::const_iterator it = locations.find(current);
QSet<SymbolLocation>::const_iterator it = locations.constFind(current);
QSet<SymbolLocation>::const_iterator end = locations.constEnd();
if (it != end) {
// we already are at the symbol, cycle to next location
++it;
if (it == end)
it = locations.begin();
it = locations.constBegin();
loc = *it;
}
}
......
......@@ -66,6 +66,7 @@ Utils::FileName BuildDirManager::workDirectory(const BuildDirParameters &paramet
const Utils::FileName bdir = parameters.buildDirectory;
const CMakeTool *cmake = parameters.cmakeTool;
if (bdir.exists()) {
m_buildDirToTempDir.erase(bdir);
return bdir;
} else {
if (cmake && cmake->autoCreateBuildDirectory()) {
......@@ -74,14 +75,19 @@ Utils::FileName BuildDirManager::workDirectory(const BuildDirParameters &paramet
return bdir;
}
}
if (!m_tempDir) {
m_tempDir.reset(new Utils::TemporaryDirectory("qtc-cmake-XXXXXXXX"));
if (!m_tempDir->isValid()) {
auto tmpDirIt = m_buildDirToTempDir.find(bdir);
if (tmpDirIt == m_buildDirToTempDir.end()) {
auto ret = m_buildDirToTempDir.emplace(std::make_pair(bdir, std::make_unique<Utils::TemporaryDirectory>("qtc-cmake-XXXXXXXX")));
QTC_ASSERT(ret.second, return bdir);
tmpDirIt = ret.first;
if (!tmpDirIt->second->isValid()) {
emitErrorOccured(tr("Failed to create temporary directory \"%1\".")
.arg(QDir::toNativeSeparators(m_tempDir->path())));
.arg(QDir::toNativeSeparators(tmpDirIt->second->path())));
return bdir;
}
}
return Utils::FileName::fromString(m_tempDir->path());
return Utils::FileName::fromString(tmpDirIt->second->path());
}
void BuildDirManager::emitDataAvailable()
......@@ -198,14 +204,20 @@ void BuildDirManager::setParametersAndRequestParse(const BuildDirParameters &par
BuildDirReader *old = m_reader.get();
m_parameters = parameters;
m_parameters.buildDirectory = workDirectory(parameters);
m_parameters.workDirectory = workDirectory(parameters);
updateReaderType(m_parameters,
[this, old, newReaderReparseOptions, existingReaderReparseOptions]() {
if (old != m_reader.get())
emit requestReparse(newReaderReparseOptions);
else
emit requestReparse(existingReaderReparseOptions);
int options = REPARSE_DEFAULT;
if (old != m_reader.get()) {
options = newReaderReparseOptions;
} else {
if (!QFileInfo::exists(m_parameters.workDirectory.toString() + "/CMakeCache.txt"))
options = newReaderReparseOptions;
else
options = existingReaderReparseOptions;
}
emit requestReparse(options);
});
}
......@@ -239,16 +251,17 @@ bool BuildDirManager::persistCMakeState()
{
QTC_ASSERT(m_parameters.isValid(), return false);
if (!m_tempDir)
if (m_parameters.workDirectory == m_parameters.buildDirectory)
return false;
const Utils::FileName buildDir = m_parameters.buildDirectory;
QDir dir(buildDir.toString());
dir.mkpath(buildDir.toString());
m_tempDir.reset(nullptr);
emit requestReparse(REPARSE_URGENT | REPARSE_FORCE_CONFIGURATION | REPARSE_CHECK_CONFIGURATION);
BuildDirParameters newParameters = m_parameters;
newParameters.workDirectory.clear();
setParametersAndRequestParse(newParameters, REPARSE_URGENT | REPARSE_FORCE_CONFIGURATION | REPARSE_CHECK_CONFIGURATION,
REPARSE_FAIL);
return true;
}
......@@ -291,8 +304,8 @@ void BuildDirManager::clearCache()
QTC_ASSERT(m_parameters.isValid(), return);
QTC_ASSERT(!m_isHandlingError, return);
auto cmakeCache = workDirectory(m_parameters).appendPath("CMakeCache.txt");
auto cmakeFiles = workDirectory(m_parameters).appendPath("CMakeFiles");
auto cmakeCache = m_parameters.workDirectory.appendPath("CMakeCache.txt");
auto cmakeFiles = m_parameters.workDirectory.appendPath("CMakeFiles");
const bool mustCleanUp = cmakeCache.exists() || cmakeFiles.exists();
if (!mustCleanUp)
......@@ -367,7 +380,7 @@ bool BuildDirManager::checkConfiguration()
{
QTC_ASSERT(m_parameters.isValid(), return false);
if (m_tempDir) // always throw away changes in the tmpdir!
if (m_parameters.workDirectory != m_parameters.buildDirectory) // always throw away changes in the tmpdir!
return false;
const CMakeConfig cache = m_parameters.buildConfiguration->configurationFromCMake();
......@@ -375,41 +388,40 @@ bool BuildDirManager::checkConfiguration()
return false; // No cache file yet.
CMakeConfig newConfig;
QSet<QString> changedKeys;
QSet<QString> removedKeys;
foreach (const CMakeConfigItem &iBc, m_parameters.configuration) {
const CMakeConfigItem &iCache
= Utils::findOrDefault(cache, [&iBc](const CMakeConfigItem &i) { return i.key == iBc.key; });
if (iCache.isNull()) {
removedKeys << QString::fromUtf8(iBc.key);
} else if (QString::fromUtf8(iCache.value) != iBc.expandedValue(m_parameters.expander)) {
changedKeys << QString::fromUtf8(iBc.key);
newConfig.append(iCache);
QHash<QString, QPair<QString, QString>> changedKeys;
foreach (const CMakeConfigItem &projectItem, m_parameters.configuration) {
const QString projectKey = QString::fromUtf8(projectItem.key);
const QString projectValue = projectItem.expandedValue(m_parameters.expander);
const CMakeConfigItem &cmakeItem
= Utils::findOrDefault(cache, [&projectItem](const CMakeConfigItem &i) { return i.key == projectItem.key; });
const QString iCacheValue = QString::fromUtf8(cmakeItem.value);
if (cmakeItem.isNull()) {
changedKeys.insert(projectKey, qMakePair(tr("<removed>"), projectValue));
} else if (iCacheValue != projectValue) {
changedKeys.insert(projectKey, qMakePair(iCacheValue, projectValue));
newConfig.append(cmakeItem);
} else {
newConfig.append(iBc);
newConfig.append(projectItem);
}
}
if (!changedKeys.isEmpty() || !removedKeys.isEmpty()) {
QSet<QString> total = removedKeys + changedKeys;
QStringList keyList = total.toList();
if (!changedKeys.isEmpty()) {
QStringList keyList = changedKeys.keys();
Utils::sort(keyList);
QString table = QLatin1String("<table>");
QString table = QString::fromLatin1("<table><tr><th>%1</th><th>%2</th><th>%3</th></tr>")
.arg(tr("Key")).arg(tr("CMake")).arg(tr("Project"));
foreach (const QString &k, keyList) {
QString change;
if (removedKeys.contains(k))
change = tr("<removed>");
else
change = QString::fromUtf8(CMakeConfigItem::valueOf(k.toUtf8(), cache)).trimmed();
if (change.isEmpty())
change = tr("<empty>");
table += QString::fromLatin1("\n<tr><td>%1</td><td>%2</td></tr>").arg(k).arg(change.toHtmlEscaped());
const QPair<QString, QString> data = changedKeys.value(k);
table += QString::fromLatin1("\n<tr><td>%1</td><td>%2</td><td>%3</td></tr>")
.arg(k)
.arg(data.first.toHtmlEscaped())
.arg(data.second.toHtmlEscaped());
}
table += QLatin1String("\n</table>");
QPointer<QMessageBox> box = new QMessageBox(Core::ICore::mainWindow());
box->setText(tr("CMake configuration has changed on disk."));
box->setInformativeText(tr("The CMakeCache.txt file has changed: %1").arg(table));
box->setInformativeText(table);
auto *defaultButton = box->addButton(tr("Overwrite Changes in CMake"), QMessageBox::RejectRole);
auto *applyButton = box->addButton(tr("Apply Changes to Project"), QMessageBox::ApplyRole);
box->setDefaultButton(defaultButton);
......
......@@ -40,6 +40,7 @@
#include <functional>
#include <memory>
#include <unordered_map>
namespace ProjectExplorer { class FileNode; }
......@@ -112,7 +113,7 @@ private:
void becameDirty();
BuildDirParameters m_parameters;
mutable std::unique_ptr<Utils::TemporaryDirectory> m_tempDir = nullptr;
mutable std::unordered_map<Utils::FileName, std::unique_ptr<Utils::TemporaryDirectory>> m_buildDirToTempDir;
mutable std::unique_ptr<BuildDirReader> m_reader;
mutable bool m_isHandlingError = false;
};
......
......@@ -52,6 +52,7 @@ public:
Utils::FileName sourceDirectory;
Utils::FileName buildDirectory;
Utils::FileName workDirectory; // either buildDirectory or a QTemporaryDirectory!
Utils::Environment environment;
CMakeTool *cmakeTool = nullptr;
......
......@@ -177,7 +177,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
m_configView->setUniformRowHeights(true);
m_configView->setSortingEnabled(true);
m_configView->sortByColumn(0, Qt::AscendingOrder);
auto stretcher = new Utils::HeaderViewStretcher(m_configView->header(), 1);
auto stretcher = new Utils::HeaderViewStretcher(m_configView->header(), 0);
m_configView->setSelectionMode(QAbstractItemView::SingleSelection);
m_configView->setSelectionBehavior(QAbstractItemView::SelectItems);
m_configView->setFrameShape(QFrame::NoFrame);
......@@ -286,7 +286,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
connect(m_resetButton, &QPushButton::clicked, m_configModel, &ConfigModel::resetAllChanges);
connect(m_reconfigureButton, &QPushButton::clicked, this, [this]() {
m_buildConfiguration->setConfigurationForCMake(m_configModel->configurationChanges());
m_buildConfiguration->setConfigurationForCMake(m_configModel->configurationForCMake());
});
connect(m_unsetButton, &QPushButton::clicked, this, [this]() {
m_configModel->toggleUnsetFlag(mapToSource(m_configView, m_configView->currentIndex()));
......@@ -320,7 +320,12 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
connect(m_buildConfiguration->target(), &ProjectExplorer::Target::kitChanged,
this, &CMakeBuildSettingsWidget::updateFromKit);
connect(m_buildConfiguration, &CMakeBuildConfiguration::enabledChanged,
this, [this]() { setError(m_buildConfiguration->disabledReason()); });
this, [this]() {
setError(m_buildConfiguration->disabledReason());
setConfigurationForCMake();
});
connect(m_buildConfiguration, &CMakeBuildConfiguration::configurationForCMakeChanged,
this, [this]() { setConfigurationForCMake(); });
updateSelection(QModelIndex(), QModelIndex());
}
......@@ -381,7 +386,19 @@ void CMakeBuildSettingsWidget::updateFromKit()
for (const CMakeConfigItem &i : config)
configHash.insert(QString::fromUtf8(i.key), i.expandedValue(k));
m_configModel->setKitConfiguration(configHash);
m_configModel->setConfigurationFromKit(configHash);
}
void CMakeBuildSettingsWidget::setConfigurationForCMake()
{
QHash<QString, QString> config;
const CMakeConfig configList = m_buildConfiguration->configurationForCMake();
for (const CMakeConfigItem &i : configList) {
config.insert(QString::fromUtf8(i.key),
CMakeConfigItem::expandedValueOf(m_buildConfiguration->target()->kit(),
i.key, configList));
}
m_configModel->setConfigurationForCMake(config);
}
void CMakeBuildSettingsWidget::updateSelection(const QModelIndex &current, const QModelIndex &previous)
......
......@@ -65,6 +65,7 @@ private:
void updateAdvancedCheckBox();
void updateFromKit();
void setConfigurationForCMake();
void updateSelection(const QModelIndex &current, const QModelIndex &previous);
QAction *createForceAction(int type, const QModelIndex &idx);
......
......@@ -300,7 +300,7 @@ void CMakeBuildStep::handleProjectWasParsed(QFutureInterface<bool> &fi, bool suc
if (success) {
runImpl(fi);
} else {
AbstractProcessStep::stdError(tr("Project did not parse successfully, can not build."));
AbstractProcessStep::stdError(tr("Project did not parse successfully, cannot build."));
reportRunResult(fi, false);
}
}
......
......@@ -160,11 +160,11 @@ CMakeProject::CMakeProject(const FileName &fileName) : Project(Constants::CMAKEM
return;
// Build configuration has switched:
// * Error out if the reader updates, can not happen since all BCs share a target/kit.
// * Check configuration if reader changes due to it not existing yet:-)
// * run cmake without configuration arguments if the reader stays
m_buildDirManager.setParametersAndRequestParse(
BuildDirParameters(bc),
BuildDirManager::REPARSE_FAIL,
BuildDirManager::REPARSE_CHECK_CONFIGURATION,
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
});
......
......@@ -26,11 +26,11 @@
#pragma once
#include "cmake_global.h"
#include "builddirmanager.h"
#include "cmakebuildtarget.h"
#include "cmakeprojectimporter.h"
#include "treescanner.h"
#include "builddirmanager.h"
#include <projectexplorer/extracompiler.h>
#include <projectexplorer/projectmacro.h>
......
......@@ -49,7 +49,7 @@ QByteArray CMakeInputsNode::generateId(const Utils::FileName &inputFile)
bool CMakeInputsNode::showInSimpleTree() const
{
return false;
return true;
}
CMakeListsNode::CMakeListsNode(const Utils::FileName &cmakeListPath) :
......
......@@ -94,13 +94,30 @@ void ConfigModel::setConfiguration(const QList<DataItem> &config)
setConfiguration(Utils::transform(config, [](const DataItem &di) { return InternalDataItem(di); }));
}
void ConfigModel::setKitConfiguration(const QHash<QString, QString> &kitConfig)
void ConfigModel::setConfigurationFromKit(const QHash<QString, QString> &kitConfig)
{
m_kitConfiguration = kitConfig;
for (InternalDataItem &i : m_configuration) {
if (m_kitConfiguration.contains(i.key)) {
if (m_kitConfiguration.contains(i.key))
i.kitValue = m_kitConfiguration.value(i.key);
}
setConfiguration(m_configuration);
}
void ConfigModel::setConfigurationForCMake(const QHash<QString, QString> &config)
{
for (InternalDataItem &i : m_configuration) {
if (!config.contains(i.key))
continue;
const QString v = config.value(i.key);
if (i.value == v) {
i.newValue.clear();
i.isUserChanged = false;
} else {
i.newValue = v;
i.isUserChanged = true;
}
}
setConfiguration(m_configuration);
......@@ -202,7 +219,7 @@ ConfigModel::DataItem ConfigModel::dataItemFromIndex(const QModelIndex &idx)
return DataItem();
}
QList<ConfigModel::DataItem> ConfigModel::configurationChanges() const
QList<ConfigModel::DataItem> ConfigModel::configurationForCMake() const
{
const QList<InternalDataItem> tmp
= Utils::filtered(m_configuration, [](const InternalDataItem &i) {
......@@ -362,7 +379,7 @@ QString ConfigModel::InternalDataItem::toolTip() const
tooltip << QCoreApplication::translate("CMakeProjectManager", "Not in CMakeCache.txt").arg(value);
}
if (!kitValue.isEmpty())
tooltip << QCoreApplication::translate("CMakeProjectManager::ConfigModel", "Current Kit: %1").arg(kitValue);
tooltip << QCoreApplication::translate("CMakeProjectManager::ConfigModel", "Current kit: %1").arg(kitValue);
return tooltip.join("<br>");
}
......@@ -511,7 +528,7 @@ QString ConfigModelTreeItem::toolTip() const
QTC_ASSERT(dataItem, return QString());
QStringList tooltip(dataItem->description);
if (!dataItem->kitValue.isEmpty())
tooltip << QCoreApplication::translate("CMakeProjectManager", "Value requested by Kit: %1").arg(dataItem->kitValue);
tooltip << QCoreApplication::translate("CMakeProjectManager", "Value requested by kit: %1").arg(dataItem->kitValue);
if (dataItem->inCMakeCache) {
if (dataItem->value != dataItem->newValue)
tooltip << QCoreApplication::translate("CMakeProjectManager", "Current CMake: %1").arg(dataItem->value);
......
......@@ -70,7 +70,8 @@ public:
const QStringList &values = QStringList());
void setConfiguration(const CMakeConfig &config);
void setConfiguration(const QList<DataItem> &config);
void setKitConfiguration(const QHash<QString, QString> &kitConfig);
void setConfigurationFromKit(const QHash<QString, QString> &kitConfig);
void setConfigurationForCMake(const QHash<QString, QString> &config);
void flush();
void resetAllChanges();
......@@ -84,7 +85,7 @@ public:
static DataItem dataItemFromIndex(const QModelIndex &idx);
QList<DataItem> configurationChanges() const;
QList<DataItem> configurationForCMake() const;
private:
......
......@@ -104,7 +104,7 @@ void ServerModeReader::setParameters(const BuildDirParameters &p)
BuildDirReader::setParameters(p);
if (!m_cmakeServer) {
m_cmakeServer.reset(new ServerMode(p.environment,
p.sourceDirectory, p.buildDirectory,
p.sourceDirectory, p.workDirectory,
p.cmakeTool->cmakeExecutable(),
p.generator, p.extraGenerator, p.platform, p.toolset,
true, 1));
......@@ -155,7 +155,7 @@ bool ServerModeReader::isCompatible(const BuildDirParameters &p)
&& p.platform == m_parameters.platform
&& p.toolset == m_parameters.toolset
&& p.sourceDirectory == m_parameters.sourceDirectory
&& p.buildDirectory == m_parameters.buildDirectory;
&& p.workDirectory == m_parameters.workDirectory;
}
void ServerModeReader::resetData()
......
......@@ -184,7 +184,7 @@ QModelIndex ExternalToolModel::index(int row, int column, const QModelIndex &par
if (row < items.count())
return createIndex(row, 0, items.at(row));
}
} else if (column == 0 && row < m_tools.keys().count()) {
} else if (column == 0 && row < m_tools.size()) {
return createIndex(row, 0);
}
return QModelIndex();
......@@ -208,7 +208,7 @@ QModelIndex ExternalToolModel::parent(const QModelIndex &child) const
int ExternalToolModel::rowCount(const QModelIndex &parent) const
{
if (!parent.isValid())
return m_tools.keys().count();
return m_tools.size();
if (toolForIndex(parent))
return 0;
bool found;
......
......@@ -534,7 +534,9 @@ QList<IDocument *> DocumentManager::modifiedDocuments()
{
QList<IDocument *> modified;
foreach (IDocument *document, d->m_documentsWithWatch.keys()) {
const auto docEnd = d->m_documentsWithWatch.keyEnd();
for (auto docIt = d->m_documentsWithWatch.keyBegin(); docIt != docEnd; ++docIt) {
IDocument *document = *docIt;
if (document->isModified())
modified << document;
}
......
......@@ -47,7 +47,7 @@ static bool validateRegExp(Utils::FancyLineEdit *edit, QString *errorMessage)
{
if (edit->text().isEmpty()) {
if (errorMessage)
*errorMessage = FindToolWindow::tr("Empty search term");
*errorMessage = FindToolWindow::tr("Empty search term.");
return false;
}
if (Find::hasFindFlag(FindRegularExpression)) {
......
......@@ -293,10 +293,11 @@ void HighlightScrollBarOverlay::paintEvent(QPaintEvent *paintEvent)
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, false);
foreach (Utils::Theme::Color themeColor, highlights.keys()) {
const QColor &color = creatorTheme()->color(themeColor);
for (int i = 0, total = highlights[themeColor].size(); i < total; ++i) {
const QRect rect = highlights[themeColor][i];
const auto highlightEnd = highlights.cend();
for (auto highlightIt = highlights.cbegin(); highlightIt != highlightEnd; ++highlightIt) {
const QColor &color = creatorTheme()->color(highlightIt.key());
for (int i = 0, total = highlightIt.value().size(); i < total; ++i) {
const QRect rect = highlightIt.value().at(i);
painter.fillRect(rect, color);
}
}
......
......@@ -100,7 +100,7 @@ QList<LocatorFilterEntry> BaseFileFilter::matchesFor(QFutureInterface<LocatorFil
const QString entry = QDir::fromNativeSeparators(origEntry);