mirror of
https://github.com/golang/go
synced 2024-11-05 15:46:11 -07:00
6b78e25f47
There were a few merge conflict-related issues in the GC optimization details CL. Also fixed a few things I noticed after the fact, like separating out a new mutex. Staticcheck caught a few things, and I also fixed a bug I noticed in the cache package. Change-Id: I3fc519373253418586dca08fdec3114b30a247ea Reviewed-on: https://go-review.googlesource.com/c/tools/+/245399 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Peter Weinberger <pjw@google.com>
122 lines
3.0 KiB
Go
122 lines
3.0 KiB
Go
// 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/lsp/protocol"
|
|
"golang.org/x/tools/internal/span"
|
|
)
|
|
|
|
func GCOptimizationDetails(ctx context.Context, snapshot Snapshot, pkgDir span.URI) (map[FileIdentity][]*Diagnostic, error) {
|
|
outDir := filepath.Join(os.TempDir(), fmt.Sprintf("gopls-%d.details", os.Getpid()))
|
|
if err := os.MkdirAll(outDir, 0700); err != nil {
|
|
return nil, err
|
|
}
|
|
args := []string{fmt.Sprintf("-gcflags=-json=0,%s", outDir), pkgDir.Filename()}
|
|
err := snapshot.RunGoCommandDirect(ctx, "build", args)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
files, err := findJSONFiles(outDir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
reports := make(map[FileIdentity][]*Diagnostic)
|
|
var parseError error
|
|
for _, fn := range files {
|
|
fname, v, err := parseDetailsFile(fn)
|
|
if err != nil {
|
|
// expect errors for all the files, save 1
|
|
parseError = err
|
|
}
|
|
if !strings.HasSuffix(fname, ".go") {
|
|
continue // <autogenerated>
|
|
}
|
|
uri := span.URIFromPath(fname)
|
|
x := snapshot.FindFile(uri)
|
|
if x == nil {
|
|
continue
|
|
}
|
|
k := x.Identity()
|
|
reports[k] = v
|
|
}
|
|
return reports, parseError
|
|
}
|
|
|
|
func parseDetailsFile(fn string) (string, []*Diagnostic, error) {
|
|
buf, err := ioutil.ReadFile(fn)
|
|
if err != nil {
|
|
return "", nil, err // This is an internal error. Likely ever file will fail.
|
|
}
|
|
var fname string
|
|
var ans []*Diagnostic
|
|
lines := bytes.Split(buf, []byte{'\n'})
|
|
for i, l := range lines {
|
|
if len(l) == 0 {
|
|
continue
|
|
}
|
|
if i == 0 {
|
|
x := make(map[string]interface{})
|
|
if err := json.Unmarshal(l, &x); err != nil {
|
|
return "", nil, fmt.Errorf("internal error (%v) parsing first line of json file %s",
|
|
err, fn)
|
|
}
|
|
fname = x["file"].(string)
|
|
continue
|
|
}
|
|
y := protocol.Diagnostic{}
|
|
if err := json.Unmarshal(l, &y); err != nil {
|
|
return "", nil, fmt.Errorf("internal error (%#v) parsing json file for %s", err, fname)
|
|
}
|
|
y.Range.Start.Line-- // change from 1-based to 0-based
|
|
y.Range.Start.Character--
|
|
y.Range.End.Line--
|
|
y.Range.End.Character--
|
|
msg := y.Code.(string)
|
|
if y.Message != "" {
|
|
msg = fmt.Sprintf("%s(%s)", msg, y.Message)
|
|
}
|
|
x := Diagnostic{
|
|
Range: y.Range,
|
|
Message: msg,
|
|
Source: y.Source,
|
|
Severity: y.Severity,
|
|
}
|
|
for _, ri := range y.RelatedInformation {
|
|
x.Related = append(x.Related, RelatedInformation{
|
|
URI: ri.Location.URI.SpanURI(),
|
|
Range: ri.Location.Range,
|
|
Message: ri.Message,
|
|
})
|
|
}
|
|
ans = append(ans, &x)
|
|
}
|
|
return fname, ans, nil
|
|
}
|
|
|
|
func findJSONFiles(dir string) ([]string, error) {
|
|
ans := []string{}
|
|
f := func(path string, fi os.FileInfo, err 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
|
|
}
|