@@ -12,6 +12,7 @@ import (
12
12
"go/token"
13
13
"go/types"
14
14
"log"
15
+ "path/filepath"
15
16
"sort"
16
17
"strings"
17
18
"time"
@@ -93,7 +94,7 @@ func (s *Server) computeSemanticTokens(ctx context.Context, td protocol.TextDocu
93
94
if err != nil {
94
95
return nil , err
95
96
}
96
- // don't return errors on pgf.ParseErr. Do what we can.
97
+ // ignore pgf.ParseErr. Do what we can.
97
98
if rng == nil && len (pgf .Src ) > maxFullFileSize {
98
99
err := fmt .Errorf ("semantic tokens: file %s too large for full (%d>%d)" ,
99
100
fh .URI ().Filename (), len (pgf .Src ), maxFullFileSize )
@@ -122,6 +123,7 @@ func (s *Server) computeSemanticTokens(ctx context.Context, td protocol.TextDocu
122
123
123
124
func (e * encoded ) semantics () {
124
125
f := e .pgf .File
126
+ // may not be in range, but harmless
125
127
e .token (f .Package , len ("package" ), tokKeyword , nil )
126
128
e .token (f .Name .NamePos , len (f .Name .Name ), tokNamespace , nil )
127
129
inspect := func (n ast.Node ) bool {
@@ -166,8 +168,11 @@ const (
166
168
)
167
169
168
170
func (e * encoded ) token (start token.Pos , leng int , typ tokenType , mods []string ) {
169
- if start == 0 {
170
- e .unexpected ("token at token.NoPos" )
171
+
172
+ if start == token .NoPos {
173
+ // This is not worth reporting
174
+ //e.unexpected("token at token.NoPos")
175
+ return
171
176
}
172
177
if start >= e .end || start + token .Pos (leng ) <= e .start {
173
178
return
@@ -186,10 +191,7 @@ func (e *encoded) token(start token.Pos, leng int, typ tokenType, mods []string)
186
191
return
187
192
}
188
193
if lspRange .End .Line != lspRange .Start .Line {
189
- // abrupt end of file, without \n. TODO(pjw): fix?
190
- pos := e .fset .PositionFor (start , false )
191
- msg := fmt .Sprintf ("token at %s:%d.%d overflows" , pos .Filename , pos .Line , pos .Column )
192
- event .Log (e .ctx , msg )
194
+ // this happens if users are typing at the end of the file, but report nothing
193
195
return
194
196
}
195
197
// token is all on one line
@@ -236,12 +238,22 @@ func (e *encoded) strStack() string {
236
238
if len (e .stack ) > 0 {
237
239
loc := e .stack [len (e .stack )- 1 ].Pos ()
238
240
add := e .pgf .Tok .PositionFor (loc , false )
239
- msg = append (msg , fmt .Sprintf ("(line:%d,col:%d)" , add .Line , add .Column ))
241
+ nm := filepath .Base (add .Filename )
242
+ msg = append (msg , fmt .Sprintf ("(%s:%d,col:%d)" , nm , add .Line , add .Column ))
240
243
}
241
244
msg = append (msg , "]" )
242
245
return strings .Join (msg , " " )
243
246
}
244
247
248
+ func (e * encoded ) srcLine (x ast.Node ) string {
249
+ file := e .pgf .Tok
250
+ line := file .Line (x .Pos ())
251
+ start := file .Offset (file .LineStart (line ))
252
+ end := file .Offset (file .LineStart (line + 1 )) // and hope it's not the last line of the file
253
+ ans := e .pgf .Src [start : end - 1 ]
254
+ return string (ans )
255
+ }
256
+
245
257
func (e * encoded ) inspector (n ast.Node ) bool {
246
258
pop := func () {
247
259
e .stack = e .stack [:len (e .stack )- 1 ]
@@ -409,6 +421,26 @@ func (e *encoded) ident(x *ast.Ident) {
409
421
use := e .ti .Uses [x ]
410
422
switch y := use .(type ) {
411
423
case nil :
424
+ // In this position we think the identifier is either a function or a variable
425
+ // and it is possible that it is being defined. The decision has to be made based
426
+ // on where we are in the parse tree (and all that's known is the parse stack).
427
+ // The present logic is inadequate, and will be fixed in the next CL:
428
+ // ExprStmt CallExpr Ident: var [x in a(x)]
429
+ // ExprStmt CallExpr Ident: function [f()]
430
+ // CallExpr TypeAssertExpr Ident: type [so not variable nor function]
431
+ log .SetFlags (log .Lshortfile )
432
+ log .Printf ("%s %s%q" , x .Name , e .strStack (), e .srcLine (x ))
433
+ if len (e .stack ) >= 3 {
434
+ n := len (e .stack ) - 1
435
+ if _ , ok := e .stack [n - 1 ].(* ast.SelectorExpr ); ok {
436
+ if _ , ok = e .stack [n - 2 ].(* ast.CallExpr ); ok {
437
+ log .Print ("function" )
438
+ e .token (x .NamePos , len (x .Name ), tokFunction , nil )
439
+ break
440
+ }
441
+ }
442
+ }
443
+ log .Print ("var def" )
412
444
e .token (x .NamePos , len (x .Name ), tokVariable , []string {"definition" })
413
445
case * types.Builtin :
414
446
e .token (x .NamePos , len (x .Name ), tokFunction , []string {"defaultLibrary" })
@@ -642,16 +674,21 @@ func (e *encoded) importSpec(d *ast.ImportSpec) {
642
674
}
643
675
// and fall through for _
644
676
}
645
- if d .Path .Value == "" {
677
+ val := d .Path .Value
678
+ if len (val ) < 2 || val [0 ] != '"' || val [len (val )- 1 ] != '"' {
679
+ // avoid panics on imports without a properly quoted string
646
680
return
647
681
}
648
- nm := d . Path . Value [1 : len (d . Path . Value )- 1 ] // trailing "
682
+ nm := val [1 : len (val )- 1 ] // remove surrounding "s
649
683
v := strings .LastIndex (nm , "/" )
650
684
if v != - 1 {
685
+ // in import "lib/math", 'math' is the package name
651
686
nm = nm [v + 1 :]
652
687
}
653
688
start := d .Path .End () - token .Pos (1 + len (nm ))
654
689
e .token (start , len (nm ), tokNamespace , nil )
690
+ // There may be more cases, as import strings are implementation defined.
691
+ // (E.g., module a.b.c (without a /), the 'a' should be tokNamespace, if we cared.)
655
692
}
656
693
657
694
// log unexpected state
0 commit comments