Coder Social home page Coder Social logo

go-critic / go-critic Goto Github PK

View Code? Open in Web Editor NEW
1.8K 22.0 112.0 3.69 MB

The most opinionated Go source code linter for code audit.

Home Page: https://go-critic.com

License: MIT License

Go 98.97% Makefile 1.03%
linter golang go style-checker conventions idiomatic-go lintpack go-lintpack hacktoberfest ruleguard

go-critic's Introduction

go-critic

Build Status Awesome Go Report Card coverage PRs Welcome

Highly extensible Go source code linter providing checks currently missing from other linters.

Logo

There is never too much static code analysis. Try it out.

Features

  • Almost 100 diagnostics that check for bugs, performance and style issues
  • Extensible without re-compilation with dynamic rules
  • Includes #opinionated checks with very strict and specific requirements
  • Self-documented: gocritic doc <checkname> gives a checker description

Documentation

The latest documentation is available at go-critic.com.

Installation

For most users, using go-critic under golangci-lint is enough.

Precompiled go-critic binaries can be found at releases page.

It can be installed in the usual Go way by running:

go install -v github.com/go-critic/go-critic/cmd/gocritic@latest

To build go-critic from sources, clone this repository and run make gocritic.

On macOS, you can also install go-critic using MacPorts: sudo port install go-critic

Usage

Be sure gocritic executable is under your $PATH.

Usage of gocritic: gocritic [sub-command] [sub-command args...] Run gocritic without arguments to get help output.

Supported sub-commands:
	check - run linter over specified targets
		$ gocritic check -help
		$ gocritic check -v -enable='paramTypeCombine,unslice' strings bytes
		$ gocritic check -v -enable='#diagnostic' -disable='#experimental,#opinionated' ./...
	version - print linter version
		$ gocritic version
	doc - get installed checkers documentation
		$ gocritic doc -help
		$ gocritic doc
		$ gocritic doc checkerName

check sub-command examples:

# Runs all stable checkers on `fmt` package:
gocritic check fmt

# Run all stable checkers on `pkg1` and `pkg2`
gocritic check pkg1 pkg2

# Run all stable checkers on `fmt` package and configure rangeExprCopy checker
gocritic check [email protected] 128 fmt

# Runs specified checkers on `fmt` package:
gocritic check -enable elseif,paramName fmt

# Run all stable checkers on current dir and all its children recursively:
gocritic check ./...

# Like above, but without `appendAssign` check:
gocritic check -disable=appendAssign ./...

# Run all stable checkers on `foo.go` file:
gocritic check foo.go

# Run stable diagnostics over `strings` package:
gocritic check -enable='#diagnostic' -disable='#experimental' strings

# Run all stable and non-opinionated checks:
gocritic check -enableAll -disable='#experimental,#opinionated' ./src/...

To get a list of available checker parameters, run gocritic doc <checkerName>.

In place of a single name, tag can be used. Tag is a named checkers group.

Tags:

  • #diagnostic - kind of checks that detect various errors in code
  • #style - kind of checks that find style issues in code
  • #performance - kind of checks that detect potential performance issues in code
  • #experimental - check is under testing and development. Disabled by default
  • #opinionated - check can be unwanted for some people. Disabled by default
  • #security - kind of checks that find security issues in code. Disabled by default and empty, so will fail if enabled.

Contributing

This project aims to be contribution-friendly.

Our chats: English or Russian (Telegram website)

We're using an optimistic merging strategy most of the time. In short, this means that if your contribution has some flaws, we can still merge it and then fix them by ourselves. Experimental and work-in-progress checkers are isolated, so nothing bad will happen.

Code style is the same as in Go project, see CodeReviewComments.

See CONTRIBUTING.md for more details. It also describes how to develop a new checker for the linter.

go-critic's People

Contributors

alexandear avatar atul9 avatar breml avatar bubblesupreme avatar cristaloleg avatar dependabot[bot] avatar dmirogin avatar ewgra avatar fexolm avatar greenhorse avatar helcaraxan avatar janisz avatar lasiar avatar levospennikov avatar liamg avatar ludweeg avatar mashadzhan avatar mcdoker18 avatar neverik avatar nexomichael avatar peakle avatar quasilyte avatar sebastien-rosset avatar snargleplax avatar sosiska avatar tamaravedenina avatar tdakkota avatar tmzane avatar uncleandy avatar weeellz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-critic's Issues

lint: add unnecessary brackets checker

We need to add checker which will find the errors described below.

  • var _ [n](*int) ===>> var _ [n]*int
  • *(name).field ===>> name.field (moved to #14.)
  • var _ (func()) ===>> var _ func()
  • func(...) (...) ===>> func(...) ...
  • (*a)[i] where a is an array (moved to #14.)

lint: parenthesis suggests to simplify size expressions inside array types

cmd/internal/obj/x86/asm6.go:2043:14: parenthesis: could simplify (ALAST + 1) to ALAST + 1

[(A + B)]int is an array of ints with size A+B.
Expressions can be complex and it's not quite right to trigger on them.

I don't remember any other cases except for array types, so maybe all what is required is to avoid array type length checks.

	ArrayType struct {
		Lbrack token.Pos // position of "["
		Len    Expr      // Ellipsis node for [...]T array types, nil for slice types
		Elt    Expr      // element type
	}

parenthesis should not visit ArrayType.Len.

lint/parenthesis_checker.go: improve output

Right now output looks like:
func(..) [](func())) ===>> func())
but should be
[]func()

Also, we need to improve suggestions for complex types like []([]([](func()))))
now, we suggest to get rid of one pair of parenthesis, but we can do better.

cmd/kfulint: type checking error on stdlib packages

Many stdlib packages cause linter to give up with type checking error.
Most likely, it's because we run Check incorrectly (maybe we should consider build tags or something).

Here is output for math package:

./bin/kfulint -dir=$GOROOT/src/math
skip math: type check error: $GOROOTsrc/math/sincos_386.go:13:6: Sincos redeclared in this block
skip math_test: type check error: $GOROOTsrc/math/all_test.go:3557:7: undeclared name: SqrtGo

There are many other packages with similar problem:

  • runtime (re-definitions of symbols)
  • net (imports "C")
  • net/http (undeclared name)

Other peculiar errors:

bufio:
scan_test.go:408:10: invalid operation: scanner (variable of type *bufio.Scanner) has no field or method MaxTokenSize

bytes:
bytes_test.go:577:31: undeclared name: EqualPortable

context:
context/x_test.go:29:58: undeclared name: XTestDeadlineExceededSupportsTimeout

crypto:
ase/cipher_ppc64le.go:27:6: encryptBlockAsm redeclared in this block
crypto/rand/rand_js.go:9:8: could not import syscall/js (can't find import: "syscall/js")
rc4/rc4_asm.go:13:18: method XORKeyStream already declared for type Cipher struct{s [256]uint32; i uint8; j uint8}
x509/root_darwin_arm_gen.go:38:6: main redeclared in this block
x509/root_cgo_darwin.go:221:8: could not import C (can't find import: "C")

These issues may be related or not.
This needs investigation.

all: fix linter warnings

cmd/kfulint/main.go:47:12:warning: parameter format always receives "Illegal empty -dir argument\n" (unparam)
lint/parenthesis-checker.go:70::warning: line is 116 characters (lll)
lint/type-guard_checker.go:21::warning: line is 81 characters (lll)
lint/type-guard_checker.go:89::warning: line is 83 characters (lll)
lint/type-guard_checker.go:101::warning: line is 87 characters (lll)
lint/internal/astfilter/astfilter.go:1::warning: line is 84 characters (lll)

lint: add intbool checker

Find integer-typed values that only receive 2 values (so, 2 states in total).
Suggest replacing them with bool.

This requires being conservative to avoid too much false-positives.

Example:

	x := 0
	if expr() > 10 {
		x = 1
	}
	return x != 0
// consider making `x' a boolean

This implies that suggested code could look like:

	x := false
	if expr() > 10 {
		x = true
	}
	return x

This whole code can be simplified to return expr() > 10, but that's irrelevant.

The checker should also detect struct fields that have integer type, but only used in boolean contexts (x != 0, x == 1, etc.).

docs: add CONTRIBUTING.md

We may need to add smth like contribution guideline which would formalize our workflow.
For example: we may add label "in progress" if someone currently working on task and remove it when switch on the other task.
It could save a lot of time if every team member would follow that rules.

lint: add type switch -> if suggestions for 1-case statements

If type switch has only 1 case, it can be replaced with if statement.

This code triggers a warning:

func intValue(x interface{}) int {
	switch x := x.(type) {
	case int:
		return x
	}
	return 0
}

Suggested alternative:

func intValueSuggested(x interface{}) int {
	if x, ok := x.(int); ok {
		return x
	}
	return 0
}

all: figure-out project name and logo

kfulint is a working name, not a final one.
When we know which name we like, it would be a time to find logo (or mascot).

We may also want to rename organization.. For reasons.
We also need a new organization that is dedicated for Go linter only.

Proposed organization names:

  • Infrared October (repo/org infrared-october)
  • multilint (repo/org go-multilint)
  • critic, critique, gritic, critig, crigeek (repo/org with "go-" prefix)
  • adviser/advisor/advicer (repo/org with "go-" prefix)

cmd/kfulint: improve test coverage for checkers

Please consider adding more corner cases for checkers.
One that can potentially cause panic or are not working/detectable yet are especially useful.

This is important to do it before we get too much untested checkers.
So, let's not implement anything outside of v0.1 milestone until we're finished with this.
This will be a closing issue for v0.1 when everything else is completed.

This issue should be referenced from every related commit.

all: add support for "experimental" checkers

Experimental checkers would not run by default.
It can be implemented this way: if "all" checkers are enabled, we still check whether particular checker is experimental or not. It it's experimental, include it only if special -experimental flag is passed to kfulint.

This will make it possible to commit partially completed checkers that lack testing or fail (panic) in some circumstances.

lint: add constexpr->named constant checker

Find constexprs that produce recognizable value that have named constant in stdlib.

Examples of such expressions:

unsafe.Sizeof(int(0)) => bits.UintSize
unsafe.Sizeof(uint(0)) => bits.UintSize

// We should check for expression result, not it's AST,
// so all of these are handled by a single rule:
(1<<31 - 1) => math.MaxInt32
0x7FFFFFFF => math.MaxInt32
2147483645+1+1 => math.MaxInt32

lint: add underef checker

Find dereference expressions (ast.StarExpr) that can be simplified.

All these cases must be detected:

/*1*/ (*x)[i] => x[i] // If `x` is an array
/*2*/ (*p).f  => p.f  // If `p` is a pointer to type with `f` field

There could be more.

lint: param-duplication gives weird output for mixed arg styles

If some argument types are duplicated and the others are not, param-duplication gives quite strange message (hard to read and commas are misplaced).

For example:

func ToText(w io.Writer, text string, indent, preIndent string, width int) {
/bin/kfulint -dir=$GOROOT/src/go/doc
$GOROOT/src/go/doc/comment.go:410:1: param-duplication/Duplication: text string, indent ,preIndent string could be replaced with text, indent ,preIndent string

lint: add index-only range loops checker

If range loop is iterating over container which has pointer-type elements (that is, any *T or reference-like type as map or chan) using only key variable (no value) and container[key] occurs more than once inside loop body, suggest using for key, v := range container form.

This code triggers a warning:

func closeFiles(files []*os.File) {
	for i := range files {
		if files[i] != nil {
			files[i].Close()
		}
	}
}

This is suggested form:

func closeFilesSuggester(files []*os.File) {
	for _, f := range files {
		if f != nil {
			f.Close()
		}
	}
}

lint: add "fat" value copy in range loops

When iterating with for-range with value variable, one should be careful to avoid unexpected performance drops.

Simple example:

type fat struct {
	body [1024]byte
	x    int
}

func fatCopy(xs []fat) int {
	v := 0
	for _, x := range xs {
		v += x.x
	}
	return v
}

func fatIndex(xs []fat) int {
	v := 0
	for i := range xs {
		v += xs[i].x
	}
	return v
}

First fatCopy does 1000+ bytes copy every iteration.
fatIndex does no copy (it reads from proper offset instead).

We should warn if values bigger than X are being iterated over.

Disasm:

"".fatCopy STEXT size=218 args=0x20 locals=0x818
	00000 (GOPATH/src/main/foo.go:8)	TEXT	"".fatCopy(SB), $2072-32
	00000 (GOPATH/src/main/foo.go:8)	MOVQ	(TLS), CX
	00009 (GOPATH/src/main/foo.go:8)	LEAQ	-1944(SP), AX
	00017 (GOPATH/src/main/foo.go:8)	CMPQ	AX, 16(CX)
	00021 (GOPATH/src/main/foo.go:8)	JLS	208
	00027 (GOPATH/src/main/foo.go:8)	SUBQ	$2072, SP
	00034 (GOPATH/src/main/foo.go:8)	MOVQ	BP, 2064(SP)
	00042 (GOPATH/src/main/foo.go:8)	LEAQ	2064(SP), BP
	00050 (GOPATH/src/main/foo.go:8)	FUNCDATA	$0, gclocals·a36216b97439c93dafebe03e7f0808b5(SB)
	00050 (GOPATH/src/main/foo.go:8)	FUNCDATA	$1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
	00050 (GOPATH/src/main/foo.go:8)	MOVQ	"".xs+2088(SP), AX
	00058 (GOPATH/src/main/foo.go:8)	MOVQ	"".xs+2080(SP), CX
	00066 (GOPATH/src/main/foo.go:8)	XORL	DX, DX
	00068 (GOPATH/src/main/foo.go:8)	XORL	BX, BX
	00070 (GOPATH/src/main/foo.go:10)	JMP	179
	00072 (GOPATH/src/main/foo.go:10)	MOVQ	(CX), R8
	00075 (GOPATH/src/main/foo.go:10)	MOVQ	R8, ""..autotmp_8+1032(SP)
	00083 (GOPATH/src/main/foo.go:10)	LEAQ	8(CX), SI
	00087 (GOPATH/src/main/foo.go:10)	LEAQ	""..autotmp_8+1040(SP), DI
	00095 (GOPATH/src/main/foo.go:10)	DUFFCOPY	$0
	00114 (GOPATH/src/main/foo.go:10)	MOVQ	""..autotmp_8+1032(SP), R8
	00122 (GOPATH/src/main/foo.go:10)	MOVQ	R8, "".x(SP)
	00126 (GOPATH/src/main/foo.go:10)	LEAQ	"".x+8(SP), DI
	00131 (GOPATH/src/main/foo.go:10)	LEAQ	""..autotmp_8+1040(SP), SI
	00139 (GOPATH/src/main/foo.go:10)	DUFFCOPY	$0
	00158 (GOPATH/src/main/foo.go:10)	ADDQ	$1032, CX
	00165 (GOPATH/src/main/foo.go:10)	INCQ	DX
	00168 (GOPATH/src/main/foo.go:11)	MOVQ	"".x+1024(SP), R8
	00176 (GOPATH/src/main/foo.go:11)	ADDQ	R8, BX
	00179 (GOPATH/src/main/foo.go:10)	CMPQ	DX, AX
	00182 (GOPATH/src/main/foo.go:10)	JLT	72
	00184 (GOPATH/src/main/foo.go:13)	MOVQ	BX, "".~r1+2104(SP)
	00192 (GOPATH/src/main/foo.go:13)	MOVQ	2064(SP), BP
	00200 (GOPATH/src/main/foo.go:13)	ADDQ	$2072, SP
	00207 (GOPATH/src/main/foo.go:13)	RET
	00208 (GOPATH/src/main/foo.go:13)	NOP
	00208 (GOPATH/src/main/foo.go:8)	PCDATA	$0, $-1
	00208 (GOPATH/src/main/foo.go:8)	CALL	runtime.morestack_noctxt(SB)
	00213 (GOPATH/src/main/foo.go:8)	JMP	0

"".fatIndex STEXT nosplit size=56 args=0x20 locals=0x0
	00000 (GOPATH/src/main/foo.go:16)	TEXT	"".fatIndex(SB), NOSPLIT, $0-32
	00000 (GOPATH/src/main/foo.go:16)	FUNCDATA	$0, gclocals·a36216b97439c93dafebe03e7f0808b5(SB)
	00000 (GOPATH/src/main/foo.go:16)	FUNCDATA	$1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
	00000 (GOPATH/src/main/foo.go:16)	MOVQ	"".xs+16(SP), AX
	00005 (GOPATH/src/main/foo.go:16)	MOVQ	"".xs+8(SP), CX
	00010 (GOPATH/src/main/foo.go:16)	XORL	DX, DX
	00012 (GOPATH/src/main/foo.go:16)	XORL	BX, BX
	00014 (GOPATH/src/main/foo.go:18)	JMP	45
	00016 (GOPATH/src/main/foo.go:18)	LEAQ	1(DX), SI
	00020 (GOPATH/src/main/foo.go:18)	MOVQ	DX, DI
	00023 (GOPATH/src/main/foo.go:19)	SHLQ	$10, DX
	00027 (GOPATH/src/main/foo.go:19)	LEAQ	(DX)(DI*8), DI
	00031 (GOPATH/src/main/foo.go:19)	MOVQ	1024(CX)(DI*1), DI
	00039 (GOPATH/src/main/foo.go:19)	ADDQ	DI, BX
	00042 (GOPATH/src/main/foo.go:19)	MOVQ	SI, DX
	00045 (GOPATH/src/main/foo.go:18)	CMPQ	DX, AX
	00048 (GOPATH/src/main/foo.go:18)	JLT	16
	00050 (GOPATH/src/main/foo.go:21)	MOVQ	BX, "".~r1+32(SP)
	00055 (GOPATH/src/main/foo.go:21)	RET

cmd/kfulint: add sanity checks

Every linter must be properly handle files that may contain unexpected input.
For example:

func external() // Function with nil body

func empty() {} // Function without input/output params and empty body

// Empty value/type specs:
var ()
const ()
type ()

And so on.

lint: add param type duplication checker

Find function signatures that can be simplified by omitting duplicate types.
This includes both input and output params (results).

func f(x int, y int) {}
=>
func f(x, y int) {}

var f func() (x float64, y float64, error)
=>
var f func() (x, y float64, error)

lint: add scope narrowing checks

Find unexported types (without methods) and constants that are only used inside one function and suggest moving them to it if they are defined at global scope.

lint: add if/else -> switch suggesting checker

If there is a chain of if/else, suggest switch as alternative.

These two functions should trigger the warning:

func cond1(x int) string {
	if x == 0 {
		return "zero"
	} else if x < 0 {
		return "negative"
	} else {
		return "positive"
	}
}

func cond2(x int) string {
	if x == 0 {
		return "zero"
	} else if x < 0 {
		return "negative"
	}
	return "positive"
}

Suggested alternative is:

func condSuggested(x int) string {
	switch {
	case x == 0:
		return "zero"
	case x < 0:
		return "negative"
	default:
		return "positive"
	}
}

TODO: find out if if/else is ever more readable or wanted instead of switch.
Maybe init statements can complicate things.

lint: add builtin shadowing detection

The builtin-shadow checker should detect assignments to builtin function names.

For example, this code triggers two warnings:

close := 1
len := close + 2

lint: add range loop suggesting checker

If particular for loop can be rewritten in form of range loop, suggest it.

This code could be rewritten, so it should trigger a warning:

func sum(xs *[count]int) int {
    res := 0
    for i := 0; i < count; i++ {
        res += xs[i]
    }
    return res
}

There are at least 2 suggested forms:

func sumRangeA(xs *[count]int) int {
    res := 0
    for i := range xs {
        res += xs[i]
    }
    return res
}
 
func sumRangeB(xs *[count]int) int {
    res := 0
    for _, x := range xs {
        res += x
    }
    return res
}

lint: underef gives false positives for multiple levels of indirection

For types like **T and ***T underef suggest to remove dereferencing even though it will lead to invalid code. It should take types into account.

Examples:

	type point struct{ x, y int }
	pt := point{}
	pt1 := &pt
	pt2 := &pt1
	pt3 := &pt2
	pt4 := &pt3
	
	_ = (*pt2).x
	_ = (**pt3).x
	_ = (***pt4).x

There can be more cases where it gives false positives, but this one can be resolved in isolation.

lint: add normalization checks

Don't know how to categorize changes, but we can detect several excessive AST elements.

switch true {/* body */}
// =>
switch {/* body */}

// This case is handled by gosimple:
for true {/* body */}
// =>
for {/* body */}

There could be more.
We must implement only new checks that are not present in, say, gosimple.

It can also be a good idea to report them in gosimple issue tracker.
It's strange that it handles for statement, but not switch.
Maybe there is a rationale for that.

lint: add unslice checker

Find slice expressions that can be simplified to sliced expression.

So, this code will trigger a warning:

s[:] // If s is a slice or string

And the alternative we are proposing:

s

So, yes, simply s[:] => s.

In other words: for any 2-index slice expression (as opposed to three-index x[a:b:c]) over value X of form X[a:b] where a=0 and b=len(X) (also includes default index values)
suggest replacing X[a:b] with just X if type of X is a string or slice of any element type.

Real-world example of code that can be detected by this check:
https://github.com/golang/go/blob/adb52cff581b13f06282bd8940a6ab8ee333cb4c/src/strings/replace.go#L450

lint: rename parenthesis-checker.go file

Naming scheme I had in mind is ${checkername}_checker.go.
So, if linter is called param-name, it's filename should be param-name_checker.go.
In case of parenthesis checker, it's filename should be parenthesis_checker.go.

lint: add type-guard checker

Finds type switch that may benefit from "type switch guard".

So, this code will trigger a warning:

	var x interface{} = 10

	switch x.(type) {
	case int:
		var _ int = x.(int)
	case float32:
		var _ float32 = x.(float32)
	}

And the alternative we are proposing:

	var x interface{} = 10

	switch x := x.(type) {
	case int:
		var _ int = x
	case float32:
		var _ float32 = x
	}

Another example:

	var v interface{} = point{1, 2}
	switch v.(type) {
	case int:
		return v.(int)
	case point:
		return v.(point).x + v.(point).y
	default:
		return 0
	}
// =>
	switch v := v.(type) {
	case int:
		return v
	case point:
		return v.x + v.y
	default:
		return 0
	}

test: add end2end testing for checkers

We need to test that checkers output does match expectations.

I like how end2end testing is done in Go, see go vet tests for example.

It's possible to grab "errcheck" functionality used there for our purposes,
or we can adapt something else (or roll our own).

lint: add long chain expression checker

Find long expression chains that are repeated more than N times (some kind of threshold) and consist of multiple selector/index expressions.

So, this code will trigger a warning:

	type something struct {
		with struct {
			very struct {
				big struct {
					nesting struct {
						value int
					}
				}
			}
		}
	}
	var x something

	switch {
	case x.with.very.big.nesting.value > 0:
		fmt.Printf("positive value: %d\n", x.with.very.big.nesting.value)
	case x.with.very.big.nesting.value < 0:
		fmt.Printf("negative value: %d\n", x.with.very.big.nesting.value)
	default:
		fmt.Println("zero")
	}

And the alternative we are proposing:

	value := x.with.very.big.nesting
	switch {
	case value > 0:
		fmt.Printf("positive value: %d\n", value)
	case value < 0:
		fmt.Printf("negative value: %d\n", value)
	default:
		fmt.Println("zero")
	}

Or, even better:

	switch value := x.with.very.big.nesting; {
	case value > 0:
		fmt.Printf("positive value: %d\n", value)
	case value < 0:
		fmt.Printf("negative value: %d\n", value)
	default:
		fmt.Println("zero")
	}

We don't have to provide "fixed" code snippet.
The minimal goal is to alert the possibility for code improvement.
It means that in the simplest case it's OK to just report the problem, like:

Expression chain x.with.very.big.nesting.value repeated 4 times, consider assigning it to local variable

lint: parenthesis checker panics on cmd/internal/obj/x86

./bin/kfulint -dir=$GOROOT/src/cmd/internal/obj/x86
panic: ast.Walk: unexpected node type <nil> [recovered]
	panic: ast.Walk: unexpected node type <nil>

goroutine 51 [running]:
main.(*linter).CheckFile.func1.1(0xc00056ea90, 0x69a792, 0xb, 0x6c9300, 0xc000504160)
	src/github.com/PieselBois/kfulint/cmd/kfulint/main.go:139 +0x14e
panic(0x63cd20, 0xc000158480)
	$GOROOTsrc/runtime/panic.go:494 +0x1b9
go/ast.Walk(0x6c97c0, 0xc000158430, 0x0, 0x0)
	$GOROOTsrc/go/ast/walk.go:364 +0x311f
go/ast.Inspect(0x0, 0x0, 0xc000158430)
	$GOROOTsrc/go/ast/walk.go:385 +0x4b
github.com/PieselBois/kfulint/lint.(*ParenthesisChecker).validateType(0xc000504160, 0x0, 0x0)
	src/github.com/PieselBois/kfulint/lint/parenthesis_checker.go:63 +0x6b
github.com/PieselBois/kfulint/lint.(*ParenthesisChecker).Check(0xc000504160, 0xc0000ac280, 0xc00056ea90, 0x69a792, 0xb)
	src/github.com/PieselBois/kfulint/lint/parenthesis_checker.go:47 +0x1f2
main.(*linter).CheckFile.func1(0xc00056ea90, 0xc0000ac280, 0xc000022340, 0x69a792, 0xb, 0x6c9300, 0xc000504160)
	src/github.com/PieselBois/kfulint/cmd/kfulint/main.go:142 +0xd5
created by main.(*linter).CheckFile
	src/github.com/PieselBois/kfulint/cmd/kfulint/main.go:126 +0xc9

lint,cmd/kfulint: record types info and parsed ast files inside context

Currently, ast.ParseDir results are ignored.
It returns multiple packages, usually it's target package (same name as containing directory name) only,
but sometimes there is also testing package with _test suffix.

Proposed plan:

  1. Collect parsed packages.
  2. Iterate over these packages, init context with current package files and types info.
  3. Run checkers over that package with properly initialized context.
  4. Repeat until there are no packages left.

Note: we may reject multi-package folders for now.
In other words: it's OK to exit if len(packages) != 1 and that package name does not
match target package name. "proper" multi-package handling may be added later.
This can simplify initial implementation significantly.

lint.Context needs additional fields.
It definitely needs *types.Info and []*ast.File. Maybe something else.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.