sa4018.go raw
1 package sa4018
2
3 import (
4 "fmt"
5 "go/ast"
6 "go/token"
7 "reflect"
8
9 "honnef.co/go/tools/analysis/code"
10 "honnef.co/go/tools/analysis/facts/generated"
11 "honnef.co/go/tools/analysis/facts/purity"
12 "honnef.co/go/tools/analysis/lint"
13 "honnef.co/go/tools/analysis/report"
14
15 "golang.org/x/tools/go/analysis"
16 "golang.org/x/tools/go/analysis/passes/inspect"
17 )
18
19 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
20 Analyzer: &analysis.Analyzer{
21 Name: "SA4018",
22 Run: run,
23 Requires: []*analysis.Analyzer{inspect.Analyzer, generated.Analyzer, purity.Analyzer},
24 },
25 Doc: &lint.RawDocumentation{
26 Title: `Self-assignment of variables`,
27 Since: "2017.1",
28 Severity: lint.SeverityWarning,
29 MergeIf: lint.MergeIfAny,
30 },
31 })
32
33 var Analyzer = SCAnalyzer.Analyzer
34
35 func run(pass *analysis.Pass) (interface{}, error) {
36 pure := pass.ResultOf[purity.Analyzer].(purity.Result)
37
38 fn := func(node ast.Node) {
39 assign := node.(*ast.AssignStmt)
40 if assign.Tok != token.ASSIGN || len(assign.Lhs) != len(assign.Rhs) {
41 return
42 }
43 for i, lhs := range assign.Lhs {
44 rhs := assign.Rhs[i]
45 if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) {
46 continue
47 }
48 if code.MayHaveSideEffects(pass, lhs, pure) || code.MayHaveSideEffects(pass, rhs, pure) {
49 continue
50 }
51
52 rlh := report.Render(pass, lhs)
53 rrh := report.Render(pass, rhs)
54 if rlh == rrh {
55 report.Report(pass, assign, fmt.Sprintf("self-assignment of %s to %s", rrh, rlh), report.FilterGenerated())
56 }
57 }
58 }
59 code.Preorder(pass, fn, (*ast.AssignStmt)(nil))
60 return nil, nil
61 }
62