diff options
Diffstat (limited to 'vendor/golang.org/x/tools/internal/tokeninternal')
| -rw-r--r-- | vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go | 92 | 
1 files changed, 92 insertions, 0 deletions
diff --git a/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go b/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go index a3fb2d4f2..7e638ec24 100644 --- a/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go +++ b/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go @@ -7,7 +7,9 @@  package tokeninternal  import ( +	"fmt"  	"go/token" +	"sort"  	"sync"  	"unsafe"  ) @@ -57,3 +59,93 @@ func GetLines(file *token.File) []int {  		panic("unexpected token.File size")  	}  } + +// AddExistingFiles adds the specified files to the FileSet if they +// are not already present. It panics if any pair of files in the +// resulting FileSet would overlap. +func AddExistingFiles(fset *token.FileSet, files []*token.File) { +	// Punch through the FileSet encapsulation. +	type tokenFileSet struct { +		// This type remained essentially consistent from go1.16 to go1.21. +		mutex sync.RWMutex +		base  int +		files []*token.File +		_     *token.File // changed to atomic.Pointer[token.File] in go1.19 +	} + +	// If the size of token.FileSet changes, this will fail to compile. +	const delta = int64(unsafe.Sizeof(tokenFileSet{})) - int64(unsafe.Sizeof(token.FileSet{})) +	var _ [-delta * delta]int + +	type uP = unsafe.Pointer +	var ptr *tokenFileSet +	*(*uP)(uP(&ptr)) = uP(fset) +	ptr.mutex.Lock() +	defer ptr.mutex.Unlock() + +	// Merge and sort. +	newFiles := append(ptr.files, files...) +	sort.Slice(newFiles, func(i, j int) bool { +		return newFiles[i].Base() < newFiles[j].Base() +	}) + +	// Reject overlapping files. +	// Discard adjacent identical files. +	out := newFiles[:0] +	for i, file := range newFiles { +		if i > 0 { +			prev := newFiles[i-1] +			if file == prev { +				continue +			} +			if prev.Base()+prev.Size()+1 > file.Base() { +				panic(fmt.Sprintf("file %s (%d-%d) overlaps with file %s (%d-%d)", +					prev.Name(), prev.Base(), prev.Base()+prev.Size(), +					file.Name(), file.Base(), file.Base()+file.Size())) +			} +		} +		out = append(out, file) +	} +	newFiles = out + +	ptr.files = newFiles + +	// Advance FileSet.Base(). +	if len(newFiles) > 0 { +		last := newFiles[len(newFiles)-1] +		newBase := last.Base() + last.Size() + 1 +		if ptr.base < newBase { +			ptr.base = newBase +		} +	} +} + +// FileSetFor returns a new FileSet containing a sequence of new Files with +// the same base, size, and line as the input files, for use in APIs that +// require a FileSet. +// +// Precondition: the input files must be non-overlapping, and sorted in order +// of their Base. +func FileSetFor(files ...*token.File) *token.FileSet { +	fset := token.NewFileSet() +	for _, f := range files { +		f2 := fset.AddFile(f.Name(), f.Base(), f.Size()) +		lines := GetLines(f) +		f2.SetLines(lines) +	} +	return fset +} + +// CloneFileSet creates a new FileSet holding all files in fset. It does not +// create copies of the token.Files in fset: they are added to the resulting +// FileSet unmodified. +func CloneFileSet(fset *token.FileSet) *token.FileSet { +	var files []*token.File +	fset.Iterate(func(f *token.File) bool { +		files = append(files, f) +		return true +	}) +	newFileSet := token.NewFileSet() +	AddExistingFiles(newFileSet, files) +	return newFileSet +}  | 
