github.com/v2fly/tools@v0.100.0/internal/lsp/semantic.go (about)

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package lsp
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"fmt"
    11  	"go/ast"
    12  	"go/token"
    13  	"go/types"
    14  	"log"
    15  	"sort"
    16  	"strings"
    17  	"time"
    18  
    19  	"github.com/v2fly/tools/internal/event"
    20  	"github.com/v2fly/tools/internal/lsp/protocol"
    21  	"github.com/v2fly/tools/internal/lsp/source"
    22  	errors "golang.org/x/xerrors"
    23  )
    24  
    25  // reject full semantic token requests for large files
    26  const maxFullFileSize int = 100000
    27  
    28  func (s *Server) semanticTokensFull(ctx context.Context, p *protocol.SemanticTokensParams) (*protocol.SemanticTokens, error) {
    29  	ret, err := s.computeSemanticTokens(ctx, p.TextDocument, nil)
    30  	return ret, err
    31  }
    32  
    33  func (s *Server) semanticTokensFullDelta(ctx context.Context, p *protocol.SemanticTokensDeltaParams) (interface{}, error) {
    34  	return nil, errors.Errorf("implement SemanticTokensFullDelta")
    35  }
    36  
    37  func (s *Server) semanticTokensRange(ctx context.Context, p *protocol.SemanticTokensRangeParams) (*protocol.SemanticTokens, error) {
    38  	ret, err := s.computeSemanticTokens(ctx, p.TextDocument, &p.Range)
    39  	return ret, err
    40  }
    41  
    42  func (s *Server) semanticTokensRefresh(ctx context.Context) error {
    43  	// in the code, but not in the protocol spec
    44  	return errors.Errorf("implement SemanticTokensRefresh")
    45  }
    46  
    47  func (s *Server) computeSemanticTokens(ctx context.Context, td protocol.TextDocumentIdentifier, rng *protocol.Range) (*protocol.SemanticTokens, error) {
    48  	ans := protocol.SemanticTokens{
    49  		Data: []uint32{},
    50  	}
    51  	snapshot, _, ok, release, err := s.beginFileRequest(ctx, td.URI, source.Go)
    52  	defer release()
    53  	if !ok {
    54  		return nil, err
    55  	}
    56  	vv := snapshot.View()
    57  	if !vv.Options().SemanticTokens {
    58  		// return an error, so if the option changes
    59  		// the client won't remember the wrong answer
    60  		return nil, errors.Errorf("semantictokens are disabled")
    61  	}
    62  	pkg, err := snapshot.PackageForFile(ctx, td.URI.SpanURI(), source.TypecheckFull, source.WidestPackage)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  	info := pkg.GetTypesInfo()
    67  	pgf, err := pkg.File(td.URI.SpanURI())
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	if pgf.ParseErr != nil {
    72  		return nil, pgf.ParseErr
    73  	}
    74  	if rng == nil && len(pgf.Src) > maxFullFileSize {
    75  		err := fmt.Errorf("semantic tokens: file %s too large for full (%d>%d)",
    76  			td.URI.SpanURI().Filename(), len(pgf.Src), maxFullFileSize)
    77  		return nil, err
    78  	}
    79  	e := &encoded{
    80  		ctx:      ctx,
    81  		pgf:      pgf,
    82  		rng:      rng,
    83  		ti:       info,
    84  		fset:     snapshot.FileSet(),
    85  		tokTypes: s.session.Options().SemanticTypes,
    86  		tokMods:  s.session.Options().SemanticMods,
    87  	}
    88  	if err := e.init(); err != nil {
    89  		return nil, err
    90  	}
    91  	e.semantics()
    92  	ans.Data, err = e.Data()
    93  	if err != nil {
    94  		// this is an internal error, likely caused by a typo
    95  		// for a token or modifier
    96  		return nil, err
    97  	}
    98  	// for small cache, some day. for now, the client ignores this
    99  	ans.ResultID = fmt.Sprintf("%v", time.Now())
   100  	return &ans, nil
   101  }
   102  
   103  func (e *encoded) semantics() {
   104  	f := e.pgf.File
   105  	e.token(f.Package, len("package"), tokKeyword, nil)
   106  	e.token(f.Name.NamePos, len(f.Name.Name), tokNamespace, nil)
   107  	inspect := func(n ast.Node) bool {
   108  		return e.inspector(n)
   109  	}
   110  	for _, d := range f.Decls {
   111  		// only look at the decls that overlap the range
   112  		start, end := d.Pos(), d.End()
   113  		if end <= e.start || start >= e.end {
   114  			continue
   115  		}
   116  		ast.Inspect(d, inspect)
   117  	}
   118  }
   119  
   120  type tokenType string
   121  
   122  const (
   123  	tokNamespace tokenType = "namespace"
   124  	tokType      tokenType = "type"
   125  	tokInterface tokenType = "interface"
   126  	tokParameter tokenType = "parameter"
   127  	tokVariable  tokenType = "variable"
   128  	tokMember    tokenType = "member"
   129  	tokFunction  tokenType = "function"
   130  	tokKeyword   tokenType = "keyword"
   131  	tokComment   tokenType = "comment"
   132  	tokString    tokenType = "string"
   133  	tokNumber    tokenType = "number"
   134  	tokOperator  tokenType = "operator"
   135  )
   136  
   137  func (e *encoded) token(start token.Pos, leng int, typ tokenType, mods []string) {
   138  	if start == 0 {
   139  		e.unexpected("token at token.NoPos")
   140  	}
   141  	if start >= e.end || start+token.Pos(leng) <= e.start {
   142  		return
   143  	}
   144  	// want a line and column from start (in LSP coordinates)
   145  	// [//line directives should be ignored]
   146  	rng := source.NewMappedRange(e.fset, e.pgf.Mapper, start, start+token.Pos(leng))
   147  	lspRange, err := rng.Range()
   148  	if err != nil {
   149  		// possibly a //line directive. TODO(pjw): fix this somehow
   150  		// "column mapper is for file...instead of..."
   151  		// "line is beyond end of file..."
   152  		// see line 116 of internal/span/token.go which uses Position not PositionFor
   153  		event.Error(e.ctx, "failed to convert to range", err)
   154  		return
   155  	}
   156  	if lspRange.End.Line != lspRange.Start.Line {
   157  		// abrupt end of file, without \n. TODO(pjw): fix?
   158  		pos := e.fset.PositionFor(start, false)
   159  		msg := fmt.Sprintf("token at %s:%d.%d overflows", pos.Filename, pos.Line, pos.Column)
   160  		event.Log(e.ctx, msg)
   161  		return
   162  	}
   163  	// token is all on one line
   164  	length := lspRange.End.Character - lspRange.Start.Character
   165  	e.add(lspRange.Start.Line, lspRange.Start.Character, length, typ, mods)
   166  }
   167  
   168  func (e *encoded) add(line, start uint32, len uint32, tok tokenType, mod []string) {
   169  	x := semItem{line, start, len, tok, mod}
   170  	e.items = append(e.items, x)
   171  }
   172  
   173  // semItem represents a token found walking the parse tree
   174  type semItem struct {
   175  	line, start uint32
   176  	len         uint32
   177  	typeStr     tokenType
   178  	mods        []string
   179  }
   180  
   181  type encoded struct {
   182  	// the generated data
   183  	items []semItem
   184  
   185  	ctx               context.Context
   186  	tokTypes, tokMods []string
   187  	pgf               *source.ParsedGoFile
   188  	rng               *protocol.Range
   189  	ti                *types.Info
   190  	fset              *token.FileSet
   191  	// allowed starting and ending token.Pos, set by init
   192  	// used to avoid looking at declarations not in range
   193  	start, end token.Pos
   194  	// path from the root of the parse tree, used for debugging
   195  	stack []ast.Node
   196  }
   197  
   198  // convert the stack to a string, for debugging
   199  func (e *encoded) strStack() string {
   200  	msg := []string{"["}
   201  	for _, s := range e.stack {
   202  		msg = append(msg, fmt.Sprintf("%T", s)[5:])
   203  	}
   204  	if len(e.stack) > 0 {
   205  		loc := e.stack[len(e.stack)-1].Pos()
   206  		add := e.pgf.Tok.PositionFor(loc, false)
   207  		msg = append(msg, fmt.Sprintf("(line:%d,col:%d)", add.Line, add.Column))
   208  	}
   209  	msg = append(msg, "]")
   210  	return strings.Join(msg, " ")
   211  }
   212  
   213  func (e *encoded) inspector(n ast.Node) bool {
   214  	pop := func() {
   215  		e.stack = e.stack[:len(e.stack)-1]
   216  	}
   217  	if n == nil {
   218  		pop()
   219  		return true
   220  	}
   221  	e.stack = append(e.stack, n)
   222  	switch x := n.(type) {
   223  	case *ast.ArrayType:
   224  	case *ast.AssignStmt:
   225  		e.token(x.TokPos, len(x.Tok.String()), tokOperator, nil)
   226  	case *ast.BasicLit:
   227  		// if it extends across a line, skip it
   228  		// better would be to mark each line as string TODO(pjw)
   229  		if strings.Contains(x.Value, "\n") {
   230  			break
   231  		}
   232  		ln := len(x.Value)
   233  		what := tokNumber
   234  		if x.Kind == token.STRING {
   235  			what = tokString
   236  			if _, ok := e.stack[len(e.stack)-2].(*ast.Field); ok {
   237  				// struct tags (this is probably pointless, as the
   238  				// TextMate grammar will treat all the other comments the same)
   239  				what = tokComment
   240  			}
   241  		}
   242  		e.token(x.Pos(), ln, what, nil)
   243  	case *ast.BinaryExpr:
   244  		e.token(x.OpPos, len(x.Op.String()), tokOperator, nil)
   245  	case *ast.BlockStmt:
   246  	case *ast.BranchStmt:
   247  		e.token(x.TokPos, len(x.Tok.String()), tokKeyword, nil)
   248  		// There's no semantic encoding for labels
   249  	case *ast.CallExpr:
   250  		if x.Ellipsis != token.NoPos {
   251  			e.token(x.Ellipsis, len("..."), tokOperator, nil)
   252  		}
   253  	case *ast.CaseClause:
   254  		iam := "case"
   255  		if x.List == nil {
   256  			iam = "default"
   257  		}
   258  		e.token(x.Case, len(iam), tokKeyword, nil)
   259  	case *ast.ChanType:
   260  		// chan | chan <- | <- chan
   261  		if x.Arrow == token.NoPos || x.Arrow != x.Begin {
   262  			e.token(x.Begin, len("chan"), tokKeyword, nil)
   263  			break
   264  		}
   265  		pos := e.findKeyword("chan", x.Begin+2, x.Value.Pos())
   266  		e.token(pos, len("chan"), tokKeyword, nil)
   267  	case *ast.CommClause:
   268  		iam := len("case")
   269  		if x.Comm == nil {
   270  			iam = len("default")
   271  		}
   272  		e.token(x.Case, iam, tokKeyword, nil)
   273  	case *ast.CompositeLit:
   274  	case *ast.DeclStmt:
   275  	case *ast.DeferStmt:
   276  		e.token(x.Defer, len("defer"), tokKeyword, nil)
   277  	case *ast.Ellipsis:
   278  		e.token(x.Ellipsis, len("..."), tokOperator, nil)
   279  	case *ast.EmptyStmt:
   280  	case *ast.ExprStmt:
   281  	case *ast.Field:
   282  	case *ast.FieldList:
   283  	case *ast.ForStmt:
   284  		e.token(x.For, len("for"), tokKeyword, nil)
   285  	case *ast.FuncDecl:
   286  	case *ast.FuncLit:
   287  	case *ast.FuncType:
   288  		if x.Func != token.NoPos {
   289  			e.token(x.Func, len("func"), tokKeyword, nil)
   290  		}
   291  	case *ast.GenDecl:
   292  		e.token(x.TokPos, len(x.Tok.String()), tokKeyword, nil)
   293  	case *ast.GoStmt:
   294  		e.token(x.Go, len("go"), tokKeyword, nil)
   295  	case *ast.Ident:
   296  		e.ident(x)
   297  	case *ast.IfStmt:
   298  		e.token(x.If, len("if"), tokKeyword, nil)
   299  		if x.Else != nil {
   300  			// x.Body.End() or x.Body.End()+1, not that it matters
   301  			pos := e.findKeyword("else", x.Body.End(), x.Else.Pos())
   302  			e.token(pos, len("else"), tokKeyword, nil)
   303  		}
   304  	case *ast.ImportSpec:
   305  		e.importSpec(x)
   306  		pop()
   307  		return false
   308  	case *ast.IncDecStmt:
   309  		e.token(x.TokPos, len(x.Tok.String()), tokOperator, nil)
   310  	case *ast.IndexExpr:
   311  	case *ast.InterfaceType:
   312  		e.token(x.Interface, len("interface"), tokKeyword, nil)
   313  	case *ast.KeyValueExpr:
   314  	case *ast.LabeledStmt:
   315  	case *ast.MapType:
   316  		e.token(x.Map, len("map"), tokKeyword, nil)
   317  	case *ast.ParenExpr:
   318  	case *ast.RangeStmt:
   319  		e.token(x.For, len("for"), tokKeyword, nil)
   320  		// x.TokPos == token.NoPos is legal (for range foo {})
   321  		offset := x.TokPos
   322  		if offset == token.NoPos {
   323  			offset = x.For
   324  		}
   325  		pos := e.findKeyword("range", offset, x.X.Pos())
   326  		e.token(pos, len("range"), tokKeyword, nil)
   327  	case *ast.ReturnStmt:
   328  		e.token(x.Return, len("return"), tokKeyword, nil)
   329  	case *ast.SelectStmt:
   330  		e.token(x.Select, len("select"), tokKeyword, nil)
   331  	case *ast.SelectorExpr:
   332  	case *ast.SendStmt:
   333  		e.token(x.Arrow, len("<-"), tokOperator, nil)
   334  	case *ast.SliceExpr:
   335  	case *ast.StarExpr:
   336  		e.token(x.Star, len("*"), tokOperator, nil)
   337  	case *ast.StructType:
   338  		e.token(x.Struct, len("struct"), tokKeyword, nil)
   339  	case *ast.SwitchStmt:
   340  		e.token(x.Switch, len("switch"), tokKeyword, nil)
   341  	case *ast.TypeAssertExpr:
   342  		if x.Type == nil {
   343  			pos := e.findKeyword("type", x.Lparen, x.Rparen)
   344  			e.token(pos, len("type"), tokKeyword, nil)
   345  		}
   346  	case *ast.TypeSpec:
   347  	case *ast.TypeSwitchStmt:
   348  		e.token(x.Switch, len("switch"), tokKeyword, nil)
   349  	case *ast.UnaryExpr:
   350  		e.token(x.OpPos, len(x.Op.String()), tokOperator, nil)
   351  	case *ast.ValueSpec:
   352  	// things we won't see
   353  	case *ast.BadDecl, *ast.BadExpr, *ast.BadStmt,
   354  		*ast.File, *ast.Package:
   355  		log.Printf("implement %T %s", x, e.pgf.Tok.PositionFor(x.Pos(), false))
   356  	// things we knowingly ignore
   357  	case *ast.Comment, *ast.CommentGroup:
   358  		pop()
   359  		return false
   360  	default: // just to be super safe.
   361  		e.unexpected(fmt.Sprintf("failed to implement %T", x))
   362  	}
   363  	return true
   364  }
   365  func (e *encoded) ident(x *ast.Ident) {
   366  	def := e.ti.Defs[x]
   367  	if def != nil {
   368  		what, mods := e.definitionFor(x)
   369  		if what != "" {
   370  			e.token(x.Pos(), len(x.String()), what, mods)
   371  		}
   372  		return
   373  	}
   374  	use := e.ti.Uses[x]
   375  	switch y := use.(type) {
   376  	case nil:
   377  		e.token(x.NamePos, len(x.Name), tokVariable, []string{"definition"})
   378  	case *types.Builtin:
   379  		e.token(x.NamePos, len(x.Name), tokFunction, []string{"defaultLibrary"})
   380  	case *types.Const:
   381  		mods := []string{"readonly"}
   382  		tt := y.Type()
   383  		if _, ok := tt.(*types.Basic); ok {
   384  			e.token(x.Pos(), len(x.String()), tokVariable, mods)
   385  			break
   386  		}
   387  		if ttx, ok := tt.(*types.Named); ok {
   388  			if x.String() == "iota" {
   389  				e.unexpected(fmt.Sprintf("iota:%T", ttx))
   390  			}
   391  			if _, ok := ttx.Underlying().(*types.Basic); ok {
   392  				e.token(x.Pos(), len(x.String()), tokVariable, mods)
   393  				break
   394  			}
   395  			e.unexpected(fmt.Sprintf("%q/%T", x.String(), tt))
   396  		}
   397  		// can this happen? Don't think so
   398  		e.unexpected(fmt.Sprintf("%s %T %#v", x.String(), tt, tt))
   399  	case *types.Func:
   400  		e.token(x.Pos(), len(x.Name), tokFunction, nil)
   401  	case *types.Label:
   402  		// nothing to map it to
   403  	case *types.Nil:
   404  		// nil is a predeclared identifier
   405  		e.token(x.Pos(), len("nil"), tokVariable, []string{"readonly", "defaultLibrary"})
   406  	case *types.PkgName:
   407  		e.token(x.Pos(), len(x.Name), tokNamespace, nil)
   408  	case *types.TypeName:
   409  		var mods []string
   410  		if _, ok := y.Type().(*types.Basic); ok {
   411  			mods = []string{"defaultLibrary"}
   412  		}
   413  		e.token(x.Pos(), len(x.String()), tokType, mods)
   414  	case *types.Var:
   415  		e.token(x.Pos(), len(x.Name), tokVariable, nil)
   416  	default:
   417  		// replace with panic after extensive testing
   418  		if use == nil {
   419  			msg := fmt.Sprintf("%#v/%#v %#v %#v", x, x.Obj, e.ti.Defs[x], e.ti.Uses[x])
   420  			e.unexpected(msg)
   421  		}
   422  		if use.Type() != nil {
   423  			e.unexpected(fmt.Sprintf("%s %T/%T,%#v", x.String(), use, use.Type(), use))
   424  		} else {
   425  			e.unexpected(fmt.Sprintf("%s %T", x.String(), use))
   426  		}
   427  	}
   428  }
   429  
   430  func isDeprecated(n *ast.CommentGroup) bool {
   431  	if n == nil {
   432  		return false
   433  	}
   434  	for _, c := range n.List {
   435  		if strings.HasPrefix(c.Text, "// Deprecated") {
   436  			return true
   437  		}
   438  	}
   439  	return false
   440  }
   441  
   442  func (e *encoded) definitionFor(x *ast.Ident) (tokenType, []string) {
   443  	mods := []string{"definition"}
   444  	for i := len(e.stack) - 1; i >= 0; i-- {
   445  		s := e.stack[i]
   446  		switch y := s.(type) {
   447  		case *ast.AssignStmt, *ast.RangeStmt:
   448  			if x.Name == "_" {
   449  				return "", nil // not really a variable
   450  			}
   451  			return "variable", mods
   452  		case *ast.GenDecl:
   453  			if isDeprecated(y.Doc) {
   454  				mods = append(mods, "deprecated")
   455  			}
   456  			if y.Tok == token.CONST {
   457  				mods = append(mods, "readonly")
   458  			}
   459  			return tokVariable, mods
   460  		case *ast.FuncDecl:
   461  			// If x is immediately under a FuncDecl, it is a function or method
   462  			if i == len(e.stack)-2 {
   463  				if isDeprecated(y.Doc) {
   464  					mods = append(mods, "deprecated")
   465  				}
   466  				if y.Recv != nil {
   467  					return tokMember, mods
   468  				}
   469  				return tokFunction, mods
   470  			}
   471  			// if x < ... < FieldList < FuncDecl, this is the receiver, a variable
   472  			if _, ok := e.stack[i+1].(*ast.FieldList); ok {
   473  				return tokVariable, nil
   474  			}
   475  			// if x < ... < FieldList < FuncType < FuncDecl, this is a param
   476  			return tokParameter, mods
   477  		case *ast.InterfaceType:
   478  			return tokMember, mods
   479  		case *ast.TypeSpec:
   480  			// GenDecl/Typespec/FuncType/FieldList/Field/Ident
   481  			// (type A func(b uint64)) (err error)
   482  			// b and err should not be tokType, but tokVaraible
   483  			// and in GenDecl/TpeSpec/StructType/FieldList/Field/Ident
   484  			// (type A struct{b uint64})
   485  			fldm := e.stack[len(e.stack)-2]
   486  			if _, ok := fldm.(*ast.Field); ok {
   487  				return tokVariable, mods
   488  			}
   489  			return tokType, mods
   490  		}
   491  	}
   492  	// panic after extensive testing
   493  	msg := fmt.Sprintf("failed to find the decl for %s", e.pgf.Tok.PositionFor(x.Pos(), false))
   494  	e.unexpected(msg)
   495  	return "", []string{""}
   496  }
   497  
   498  // findKeyword finds a keyword rather than guessing its location
   499  func (e *encoded) findKeyword(keyword string, start, end token.Pos) token.Pos {
   500  	offset := int(start) - e.pgf.Tok.Base()
   501  	last := int(end) - e.pgf.Tok.Base()
   502  	buf := e.pgf.Src
   503  	idx := bytes.Index(buf[offset:last], []byte(keyword))
   504  	if idx != -1 {
   505  		return start + token.Pos(idx)
   506  	}
   507  	// can't happen
   508  	e.unexpected(fmt.Sprintf("not found:%s %v", keyword, e.fset.PositionFor(start, false)))
   509  	return token.NoPos
   510  }
   511  
   512  func (e *encoded) init() error {
   513  	e.start = token.Pos(e.pgf.Tok.Base())
   514  	e.end = e.start + token.Pos(e.pgf.Tok.Size())
   515  	if e.rng == nil {
   516  		return nil
   517  	}
   518  	span, err := e.pgf.Mapper.RangeSpan(*e.rng)
   519  	if err != nil {
   520  		return errors.Errorf("range span (%v) error for %s", err, e.pgf.File.Name)
   521  	}
   522  	e.end = e.start + token.Pos(span.End().Offset())
   523  	e.start += token.Pos(span.Start().Offset())
   524  	return nil
   525  }
   526  
   527  func (e *encoded) Data() ([]uint32, error) {
   528  	// binary operators, at least, will be out of order
   529  	sort.Slice(e.items, func(i, j int) bool {
   530  		if e.items[i].line != e.items[j].line {
   531  			return e.items[i].line < e.items[j].line
   532  		}
   533  		return e.items[i].start < e.items[j].start
   534  	})
   535  	typeMap, modMap := e.maps()
   536  	// each semantic token needs five values
   537  	// (see Integer Encoding for Tokens in the LSP spec)
   538  	x := make([]uint32, 5*len(e.items))
   539  	for i := 0; i < len(e.items); i++ {
   540  		j := 5 * i
   541  		if i == 0 {
   542  			x[0] = e.items[0].line
   543  		} else {
   544  			x[j] = e.items[i].line - e.items[i-1].line
   545  		}
   546  		x[j+1] = e.items[i].start
   547  		if i > 0 && e.items[i].line == e.items[i-1].line {
   548  			x[j+1] = e.items[i].start - e.items[i-1].start
   549  		}
   550  		x[j+2] = e.items[i].len
   551  		x[j+3] = uint32(typeMap[e.items[i].typeStr])
   552  		mask := 0
   553  		for _, s := range e.items[i].mods {
   554  			mask |= modMap[s]
   555  		}
   556  		x[j+4] = uint32(mask)
   557  	}
   558  	return x, nil
   559  }
   560  
   561  func (e *encoded) importSpec(d *ast.ImportSpec) {
   562  	// a local package name or the last component of the Path
   563  	if d.Name != nil {
   564  		nm := d.Name.String()
   565  		// import . x => x is not a namespace
   566  		// import _ x => x is a namespace
   567  		if nm != "_" && nm != "." {
   568  			e.token(d.Name.Pos(), len(nm), tokNamespace, nil)
   569  			return
   570  		}
   571  		if nm == "." {
   572  			return
   573  		}
   574  		// and fall through for _
   575  	}
   576  	nm := d.Path.Value[1 : len(d.Path.Value)-1] // trailing "
   577  	v := strings.LastIndex(nm, "/")
   578  	if v != -1 {
   579  		nm = nm[v+1:]
   580  	}
   581  	start := d.Path.End() - token.Pos(1+len(nm))
   582  	e.token(start, len(nm), tokNamespace, nil)
   583  }
   584  
   585  // panic on unexpected state
   586  func (e *encoded) unexpected(msg string) {
   587  	log.Print(msg)
   588  	log.Print(e.strStack())
   589  	panic(msg)
   590  }
   591  
   592  // SemType returns a string equivalent of the type, for gopls semtok
   593  func SemType(n int) string {
   594  	tokTypes := SemanticTypes()
   595  	tokMods := SemanticModifiers()
   596  	if n >= 0 && n < len(tokTypes) {
   597  		return tokTypes[n]
   598  	}
   599  	return fmt.Sprintf("?%d[%d,%d]?", n, len(tokTypes), len(tokMods))
   600  }
   601  
   602  // SemMods returns the []string equivalent of the mods, for gopls semtok.
   603  func SemMods(n int) []string {
   604  	tokMods := SemanticModifiers()
   605  	mods := []string{}
   606  	for i := 0; i < len(tokMods); i++ {
   607  		if (n & (1 << uint(i))) != 0 {
   608  			mods = append(mods, tokMods[i])
   609  		}
   610  	}
   611  	return mods
   612  }
   613  
   614  func (e *encoded) maps() (map[tokenType]int, map[string]int) {
   615  	tmap := make(map[tokenType]int)
   616  	mmap := make(map[string]int)
   617  	for i, t := range e.tokTypes {
   618  		tmap[tokenType(t)] = i
   619  	}
   620  	for i, m := range e.tokMods {
   621  		mmap[m] = 1 << uint(i) // go 1.12 compatibility
   622  	}
   623  	return tmap, mmap
   624  }
   625  
   626  // SemanticTypes to use in case there is no client, as in the command line, or tests
   627  func SemanticTypes() []string {
   628  	return semanticTypes[:]
   629  }
   630  
   631  // SemanticModifiers to use in case there is no client.
   632  func SemanticModifiers() []string {
   633  	return semanticModifiers[:]
   634  }
   635  
   636  var (
   637  	semanticTypes = [...]string{
   638  		"namespace", "type", "class", "enum", "interface",
   639  		"struct", "typeParameter", "parameter", "variable", "property", "enumMember",
   640  		"event", "function", "member", "macro", "keyword", "modifier", "comment",
   641  		"string", "number", "regexp", "operator"}
   642  	semanticModifiers = [...]string{
   643  		"declaration", "definition", "readonly", "static",
   644  		"deprecated", "abstract", "async", "modification", "documentation", "defaultLibrary"}
   645  )