GoPLS Viewer

Home|gopls/go/analysis/passes/assign/assign.go
1// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package assign defines an Analyzer that detects useless assignments.
6package assign
7
8// TODO(adonovan): check also for assignments to struct fields inside
9// methods that are on T instead of *T.
10
11import (
12    "fmt"
13    "go/ast"
14    "go/token"
15    "go/types"
16    "reflect"
17
18    "golang.org/x/tools/go/analysis"
19    "golang.org/x/tools/go/analysis/passes/inspect"
20    "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
21    "golang.org/x/tools/go/ast/inspector"
22)
23
24const Doc = `check for useless assignments
25
26This checker reports assignments of the form x = x or a[i] = a[i].
27These are almost always useless, and even when they aren't they are
28usually a mistake.`
29
30var Analyzer = &analysis.Analyzer{
31    Name:     "assign",
32    Doc:      Doc,
33    Requires: []*analysis.Analyzer{inspect.Analyzer},
34    Run:      run,
35}
36
37func run(pass *analysis.Pass) (interface{}, error) {
38    inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
39
40    nodeFilter := []ast.Node{
41        (*ast.AssignStmt)(nil),
42    }
43    inspect.Preorder(nodeFilter, func(n ast.Node) {
44        stmt := n.(*ast.AssignStmt)
45        if stmt.Tok != token.ASSIGN {
46            return // ignore :=
47        }
48        if len(stmt.Lhs) != len(stmt.Rhs) {
49            // If LHS and RHS have different cardinality, they can't be the same.
50            return
51        }
52        for ilhs := range stmt.Lhs {
53            rhs := stmt.Rhs[i]
54            if analysisutil.HasSideEffects(pass.TypesInfolhs) ||
55                analysisutil.HasSideEffects(pass.TypesInforhs) ||
56                isMapIndex(pass.TypesInfolhs) {
57                continue // expressions may not be equal
58            }
59            if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) {
60                continue // short-circuit the heavy-weight gofmt check
61            }
62            le := analysisutil.Format(pass.Fsetlhs)
63            re := analysisutil.Format(pass.Fsetrhs)
64            if le == re {
65                pass.Report(analysis.Diagnostic{
66                    Posstmt.Pos(), Messagefmt.Sprintf("self-assignment of %s to %s"rele),
67                    SuggestedFixes: []analysis.SuggestedFix{
68                        {Message"Remove"TextEdits: []analysis.TextEdit{
69                            {Posstmt.Pos(), Endstmt.End(), NewText: []byte{}},
70                        }},
71                    },
72                })
73            }
74        }
75    })
76
77    return nilnil
78}
79
80// isMapIndex returns true if e is a map index expression.
81func isMapIndex(info *types.Infoe ast.Exprbool {
82    if idxok := analysisutil.Unparen(e).(*ast.IndexExpr); ok {
83        if typ := info.Types[idx.X].Typetyp != nil {
84            _ok := typ.Underlying().(*types.Map)
85            return ok
86        }
87    }
88    return false
89}
90
MembersX
isMapIndex.e
types
analysisutil
run.nodeFilter
run.BlockStmt.RangeStmt_1394.BlockStmt.re
isMapIndex
isMapIndex.info
inspect
run.BlockStmt.RangeStmt_1394.BlockStmt.le
isMapIndex.BlockStmt.typ
ast
token
reflect
analysis
run
fmt
inspector
Doc
run.pass
run.BlockStmt.RangeStmt_1394.i
run.BlockStmt.RangeStmt_1394.lhs
Members
X