...
1
2
3
4
5
6
7 package tokeninternal
8
9 import (
10 "fmt"
11 "go/token"
12 "sort"
13 "sync"
14 "unsafe"
15 )
16
17
18 func GetLines(file *token.File) []int {
19
20 if file, ok := (interface{})(file).(interface{ Lines() []int }); ok {
21 return file.Lines()
22 }
23
24
25
26
27
28
29 type tokenFile119 struct {
30 _ string
31 _ int
32 _ int
33 mu sync.Mutex
34 lines []int
35 _ []struct{}
36 }
37
38 if unsafe.Sizeof(*file) != unsafe.Sizeof(tokenFile119{}) {
39 panic("unexpected token.File size")
40 }
41 var ptr *tokenFile119
42 type uP = unsafe.Pointer
43 *(*uP)(uP(&ptr)) = uP(file)
44 ptr.mu.Lock()
45 defer ptr.mu.Unlock()
46 return ptr.lines
47 }
48
49
50
51
52 func AddExistingFiles(fset *token.FileSet, files []*token.File) {
53
54 type tokenFileSet struct {
55
56 mutex sync.RWMutex
57 base int
58 files []*token.File
59 _ *token.File
60 }
61
62
63 const delta = int64(unsafe.Sizeof(tokenFileSet{})) - int64(unsafe.Sizeof(token.FileSet{}))
64 var _ [-delta * delta]int
65
66 type uP = unsafe.Pointer
67 var ptr *tokenFileSet
68 *(*uP)(uP(&ptr)) = uP(fset)
69 ptr.mutex.Lock()
70 defer ptr.mutex.Unlock()
71
72
73 newFiles := append(ptr.files, files...)
74 sort.Slice(newFiles, func(i, j int) bool {
75 return newFiles[i].Base() < newFiles[j].Base()
76 })
77
78
79
80 out := newFiles[:0]
81 for i, file := range newFiles {
82 if i > 0 {
83 prev := newFiles[i-1]
84 if file == prev {
85 continue
86 }
87 if prev.Base()+prev.Size()+1 > file.Base() {
88 panic(fmt.Sprintf("file %s (%d-%d) overlaps with file %s (%d-%d)",
89 prev.Name(), prev.Base(), prev.Base()+prev.Size(),
90 file.Name(), file.Base(), file.Base()+file.Size()))
91 }
92 }
93 out = append(out, file)
94 }
95 newFiles = out
96
97 ptr.files = newFiles
98
99
100 if len(newFiles) > 0 {
101 last := newFiles[len(newFiles)-1]
102 newBase := last.Base() + last.Size() + 1
103 if ptr.base < newBase {
104 ptr.base = newBase
105 }
106 }
107 }
108
109
110
111
112
113
114
115 func FileSetFor(files ...*token.File) *token.FileSet {
116 fset := token.NewFileSet()
117 for _, f := range files {
118 f2 := fset.AddFile(f.Name(), f.Base(), f.Size())
119 lines := GetLines(f)
120 f2.SetLines(lines)
121 }
122 return fset
123 }
124
125
126
127
128 func CloneFileSet(fset *token.FileSet) *token.FileSet {
129 var files []*token.File
130 fset.Iterate(func(f *token.File) bool {
131 files = append(files, f)
132 return true
133 })
134 newFileSet := token.NewFileSet()
135 AddExistingFiles(newFileSet, files)
136 return newFileSet
137 }
138
View as plain text