aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/logopt
diff options
context:
space:
mode:
authorDavid Chase <drchase@google.com>2019-11-11 13:18:38 -0500
committerDavid Chase <drchase@google.com>2020-04-11 02:04:15 +0000
commit06314b620d782bf295a07745c7f14b4738e7109a (patch)
tree47287ac2fd0c072d60a39a9a2d44015d4516ebff /src/cmd/compile/internal/logopt
parentfced302aa15702056e0d4a264c80e74c462cdd22 (diff)
downloadgo-06314b620d782bf295a07745c7f14b4738e7109a.tar.gz
go-06314b620d782bf295a07745c7f14b4738e7109a.zip
cmd/compile: add explanations to escape-analysis JSON/LSP logging
For 1.15. From the test: {"range":{"start":{"line":7,"character":13},"end":{...},"severity":3,"code":"leaks","source":"go compiler","message":"parameter z leaks to ~r2 with derefs=0","relatedInformation":[ {"location":{"uri":"file://T/file.go","range":{"start":{"line":9,"character":13},"end":{...}},"message":"escflow: flow: y = z:"}, {"location":{"uri":"file://T/file.go","range":{"start":{"line":9,"character":13},"end":{...}},"message":"escflow: from y = \u003cN\u003e (assign-pair)"}, {"location":{"uri":"file://T/file.go","range":{"start":{"line":9,"character":13},"end":{...}},"message":"escflow: flow: ~r1 = y:"}, {"location":{"uri":"file://T/file.go","range":{"start":{"line":4,"character":11},"end":{...}},"message":"inlineLoc"}, {"location":{"uri":"file://T/file.go","range":{"start":{"line":9,"character":13},"end":{...}},"message":"escflow: from y.b (dot of pointer)"}, {"location":{"uri":"file://T/file.go","range":{"start":{"line":4,"character":11},"end":{...}},"message":"inlineLoc"}, {"location":{"uri":"file://T/file.go","range":{"start":{"line":9,"character":13},"end":{...}},"message":"escflow: from \u0026y.b (address-of)"}, {"location":{"uri":"file://T/file.go","range":{"start":{"line":4,"character":9},"end":...}},"message":"inlineLoc"}, {"location":{"uri":"file://T/file.go","range":{"start":{"line":9,"character":13},"end":{...}},"message":"escflow: from ~r1 = \u003cN\u003e (assign-pair)"}, {"location":{"uri":"file://T/file.go","range":{"start":{"line":9,"character":3},"end":...}},"message":"escflow: flow: ~r2 = ~r1:"}, {"location":{"uri":"file://T/file.go","range":{"start":{"line":9,"character":3},"end":...}},"message":"escflow: from return (*int)(~r1) (return)"}]} Change-Id: Idf02438801f63e487c35a928cf5a0b6d3cc48674 Reviewed-on: https://go-review.googlesource.com/c/go/+/206658 Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/cmd/compile/internal/logopt')
-rw-r--r--src/cmd/compile/internal/logopt/log_opts.go80
-rw-r--r--src/cmd/compile/internal/logopt/logopt_test.go22
2 files changed, 79 insertions, 23 deletions
diff --git a/src/cmd/compile/internal/logopt/log_opts.go b/src/cmd/compile/internal/logopt/log_opts.go
index 49cb9cf57f..22a94b0f2d 100644
--- a/src/cmd/compile/internal/logopt/log_opts.go
+++ b/src/cmd/compile/internal/logopt/log_opts.go
@@ -294,18 +294,23 @@ func checkLogPath(flag, destination string) {
dest = destination
}
-var loggedOpts []LoggedOpt
+var loggedOpts []*LoggedOpt
var mu = sync.Mutex{} // mu protects loggedOpts.
+func NewLoggedOpt(pos src.XPos, what, pass, fname string, args ...interface{}) *LoggedOpt {
+ pass = strings.Replace(pass, " ", "_", -1)
+ return &LoggedOpt{pos, pass, fname, what, args}
+}
+
func LogOpt(pos src.XPos, what, pass, fname string, args ...interface{}) {
if Format == None {
return
}
- pass = strings.Replace(pass, " ", "_", -1)
+ lo := NewLoggedOpt(pos, what, pass, fname, args...)
mu.Lock()
defer mu.Unlock()
// Because of concurrent calls from back end, no telling what the order will be, but is stable-sorted by outer Pos before use.
- loggedOpts = append(loggedOpts, LoggedOpt{pos, pass, fname, what, args})
+ loggedOpts = append(loggedOpts, lo)
}
func Enabled() bool {
@@ -321,7 +326,7 @@ func Enabled() bool {
// byPos sorts diagnostics by source position.
type byPos struct {
ctxt *obj.Link
- a []LoggedOpt
+ a []*LoggedOpt
}
func (x byPos) Len() int { return len(x.a) }
@@ -402,15 +407,9 @@ func FlushLoggedOpts(ctxt *obj.Link, slashPkgPath string) {
// For LSP, make a subdirectory for the package, and for each file foo.go, create foo.json in that subdirectory.
currentFile := ""
for _, x := range loggedOpts {
- posTmp = ctxt.AllPos(x.pos, posTmp)
- // Reverse posTmp to put outermost first.
- l := len(posTmp)
- for i := 0; i < l/2; i++ {
- posTmp[i], posTmp[l-i-1] = posTmp[l-i-1], posTmp[i]
- }
-
- p0 := posTmp[0]
+ posTmp, p0 := x.parsePos(ctxt, posTmp)
p0f := uprootedPath(p0.Filename())
+
if currentFile != p0f {
if w != nil {
w.Close()
@@ -429,16 +428,27 @@ func FlushLoggedOpts(ctxt *obj.Link, slashPkgPath string) {
diagnostic.Code = x.what
diagnostic.Message = target
- diagnostic.Range = Range{Start: Position{p0.Line(), p0.Col()},
- End: Position{p0.Line(), p0.Col()}}
+ diagnostic.Range = newPointRange(p0)
diagnostic.RelatedInformation = diagnostic.RelatedInformation[:0]
- for i := 1; i < l; i++ {
- p := posTmp[i]
- loc := Location{URI: uriIfy(uprootedPath(p.Filename())),
- Range: Range{Start: Position{p.Line(), p.Col()},
- End: Position{p.Line(), p.Col()}}}
- diagnostic.RelatedInformation = append(diagnostic.RelatedInformation, DiagnosticRelatedInformation{Location: loc, Message: "inlineLoc"})
+ appendInlinedPos(posTmp, &diagnostic)
+
+ // Diagnostic explanation is stored in RelatedInformation after inlining info
+ if len(x.target) > 1 {
+ switch y := x.target[1].(type) {
+ case []*LoggedOpt:
+ for _, z := range y {
+ posTmp, p0 := z.parsePos(ctxt, posTmp)
+ loc := newLocation(p0)
+ msg := z.what
+ if len(z.target) > 0 {
+ msg = msg + ": " + fmt.Sprint(z.target[0])
+ }
+
+ diagnostic.RelatedInformation = append(diagnostic.RelatedInformation, DiagnosticRelatedInformation{Location: loc, Message: msg})
+ appendInlinedPos(posTmp, &diagnostic)
+ }
+ }
}
encoder.Encode(diagnostic)
@@ -448,3 +458,33 @@ func FlushLoggedOpts(ctxt *obj.Link, slashPkgPath string) {
}
}
}
+
+func newPointRange(p src.Pos) Range {
+ return Range{Start: Position{p.Line(), p.Col()},
+ End: Position{p.Line(), p.Col()}}
+}
+
+func newLocation(p src.Pos) Location {
+ loc := Location{URI: uriIfy(uprootedPath(p.Filename())), Range: newPointRange(p)}
+ return loc
+}
+
+// appendInlinedPos extracts inlining information from posTmp and append it to diagnostic
+func appendInlinedPos(posTmp []src.Pos, diagnostic *Diagnostic) {
+ for i := 1; i < len(posTmp); i++ {
+ p := posTmp[i]
+ loc := newLocation(p)
+ diagnostic.RelatedInformation = append(diagnostic.RelatedInformation, DiagnosticRelatedInformation{Location: loc, Message: "inlineLoc"})
+ }
+}
+
+func (x *LoggedOpt) parsePos(ctxt *obj.Link, posTmp []src.Pos) ([]src.Pos, src.Pos) {
+ posTmp = ctxt.AllPos(x.pos, posTmp)
+ // Reverse posTmp to put outermost first.
+ l := len(posTmp)
+ for i := 0; i < l/2; i++ {
+ posTmp[i], posTmp[l-i-1] = posTmp[l-i-1], posTmp[i]
+ }
+ p0 := posTmp[0]
+ return posTmp, p0
+}
diff --git a/src/cmd/compile/internal/logopt/logopt_test.go b/src/cmd/compile/internal/logopt/logopt_test.go
index 9704bc79d5..fb08393bdb 100644
--- a/src/cmd/compile/internal/logopt/logopt_test.go
+++ b/src/cmd/compile/internal/logopt/logopt_test.go
@@ -41,8 +41,11 @@ func n() int {
`
func want(t *testing.T, out string, desired string) {
- if !strings.Contains(out, desired) {
- t.Errorf("did not see phrase %s in \n%s", desired, out)
+ // On Windows, Unicode escapes in the JSON output end up "normalized" elsewhere to /u....,
+ // so "normalize" what we're looking for to match that.
+ s := strings.ReplaceAll(desired, string(os.PathSeparator), "/")
+ if !strings.Contains(out, s) {
+ t.Errorf("did not see phrase %s in \n%s", s, out)
}
}
@@ -178,7 +181,20 @@ func s15a8(x *[15]int64) [15]int64 {
want(t, slogged, `{"range":{"start":{"line":11,"character":6},"end":{"line":11,"character":6}},"severity":3,"code":"isInBounds","source":"go compiler","message":""}`)
want(t, slogged, `{"range":{"start":{"line":7,"character":6},"end":{"line":7,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 35"}`)
want(t, slogged, `{"range":{"start":{"line":21,"character":21},"end":{"line":21,"character":21}},"severity":3,"code":"cannotInlineCall","source":"go compiler","message":"foo cannot be inlined (escaping closure variable)"}`)
-
+ // escape analysis explanation
+ want(t, slogged, `{"range":{"start":{"line":7,"character":13},"end":{"line":7,"character":13}},"severity":3,"code":"leak","source":"go compiler","message":"parameter z leaks to ~r2 with derefs=0",`+
+ `"relatedInformation":[`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: y = z:"},`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y = \u003cN\u003e (assign-pair)"},`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: ~r1 = y:"},`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y.b (dot of pointer)"},`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from \u0026y.b (address-of)"},`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":9},"end":{"line":4,"character":9}}},"message":"inlineLoc"},`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from ~r1 = \u003cN\u003e (assign-pair)"},`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r2 = ~r1:"},`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return (*int)(~r1) (return)"}]}`)
})
}