aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Komissarov <[email protected]>2025-06-14 13:19:37 +0300
committerIvan Komissarov <[email protected]>2025-06-25 11:48:47 +0000
commit27cc61e6693670054c11e669ade4697baf350ecd (patch)
tree236e0ce99635da61c6a3cac7156a6e6093b36181
parent314765f95436b399fa251d92af32eaab9d87795a (diff)
generators: add artifacts to graphviz generator
Change-Id: Id494b304a29c04ea74a4dbdb40bf6ef50baf6993 Reviewed-by: Christian Kandeler <[email protected]>
-rw-r--r--src/lib/corelib/api/project.cpp13
-rw-r--r--src/lib/corelib/api/projectdata.cpp5
-rw-r--r--src/lib/corelib/api/projectdata.h1
-rw-r--r--src/lib/corelib/api/projectdata_p.h1
-rw-r--r--src/plugins/generator/graphviz/dotgraph.h6
-rw-r--r--src/plugins/generator/graphviz/graphvizgenerator.cpp55
6 files changed, 80 insertions, 1 deletions
diff --git a/src/lib/corelib/api/project.cpp b/src/lib/corelib/api/project.cpp
index 658e04814..abab9c94c 100644
--- a/src/lib/corelib/api/project.cpp
+++ b/src/lib/corelib/api/project.cpp
@@ -285,6 +285,11 @@ ArtifactData ProjectPrivate::createArtifactData(const Artifact *artifact,
ta.d->filePath = artifact->filePath();
ta.d->fileTags = artifact->fileTags().toStringList();
ta.d->properties.d->m_map = artifact->properties;
+ for (const Artifact *a : filterByType<Artifact>(artifact->children)) {
+ ta.d->childPaths << a->filePath();
+ for (const auto *f : a->fileDependencies)
+ ta.d->childPaths << f->filePath();
+ }
ta.d->isGenerated = artifact->artifactType == Artifact::Generated;
ta.d->isTargetArtifact = targetArtifacts.contains(const_cast<Artifact *>(artifact));
ta.d->isValid = true;
@@ -678,6 +683,14 @@ void ProjectPrivate::retrieveProjectData(ProjectData &projectData,
ta.d->filePath = it.key();
ta.d->fileTags = it.value().fileTags.toStringList();
ta.d->properties.d->m_map = it.value().properties;
+ Artifact * const child = lookupArtifact(resolvedProduct, it.key(), true);
+ if (child) {
+ for (const Artifact *a : filterByType<Artifact>(child->children)) {
+ ta.d->childPaths << a->filePath();
+ for (const auto *f : a->fileDependencies)
+ ta.d->childPaths << f->filePath();
+ }
+ }
ta.d->isGenerated = true;
ta.d->isTargetArtifact = resolvedProduct->fileTags.intersects(it.value().fileTags);
ta.d->isValid = true;
diff --git a/src/lib/corelib/api/projectdata.cpp b/src/lib/corelib/api/projectdata.cpp
index 0a4fe5486..cc4a9ea60 100644
--- a/src/lib/corelib/api/projectdata.cpp
+++ b/src/lib/corelib/api/projectdata.cpp
@@ -354,6 +354,11 @@ InstallData ArtifactData::installData() const
return d->installData;
}
+QStringList ArtifactData::childPaths() const
+{
+ return d->childPaths;
+}
+
bool operator==(const ArtifactData &ad1, const ArtifactData &ad2)
{
return ad1.filePath() == ad2.filePath()
diff --git a/src/lib/corelib/api/projectdata.h b/src/lib/corelib/api/projectdata.h
index 4b7bc2803..5b4dde686 100644
--- a/src/lib/corelib/api/projectdata.h
+++ b/src/lib/corelib/api/projectdata.h
@@ -129,6 +129,7 @@ public:
bool isTargetArtifact() const;
PropertyMap properties() const;
InstallData installData() const;
+ QStringList childPaths() const;
private:
QExplicitlySharedDataPointer<Internal::ArtifactDataPrivate> d;
diff --git a/src/lib/corelib/api/projectdata_p.h b/src/lib/corelib/api/projectdata_p.h
index e241ea92c..5b6a8c037 100644
--- a/src/lib/corelib/api/projectdata_p.h
+++ b/src/lib/corelib/api/projectdata_p.h
@@ -63,6 +63,7 @@ public:
QStringList fileTags;
PropertyMap properties;
InstallData installData;
+ QStringList childPaths;
bool isValid = false;
bool isGenerated = false;
bool isTargetArtifact = false;
diff --git a/src/plugins/generator/graphviz/dotgraph.h b/src/plugins/generator/graphviz/dotgraph.h
index ed449c92f..ddd28795a 100644
--- a/src/plugins/generator/graphviz/dotgraph.h
+++ b/src/plugins/generator/graphviz/dotgraph.h
@@ -53,7 +53,7 @@ struct DotGraphNode
QString label;
bool enabled{true};
- enum class Type { Product, Project, Module };
+ enum class Type { Product, Project, Module, Artifact, File };
Type type;
static QByteArray typeToString(Type type)
@@ -64,6 +64,10 @@ struct DotGraphNode
return QByteArray("box");
if (type == Type::Module)
return QByteArray("diamond");
+ if (type == Type::Artifact)
+ return QByteArray("pentagon");
+ if (type == Type::File)
+ return QByteArray("note");
return QByteArray("box");
}
diff --git a/src/plugins/generator/graphviz/graphvizgenerator.cpp b/src/plugins/generator/graphviz/graphvizgenerator.cpp
index f8041d0a8..c142cd682 100644
--- a/src/plugins/generator/graphviz/graphvizgenerator.cpp
+++ b/src/plugins/generator/graphviz/graphvizgenerator.cpp
@@ -219,6 +219,61 @@ void GraphvizGenerator::writeProductGraph(
dotGraph.addRelation({productNode, childNode});
}
+ const auto fileTagsString = [](const ArtifactData &artifact) {
+ return QStringLiteral("[%1]").arg(artifact.fileTags().join(QLatin1String(", ")));
+ };
+
+ const auto productNode2 = dotGraph.addNode(
+ makeProductNode(dotGraph.createNodeId(), productMap.at(product.name())));
+
+ std::unordered_map<QString, size_t> artifactToNode;
+ std::unordered_map<QString, ArtifactData> artifactMap;
+
+ for (const auto &group : product.groups()) {
+ for (const auto &artifact : group.allSourceArtifacts()) {
+ artifactMap[artifact.filePath()] = artifact;
+ }
+ }
+
+ std::deque<std::pair<ArtifactData, size_t /*node*/>> artifactQueue;
+ for (const auto &artifact : product.generatedArtifacts()) {
+ artifactMap[artifact.filePath()] = artifact;
+ if (artifact.isTargetArtifact())
+ artifactQueue.push_back({artifact, productNode2});
+ }
+
+ // Traverse artifacts starting from target artifacts down to their dependencies.
+ // This way we create nodes only for artifacts reachable from the top of the graph.
+ // Otherwise, graph becomes too complicated.
+ while (!artifactQueue.empty()) {
+ const auto &[artifact, parentNodeId] = artifactQueue.front();
+ const auto currentPath = artifact.filePath();
+
+ auto &nodeId = artifactToNode[currentPath];
+ if (nodeId) {
+ dotGraph.addRelation({parentNodeId, nodeId});
+ artifactQueue.pop_front();
+ continue;
+ }
+ DotGraphNode node;
+ node.id = dotGraph.createNodeId();
+ node.label = QFileInfo(currentPath).fileName() + QLatin1String("\n")
+ + fileTagsString(artifact);
+ node.type = artifact.isGenerated() ? DotGraphNode::Type::Artifact
+ : DotGraphNode::Type::File;
+ nodeId = dotGraph.addNode(std::move(node));
+
+ dotGraph.addRelation({parentNodeId, nodeId});
+
+ for (const auto &childPath : artifact.childPaths()) {
+ auto it = artifactMap.find(childPath);
+ if (it != artifactMap.end()) {
+ artifactQueue.push_back({it->second, nodeId});
+ }
+ }
+ artifactQueue.pop_front();
+ }
+
const QString graphFilePath = getFileName(
projectData, QLatin1String(".products/") + product.name());
dotGraph.write(graphFilePath);