@@ -3,6 +3,7 @@ package analysistest
3
3
4
4
import (
5
5
"fmt"
6
+ "go/format"
6
7
"go/token"
7
8
"go/types"
8
9
"io/ioutil"
@@ -18,6 +19,8 @@ import (
18
19
"golang.org/x/tools/go/analysis"
19
20
"golang.org/x/tools/go/analysis/internal/checker"
20
21
"golang.org/x/tools/go/packages"
22
+ "golang.org/x/tools/internal/lsp/diff"
23
+ "golang.org/x/tools/internal/span"
21
24
"golang.org/x/tools/internal/testenv"
22
25
)
23
26
@@ -61,6 +64,75 @@ type Testing interface {
61
64
Errorf (format string , args ... interface {})
62
65
}
63
66
67
+ func RunWithSuggestedFixes (t Testing , dir string , a * analysis.Analyzer , patterns ... string ) []* Result {
68
+ r := Run (t , dir , a , patterns ... )
69
+
70
+ fileEdits := make (map [* token.File ][]diff.TextEdit )
71
+ fileContents := make (map [* token.File ][]byte )
72
+
73
+ // Validate edits, prepare the fileEdits map and read the file contents.
74
+ for _ , act := range r {
75
+ for _ , diag := range act .Diagnostics {
76
+ for _ , sf := range diag .SuggestedFixes {
77
+ for _ , edit := range sf .TextEdits {
78
+ // Validate the edit.
79
+ if edit .Pos > edit .End {
80
+ t .Errorf (
81
+ "diagnostic for analysis %v contains Suggested Fix with malformed edit: pos (%v) > end (%v)" ,
82
+ act .Pass .Analyzer .Name , edit .Pos , edit .End )
83
+ continue
84
+ }
85
+ file , endfile := act .Pass .Fset .File (edit .Pos ), act .Pass .Fset .File (edit .End )
86
+ if file == nil || endfile == nil || file != endfile {
87
+ t .Errorf (
88
+ "diagnostic for analysis %v contains Suggested Fix with malformed spanning files %v and %v" ,
89
+ act .Pass .Analyzer .Name , file .Name (), endfile .Name ())
90
+ continue
91
+ }
92
+ if _ , ok := fileContents [file ]; ! ok {
93
+ contents , err := ioutil .ReadFile (file .Name ())
94
+ if err != nil {
95
+ t .Errorf ("error reading %s: %v" , file .Name (), err )
96
+ }
97
+ fileContents [file ] = contents
98
+ }
99
+ spn , err := span .NewRange (act .Pass .Fset , edit .Pos , edit .End ).Span ()
100
+ if err != nil {
101
+ t .Errorf ("error converting edit to span %s: %v" , file .Name (), err )
102
+ }
103
+ fileEdits [file ] = append (fileEdits [file ], diff.TextEdit {
104
+ Span : spn ,
105
+ NewText : string (edit .NewText ),
106
+ })
107
+ }
108
+ }
109
+ }
110
+ }
111
+
112
+ for file , edits := range fileEdits {
113
+ // Get the original file contents.
114
+ orig , ok := fileContents [file ]
115
+ if ! ok {
116
+ t .Errorf ("could not find file contents for %s" , file .Name ())
117
+ continue
118
+ }
119
+ out := diff .ApplyEdits (string (orig ), edits )
120
+ // Get the golden file and read the contents.
121
+ want , err := ioutil .ReadFile (file .Name () + ".golden" )
122
+ if err != nil {
123
+ t .Errorf ("error reading %s.golden: %v" , file .Name (), err )
124
+ }
125
+ formatted , err := format .Source ([]byte (out ))
126
+ if err != nil {
127
+ continue
128
+ }
129
+ if string (want ) != string (formatted ) {
130
+ t .Errorf ("suggested fixes failed for %s, expected:\n %#v\n got:\n %#v" , file .Name (), string (want ), string (formatted ))
131
+ }
132
+ }
133
+ return r
134
+ }
135
+
64
136
// Run applies an analysis to the packages denoted by the "go list" patterns.
65
137
//
66
138
// It loads the packages from the specified GOPATH-style project
0 commit comments