1
0
mirror of https://github.com/golang/go synced 2024-11-18 18:54:42 -07:00

internal/lsp/cache: refactor a few small things

In preparation for some meaningful changes, rework a few things:

- rename "fix" to "fixAST"
- separate "parseExpr" into "parseStmt" and "parseExpr"
- pull out "walkASTWithParent" function

Change-Id: If6c8a249441feda95704f37bc9bde3ef2b64cbd2
Reviewed-on: https://go-review.googlesource.com/c/tools/+/216481
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Muir Manders 2020-01-26 13:49:43 -08:00 committed by Rebecca Stambler
parent bc0b458b10
commit 6f24f261da

View File

@ -138,7 +138,7 @@ func parseGo(ctx context.Context, fset *token.FileSet, fh source.FileHandle, mod
if mode == source.ParseExported { if mode == source.ParseExported {
trimAST(file) trimAST(file)
} }
if err := fix(ctx, file, tok, buf); err != nil { if err := fixAST(ctx, file, tok, buf); err != nil {
log.Error(ctx, "failed to fix AST", err) log.Error(ctx, "failed to fix AST", err)
} }
} }
@ -151,16 +151,12 @@ func parseGo(ctx context.Context, fset *token.FileSet, fh source.FileHandle, mod
} }
return nil, nil, parseError, err return nil, nil, parseError, err
} }
uri := fh.Identity().URI
content, _, err := fh.Read(ctx)
if err != nil {
return nil, nil, parseError, err
}
m := &protocol.ColumnMapper{ m := &protocol.ColumnMapper{
URI: uri, URI: fh.Identity().URI,
Converter: span.NewTokenConverter(fset, tok), Converter: span.NewTokenConverter(fset, tok),
Content: content, Content: buf,
} }
return file, m, parseError, nil return file, m, parseError, nil
} }
@ -201,36 +197,17 @@ func isEllipsisArray(n ast.Expr) bool {
return ok return ok
} }
// fix inspects the AST and potentially modifies any *ast.BadStmts so that it can be // fixAST inspects the AST and potentially modifies any *ast.BadStmts so that it can be
// type-checked more effectively. // type-checked more effectively.
func fix(ctx context.Context, n ast.Node, tok *token.File, src []byte) error { func fixAST(ctx context.Context, n ast.Node, tok *token.File, src []byte) error {
var ( var err error
ancestors []ast.Node walkASTWithParent(n, func(n, parent ast.Node) bool {
err error
)
ast.Inspect(n, func(n ast.Node) (recurse bool) {
defer func() {
if recurse {
ancestors = append(ancestors, n)
}
}()
if n == nil {
ancestors = ancestors[:len(ancestors)-1]
return false
}
var parent ast.Node
if len(ancestors) > 0 {
parent = ancestors[len(ancestors)-1]
}
switch n := n.(type) { switch n := n.(type) {
case *ast.BadStmt: case *ast.BadStmt:
err = fixDeferOrGoStmt(n, parent, tok, src) // don't shadow err err = fixDeferOrGoStmt(n, parent, tok, src) // don't shadow err
if err == nil { if err == nil {
// Recursively fix in our fixed node. // Recursively fix in our fixed node.
err = fix(ctx, parent, tok, src) err = fixAST(ctx, parent, tok, src)
} else { } else {
err = errors.Errorf("unable to parse defer or go from *ast.BadStmt: %v", err) err = errors.Errorf("unable to parse defer or go from *ast.BadStmt: %v", err)
} }
@ -241,7 +218,7 @@ func fix(ctx context.Context, n ast.Node, tok *token.File, src []byte) error {
// are expected and not actionable in general. // are expected and not actionable in general.
if fixArrayType(n, parent, tok, src) == nil { if fixArrayType(n, parent, tok, src) == nil {
// Recursively fix in our fixed node. // Recursively fix in our fixed node.
err = fix(ctx, parent, tok, src) err = fixAST(ctx, parent, tok, src)
return false return false
} }
@ -275,6 +252,31 @@ func fix(ctx context.Context, n ast.Node, tok *token.File, src []byte) error {
return err return err
} }
// walkASTWithParent walks the AST rooted at n. The semantics are
// similar to ast.Inspect except it does not call f(nil).
func walkASTWithParent(n ast.Node, f func(n ast.Node, parent ast.Node) bool) {
var ancestors []ast.Node
ast.Inspect(n, func(n ast.Node) (recurse bool) {
defer func() {
if recurse {
ancestors = append(ancestors, n)
}
}()
if n == nil {
ancestors = ancestors[:len(ancestors)-1]
return false
}
var parent ast.Node
if len(ancestors) > 0 {
parent = ancestors[len(ancestors)-1]
}
return f(n, parent)
})
}
// fixAccidentalDecl tries to fix "accidental" declarations. For example: // fixAccidentalDecl tries to fix "accidental" declarations. For example:
// //
// func typeOf() {} // func typeOf() {}
@ -597,9 +599,9 @@ FindTo:
return nil return nil
} }
// parseExpr parses the expression in src and updates its position to // parseStmt parses the statement in src and updates its position to
// start at pos. // start at pos.
func parseExpr(pos token.Pos, src []byte) (ast.Expr, error) { func parseStmt(pos token.Pos, src []byte) (ast.Stmt, error) {
// Wrap our expression to make it a valid Go file we can pass to ParseFile. // Wrap our expression to make it a valid Go file we can pass to ParseFile.
fileSrc := bytes.Join([][]byte{ fileSrc := bytes.Join([][]byte{
[]byte("package fake;func _(){"), []byte("package fake;func _(){"),
@ -624,25 +626,36 @@ func parseExpr(pos token.Pos, src []byte) (ast.Expr, error) {
return nil, errors.Errorf("no statement in %s: %v", src, err) return nil, errors.Errorf("no statement in %s: %v", src, err)
} }
exprStmt, ok := fakeDecl.Body.List[0].(*ast.ExprStmt) stmt := fakeDecl.Body.List[0]
// parser.ParseFile returns undefined positions.
// Adjust them for the current file.
offsetPositions(stmt, pos-1-(stmt.Pos()-1))
return stmt, nil
}
// parseExpr parses the expression in src and updates its position to
// start at pos.
func parseExpr(pos token.Pos, src []byte) (ast.Expr, error) {
stmt, err := parseStmt(pos, src)
if err != nil {
return nil, err
}
exprStmt, ok := stmt.(*ast.ExprStmt)
if !ok { if !ok {
return nil, errors.Errorf("no expr in %s: %v", src, err) return nil, errors.Errorf("no expr in %s: %v", src, err)
} }
expr := exprStmt.X return exprStmt.X, nil
// parser.ParseExpr returns undefined positions.
// Adjust them for the current file.
offsetPositions(expr, pos-1-(expr.Pos()-1))
return expr, nil
} }
var tokenPosType = reflect.TypeOf(token.NoPos) var tokenPosType = reflect.TypeOf(token.NoPos)
// offsetPositions applies an offset to the positions in an ast.Node. // offsetPositions applies an offset to the positions in an ast.Node.
func offsetPositions(expr ast.Expr, offset token.Pos) { func offsetPositions(n ast.Node, offset token.Pos) {
ast.Inspect(expr, func(n ast.Node) bool { ast.Inspect(n, func(n ast.Node) bool {
if n == nil { if n == nil {
return false return false
} }