mirror of
https://github.com/golang/go
synced 2024-11-18 16:54:43 -07:00
go/analysis: add an End field to Diagnostic
This will allow diagnostics to denote the range they apply to. The ranges are now interpreted using the internal/span library. This is primarily intended for the benefit of the LSP, which will be able to (in future CLs) more accurately highlight the part of the code a diagnostic applies to. Change-Id: Ic35cec2b21060c9dc6a8f5ebb7faa62d81a07435 Reviewed-on: https://go-review.googlesource.com/c/tools/+/179237 Run-TryBot: Michael Matloob <matloob@golang.org> Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
parent
12d7342421
commit
2b03ca6e44
@ -161,6 +161,15 @@ func (pass *Pass) Reportf(pos token.Pos, format string, args ...interface{}) {
|
||||
pass.Report(Diagnostic{Pos: pos, Message: msg})
|
||||
}
|
||||
|
||||
// reportNodef is a helper function that reports a Diagnostic using the
|
||||
// range denoted by the AST node.
|
||||
//
|
||||
// WARNING: This is an experimental API and may change in the future.
|
||||
func (pass *Pass) reportNodef(node ast.Node, format string, args ...interface{}) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
pass.Report(Diagnostic{Pos: node.Pos(), End: node.End(), Message: msg})
|
||||
}
|
||||
|
||||
func (pass *Pass) String() string {
|
||||
return fmt.Sprintf("%s@%s", pass.Analyzer.Name, pass.Pkg.Path())
|
||||
}
|
||||
@ -203,13 +212,17 @@ type Fact interface {
|
||||
AFact() // dummy method to avoid type errors
|
||||
}
|
||||
|
||||
// A Diagnostic is a message associated with a source location.
|
||||
// A Diagnostic is a message associated with a source location or range.
|
||||
//
|
||||
// An Analyzer may return a variety of diagnostics; the optional Category,
|
||||
// which should be a constant, may be used to classify them.
|
||||
// It is primarily intended to make it easy to look up documentation.
|
||||
//
|
||||
// If End is provided, the diagnostic is specified to apply to the range between
|
||||
// Pos and End.
|
||||
type Diagnostic struct {
|
||||
Pos token.Pos
|
||||
Category string // optional
|
||||
End token.Pos // optional
|
||||
Category string // optional
|
||||
Message string
|
||||
}
|
||||
|
@ -257,6 +257,7 @@ func check(t Testing, gopath string, pass *analysis.Pass, diagnostics []analysis
|
||||
|
||||
// Check the diagnostics match expectations.
|
||||
for _, f := range diagnostics {
|
||||
// TODO(matloob): Support ranges in analysistest.
|
||||
posn := pass.Fset.Position(f.Pos)
|
||||
checkMessage(posn, "diagnostic", "", f.Message)
|
||||
}
|
||||
|
@ -323,9 +323,14 @@ func PrintPlain(fset *token.FileSet, diag analysis.Diagnostic) {
|
||||
|
||||
// -c=N: show offending line plus N lines of context.
|
||||
if Context >= 0 {
|
||||
posn := fset.Position(diag.Pos)
|
||||
end := fset.Position(diag.End)
|
||||
if !end.IsValid() {
|
||||
end = posn
|
||||
}
|
||||
data, _ := ioutil.ReadFile(posn.Filename)
|
||||
lines := strings.Split(string(data), "\n")
|
||||
for i := posn.Line - Context; i <= posn.Line+Context; i++ {
|
||||
for i := posn.Line - Context; i <= end.Line+Context; i++ {
|
||||
if 1 <= i && i <= len(lines) {
|
||||
fmt.Fprintf(os.Stderr, "%d\t%s\n", i, lines[i-1])
|
||||
}
|
||||
@ -353,6 +358,8 @@ func (tree JSONTree) Add(fset *token.FileSet, id, name string, diags []analysis.
|
||||
Message string `json:"message"`
|
||||
}
|
||||
var diagnostics []jsonDiagnostic
|
||||
// TODO(matloob): Should the JSON diagnostics contain ranges?
|
||||
// If so, how should they be formatted?
|
||||
for _, f := range diags {
|
||||
diagnostics = append(diagnostics, jsonDiagnostic{
|
||||
Category: f.Category,
|
||||
|
@ -295,7 +295,8 @@ func printDiagnostics(roots []*action) (exitcode int) {
|
||||
// avoid double-reporting in source files that belong to
|
||||
// multiple packages, such as foo and foo.test.
|
||||
type key struct {
|
||||
token.Position
|
||||
pos token.Position
|
||||
end token.Position
|
||||
*analysis.Analyzer
|
||||
message string
|
||||
}
|
||||
@ -313,7 +314,8 @@ func printDiagnostics(roots []*action) (exitcode int) {
|
||||
// as most users don't care.
|
||||
|
||||
posn := act.pkg.Fset.Position(diag.Pos)
|
||||
k := key{posn, act.a, diag.Message}
|
||||
end := act.pkg.Fset.Position(diag.End)
|
||||
k := key{posn, end, act.a, diag.Message}
|
||||
if seen[k] {
|
||||
continue // duplicate
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ func diagnostics(ctx context.Context, v View, pkg Package, reports map[span.URI]
|
||||
func analyses(ctx context.Context, v View, pkg Package, reports map[span.URI][]Diagnostic) error {
|
||||
// Type checking and parsing succeeded. Run analyses.
|
||||
if err := runAnalyses(ctx, v, pkg, func(a *analysis.Analyzer, diag analysis.Diagnostic) error {
|
||||
r := span.NewRange(v.Session().Cache().FileSet(), diag.Pos, 0)
|
||||
r := span.NewRange(v.Session().Cache().FileSet(), diag.Pos, diag.End)
|
||||
s, err := r.Span()
|
||||
if err != nil {
|
||||
// The diagnostic has an invalid position, so we don't have a valid span.
|
||||
|
Loading…
Reference in New Issue
Block a user