Files
qt-creator/src/plugins/debugger/debuggerkitinformation.cpp
Eike Ziller ea27143239 Merge remote-tracking branch 'origin/3.2'
Conflicts:
	src/libs/utils/ipaddresslineedit.cpp
	src/libs/utils/logging.h
	src/plugins/analyzerbase/AnalyzerBase.pluginspec.in
	src/plugins/android/Android.pluginspec.in
	src/plugins/android/androiddeploystep.cpp
	src/plugins/android/androiddeploystep.h
	src/plugins/android/androiddeploystepfactory.cpp
	src/plugins/android/androiddeploystepwidget.cpp
	src/plugins/android/androidpackagecreationfactory.cpp
	src/plugins/android/androidpackagecreationstep.cpp
	src/plugins/android/androidpackagecreationstep.h
	src/plugins/android/androidpackagecreationwidget.cpp
	src/plugins/android/androidpackagecreationwidget.h
	src/plugins/android/javafilewizard.cpp
	src/plugins/autotoolsprojectmanager/AutotoolsProjectManager.pluginspec.in
	src/plugins/baremetal/BareMetal.pluginspec.in
	src/plugins/bazaar/Bazaar.pluginspec.in
	src/plugins/beautifier/Beautifier.pluginspec.in
	src/plugins/bineditor/BinEditor.pluginspec.in
	src/plugins/bookmarks/Bookmarks.pluginspec.in
	src/plugins/clangcodemodel/ClangCodeModel.pluginspec.in
	src/plugins/clangcodemodel/clanghighlightingsupport.cpp
	src/plugins/clangcodemodel/clangsymbolsearcher.cpp
	src/plugins/classview/ClassView.pluginspec.in
	src/plugins/clearcase/ClearCase.pluginspec.in
	src/plugins/cmakeprojectmanager/CMakeProjectManager.pluginspec.in
	src/plugins/cmakeprojectmanager/cmakeeditorfactory.cpp
	src/plugins/cmakeprojectmanager/cmakehighlighter.cpp
	src/plugins/coreplugin/Core.pluginspec.in
	src/plugins/cpaster/CodePaster.pluginspec.in
	src/plugins/cppeditor/CppEditor.pluginspec.in
	src/plugins/cppeditor/cppfilewizard.cpp
	src/plugins/cpptools/CppTools.pluginspec.in
	src/plugins/cpptools/cpphighlightingsupportinternal.cpp
	src/plugins/cpptools/cppmodelmanagerinterface.cpp
	src/plugins/cpptools/cppmodelmanagerinterface.h
	src/plugins/cvs/CVS.pluginspec.in
	src/plugins/debugger/Debugger.pluginspec.in
	src/plugins/designer/Designer.pluginspec.in
	src/plugins/diffeditor/DiffEditor.pluginspec.in
	src/plugins/emacskeys/EmacsKeys.pluginspec.in
	src/plugins/fakevim/FakeVim.pluginspec.in
	src/plugins/genericprojectmanager/GenericProjectManager.pluginspec.in
	src/plugins/git/Git.pluginspec.in
	src/plugins/git/gitorious/gitorious.cpp
	src/plugins/git/gitorious/gitorious.h
	src/plugins/git/gitorious/gitoriousclonewizard.cpp
	src/plugins/git/gitorious/gitorioushostwidget.cpp
	src/plugins/git/gitorious/gitorioushostwidget.h
	src/plugins/git/gitorious/gitorioushostwizardpage.cpp
	src/plugins/git/gitorious/gitoriousprojectwidget.cpp
	src/plugins/git/gitorious/gitoriousprojectwidget.h
	src/plugins/git/gitorious/gitoriousprojectwizardpage.cpp
	src/plugins/git/gitorious/gitoriousprojectwizardpage.h
	src/plugins/git/gitorious/gitoriousrepositorywizardpage.cpp
	src/plugins/git/gitorious/gitoriousrepositorywizardpage.h
	src/plugins/glsleditor/GLSLEditor.pluginspec.in
	src/plugins/glsleditor/glsleditorfactory.cpp
	src/plugins/glsleditor/glslfilewizard.cpp
	src/plugins/helloworld/HelloWorld.pluginspec.in
	src/plugins/help/Help.pluginspec.in
	src/plugins/imageviewer/ImageViewer.pluginspec.in
	src/plugins/ios/Ios.pluginspec.in
	src/plugins/macros/Macros.pluginspec.in
	src/plugins/mercurial/Mercurial.pluginspec.in
	src/plugins/perforce/Perforce.pluginspec.in
	src/plugins/projectexplorer/ProjectExplorer.pluginspec.in
	src/plugins/pythoneditor/PythonEditor.pluginspec.in
	src/plugins/pythoneditor/pythoneditorwidget.cpp
	src/plugins/pythoneditor/wizard/pythonfilewizard.cpp
	src/plugins/qbsprojectmanager/QbsProjectManager.pluginspec.in
	src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp
	src/plugins/qmakeprojectmanager/QmakeProjectManager.pluginspec.in
	src/plugins/qmakeprojectmanager/profileeditorfactory.cpp
	src/plugins/qmldesigner/QmlDesigner.pluginspec.in
	src/plugins/qmljseditor/QmlJSEditor.pluginspec.in
	src/plugins/qmljseditor/qmljseditorfactory.cpp
	src/plugins/qmljstools/QmlJSTools.pluginspec.in
	src/plugins/qmlprofiler/QmlProfiler.pluginspec.in
	src/plugins/qmlprojectmanager/QmlProjectManager.pluginspec.in
	src/plugins/qnx/Qnx.pluginspec.in
	src/plugins/qtsupport/QtSupport.pluginspec.in
	src/plugins/remotelinux/RemoteLinux.pluginspec.in
	src/plugins/resourceeditor/ResourceEditor.pluginspec.in
	src/plugins/resourceeditor/resourcewizard.h
	src/plugins/subversion/Subversion.pluginspec.in
	src/plugins/tasklist/TaskList.pluginspec.in
	src/plugins/texteditor/TextEditor.pluginspec.in
	src/plugins/texteditor/basetexteditor_p.h
	src/plugins/texteditor/basetextmark.cpp
	src/plugins/texteditor/codeassist/basicproposalitemlistmodel.h
	src/plugins/texteditor/codeassist/defaultassistinterface.h
	src/plugins/texteditor/codeassist/iassistproposalitem.cpp
	src/plugins/texteditor/itexteditor.cpp
	src/plugins/texteditor/itexteditor.h
	src/plugins/texteditor/itextmark.cpp
	src/plugins/texteditor/plaintexteditor.cpp
	src/plugins/texteditor/plaintexteditor.h
	src/plugins/texteditor/texteditoractionhandler.cpp
	src/plugins/todo/Todo.pluginspec.in
	src/plugins/updateinfo/UpdateInfo.pluginspec.in
	src/plugins/valgrind/Valgrind.pluginspec.in
	src/plugins/vcsbase/VcsBase.pluginspec.in
	src/plugins/welcome/Welcome.pluginspec.in
	src/plugins/winrt/WinRt.pluginspec.in
	tests/auto/debugger/temporarydir.h

Change-Id: I254af8be8119fe9855287909e17d4b8ca9d2fc2f
2014-10-14 15:36:16 +02:00

361 lines
13 KiB
C++

/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://www.qt.io/licensing. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "debuggerkitinformation.h"
#include "debuggeritemmanager.h"
#include "debuggerkitconfigwidget.h"
#include <projectexplorer/toolchain.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/kitinformationmacroexpander.h>
#include <utils/fileutils.h>
#include <utils/macroexpander.h>
#include <utils/qtcassert.h>
#include <QFileInfo>
#include <utility>
using namespace ProjectExplorer;
using namespace Utils;
namespace Debugger {
// --------------------------------------------------------------------------
// DebuggerKitInformation
// --------------------------------------------------------------------------
DebuggerKitInformation::DebuggerKitInformation()
{
setObjectName(QLatin1String("DebuggerKitInformation"));
setId(DebuggerKitInformation::id());
setPriority(28000);
}
QVariant DebuggerKitInformation::defaultValue(Kit *k) const
{
ToolChain *tc = ToolChainKitInformation::toolChain(k);
if (!tc)
return QVariant();
const Abi toolChainAbi = tc->targetAbi();
foreach (const DebuggerItem &item, DebuggerItemManager::debuggers())
foreach (const Abi targetAbi, item.abis())
if (targetAbi.isCompatibleWith(toolChainAbi))
return item.id();
return QVariant();
}
void DebuggerKitInformation::setup(Kit *k)
{
// This can be anything (Id, binary path, "auto")
// With 3.0 we have:
// <value type="QString" key="Debugger.Information">{75ecf347-f221-44c3-b613-ea1d29929cd4}</value>
// Before we had:
// <valuemap type="QVariantMap" key="Debugger.Information">
// <value type="QString" key="Binary">/data/dev/debugger/gdb-git/gdb/gdb</value>
// <value type="int" key="EngineType">1</value>
// </valuemap>
// Or for force auto-detected CDB
// <valuemap type="QVariantMap" key="Debugger.Information">
// <value type="QString" key="Binary">auto</value>
// <value type="int" key="EngineType">4</value>
// </valuemap>
const QVariant rawId = k->value(DebuggerKitInformation::id());
const ToolChain *tc = ToolChainKitInformation::toolChain(k);
// Get the best of the available debugger matching the kit's toolchain.
// The general idea is to find an item that exactly matches what
// is stored in the kit information, but also accept item based
// on toolchain matching as fallback with a lower priority.
const DebuggerItem *bestItem = 0;
DebuggerItem::MatchLevel bestLevel = DebuggerItem::DoesNotMatch;
foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) {
DebuggerItem::MatchLevel level = DebuggerItem::DoesNotMatch;
if (rawId.isNull()) {
// Initial setup of a kit.
if (tc) {
// Use item if target toolchain fits.
level = item.matchTarget(tc->targetAbi());
} else {
// Use item if host toolchain fits, but only as fallback.
level = std::min(item.matchTarget(Abi::hostAbi()), DebuggerItem::MatchesSomewhat);
}
} else if (rawId.type() == QVariant::String) {
// New structure.
if (item.id() == rawId) {
// Detected by ID.
level = DebuggerItem::MatchesPerfectly;
} else {
// This item does not match by ID, and is an unlikely candidate.
// However, consider using it as fallback if the tool chain fits.
if (tc)
level = std::min(item.matchTarget(tc->targetAbi()), DebuggerItem::MatchesSomewhat);
}
} else {
// Old structure.
const QMap<QString, QVariant> map = rawId.toMap();
QString binary = map.value(QLatin1String("Binary")).toString();
if (binary == QLatin1String("auto")) {
// This is close to the "new kit" case, except that we know
// an engine type.
DebuggerEngineType autoEngine = DebuggerEngineType(map.value(QLatin1String("EngineType")).toInt());
if (item.engineType() == autoEngine) {
if (tc) {
// Use item if target toolchain fits.
level = item.matchTarget(tc->targetAbi());
} else {
// Use item if host toolchain fits, but only as fallback.
level = std::min(item.matchTarget(Abi::hostAbi()), DebuggerItem::MatchesSomewhat);
}
}
} else {
// We have an executable path.
FileName fileName = FileName::fromUserInput(binary);
if (item.command() == fileName) {
// And it's is the path of this item.
if (tc) {
// Use item if target toolchain fits.
level = item.matchTarget(tc->targetAbi());
} else {
// Use item if host toolchain fits, but only as fallback.
level = std::min(item.matchTarget(Abi::hostAbi()), DebuggerItem::MatchesSomewhat);
}
} else {
// This item does not match by filename, and is an unlikely candidate.
// However, consider using it as fallback if the tool chain fits.
if (tc)
level = std::min(item.matchTarget(tc->targetAbi()), DebuggerItem::MatchesSomewhat);
}
}
}
if (level > bestLevel) {
bestLevel = level;
bestItem = &item;
}
}
// Use the best id we found, or an invalid one.
k->setValue(DebuggerKitInformation::id(), bestItem ? bestItem->id() : QVariant());
}
// This handles the upgrade path from 2.8 to 3.0
void DebuggerKitInformation::fix(Kit *k)
{
// This can be Id, binary path, but not "auto" anymore.
const QVariant rawId = k->value(DebuggerKitInformation::id());
if (rawId.isNull()) // No debugger set, that is fine.
return;
if (rawId.type() == QVariant::String) {
if (!DebuggerItemManager::findById(rawId)) {
qWarning("Unknown debugger id %s in kit %s",
qPrintable(rawId.toString()), qPrintable(k->displayName()));
k->setValue(DebuggerKitInformation::id(), QVariant());
}
return; // All fine (now).
}
QMap<QString, QVariant> map = rawId.toMap();
QString binary = map.value(QLatin1String("Binary")).toString();
if (binary == QLatin1String("auto")) {
// This should not happen as "auto" is handled by setup() already.
QTC_CHECK(false);
k->setValue(DebuggerKitInformation::id(), QVariant());
return;
}
FileName fileName = FileName::fromUserInput(binary);
const DebuggerItem *item = DebuggerItemManager::findByCommand(fileName);
if (!item) {
qWarning("Debugger command %s invalid in kit %s",
qPrintable(binary), qPrintable(k->displayName()));
k->setValue(DebuggerKitInformation::id(), QVariant());
return;
}
k->setValue(DebuggerKitInformation::id(), item->id());
}
// Check the configuration errors and return a flag mask. Provide a quick check and
// a verbose one with a list of errors.
enum DebuggerConfigurationErrors {
NoDebugger = 0x1,
DebuggerNotFound = 0x2,
DebuggerNotExecutable = 0x4,
DebuggerNeedsAbsolutePath = 0x8
};
static unsigned debuggerConfigurationErrors(const Kit *k)
{
QTC_ASSERT(k, return NoDebugger);
const DebuggerItem *item = DebuggerKitInformation::debugger(k);
if (!item)
return NoDebugger;
if (item->command().isEmpty())
return NoDebugger;
unsigned result = 0;
const QFileInfo fi = item->command().toFileInfo();
if (!fi.exists() || fi.isDir())
result |= DebuggerNotFound;
else if (!fi.isExecutable())
result |= DebuggerNotExecutable;
if (!fi.exists() || fi.isDir()) {
if (item->engineType() == NoEngineType)
return NoDebugger;
// We need an absolute path to be able to locate Python on Windows.
if (item->engineType() == GdbEngineType)
if (const ToolChain *tc = ToolChainKitInformation::toolChain(k))
if (tc->targetAbi().os() == Abi::WindowsOS && !fi.isAbsolute())
result |= DebuggerNeedsAbsolutePath;
}
return result;
}
const DebuggerItem *DebuggerKitInformation::debugger(const Kit *kit)
{
QTC_ASSERT(kit, return 0);
const QVariant id = kit->value(DebuggerKitInformation::id());
return DebuggerItemManager::findById(id);
}
bool DebuggerKitInformation::isValidDebugger(const Kit *k)
{
return debuggerConfigurationErrors(k) == 0;
}
QList<Task> DebuggerKitInformation::validateDebugger(const Kit *k)
{
QList<Task> result;
const unsigned errors = debuggerConfigurationErrors(k);
if (!errors)
return result;
QString path;
if (const DebuggerItem *item = debugger(k))
path = item->command().toUserOutput();
const Core::Id id = ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM;
if (errors & NoDebugger)
result << Task(Task::Warning, tr("No debugger set up."), FileName(), -1, id);
if (errors & DebuggerNotFound)
result << Task(Task::Error, tr("Debugger \"%1\" not found.").arg(path),
FileName(), -1, id);
if (errors & DebuggerNotExecutable)
result << Task(Task::Error, tr("Debugger \"%1\" not executable.").arg(path), FileName(), -1, id);
if (errors & DebuggerNeedsAbsolutePath) {
const QString message =
tr("The debugger location must be given as an "
"absolute path (%1).").arg(path);
result << Task(Task::Error, message, FileName(), -1, id);
}
return result;
}
KitConfigWidget *DebuggerKitInformation::createConfigWidget(Kit *k) const
{
return new Internal::DebuggerKitConfigWidget(k, this);
}
AbstractMacroExpander *DebuggerKitInformation::createMacroExpander(const Kit *k) const
{
return new MacroExpander([k, this](const QString &name, QString *ret) -> bool {
const DebuggerItem *item = DebuggerKitInformation::debugger(k);
if (name == QLatin1String("Debugger:engineType")) {
*ret = item ? item->engineTypeName() : tr("none");
return true;
}
return false;
});
}
KitInformation::ItemList DebuggerKitInformation::toUserOutput(const Kit *k) const
{
return ItemList() << qMakePair(tr("Debugger"), displayString(k));
}
FileName DebuggerKitInformation::debuggerCommand(const ProjectExplorer::Kit *k)
{
const DebuggerItem *item = debugger(k);
QTC_ASSERT(item, return FileName());
return item->command();
}
DebuggerEngineType DebuggerKitInformation::engineType(const ProjectExplorer::Kit *k)
{
const DebuggerItem *item = debugger(k);
QTC_ASSERT(item, return NoEngineType);
return item->engineType();
}
QString DebuggerKitInformation::displayString(const Kit *k)
{
const DebuggerItem *item = debugger(k);
if (!item)
return tr("No Debugger");
QString binary = item->command().toUserOutput();
QString name = tr("%1 Engine").arg(item->engineTypeName());
return binary.isEmpty() ? tr("%1 <None>").arg(name) : tr("%1 using \"%2\"").arg(name, binary);
}
void DebuggerKitInformation::setDebugger(Kit *k, const QVariant &id)
{
// Only register reasonably complete debuggers.
QTC_ASSERT(DebuggerItemManager::findById(id), return);
k->setValue(DebuggerKitInformation::id(), id);
}
Core::Id DebuggerKitInformation::id()
{
return "Debugger.Information";
}
} // namespace Debugger