
This update should fix go get issues because of deps. go-critic: $ git cherry -v c3db6069acc5 + fe28ac328f474c02e2383ca2bf44a606929a7048 checkers: add integration tests with cgo for dupImports (#846) + 48a15b03b630252319474ba5ddc8455d2aebf34f checkers: fix fold-ranges for floats in boolExprSimplify (#849) + 7bf73388643eb226addf2d5ed8a2c104be244b2e checkers: fix "Output:" false positive in commentedOutCode (#852) + f6f702b31734df26415c2bd135f272d1a34d2973 checkers: extend yodaStyleExpr supported ops list (#856) + 07bf84df361735ad1d90f84e79eb60c8386325c7 fix dependencies (#857) + 1df30086654074503eab008bdde4f3ce1921128d checkers: fix collection URL (#860) x/tools: $ git cherry -v 685fecacd0a0 521d6ed310dd | fgrep -v internal/lsp + fe54fb35175bb1c0c175e2335e23d7fa90ca987a apidiff: represent a Report as a list of Changes + 15bbd99efc6f20619676dec93f914d12e5139e83 all: run go mod tidy + bb3b3ca95aec36bfc4a5cb10b58022e64aca735b go/packages: add some documentation for extractPackage + 4bf14f7f0668366a4275c6ef5e99bd8e807da1d3 internal/span: fix off-by-one in ToUTF16Column + cb2dda6eabdf9160e66ca7293897f984154a7f8b go/packages: deduplicate file parsing + 9e44c1c403071e0c2831952513e7b948587d94af go/internal/gccgoimporter: update package to match std lib version + 36563e24a2627da92566d43aa1c7a2dd895fc60d cmd/vet: verify potentially-recursive Stringers are actually Stringers + 31fd60d6bfdcfb2861856aa5b333bb135f6bbfd8 x/tools/go/packages/packagestest: fix GOPROXY file URLs for Windows + 2d660fb8a000e1c288dc2f2150401b364922ebe9 go/packages/packagestest: fix GOPROXY file URLs for Windows + 7af746645d5165109de0b5cb499980c22812dfc2 internal/span: fix another off-by-one in ToUTF16Column + 9d4d845e86f14303813298ede731a971dd65b593 cmd/goimports: add -format-only flag + 83df196e5764ed2415c28c1f39ba6cb3db747da0 internal/span: add a filename only print for spans + 5cec639030af3a6ada2732d9bfa1d3731ed55106 go/analysis: proposed fact enumeration API + 9cb3dcf692a103de0fd68c26f4f04183e0933f7c internal/span: update the offset if the end offset should be valid but is not + 2d16b83fe98cd1bed9e2ce9fdc86bd438d14aab7 go/vcs: ignore "mod" VCS type + 95299016986435f846545c27f956768ad3c3cb2f lostcancel: do not analyze cancel variable which defined outside current function scope + 8a42e17289ea392d63892321ce1f40bd07efcc9f compilebench: clean up different benchmark types + eeb76a0c47a3b97e99f330dc14174ef14777d2ba compilebench: factor running build tool commands + 60140f09094406e46618ef436a26dd8394983503 compilebench: add a linker benchmark + e31d36578abb3d202c4007c3747bf8ebb7c51011 compilebench: handle missing MemStats more gracefully + d996b19ee77cd9c8df974510f23b0696cedf1ca1 go/analysis/analysistest: fix word usage + 73554e0f78058c37e5421bc48273a72400172221 go/analysis/passes: fix bugs discovered in std + 35884eef200b5fc81c9044f644a8d9d911262488 cmd/vet: print help to stdout only + 45e43b2cb4facd370abb846ebf35575161849f3b go/packages/packagestest: fix MustCopyFileTree so that file fragments are always slash form + d81a07b7e58487eed036bf115fa834653590d6cd go/analysis/passes/bools: eliminate quadratic runtime, output + 2a413a02cc735933997fa1b467a7b27bc1b82567 godoc/static: let client use vet check returned by /compile endpoint + 4789ca9922f080dd3a8fc3c74df1c1306db2bb0b go/analysis/internal/analysisflags: call gob.Register on deleted analyzers + d1a3278ee74994e9aa609e9e711c616bba677d5d godoc/util: serve SVG files raw + 1da8801a9502f29f3f03edfc3149b947e6e1913c godoc: declare small victory over the punched card tyranny + 757ca719ca9689950c69081c10c5300fbb8e35db imports: rename to internal/imports + 0133cac3176f225883c5d817146de8633ed07ebc cmd/goimports: reuse cached state + 26647e34d3c04fd3eaef6fb824493b00af7b1b26 imports: allow nil Options in Process
158 lines
3.7 KiB
Go
158 lines
3.7 KiB
Go
package checkers
|
|
|
|
import (
|
|
"fmt"
|
|
"go/ast"
|
|
"go/token"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/go-lintpack/lintpack"
|
|
"github.com/go-lintpack/lintpack/astwalk"
|
|
"github.com/go-toolsmith/strparse"
|
|
)
|
|
|
|
func init() {
|
|
var info lintpack.CheckerInfo
|
|
info.Name = "commentedOutCode"
|
|
info.Tags = []string{"diagnostic", "experimental"}
|
|
info.Summary = "Detects commented-out code inside function bodies"
|
|
info.Before = `
|
|
// fmt.Println("Debugging hard")
|
|
foo(1, 2)`
|
|
info.After = `foo(1, 2)`
|
|
|
|
collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
|
|
return astwalk.WalkerForLocalComment(&commentedOutCodeChecker{
|
|
ctx: ctx,
|
|
notQuiteFuncCall: regexp.MustCompile(`\w+\s+\([^)]*\)\s*$`),
|
|
})
|
|
})
|
|
}
|
|
|
|
type commentedOutCodeChecker struct {
|
|
astwalk.WalkHandler
|
|
ctx *lintpack.CheckerContext
|
|
fn *ast.FuncDecl
|
|
|
|
notQuiteFuncCall *regexp.Regexp
|
|
}
|
|
|
|
func (c *commentedOutCodeChecker) EnterFunc(fn *ast.FuncDecl) bool {
|
|
c.fn = fn // Need to store current function inside checker context
|
|
return fn.Body != nil
|
|
}
|
|
|
|
func (c *commentedOutCodeChecker) VisitLocalComment(cg *ast.CommentGroup) {
|
|
s := cg.Text() // Collect text once
|
|
|
|
// We do multiple heuristics to avoid false positives.
|
|
// Many things can be improved here.
|
|
|
|
markers := []string{
|
|
"TODO", // TODO comments with code are permitted.
|
|
|
|
// "http://" is interpreted as a label with comment.
|
|
// There are other protocols we might want to include.
|
|
"http://",
|
|
"https://",
|
|
|
|
"e.g. ", // Clearly not a "selector expr" (mostly due to extra space)
|
|
}
|
|
for _, m := range markers {
|
|
if strings.Contains(s, m) {
|
|
return
|
|
}
|
|
}
|
|
|
|
// Some very short comment that can be skipped.
|
|
// Usually triggering on these results in false positive.
|
|
// Unless there is a very popular call like print/println.
|
|
cond := len(s) < len("quite too short") &&
|
|
!strings.Contains(s, "print") &&
|
|
!strings.Contains(s, "fmt.") &&
|
|
!strings.Contains(s, "log.")
|
|
if cond {
|
|
return
|
|
}
|
|
|
|
// Almost looks like a commented-out function call,
|
|
// but there is a whitespace between function name and
|
|
// parameters list. Skip these to avoid false positives.
|
|
if c.notQuiteFuncCall.MatchString(s) {
|
|
return
|
|
}
|
|
|
|
stmt := strparse.Stmt(s)
|
|
|
|
if c.isPermittedStmt(stmt) {
|
|
return
|
|
}
|
|
|
|
if stmt != strparse.BadStmt {
|
|
c.warn(cg)
|
|
return
|
|
}
|
|
|
|
// Don't try to parse one-liner as block statement
|
|
if len(cg.List) == 1 && !strings.Contains(s, "\n") {
|
|
return
|
|
}
|
|
|
|
// Some attempts to avoid false positives.
|
|
if c.skipBlock(s) {
|
|
return
|
|
}
|
|
|
|
// Add braces to make block statement from
|
|
// multiple statements.
|
|
stmt = strparse.Stmt(fmt.Sprintf("{ %s }", s))
|
|
|
|
if stmt, ok := stmt.(*ast.BlockStmt); ok && len(stmt.List) != 0 {
|
|
c.warn(cg)
|
|
}
|
|
}
|
|
|
|
func (c *commentedOutCodeChecker) skipBlock(s string) bool {
|
|
lines := strings.Split(s, "\n") // There is at least 1 line, that's invariant
|
|
|
|
// Special example test block.
|
|
if isExampleTestFunc(c.fn) && strings.Contains(lines[0], "Output:") {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (c *commentedOutCodeChecker) isPermittedStmt(stmt ast.Stmt) bool {
|
|
switch stmt := stmt.(type) {
|
|
case *ast.ExprStmt:
|
|
return c.isPermittedExpr(stmt.X)
|
|
case *ast.LabeledStmt:
|
|
return c.isPermittedStmt(stmt.Stmt)
|
|
case *ast.DeclStmt:
|
|
decl := stmt.Decl.(*ast.GenDecl)
|
|
return decl.Tok == token.TYPE
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (c *commentedOutCodeChecker) isPermittedExpr(x ast.Expr) bool {
|
|
// Permit anything except expressions that can be used
|
|
// with complete result discarding.
|
|
switch x := x.(type) {
|
|
case *ast.CallExpr:
|
|
return false
|
|
case *ast.UnaryExpr:
|
|
// "<-" channel receive is not permitted.
|
|
return x.Op != token.ARROW
|
|
default:
|
|
return true
|
|
}
|
|
}
|
|
|
|
func (c *commentedOutCodeChecker) warn(cause ast.Node) {
|
|
c.ctx.Warn(cause, "may want to remove commented-out code")
|
|
}
|