-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add static analysis to enforce usage of InitWithReset (#5654)
* Refactor attestation packing slightly to reduce the skip slot / HTR of process slots * Merge branch 'master' into refactor-attestation-packing * gofmt * Merge branch 'refactor-attestation-packing' of github.com:prysmaticlabs/prysm into refactor-attestation-packing * Merge branch 'master' of github.com:prysmaticlabs/prysm into refactor-attestation-packing * Add static analysis to enforce usage of InitWithReset * Add comment / lint * fix a few usages * more fixes for featureconfig.Init * Fix analyzer * Merge branch 'sa-fc-init' of github.com:prysmaticlabs/prysm into sa-fc-init * Merge refs/heads/master into sa-fc-init * Merge refs/heads/master into sa-fc-init
- Loading branch information
1 parent
6700383
commit e30349d
Showing
11 changed files
with
151 additions
and
23 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,25 @@ | ||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_tool_library") | ||
|
||
go_library( | ||
name = "go_default_library", | ||
srcs = ["analyzer.go"], | ||
importpath = "github.com/prysmaticlabs/prysm/tools/analyzers/featureconfig", | ||
visibility = ["//visibility:public"], | ||
deps = [ | ||
"@org_golang_x_tools//go/analysis:go_default_library", | ||
"@org_golang_x_tools//go/analysis/passes/inspect:go_default_library", | ||
"@org_golang_x_tools//go/ast/inspector:go_default_library", | ||
], | ||
) | ||
|
||
go_tool_library( | ||
name = "go_tool_library", | ||
srcs = ["analyzer.go"], | ||
importpath = "featureconfig", | ||
visibility = ["//visibility:public"], | ||
deps = [ | ||
"@org_golang_x_tools//go/analysis:go_tool_library", | ||
"@org_golang_x_tools//go/analysis/passes/inspect:go_tool_library", | ||
"@org_golang_x_tools//go/ast/inspector:go_tool_library", | ||
], | ||
) |
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,91 @@ | ||
package featureconfig | ||
|
||
import ( | ||
"errors" | ||
"go/ast" | ||
"go/token" | ||
"golang.org/x/tools/go/analysis" | ||
"golang.org/x/tools/go/analysis/passes/inspect" | ||
"golang.org/x/tools/go/ast/inspector" | ||
) | ||
|
||
// Doc explaining the tool. | ||
const Doc = "Enforce usage of featureconfig.InitWithReset to prevent leaking globals in tests." | ||
|
||
// Analyzer runs static analysis. | ||
var Analyzer = &analysis.Analyzer{ | ||
Name: "featureconfig", | ||
Doc: Doc, | ||
Requires: []*analysis.Analyzer{inspect.Analyzer}, | ||
Run: run, | ||
} | ||
|
||
func run(pass *analysis.Pass) (interface{}, error) { | ||
inspect, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) | ||
if !ok { | ||
return nil, errors.New("analyzer is not type *inspector.Inspector") | ||
} | ||
|
||
nodeFilter := []ast.Node{ | ||
(*ast.CallExpr)(nil), | ||
(*ast.ExprStmt)(nil), | ||
(*ast.GoStmt)(nil), | ||
(*ast.DeferStmt)(nil), | ||
(*ast.AssignStmt)(nil), | ||
} | ||
|
||
inspect.Preorder(nodeFilter, func(node ast.Node) { | ||
if ce, ok := node.(*ast.CallExpr); ok && isPkgDot(ce.Fun, "featureconfig", "Init") { | ||
reportForbiddenUsage(pass, ce.Pos()) | ||
return | ||
} | ||
switch stmt := node.(type) { | ||
case *ast.ExprStmt: | ||
if call, ok := stmt.X.(*ast.CallExpr); ok&& isPkgDot(call.Fun, "featureconfig", "InitWithReset"){ | ||
reportUnhandledReset(pass, call.Lparen) | ||
} | ||
case *ast.GoStmt: | ||
if isPkgDot(stmt.Call, "featureconfig", "InitWithReset") { | ||
reportUnhandledReset(pass, stmt.Call.Lparen) | ||
} | ||
case *ast.DeferStmt: | ||
if isPkgDot(stmt.Call, "featureconfig", "InitWithReset") { | ||
reportUnhandledReset(pass, stmt.Call.Lparen) | ||
} | ||
case *ast.AssignStmt: | ||
if ce, ok := stmt.Rhs[0].(*ast.CallExpr); ok && isPkgDot(ce.Fun, "featureconfig", "InitWithReset") { | ||
for i := 0; i < len(stmt.Lhs); i++ { | ||
if id, ok := stmt.Lhs[i].(*ast.Ident); ok { | ||
if id.Name == "_" { | ||
reportUnhandledReset(pass, id.NamePos) | ||
} | ||
} | ||
} | ||
} | ||
default: | ||
} | ||
}) | ||
|
||
return nil, nil | ||
} | ||
|
||
func reportForbiddenUsage(pass *analysis.Pass, pos token.Pos) { | ||
pass.Reportf(pos, "Use of featureconfig.Init is forbidden in test code. Please use " + | ||
"featureconfig.InitWithReset and call reset in the same test function.") | ||
} | ||
|
||
func reportUnhandledReset(pass *analysis.Pass, pos token.Pos) { | ||
pass.Reportf(pos, "Unhandled reset featureconfig not found in test " + | ||
"method. Be sure to call the returned reset function from featureconfig.InitWithReset " + | ||
"within this test method.") | ||
} | ||
|
||
func isPkgDot(expr ast.Expr, pkg, name string) bool { | ||
sel, ok := expr.(*ast.SelectorExpr) | ||
return ok && isIdent(sel.X, pkg) && isIdent(sel.Sel, name) | ||
} | ||
|
||
func isIdent(expr ast.Expr, ident string) bool { | ||
id, ok := expr.(*ast.Ident) | ||
return ok && id.Name == ident | ||
} |
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