Skip to content

Commit b00b27a

Browse files
committed
12/18: address comments batch 2
1 parent ef0986d commit b00b27a

File tree

5 files changed

+155
-201
lines changed

5 files changed

+155
-201
lines changed

go/private/rules/binary.bzl

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,17 +154,13 @@ def _go_binary_impl(ctx):
154154
validation_output = archive.data._validation_output
155155
nogo_fix_output = archive.data._nogo_fix_output
156156

157-
nogo_validation_outputs = []
158-
if validation_output:
159-
nogo_validation_outputs.append(validation_output)
160-
161157
providers = [
162158
archive,
163159
OutputGroupInfo(
164160
cgo_exports = archive.cgo_exports,
165161
compilation_outputs = [archive.data.file],
166162
nogo_fix = [nogo_fix_output] if nogo_fix_output else [],
167-
_validation = nogo_validation_outputs,
163+
_validation = [validation_output] if validation_output else [],
168164
),
169165
]
170166

go/private/rules/library.bzl

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,6 @@ def _go_library_impl(ctx):
5151
validation_output = archive.data._validation_output
5252
nogo_fix_output = archive.data._nogo_fix_output
5353

54-
nogo_validation_outputs = []
55-
if validation_output:
56-
nogo_validation_outputs.append(validation_output)
57-
5854
return [
5955
go_info,
6056
archive,
@@ -71,7 +67,7 @@ def _go_library_impl(ctx):
7167
cgo_exports = archive.cgo_exports,
7268
compilation_outputs = [archive.data.file],
7369
nogo_fix = [nogo_fix_output] if nogo_fix_output else [],
74-
_validation = nogo_validation_outputs,
70+
_validation = [validation_output] if validation_output else [],
7571
),
7672
]
7773

go/tools/builders/nogo_change.go

Lines changed: 57 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -19,64 +19,53 @@ type diagnosticEntry struct {
1919
*analysis.Analyzer
2020
}
2121

22-
// This file contains two main entities: NogoEdit and NogoChange, which correspond to the low-level
23-
// and high-level abstractions. See them below.
24-
25-
// The following is about the `NogoEdit`, a low-level abstraction of edits.
26-
// A NogoEdit describes the replacement of a portion of a text file.
27-
type NogoEdit struct {
22+
// A nogoEdit describes the replacement of a portion of a text file.
23+
type nogoEdit struct {
2824
New string // the replacement
2925
Start int // starting byte offset of the region to replace
3026
End int // (exclusive) ending byte offset of the region to replace
3127
}
3228

33-
// NogoFileEdits represents the mapping of analyzers to their edits for a specific file.
34-
type NogoFileEdits struct {
35-
AnalyzerToEdits map[string][]NogoEdit // Analyzer as the key, edits as the value
36-
}
29+
// analyzerToEdits represents the mapping of analyzers to their edits for a specific file.
30+
type analyzerToEdits map[string][]nogoEdit // Analyzer as the key, edits as the value
3731

38-
// NogoChange represents a collection of file edits.
39-
type NogoChange struct {
40-
FileToEdits map[string]NogoFileEdits // File path as the key, analyzer-to-edits mapping as the value
41-
}
32+
// nogoChange represents a collection of file edits.
33+
// It is a map with file paths as keys and analyzerToEdits as values.
34+
type nogoChange map[string]analyzerToEdits
4235

43-
// newChange creates a new NogoChange object.
44-
func newChange() *NogoChange {
45-
return &NogoChange{
46-
FileToEdits: make(map[string]NogoFileEdits),
47-
}
36+
// newChange creates a new nogoChange object.
37+
func newChange() nogoChange {
38+
return make(nogoChange)
4839
}
4940

50-
func (e NogoEdit) String() string {
41+
func (e nogoEdit) String() string {
5142
return fmt.Sprintf("{Start:%d,End:%d,New:%q}", e.Start, e.End, e.New)
5243
}
5344

54-
// sortEdits orders a slice of NogoEdits by (start, end) offset.
45+
// sortEdits orders a slice of nogoEdits by (start, end) offset.
5546
// This ordering puts insertions (end = start) before deletions
5647
// (end > start) at the same point, but uses a stable sort to preserve
5748
// the order of multiple insertions at the same point.
58-
// (applyEditsBytes detects multiple deletions at the same point as an error.)
59-
func sortEdits(edits []NogoEdit) {
60-
sort.Stable(editsSort(edits))
49+
func sortEdits(edits []nogoEdit) {
50+
sort.Stable(byStartEnd(edits))
6151
}
6252

63-
type editsSort []NogoEdit
53+
type byStartEnd []nogoEdit
6454

65-
func (a editsSort) Len() int { return len(a) }
66-
func (a editsSort) Less(i, j int) bool {
67-
if cmp := a[i].Start - a[j].Start; cmp != 0 {
68-
return cmp < 0
55+
func (a byStartEnd) Len() int { return len(a) }
56+
func (a byStartEnd) Less(i, j int) bool {
57+
if a[i].Start != a[j].Start {
58+
return a[i].Start < a[j].Start
6959
}
7060
return a[i].End < a[j].End
7161
}
72-
func (a editsSort) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
73-
62+
func (a byStartEnd) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
7463

7564
// validateBytes checks that edits are consistent with the src byte slice,
7665
// and returns the size of the patched output. It may return a different slice if edits are sorted.
77-
func validateBytes(src []byte, edits []NogoEdit) ([]NogoEdit, int, error) {
78-
if !sort.IsSorted(editsSort(edits)) {
79-
edits = append([]NogoEdit(nil), edits...)
66+
func validateBytes(src []byte, edits []nogoEdit) ([]nogoEdit, int, error) {
67+
if !sort.IsSorted(byStartEnd(edits)) {
68+
edits = append([]nogoEdit(nil), edits...)
8069
sortEdits(edits)
8170
}
8271

@@ -96,10 +85,10 @@ func validateBytes(src []byte, edits []NogoEdit) ([]NogoEdit, int, error) {
9685
return edits, size, nil
9786
}
9887

99-
// applyEditsBytes applies a sequence of NogoEdits to the src byte slice and returns the result.
88+
// applyEditsBytes applies a sequence of nogoEdits to the src byte slice and returns the result.
10089
// Edits are applied in order of start offset; edits with the same start offset are applied in the order they were provided.
10190
// applyEditsBytes returns an error if any edit is out of bounds, or if any pair of edits is overlapping.
102-
func applyEditsBytes(src []byte, edits []NogoEdit) ([]byte, error) {
91+
func applyEditsBytes(src []byte, edits []nogoEdit) ([]byte, error) {
10392
edits, size, err := validateBytes(src, edits)
10493
if err != nil {
10594
return nil, err
@@ -124,12 +113,11 @@ func applyEditsBytes(src []byte, edits []NogoEdit) ([]byte, error) {
124113
return out, nil
125114
}
126115

127-
128-
// newChangeFromDiagnostics builds a NogoChange from a set of diagnostics.
129-
// Unlike Diagnostic, NogoChange is independent of the FileSet given it uses perf-file offsets instead of token.Pos.
130-
// This allows NogoChange to be used in contexts where the FileSet is not available, e.g., it remains applicable after it is saved to disk and loaded back.
116+
// newChangeFromDiagnostics builds a nogoChange from a set of diagnostics.
117+
// Unlike Diagnostic, nogoChange is independent of the FileSet given it uses perf-file offsets instead of token.Pos.
118+
// This allows nogoChange to be used in contexts where the FileSet is not available, e.g., it remains applicable after it is saved to disk and loaded back.
131119
// See https://github.com/golang/tools/blob/master/go/analysis/diagnostic.go for details.
132-
func newChangeFromDiagnostics(entries []diagnosticEntry, fileSet *token.FileSet) (*NogoChange, error) {
120+
func newChangeFromDiagnostics(entries []diagnosticEntry, fileSet *token.FileSet) (nogoChange, error) {
133121
c := newChange()
134122

135123
cwd, err := os.Getwd()
@@ -162,58 +150,53 @@ func newChangeFromDiagnostics(entries []diagnosticEntry, fileSet *token.FileSet)
162150
continue
163151
}
164152

165-
nogoEdit := NogoEdit{Start: file.Offset(start), End: file.Offset(end), New: string(edit.NewText)}
153+
nEdit := nogoEdit{Start: file.Offset(start), End: file.Offset(end), New: string(edit.NewText)}
166154
fileRelativePath, err := filepath.Rel(cwd, file.Name())
167155
if err != nil {
168156
fileRelativePath = file.Name() // fallback logic
169157
}
170-
c.addEdit(fileRelativePath, analyzer, nogoEdit)
158+
addEdit(c, fileRelativePath, analyzer, nEdit)
171159
}
172160
}
173161
}
174162

175163
if len(allErrors) > 0 {
176164
var errMsg bytes.Buffer
177165
sep := ""
178-
for _, err := range allErrors {
166+
for _, e := range allErrors {
179167
errMsg.WriteString(sep)
180168
sep = "\n"
181-
errMsg.WriteString(err.Error())
169+
errMsg.WriteString(e.Error())
182170
}
183171
return c, fmt.Errorf("errors:\n%s", errMsg.String())
184172
}
185173

186174
return c, nil
187175
}
188176

189-
// addEdit adds an edit to the NogoChange, organizing by file and analyzer.
190-
func (c *NogoChange) addEdit(file string, analyzer string, edit NogoEdit) {
191-
// Ensure the NogoFileEdits structure exists for the file
192-
fileEdits, exists := c.FileToEdits[file]
177+
// addEdit adds an edit to the nogoChange, organizing by file and analyzer.
178+
func addEdit(c nogoChange, file string, analyzer string, edit nogoEdit) {
179+
fileEdits, exists := c[file]
193180
if !exists {
194-
fileEdits = NogoFileEdits{
195-
AnalyzerToEdits: make(map[string][]NogoEdit),
196-
}
197-
c.FileToEdits[file] = fileEdits
181+
fileEdits = make(analyzerToEdits)
182+
c[file] = fileEdits
198183
}
199-
200-
// Append the edit to the list of edits for the analyzer
201-
fileEdits.AnalyzerToEdits[analyzer] = append(fileEdits.AnalyzerToEdits[analyzer], edit)
184+
fileEdits[analyzer] = append(fileEdits[analyzer], edit)
202185
}
203186

204187
// uniqueSortedEdits returns a list of edits that is sorted and
205188
// contains no duplicate edits. Returns whether there is overlap.
206189
// Deduplication helps in the cases where two analyzers produce duplicate edits.
207-
func uniqueSortedEdits(edits []NogoEdit) ([]NogoEdit, bool) {
190+
func uniqueSortedEdits(edits []nogoEdit) ([]nogoEdit, bool) {
208191
hasOverlap := false
209192
if len(edits) == 0 {
210193
return edits, hasOverlap
211194
}
212-
equivalent := func(x, y NogoEdit) bool {
195+
equivalent := func(x, y nogoEdit) bool {
213196
return x.Start == y.Start && x.End == y.End && x.New == y.New
214197
}
215198
sortEdits(edits)
216-
unique := []NogoEdit{edits[0]}
199+
unique := []nogoEdit{edits[0]}
217200
for i := 1; i < len(edits); i++ {
218201
prev, cur := edits[i-1], edits[i]
219202
if !equivalent(prev, cur) { // equivalent ones are safely skipped
@@ -227,23 +210,23 @@ func uniqueSortedEdits(edits []NogoEdit) ([]NogoEdit, bool) {
227210
return unique, hasOverlap
228211
}
229212

230-
// flatten merges all edits for a file from different analyzers into a single map of file-to-edits.
231-
// Edits from each analyzer are processed in a deterministic order, and overlapping edits are skipped.
232-
func flatten(change NogoChange) map[string][]NogoEdit {
233-
fileToEdits := make(map[string][]NogoEdit)
213+
type fileToEdits map[string][]nogoEdit // File path as the key, list of nogoEdit as the value
214+
215+
func flatten(change nogoChange) fileToEdits {
216+
result := make(fileToEdits)
234217

235-
for file, fileEdits := range change.FileToEdits {
218+
for file, fileEdits := range change {
236219
// Get a sorted list of analyzers for deterministic processing order
237-
analyzers := make([]string, 0, len(fileEdits.AnalyzerToEdits))
238-
for analyzer := range fileEdits.AnalyzerToEdits {
220+
analyzers := make([]string, 0, len(fileEdits))
221+
for analyzer := range fileEdits {
239222
analyzers = append(analyzers, analyzer)
240223
}
241224
sort.Strings(analyzers)
242225

243-
mergedEdits := make([]NogoEdit, 0)
226+
mergedEdits := make([]nogoEdit, 0)
244227

245228
for _, analyzer := range analyzers {
246-
edits := fileEdits.AnalyzerToEdits[analyzer]
229+
edits := fileEdits[analyzer]
247230
if len(edits) == 0 {
248231
continue
249232
}
@@ -253,10 +236,6 @@ func flatten(change NogoChange) map[string][]NogoEdit {
253236
candidateEdits, hasOverlap := uniqueSortedEdits(candidateEdits)
254237
if hasOverlap {
255238
// Skip edits from this analyzer if merging them would cause overlaps.
256-
// Apply the non-overlapping edits first. After that, a rerun of bazel build will
257-
// allows these skipped edits to be applied separately.
258-
// Note the resolution happens to each file independently.
259-
// Also for clarity, we would accept all or none of an analyzer.
260239
continue
261240
}
262241

@@ -265,28 +244,24 @@ func flatten(change NogoChange) map[string][]NogoEdit {
265244
}
266245

267246
// Store the final merged edits for the file
268-
fileToEdits[file] = mergedEdits
247+
result[file] = mergedEdits
269248
}
270249

271-
return fileToEdits
250+
return result
272251
}
273252

274-
// toCombinedPatch converts all edits to a single consolidated patch.
275-
func toCombinedPatch(fileToEdits map[string][]NogoEdit) (string, error) {
253+
func toCombinedPatch(fte fileToEdits) (string, error) {
276254
var combinedPatch strings.Builder
277255

278-
filePaths := make([]string, 0, len(fileToEdits))
279-
for filePath := range fileToEdits {
256+
filePaths := make([]string, 0, len(fte))
257+
for filePath := range fte {
280258
filePaths = append(filePaths, filePath)
281259
}
282260
sort.Strings(filePaths) // Sort file paths alphabetically
283261

284262
// Iterate over sorted file paths
285263
for _, filePath := range filePaths {
286-
// edits are unique and sorted, as ensured by the flatten() method that is invoked earlier.
287-
// for performance reason, let us skip uniqueSortedEdits() call here,
288-
// although in general a library API shall not assume other calls have been made.
289-
edits := fileToEdits[filePath]
264+
edits := fte[filePath]
290265
if len(edits) == 0 {
291266
continue
292267
}
@@ -314,7 +289,6 @@ func toCombinedPatch(fileToEdits map[string][]NogoEdit) (string, error) {
314289
return "", fmt.Errorf("failed to generate patch for file %s: %v", filePath, err)
315290
}
316291

317-
// Append the patch for this file to the giant patch
318292
combinedPatch.WriteString(patch)
319293
combinedPatch.WriteString("\n") // Ensure separation between file patches
320294
}

0 commit comments

Comments
 (0)