Skip to content

Commit f45e2fb

Browse files
[SymbolGraph] Make symbol-graph output deterministic
SymbolGraph generation iterating over llvm::DenseSet, which makes the symbols and relationship fields appear in non-deterministic ordering. Always sort the entries before serialization to make output deterministic. rdar://148839911
1 parent 56746e3 commit f45e2fb

File tree

2 files changed

+15
-12
lines changed

2 files changed

+15
-12
lines changed

lib/SymbolGraphGen/SymbolGraph.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -645,29 +645,31 @@ void SymbolGraph::serialize(llvm::json::OStream &OS) {
645645
symbolgraphgen::serialize(*ModuleVersion, OS);
646646
}
647647

648+
// Sort symbols for deterministic output.
649+
SmallVector<Symbol> Symbols(Nodes.begin(), Nodes.end());
650+
llvm::sort(Symbols, [](const Symbol &LHS, const Symbol &RHS) {
651+
SmallString<256> LHSUSR, RHSUSR;
652+
LHS.getUSR(LHSUSR);
653+
RHS.getUSR(RHSUSR);
654+
return LHSUSR < RHSUSR;
655+
});
648656
OS.attributeArray("symbols", [&](){
649-
for (const auto &S: Nodes) {
657+
for (const auto &S: Symbols) {
650658
S.serialize(OS);
651659
}
652660
});
653661

654-
#ifndef NDEBUG
655-
// FIXME (solver-based-verification-sorting): In assert builds sort the
656-
// edges so we get consistent symbol graph output. This allows us to compare
657-
// the string representation of the symbolgraph between the solver-based
658-
// and AST-based result.
659-
// This can be removed once the AST-based cursor info has been removed.
660-
SmallVector<Edge> Edges(this->Edges.begin(), this->Edges.end());
661-
std::sort(Edges.begin(), Edges.end(), [](const Edge &LHS, const Edge &RHS) {
662+
// Sort the edges so we get consistent symbol graph output.
663+
SmallVector<Edge> OrderedEdges(Edges.begin(), Edges.end());
664+
llvm::sort(OrderedEdges, [](const Edge &LHS, const Edge &RHS) {
662665
SmallString<256> LHSTargetUSR, RHSTargetUSR;
663666
LHS.Target.getUSR(LHSTargetUSR);
664667
RHS.Target.getUSR(RHSTargetUSR);
665668
return LHSTargetUSR < RHSTargetUSR;
666669
});
667-
#endif
668670

669671
OS.attributeArray("relationships", [&](){
670-
for (const auto &Relationship : Edges) {
672+
for (const auto &Relationship : OrderedEdges) {
671673
Relationship.serialize(OS);
672674
}
673675
});

test/Frontend/output_determinism_check.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %empty-directory(%t)
22
// RUN: echo '[]' > %t/protocol.json
3-
// 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
3+
// 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
44
// 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
55

66
/// object files are "not" deterministic because the second run going to match the mod hash and skip code generation.
@@ -22,6 +22,7 @@
2222

2323
// 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
2424

25+
// SYMBOLGRAPH_OUTPUT: remark: produced matching output file '{{.*}}{{/|\\}}test.symbols.json'
2526
// DOCC_OUTPUT: remark: produced matching output file '{{.*}}{{/|\\}}test.docc'
2627
// CONSTVALUE_OUTPUT: remark: produced matching output file '{{.*}}{{/|\\}}test.swiftconstvalues'
2728
// MODULE_OUTPUT: remark: produced matching output file '{{.*}}{{/|\\}}test.swiftmodule'

0 commit comments

Comments
 (0)