aboutsummaryrefslogtreecommitdiff
path: root/internal/lsp/source/gc_annotations.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/lsp/source/gc_annotations.go')
-rw-r--r--internal/lsp/source/gc_annotations.go214
1 files changed, 0 insertions, 214 deletions
diff --git a/internal/lsp/source/gc_annotations.go b/internal/lsp/source/gc_annotations.go
deleted file mode 100644
index 3616bbfb1..000000000
--- a/internal/lsp/source/gc_annotations.go
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright 2020 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 source
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
-
- "golang.org/x/tools/internal/gocommand"
- "golang.org/x/tools/internal/lsp/protocol"
- "golang.org/x/tools/internal/span"
-)
-
-type Annotation string
-
-const (
- // Nil controls nil checks.
- Nil Annotation = "nil"
-
- // Escape controls diagnostics about escape choices.
- Escape Annotation = "escape"
-
- // Inline controls diagnostics about inlining choices.
- Inline Annotation = "inline"
-
- // Bounds controls bounds checking diagnostics.
- Bounds Annotation = "bounds"
-)
-
-func GCOptimizationDetails(ctx context.Context, snapshot Snapshot, pkg Package) (map[VersionedFileIdentity][]*Diagnostic, error) {
- if len(pkg.CompiledGoFiles()) == 0 {
- return nil, nil
- }
- pkgDir := filepath.Dir(pkg.CompiledGoFiles()[0].URI.Filename())
- outDir := filepath.Join(os.TempDir(), fmt.Sprintf("gopls-%d.details", os.Getpid()))
-
- if err := os.MkdirAll(outDir, 0700); err != nil {
- return nil, err
- }
- tmpFile, err := ioutil.TempFile(os.TempDir(), "gopls-x")
- if err != nil {
- return nil, err
- }
- defer os.Remove(tmpFile.Name())
-
- outDirURI := span.URIFromPath(outDir)
- // GC details doesn't handle Windows URIs in the form of "file:///C:/...",
- // so rewrite them to "file://C:/...". See golang/go#41614.
- if !strings.HasPrefix(outDir, "/") {
- outDirURI = span.URI(strings.Replace(string(outDirURI), "file:///", "file://", 1))
- }
- inv := &gocommand.Invocation{
- Verb: "build",
- Args: []string{
- fmt.Sprintf("-gcflags=-json=0,%s", outDirURI),
- fmt.Sprintf("-o=%s", tmpFile.Name()),
- ".",
- },
- WorkingDir: pkgDir,
- }
- _, err = snapshot.RunGoCommandDirect(ctx, Normal, inv)
- if err != nil {
- return nil, err
- }
- files, err := findJSONFiles(outDir)
- if err != nil {
- return nil, err
- }
- reports := make(map[VersionedFileIdentity][]*Diagnostic)
- opts := snapshot.View().Options()
- var parseError error
- for _, fn := range files {
- uri, diagnostics, err := parseDetailsFile(fn, opts)
- if err != nil {
- // expect errors for all the files, save 1
- parseError = err
- }
- fh := snapshot.FindFile(uri)
- if fh == nil {
- continue
- }
- if pkgDir != filepath.Dir(fh.URI().Filename()) {
- // https://github.com/golang/go/issues/42198
- // sometimes the detail diagnostics generated for files
- // outside the package can never be taken back.
- continue
- }
- reports[fh.VersionedFileIdentity()] = diagnostics
- }
- return reports, parseError
-}
-
-func parseDetailsFile(filename string, options *Options) (span.URI, []*Diagnostic, error) {
- buf, err := ioutil.ReadFile(filename)
- if err != nil {
- return "", nil, err
- }
- var (
- uri span.URI
- i int
- diagnostics []*Diagnostic
- )
- type metadata struct {
- File string `json:"file,omitempty"`
- }
- for dec := json.NewDecoder(bytes.NewReader(buf)); dec.More(); {
- // The first element always contains metadata.
- if i == 0 {
- i++
- m := new(metadata)
- if err := dec.Decode(m); err != nil {
- return "", nil, err
- }
- if !strings.HasSuffix(m.File, ".go") {
- continue // <autogenerated>
- }
- uri = span.URIFromPath(m.File)
- continue
- }
- d := new(protocol.Diagnostic)
- if err := dec.Decode(d); err != nil {
- return "", nil, err
- }
- msg := d.Code.(string)
- if msg != "" {
- msg = fmt.Sprintf("%s(%s)", msg, d.Message)
- }
- if !showDiagnostic(msg, d.Source, options) {
- continue
- }
- var related []RelatedInformation
- for _, ri := range d.RelatedInformation {
- related = append(related, RelatedInformation{
- URI: ri.Location.URI.SpanURI(),
- Range: zeroIndexedRange(ri.Location.Range),
- Message: ri.Message,
- })
- }
- diagnostic := &Diagnostic{
- URI: uri,
- Range: zeroIndexedRange(d.Range),
- Message: msg,
- Severity: d.Severity,
- Source: OptimizationDetailsError, // d.Source is always "go compiler" as of 1.16, use our own
- Tags: d.Tags,
- Related: related,
- }
- diagnostics = append(diagnostics, diagnostic)
- i++
- }
- return uri, diagnostics, nil
-}
-
-// showDiagnostic reports whether a given diagnostic should be shown to the end
-// user, given the current options.
-func showDiagnostic(msg, source string, o *Options) bool {
- if source != "go compiler" {
- return false
- }
- if o.Annotations == nil {
- return true
- }
- switch {
- case strings.HasPrefix(msg, "canInline") ||
- strings.HasPrefix(msg, "cannotInline") ||
- strings.HasPrefix(msg, "inlineCall"):
- return o.Annotations[Inline]
- case strings.HasPrefix(msg, "escape") || msg == "leak":
- return o.Annotations[Escape]
- case strings.HasPrefix(msg, "nilcheck"):
- return o.Annotations[Nil]
- case strings.HasPrefix(msg, "isInBounds") ||
- strings.HasPrefix(msg, "isSliceInBounds"):
- return o.Annotations[Bounds]
- }
- return false
-}
-
-// The range produced by the compiler is 1-indexed, so subtract range by 1.
-func zeroIndexedRange(rng protocol.Range) protocol.Range {
- return protocol.Range{
- Start: protocol.Position{
- Line: rng.Start.Line - 1,
- Character: rng.Start.Character - 1,
- },
- End: protocol.Position{
- Line: rng.End.Line - 1,
- Character: rng.End.Character - 1,
- },
- }
-}
-
-func findJSONFiles(dir string) ([]string, error) {
- ans := []string{}
- f := func(path string, fi os.FileInfo, _ error) error {
- if fi.IsDir() {
- return nil
- }
- if strings.HasSuffix(path, ".json") {
- ans = append(ans, path)
- }
- return nil
- }
- err := filepath.Walk(dir, f)
- return ans, err
-}