From d8e0ecb0ab6ef5d2bf78160064fc69fd92ab2086 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Tue, 4 Jul 2017 15:49:29 +0200 Subject: [PATCH] CMake: Extract crossReferences data of targets in server-mode Use the information to add a filenode below a target that takes you directly to the target definition. Change-Id: Ifcb8e2c4f085110033019ea3816c79f5b8630472 Reviewed-by: Tim Jenssen --- .../cmakeprojectmanager/servermodereader.cpp | 101 ++++++++++++++++++ .../cmakeprojectmanager/servermodereader.h | 26 ++++- 2 files changed, 126 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/servermodereader.cpp b/src/plugins/cmakeprojectmanager/servermodereader.cpp index c784997332b..babd4781739 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.cpp +++ b/src/plugins/cmakeprojectmanager/servermodereader.cpp @@ -56,7 +56,10 @@ const char CONFIGURE_TYPE[] = "configure"; const char CMAKE_INPUTS_TYPE[] = "cmakeInputs"; const char COMPUTE_TYPE[] = "compute"; +const char BACKTRACE_KEY[] = "backtrace"; +const char LINE_KEY[] = "line"; const char NAME_KEY[] = "name"; +const char PATH_KEY[] = "path"; const char SOURCE_DIRECTORY_KEY[] = "sourceDirectory"; const char SOURCES_KEY[] = "sources"; @@ -484,6 +487,8 @@ ServerModeReader::Target *ServerModeReader::extractTargetData(const QVariantMap target->sourceDirectory = FileName::fromString(data.value(SOURCE_DIRECTORY_KEY).toString()); target->buildDirectory = FileName::fromString(data.value("buildDirectory").toString()); + target->crossReferences = extractCrossReferences(data.value("crossReferences").toMap()); + QDir srcDir(target->sourceDirectory.toString()); target->type = data.value("type").toString(); @@ -528,6 +533,72 @@ ServerModeReader::FileGroup *ServerModeReader::extractFileGroupData(const QVaria return fileGroup; } +QList ServerModeReader::extractCrossReferences(const QVariantMap &data) +{ + QList crossReferences; + + if (data.isEmpty()) + return crossReferences; + + auto cr = std::make_unique(); + cr->backtrace = extractBacktrace(data.value(BACKTRACE_KEY, QVariantList()).toList()); + QTC_ASSERT(!cr->backtrace.isEmpty(), return {}); + crossReferences.append(cr.release()); + + const QVariantList related = data.value("relatedStatements", QVariantList()).toList(); + for (const QVariant &relatedData : related) { + auto cr = std::make_unique(); + + // extract information: + const QVariantMap map = relatedData.toMap(); + const QString typeString = map.value("type", QString()).toString(); + if (typeString.isEmpty()) + cr->type = CrossReference::TARGET; + else if (typeString == "target_link_libraries") + cr->type = CrossReference::LIBRARIES; + else if (typeString == "target_compile_defines") + cr->type = CrossReference::DEFINES; + else if (typeString == "target_include_directories") + cr->type = CrossReference::INCLUDES; + else + cr->type = CrossReference::UNKNOWN; + cr->backtrace = extractBacktrace(map.value(BACKTRACE_KEY, QVariantList()).toList()); + + // sanity check: + if (cr->backtrace.isEmpty()) + continue; + + // store information: + crossReferences.append(cr.release()); + } + return crossReferences; +} + +ServerModeReader::BacktraceItem *ServerModeReader::extractBacktraceItem(const QVariantMap &data) +{ + QTC_ASSERT(!data.isEmpty(), return nullptr); + auto item = std::make_unique(); + + item->line = data.value(LINE_KEY, -1).toInt(); + item->name = data.value(NAME_KEY, QString()).toString(); + item->path = data.value(PATH_KEY, QString()).toString(); + + QTC_ASSERT(!item->path.isEmpty(), return nullptr); + return item.release(); +} + +QList ServerModeReader::extractBacktrace(const QVariantList &data) +{ + QList btResult; + for (const QVariant &bt : data) { + BacktraceItem *btItem = extractBacktraceItem(bt.toMap()); + QTC_ASSERT(btItem, continue); + + btResult.append(btItem); + } + return btResult; +} + void ServerModeReader::extractCMakeInputsData(const QVariantMap &data) { const FileName src = FileName::fromString(data.value(SOURCE_DIRECTORY_KEY).toString()); @@ -699,6 +770,36 @@ void ServerModeReader::addTargets(const QHashsourceDirectory, t->name); QTC_ASSERT(tNode, qDebug() << "No target node for" << t->sourceDirectory << t->name; continue); tNode->setTargetInformation(t->artifacts, t->type); + QList info; + // Set up a default target path: + FileName targetPath = t->sourceDirectory; + targetPath.appendPath("CMakeLists.txt"); + for (CrossReference *cr : Utils::asConst(t->crossReferences)) { + BacktraceItem *bt = cr->backtrace.isEmpty() ? nullptr : cr->backtrace.at(0); + if (bt) { + const QString btName = bt->name.toLower(); + const FileName path = Utils::FileName::fromUserInput(bt->path); + QString dn; + if (cr->type != CrossReference::TARGET) { + if (path == targetPath) { + if (bt->line >= 0) + dn = tr("%1 in line %3").arg(btName).arg(bt->line); + else + dn = tr("%1").arg(btName); + } else { + if (bt->line >= 0) + dn = tr("%1 in %2:%3").arg(btName, path.toUserOutput()).arg(bt->line); + else + dn = tr("%1 in %2").arg(btName, path.toUserOutput()); + } + } else { + dn = tr("Target Definition"); + targetPath = path; + } + info.append(FolderNode::LocationInfo(dn, path, bt->line)); + } + } + tNode->setLocationInfo(info); addFileGroups(tNode, t->sourceDirectory, t->buildDirectory, t->fileGroups, knownHeaderNodes); } } diff --git a/src/plugins/cmakeprojectmanager/servermodereader.h b/src/plugins/cmakeprojectmanager/servermodereader.h index 4265d9627c3..f94e4d92231 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.h +++ b/src/plugins/cmakeprojectmanager/servermodereader.h @@ -29,6 +29,8 @@ #include "servermode.h" #include "cmakeparser.h" +#include + #include namespace CMakeProjectManager { @@ -87,8 +89,26 @@ private: bool isGenerated; }; + struct BacktraceItem { + int line = -1; + QString path; + QString name; + }; + + struct CrossReference { + ~CrossReference() { qDeleteAll(backtrace); backtrace.clear(); } + QList backtrace; + enum Type { TARGET, LIBRARIES, DEFINES, INCLUDES, UNKNOWN }; + Type type; + }; + struct Target { - ~Target() { qDeleteAll(fileGroups); fileGroups.clear(); } + ~Target() { + qDeleteAll(fileGroups); + fileGroups.clear(); + qDeleteAll(crossReferences); + crossReferences.clear(); + } Project *project = nullptr; QString name; @@ -97,6 +117,7 @@ private: Utils::FileName sourceDirectory; Utils::FileName buildDirectory; QList fileGroups; + QList crossReferences; }; struct Project { @@ -111,6 +132,9 @@ private: Project *extractProjectData(const QVariantMap &data, QSet &knownTargets); Target *extractTargetData(const QVariantMap &data, Project *p, QSet &knownTargets); FileGroup *extractFileGroupData(const QVariantMap &data, const QDir &srcDir, Target *t); + QList extractCrossReferences(const QVariantMap &data); + QList extractBacktrace(const QVariantList &data); + BacktraceItem *extractBacktraceItem(const QVariantMap &data); void extractCMakeInputsData(const QVariantMap &data); void extractCacheData(const QVariantMap &data);