From 58087af6105af816fd8512285c17a906b699372b Mon Sep 17 00:00:00 2001 From: Steven Wu Date: Tue, 8 Apr 2025 12:30:09 -0700 Subject: [PATCH] [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 dfa4a27ec865419ecc8086f9ad6c20d163e8fdb5) --- lib/SymbolGraphGen/SymbolGraph.cpp | 15 --------------- lib/SymbolGraphGen/SymbolGraph.h | 15 +++++++-------- test/Frontend/output_determinism_check.swift | 3 ++- 3 files changed, 9 insertions(+), 24 deletions(-) diff --git a/lib/SymbolGraphGen/SymbolGraph.cpp b/lib/SymbolGraphGen/SymbolGraph.cpp index bc22d5296d6..268e19b326c 100644 --- a/lib/SymbolGraphGen/SymbolGraph.cpp +++ b/lib/SymbolGraphGen/SymbolGraph.cpp @@ -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 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); diff --git a/lib/SymbolGraphGen/SymbolGraph.h b/lib/SymbolGraphGen/SymbolGraph.h index 6e33785e9e9..7750ad798ee 100644 --- a/lib/SymbolGraphGen/SymbolGraph.h +++ b/lib/SymbolGraphGen/SymbolGraph.h @@ -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 Nodes; + llvm::SetVector Nodes; /** The relationships between symbols: the edges in the graph. */ - llvm::DenseSet Edges; + llvm::SetVector Edges; /** True if this graph is for a single symbol, rather than an entire module. diff --git a/test/Frontend/output_determinism_check.swift b/test/Frontend/output_determinism_check.swift index b5320e7a178..1502fb26437 100644 --- a/test/Frontend/output_determinism_check.swift +++ b/test/Frontend/output_determinism_check.swift @@ -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'