-
Notifications
You must be signed in to change notification settings - Fork 468
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement linter for checking 1>>x expressions
- Loading branch information
Showing
10 changed files
with
130 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package main | ||
|
||
import ( | ||
"go/ast" | ||
"go/token" | ||
"reflect" | ||
|
||
"golang.org/x/tools/go/analysis" | ||
"golang.org/x/tools/go/analysis/singlechecker" | ||
) | ||
|
||
var Analyzer = &analysis.Analyzer{ | ||
Name: "rightshift", | ||
Doc: "check for 1 >> x operation", | ||
Run: func(p *analysis.Pass) (interface{}, error) { return run(false, p) }, | ||
ResultType: reflect.TypeOf(Result{}), | ||
} | ||
|
||
var analyzerForTests = &analysis.Analyzer{ | ||
Name: "testrightshift", | ||
Doc: "check for pointer comparison (for tests)", | ||
Run: func(p *analysis.Pass) (interface{}, error) { return run(true, p) }, | ||
ResultType: reflect.TypeOf(Result{}), | ||
} | ||
|
||
// rightShiftError indicates the position of pointer comparison. | ||
type rightShiftError struct { | ||
Pos token.Position | ||
Message string | ||
} | ||
|
||
// Result is returned from the checkStruct function, and holds all rightshift | ||
// operations. | ||
type Result struct { | ||
Errors []rightShiftError | ||
} | ||
|
||
func run(dryRun bool, pass *analysis.Pass) (interface{}, error) { | ||
var ret Result | ||
for _, f := range pass.Files { | ||
ast.Inspect(f, func(node ast.Node) bool { | ||
be, ok := node.(*ast.BinaryExpr) | ||
if !ok { | ||
return true | ||
} | ||
// Check if the expression is '1 >> x'. | ||
if be.Op == token.SHR && isOne(be.X) { | ||
err := rightShiftError{ | ||
Pos: pass.Fset.Position(be.Pos()), | ||
Message: "found rightshift ('1 >> x') expression, did you mean '1 << x' ?", | ||
} | ||
ret.Errors = append(ret.Errors, err) | ||
if !dryRun { | ||
pass.Report(analysis.Diagnostic{ | ||
Pos: pass.Fset.File(f.Pos()).Pos(err.Pos.Offset), | ||
Message: err.Message, | ||
Category: "pointercheck", | ||
}) | ||
} | ||
} | ||
return true | ||
}, | ||
) | ||
} | ||
return ret, nil | ||
} | ||
|
||
// isOne checks if the expression is a constant 1. | ||
func isOne(expr ast.Expr) bool { | ||
bl, ok := expr.(*ast.BasicLit) | ||
return ok && bl.Kind == token.INT && bl.Value == "1" | ||
} | ||
|
||
func main() { | ||
singlechecker.Main(Analyzer) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package main | ||
|
||
import ( | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
"golang.org/x/tools/go/analysis/analysistest" | ||
) | ||
|
||
func TestAll(t *testing.T) { | ||
wd, err := os.Getwd() | ||
if err != nil { | ||
t.Fatalf("Failed to get working directory: %v", err) | ||
} | ||
testdata := filepath.Join(filepath.Dir(wd), "testdata") | ||
res := analysistest.Run(t, testdata, analyzerForTests, "rightshift") | ||
want := []int{6, 11, 12} | ||
got := erroLines(res) | ||
if diff := cmp.Diff(want, got); diff != "" { | ||
t.Errorf("analysistest.Ru() unexpected diff in error lines:\n%s\n", diff) | ||
} | ||
} | ||
|
||
func erroLines(errs []*analysistest.Result) []int { | ||
var ret []int | ||
for _, e := range errs { | ||
if r, ok := e.Result.(Result); ok { | ||
for _, err := range r.Errors { | ||
ret = append(ret, err.Pos.Line) | ||
} | ||
} | ||
} | ||
return ret | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package rightshift | ||
|
||
import "fmt" | ||
|
||
func doThing(v int) int { | ||
return 1 >> v // Error: Ln: 6 | ||
} | ||
|
||
func calc() { | ||
val := 10 | ||
fmt.Printf("%v", 1>>val) // Error: Ln 11 | ||
_ = doThing(1 >> val) // Error: Ln 12 | ||
fmt.Printf("%v", 1<<val) // valid | ||
} |