[SymbolGraph] Make symbol-graph output deterministic

SymbolGraph generation iterating over llvm::DenseSet, which makes the
symbols and relationship fields appear in non-deterministic ordering.
Switch to use llvm::SetVector to preserve the insertion order from
SourceEntityWalker to make order deterministic.

Resolves: https://github.com/swiftlang/swift/issues/59602
(cherry picked from commit dfa4a27ec8)
This commit is contained in:
Steven Wu
2025-04-08 12:30:09 -07:00
parent 7be76400c4
commit 58087af610
3 changed files with 9 additions and 24 deletions

View File

@@ -650,21 +650,6 @@ void SymbolGraph::serialize(llvm::json::OStream &OS) {
}
});
#ifndef NDEBUG
// FIXME (solver-based-verification-sorting): In assert builds sort the
// edges so we get consistent symbol graph output. This allows us to compare
// the string representation of the symbolgraph between the solver-based
// and AST-based result.
// This can be removed once the AST-based cursor info has been removed.
SmallVector<Edge> Edges(this->Edges.begin(), this->Edges.end());
std::sort(Edges.begin(), Edges.end(), [](const Edge &LHS, const Edge &RHS) {
SmallString<256> LHSTargetUSR, RHSTargetUSR;
LHS.Target.getUSR(LHSTargetUSR);
RHS.Target.getUSR(RHSTargetUSR);
return LHSTargetUSR < RHSTargetUSR;
});
#endif
OS.attributeArray("relationships", [&](){
for (const auto &Relationship : Edges) {
Relationship.serialize(OS);

View File

@@ -13,15 +13,14 @@
#ifndef SWIFT_SYMBOLGRAPHGEN_SYMBOLGRAPH_H
#define SWIFT_SYMBOLGRAPHGEN_SYMBOLGRAPH_H
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/VersionTuple.h"
#include "Edge.h"
#include "Symbol.h"
#include "swift/Basic/LLVM.h"
#include "swift/Markup/Markup.h"
#include "swift/SymbolGraphGen/SymbolGraphOptions.h"
#include "Edge.h"
#include "JSON.h"
#include "Symbol.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/VersionTuple.h"
namespace swift {
namespace symbolgraphgen {
@@ -67,12 +66,12 @@ struct SymbolGraph {
/**
The symbols in a module: the nodes in the graph.
*/
llvm::DenseSet<Symbol> Nodes;
llvm::SetVector<Symbol> Nodes;
/**
The relationships between symbols: the edges in the graph.
*/
llvm::DenseSet<Edge> Edges;
llvm::SetVector<Edge> Edges;
/**
True if this graph is for a single symbol, rather than an entire module.

View File

@@ -1,6 +1,6 @@
// RUN: %empty-directory(%t)
// RUN: echo '[]' > %t/protocol.json
// RUN: %target-swift-frontend -module-name test -emit-module -o %t/test.swiftmodule %s -emit-module-doc-path %t/test.docc -const-gather-protocols-file %t/protocol.json -emit-const-values-path %t/test.swiftconstvalues -emit-tbd-path %t/test.tbd -tbd-current-version 1 -tbd-compatibility-version 1 -tbd-install_name @rpath/test.dylib -emit-loaded-module-trace -emit-loaded-module-trace-path %t/test.trace.json -enable-deterministic-check 2>&1 | %FileCheck %s --check-prefix=MODULE_OUTPUT --check-prefix=DOCC_OUTPUT --check-prefix=CONSTVALUE_OUTPUT --check-prefix=TBD_OUTPUT --check-prefix=TRACE_OUTPUT
// RUN: %target-swift-frontend -module-name test -emit-module -o %t/test.swiftmodule %s -emit-module-doc-path %t/test.docc -const-gather-protocols-file %t/protocol.json -emit-const-values-path %t/test.swiftconstvalues -emit-symbol-graph -emit-symbol-graph-dir %t/symbols -emit-tbd-path %t/test.tbd -tbd-current-version 1 -tbd-compatibility-version 1 -tbd-install_name @rpath/test.dylib -emit-loaded-module-trace -emit-loaded-module-trace-path %t/test.trace.json -enable-deterministic-check 2>&1 | %FileCheck %s --check-prefix=MODULE_OUTPUT --check-prefix=DOCC_OUTPUT --check-prefix=CONSTVALUE_OUTPUT --check-prefix=TBD_OUTPUT --check-prefix=TRACE_OUTPUT --check-prefix=SYMBOLGRAPH_OUTPUT
// RUN: %target-swift-frontend -module-name test -emit-sib -o %t/test.sib -primary-file %s -enable-deterministic-check 2>&1 | %FileCheck %s --check-prefix=SIB_OUTPUT
/// object files are "not" deterministic because the second run going to match the mod hash and skip code generation.
@@ -22,6 +22,7 @@
// RUN: %target-swift-frontend -emit-pcm -module-name UserClangModule -o %t/test.pcm %S/Inputs/dependencies/module.modulemap -enable-deterministic-check 2>&1 | %FileCheck %s --check-prefix=PCM_OUTPUT
// SYMBOLGRAPH_OUTPUT: remark: produced matching output file '{{.*}}{{/|\\}}test.symbols.json'
// DOCC_OUTPUT: remark: produced matching output file '{{.*}}{{/|\\}}test.docc'
// CONSTVALUE_OUTPUT: remark: produced matching output file '{{.*}}{{/|\\}}test.swiftconstvalues'
// MODULE_OUTPUT: remark: produced matching output file '{{.*}}{{/|\\}}test.swiftmodule'