Skip to content

Commit

Permalink
internal/lsp: handle panics due to line numbers in fillstruct
Browse files Browse the repository at this point in the history
Change-Id: I90f3fd2daf180705048d494476acac5a213f5fb3
Reviewed-on: https://go-review.googlesource.com/c/tools/+/239751
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Baum <joshbaum@google.com>
  • Loading branch information
stamblerre committed Jun 25, 2020
1 parent 88f3c62 commit aa12c9e
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 11 deletions.
24 changes: 16 additions & 8 deletions internal/lsp/analysis/fillstruct/fillstruct.go
Expand Up @@ -107,7 +107,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
case *ast.SelectorExpr:
name = fmt.Sprintf("%s.%s", typ.X, typ.Sel.Name)
default:
log.Printf("anonymous structs are not yet supported: %v (%T)", expr.Type, expr.Type)
log.Printf("anonymous structs are not yet supported: (%T)", expr.Type)
return
}

Expand All @@ -119,6 +119,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
fset := token.NewFileSet()
tok := fset.AddFile("", -1, fieldCount+2)

line := 2 // account for 1-based lines and the left brace
var elts []ast.Expr
for i := 0; i < fieldCount; i++ {
field := obj.Field(i)
Expand All @@ -133,8 +134,10 @@ func run(pass *analysis.Pass) (interface{}, error) {
continue
}

line := i + 2 // account for 1-based lines and the left brace
tok.AddLine(i + 1) // add 1 byte per line
tok.AddLine(line - 1) // add 1 byte per line
if line > tok.LineCount() {
panic(fmt.Sprintf("invalid line number %v (of %v) for fillstruct %s", line, tok.LineCount(), name))
}
pos := tok.LineStart(line)

kv := &ast.KeyValueExpr{
Expand All @@ -146,6 +149,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
Value: value,
}
elts = append(elts, kv)
line++
}

// If all of the struct's fields are unexported, we have nothing to do.
Expand All @@ -156,12 +160,16 @@ func run(pass *analysis.Pass) (interface{}, error) {
// Add the final line for the right brace. Offset is the number of
// bytes already added plus 1.
tok.AddLine(len(elts) + 1)
line = len(elts) + 2
if line > tok.LineCount() {
panic(fmt.Sprintf("invalid line number %v (of %v) for fillstruct %s", line, tok.LineCount(), name))
}

cl := &ast.CompositeLit{
Type: expr.Type,
Lbrace: tok.LineStart(1),
Elts: elts,
Rbrace: tok.LineStart(len(elts) + 2),
Rbrace: tok.LineStart(line),
}

// Print the AST to get the the original source code.
Expand All @@ -174,13 +182,13 @@ func run(pass *analysis.Pass) (interface{}, error) {
// Find the line on which the composite literal is declared.
split := strings.Split(b.String(), "\n")
lineNumber := pass.Fset.Position(expr.Type.Pos()).Line
line := split[lineNumber-1] // lines are 1-indexed
firstLine := split[lineNumber-1] // lines are 1-indexed

// Trim the whitespace from the left of the line, and use the index
// to get the amount of whitespace on the left.
trimmed := strings.TrimLeftFunc(line, unicode.IsSpace)
i := strings.Index(line, trimmed)
whitespace := line[:i]
trimmed := strings.TrimLeftFunc(firstLine, unicode.IsSpace)
index := strings.Index(firstLine, trimmed)
whitespace := firstLine[:index]

var newExpr bytes.Buffer
if err := format.Node(&newExpr, fset, cl); err != nil {
Expand Down
@@ -1,9 +1,12 @@
package fillstruct

import (
h2 "net/http"

"golang.org/x/tools/internal/lsp/fillstruct/data"
)

func unexported() {
a := data.A{} //@suggestedfix("}", "refactor.rewrite")
a := data.A{} //@suggestedfix("}", "refactor.rewrite")
_ = h2.Client{} //@suggestedfix("}", "refactor.rewrite")
}
@@ -1,13 +1,34 @@
-- suggestedfix_fill_struct_package_8_14 --
-- suggestedfix_fill_struct_package_10_14 --
package fillstruct

import (
h2 "net/http"

"golang.org/x/tools/internal/lsp/fillstruct/data"
)

func unexported() {
a := data.A{
ExportedInt: 0,
} //@suggestedfix("}", "refactor.rewrite")
_ = h2.Client{} //@suggestedfix("}", "refactor.rewrite")
}

-- suggestedfix_fill_struct_package_11_16 --
package fillstruct

import (
h2 "net/http"

"golang.org/x/tools/internal/lsp/fillstruct/data"
)

func unexported() {
a := data.A{} //@suggestedfix("}", "refactor.rewrite")
_ = h2.Client{
Transport: nil,
Jar: nil,
Timeout: 0,
} //@suggestedfix("}", "refactor.rewrite")
}

2 changes: 1 addition & 1 deletion internal/lsp/testdata/lsp/summary.txt.golden
Expand Up @@ -11,7 +11,7 @@ DiagnosticsCount = 44
FoldingRangesCount = 2
FormatCount = 6
ImportCount = 8
SuggestedFixCount = 13
SuggestedFixCount = 14
DefinitionsCount = 53
TypeDefinitionsCount = 2
HighlightsCount = 69
Expand Down

0 comments on commit aa12c9e

Please sign in to comment.