@@ -41,9 +41,10 @@ type parseGoHandle struct {
41
41
type parseGoData struct {
42
42
memoize.NoCopy
43
43
44
- ast * ast.File
45
- mapper * protocol.ColumnMapper
46
- err error
44
+ ast * ast.File
45
+ parseError error // errors associated with parsing the file
46
+ mapper * protocol.ColumnMapper
47
+ err error
47
48
}
48
49
49
50
func (c * cache ) ParseGoHandle (fh source.FileHandle , mode source.ParseMode ) source.ParseGoHandle {
@@ -53,18 +54,7 @@ func (c *cache) ParseGoHandle(fh source.FileHandle, mode source.ParseMode) sourc
53
54
}
54
55
h := c .store .Bind (key , func (ctx context.Context ) interface {} {
55
56
data := & parseGoData {}
56
- data .ast , data .err = parseGo (ctx , c , fh , mode )
57
- tok := c .FileSet ().File (data .ast .Pos ())
58
- if tok == nil {
59
- return data
60
- }
61
- uri := fh .Identity ().URI
62
- content , _ , err := fh .Read (ctx )
63
- if err != nil {
64
- data .err = err
65
- return data
66
- }
67
- data .mapper = newColumnMapper (uri , c .FileSet (), tok , content )
57
+ data .ast , data .mapper , data .parseError , data .err = parseGo (ctx , c , fh , mode )
68
58
return data
69
59
})
70
60
return & parseGoHandle {
@@ -73,13 +63,6 @@ func (c *cache) ParseGoHandle(fh source.FileHandle, mode source.ParseMode) sourc
73
63
mode : mode ,
74
64
}
75
65
}
76
- func newColumnMapper (uri span.URI , fset * token.FileSet , tok * token.File , content []byte ) * protocol.ColumnMapper {
77
- return & protocol.ColumnMapper {
78
- URI : uri ,
79
- Converter : span .NewTokenConverter (fset , tok ),
80
- Content : content ,
81
- }
82
- }
83
66
84
67
func (h * parseGoHandle ) File () source.FileHandle {
85
68
return h .file
@@ -89,22 +72,22 @@ func (h *parseGoHandle) Mode() source.ParseMode {
89
72
return h .mode
90
73
}
91
74
92
- func (h * parseGoHandle ) Parse (ctx context.Context ) (* ast.File , * protocol.ColumnMapper , error ) {
75
+ func (h * parseGoHandle ) Parse (ctx context.Context ) (* ast.File , * protocol.ColumnMapper , error , error ) {
93
76
v := h .handle .Get (ctx )
94
77
if v == nil {
95
- return nil , nil , ctx .Err ()
78
+ return nil , nil , nil , ctx .Err ()
96
79
}
97
80
data := v .(* parseGoData )
98
- return data .ast , data .mapper , data .err
81
+ return data .ast , data .mapper , data .parseError , data . err
99
82
}
100
83
101
- func (h * parseGoHandle ) Cached (ctx context.Context ) (* ast.File , * protocol.ColumnMapper , error ) {
84
+ func (h * parseGoHandle ) Cached (ctx context.Context ) (* ast.File , * protocol.ColumnMapper , error , error ) {
102
85
v := h .handle .Cached ()
103
86
if v == nil {
104
- return nil , nil , errors .Errorf ("no cached value for %s" , h .file .Identity ().URI )
87
+ return nil , nil , nil , errors .Errorf ("no cached AST for %s" , h .file .Identity ().URI )
105
88
}
106
89
data := v .(* parseGoData )
107
- return data .ast , data .mapper , data .err
90
+ return data .ast , data .mapper , data .parseError , data . err
108
91
}
109
92
110
93
func hashParseKey (ph source.ParseGoHandle ) string {
@@ -122,35 +105,51 @@ func hashParseKeys(phs []source.ParseGoHandle) string {
122
105
return hashContents (b .Bytes ())
123
106
}
124
107
125
- func parseGo (ctx context.Context , c * cache , fh source.FileHandle , mode source.ParseMode ) (* ast.File , error ) {
108
+ func parseGo (ctx context.Context , c * cache , fh source.FileHandle , mode source.ParseMode ) (file * ast.File , mapper * protocol. ColumnMapper , parseError error , err error ) {
126
109
ctx , done := trace .StartSpan (ctx , "cache.parseGo" , telemetry .File .Of (fh .Identity ().URI .Filename ()))
127
110
defer done ()
128
111
129
112
buf , _ , err := fh .Read (ctx )
130
113
if err != nil {
131
- return nil , err
114
+ return nil , nil , nil , err
132
115
}
133
116
parseLimit <- struct {}{}
134
117
defer func () { <- parseLimit }()
135
118
parserMode := parser .AllErrors | parser .ParseComments
136
119
if mode == source .ParseHeader {
137
120
parserMode = parser .ImportsOnly | parser .ParseComments
138
121
}
139
- ast , err : = parser .ParseFile (c .fset , fh .Identity ().URI .Filename (), buf , parserMode )
140
- if ast != nil {
122
+ file , parseError = parser .ParseFile (c .fset , fh .Identity ().URI .Filename (), buf , parserMode )
123
+ if file != nil {
141
124
if mode == source .ParseExported {
142
- trimAST (ast )
125
+ trimAST (file )
143
126
}
144
127
// Fix any badly parsed parts of the AST.
145
- tok := c .fset .File (ast .Pos ())
146
- if err := fix (ctx , ast , tok , buf ); err != nil {
128
+ tok := c .fset .File (file .Pos ())
129
+ if err := fix (ctx , file , tok , buf ); err != nil {
147
130
log .Error (ctx , "failed to fix AST" , err )
148
131
}
149
132
}
150
- if ast == nil {
151
- return nil , err
133
+ // If the file is nil only due to parse errors,
134
+ // the parse errors are the actual errors.
135
+ if file == nil {
136
+ return nil , nil , parseError , parseError
137
+ }
138
+ tok := c .FileSet ().File (file .Pos ())
139
+ if tok == nil {
140
+ return nil , nil , parseError , err
141
+ }
142
+ uri := fh .Identity ().URI
143
+ content , _ , err := fh .Read (ctx )
144
+ if err != nil {
145
+ return nil , nil , parseError , err
146
+ }
147
+ m := & protocol.ColumnMapper {
148
+ URI : uri ,
149
+ Converter : span .NewTokenConverter (c .FileSet (), tok ),
150
+ Content : content ,
152
151
}
153
- return ast , err
152
+ return file , m , parseError , nil
154
153
}
155
154
156
155
// trimAST clears any part of the AST not relevant to type checking
0 commit comments