Skip to content

Commit

Permalink
checkers: add octalLiteral checker (go-critic#798)
Browse files Browse the repository at this point in the history
  • Loading branch information
ludweeg authored and quasilyte committed Feb 4, 2019
1 parent 4adbf9a commit 07de34a
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 0 deletions.
82 changes: 82 additions & 0 deletions checkers/octalLiteral_checker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package checkers

import (
"go/ast"
"go/token"
"go/types"

"github.com/go-lintpack/lintpack"
"github.com/go-lintpack/lintpack/astwalk"
"github.com/go-toolsmith/astcast"
)

func init() {
var info lintpack.CheckerInfo
info.Name = "octalLiteral"
info.Tags = []string{"diagnostic", "experimental"}
info.Summary = "Detects octal literals passed to functions"
info.Before = `foo(02)`
info.After = `foo(2)`

collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
c := &octalLiteralChecker{
ctx: ctx,
octFriendlyPkg: map[string]bool{
"os": true,
"io/ioutil": true,
},
}
return astwalk.WalkerForExpr(c)
})
}

type octalLiteralChecker struct {
astwalk.WalkHandler
ctx *lintpack.CheckerContext

octFriendlyPkg map[string]bool
}

func (c *octalLiteralChecker) VisitExpr(expr ast.Expr) {
call := astcast.ToCallExpr(expr)
calledExpr := astcast.ToSelectorExpr(call.Fun)
ident := astcast.ToIdent(calledExpr.X)

if obj, ok := c.ctx.TypesInfo.ObjectOf(ident).(*types.PkgName); ok {
pkg := obj.Imported()
if c.octFriendlyPkg[pkg.Path()] {
return
}
}

for _, arg := range call.Args {
if lit := astcast.ToBasicLit(c.unsign(arg)); len(lit.Value) > 1 &&
c.isIntLiteral(lit) &&
c.isOctalLiteral(lit) {
c.warn(call)
return
}
}
}

func (c *octalLiteralChecker) unsign(e ast.Expr) ast.Expr {
u, ok := e.(*ast.UnaryExpr)
if !ok {
return e
}
return u.X
}

func (c *octalLiteralChecker) isIntLiteral(lit *ast.BasicLit) bool {
return lit.Kind == token.INT
}

func (c *octalLiteralChecker) isOctalLiteral(lit *ast.BasicLit) bool {
return lit.Value[0] == '0' &&
lit.Value[1] != 'x' &&
lit.Value[1] != 'X'
}

func (c *octalLiteralChecker) warn(expr ast.Expr) {
c.ctx.Warn(expr, "suspicious octal args in `%s`", expr)
}
76 changes: 76 additions & 0 deletions checkers/testdata/octalLiteral/negative_tests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package checker_test

import (
"io/ioutil"
"log"
"math"
"os"
)

func calculateInt(x int) int {
return x
}

func calculateHex(x int) int {
return x
}

func calculateFloat(x float64) float64 {
return x
}

func calculateString(x string) string {
return x
}

func calculateIntPair(x, y int) (int, int) {
return x, y
}

func NoWarningsCalc() {
_ = calculateInt(0)
_ = calculateInt(1)
_ = calculateInt(+1)
_ = calculateInt(-1)
_ = calculateInt(12)
_ = calculateInt(1 + 2)

var int x = 03
_ = calculateInt(x)

_ = calculateHex(0x0)
_ = calculateHex(0X42)
_ = calculateHex(0xAA1)
_ = calculateHex(-0xaa1)

_ = calculateFloat(0.2)
_ = calculateFloat(+0.2)
_ = calculateFloat(-0.2)

_ = calculateString("1")
_ = calculateString("01")
_ = calculateString("0.1")

_ = calculateIntPair(1, 2)
_ = calculateIntPair(-1, 2)
_ = calculateIntPair(0, 2)

_ = math.Exp(12)
_ = math.Exp(0x12)
_ = math.Max(12, 0xd)
_ = math.Min(0, 1)
}

func NoWarningsOs() {
f, err := os.OpenFile("notes.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
log.Fatal(err)
}
if err := f.Close(); err != nil {
log.Fatal(err)
}
}

func NoWarningsIoutil() {
_ = ioutil.WriteFile("notes.txt", []byte(), 0666)
}
77 changes: 77 additions & 0 deletions checkers/testdata/octalLiteral/positive_tests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package checker_test

import (
"math"
)

func calculateInt(x int) int {
return x
}

func calculateIntPair(x, y int) (int, int) {
return x, y
}

func calculateManyArgs(x int, s string, y int) (int, string, int) {
return x, s, y
}

func warningsCalc() {
/*! suspicious octal args in `calculateInt(00)` */
_ = calculateInt(00)

/*! suspicious octal args in `calculateInt(+01)` */
_ = calculateInt(+01)

/*! suspicious octal args in `calculateInt(-01)` */
_ = calculateInt(-01)

/*! suspicious octal args in `calculateInt(012)` */
_ = calculateInt(calculateInt(012))

/*! suspicious octal args in `calculateIntPair(01, 2)` */
_ = calculateIntPair(01, 2)

/*! suspicious octal args in `calculateIntPair(-1, -012)` */
_ = calculateIntPair(-1, -012)

/*! suspicious octal args in `calculateIntPair(01, 02)` */
_ = calculateIntPair(01, 02)

/*! suspicious octal args in `calculateInt(01)` */
/*! suspicious octal args in `calculateInt(02)` */
_ = calculateIntPair(calculateInt(01), calculateInt(02))

/*! suspicious octal args in `calculateIntPair(01, calculateInt(02))` */
/*! suspicious octal args in `calculateInt(02)` */
_ = calculateIntPair(01, calculateInt(02))

/*! suspicious octal args in `calculateManyArgs(11, "12", 013)` */
_ = calculateManyArgs(11, "12", 013)

/*! suspicious octal args in `calculateManyArgs(-02, "3", -04)` */
_ = calculateManyArgs(-02, "3", -04)

/*! suspicious octal args in `math.Exp(012)` */
_ = math.Exp(012)

/*! suspicious octal args in `math.Max(12, 01)` */
_ = math.Max(12, 01)

/*! suspicious octal args in `math.Max(1, 01)` */
_ = math.Max(1, math.Max(1, 01))
}

type OpenServer struct {
x int
}

func (os *OpenServer) Init(x int) {
os.x = x
}

func warningsOs() {
var os OpenServer
/*! suspicious octal args in `os.Init(02)` */
os.Init(02)
}

0 comments on commit 07de34a

Please sign in to comment.