summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go
blob: a3fb2d4f29d0f16e2ddeef88ecbdbb2fcc001e32 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// package tokeninternal provides access to some internal features of the token
// package.
package tokeninternal

import (
	"go/token"
	"sync"
	"unsafe"
)

// GetLines returns the table of line-start offsets from a token.File.
func GetLines(file *token.File) []int {
	// token.File has a Lines method on Go 1.21 and later.
	if file, ok := (interface{})(file).(interface{ Lines() []int }); ok {
		return file.Lines()
	}

	// This declaration must match that of token.File.
	// This creates a risk of dependency skew.
	// For now we check that the size of the two
	// declarations is the same, on the (fragile) assumption
	// that future changes would add fields.
	type tokenFile119 struct {
		_     string
		_     int
		_     int
		mu    sync.Mutex // we're not complete monsters
		lines []int
		_     []struct{}
	}
	type tokenFile118 struct {
		_ *token.FileSet // deleted in go1.19
		tokenFile119
	}

	type uP = unsafe.Pointer
	switch unsafe.Sizeof(*file) {
	case unsafe.Sizeof(tokenFile118{}):
		var ptr *tokenFile118
		*(*uP)(uP(&ptr)) = uP(file)
		ptr.mu.Lock()
		defer ptr.mu.Unlock()
		return ptr.lines

	case unsafe.Sizeof(tokenFile119{}):
		var ptr *tokenFile119
		*(*uP)(uP(&ptr)) = uP(file)
		ptr.mu.Lock()
		defer ptr.mu.Unlock()
		return ptr.lines

	default:
		panic("unexpected token.File size")
	}
}