aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/esimonov
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2021-02-22 20:37:25 +0100
committerDmitry Vyukov <dvyukov@google.com>2021-02-22 21:02:12 +0100
commitfcc6d71be2c3ce7d9305c04fc2e87af554571bac (patch)
treeb01dbb3d1e2988e28ea158d2d543d603ec0b9569 /vendor/github.com/esimonov
parent8f23c528ad5a943b9ffec5dcaf332fd0f614006e (diff)
go.mod: update golangci-lint to v1.37
Diffstat (limited to 'vendor/github.com/esimonov')
-rw-r--r--vendor/github.com/esimonov/ifshort/LICENSE21
-rw-r--r--vendor/github.com/esimonov/ifshort/pkg/analyzer/analyzer.go247
-rw-r--r--vendor/github.com/esimonov/ifshort/pkg/analyzer/occurrences.go259
3 files changed, 527 insertions, 0 deletions
diff --git a/vendor/github.com/esimonov/ifshort/LICENSE b/vendor/github.com/esimonov/ifshort/LICENSE
new file mode 100644
index 000000000..a04e339c0
--- /dev/null
+++ b/vendor/github.com/esimonov/ifshort/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Eugene Simonov
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/esimonov/ifshort/pkg/analyzer/analyzer.go b/vendor/github.com/esimonov/ifshort/pkg/analyzer/analyzer.go
new file mode 100644
index 000000000..df3d1211a
--- /dev/null
+++ b/vendor/github.com/esimonov/ifshort/pkg/analyzer/analyzer.go
@@ -0,0 +1,247 @@
+package analyzer
+
+import (
+ "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"
+)
+
+var maxDeclChars, maxDeclLines int
+
+const (
+ maxDeclLinesUsage = `maximum length of variable declaration measured in number of lines, after which the linter won't suggest using short syntax.
+Has precedence over max-decl-chars.`
+ maxDeclCharsUsage = `maximum length of variable declaration measured in number of characters, after which the linter won't suggest using short syntax.`
+)
+
+func init() {
+ Analyzer.Flags.IntVar(&maxDeclLines, "max-decl-lines", 1, maxDeclLinesUsage)
+ Analyzer.Flags.IntVar(&maxDeclChars, "max-decl-chars", 30, maxDeclCharsUsage)
+}
+
+// Analyzer is an analysis.Analyzer instance for ifshort linter.
+var Analyzer = &analysis.Analyzer{
+ Name: "ifshort",
+ Doc: "Checks that your code uses short syntax for if-statements whenever possible.",
+ Run: run,
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ inspector := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+ nodeFilter := []ast.Node{
+ (*ast.FuncDecl)(nil),
+ }
+
+ inspector.Preorder(nodeFilter, func(node ast.Node) {
+ fdecl := node.(*ast.FuncDecl)
+
+ /*if fdecl.Name.Name != "notUsed_BinaryExpressionInIndex_OK" {
+ return
+ }*/
+
+ if fdecl == nil || fdecl.Body == nil {
+ return
+ }
+
+ candidates := getNamedOccurrenceMap(fdecl, pass)
+
+ for _, stmt := range fdecl.Body.List {
+ candidates.checkStatement(stmt, token.NoPos)
+ }
+
+ for varName := range candidates {
+ for marker, occ := range candidates[varName] {
+ // If two or more vars with the same scope marker - skip them.
+ if candidates.isFoundByScopeMarker(marker) {
+ continue
+ }
+
+ pass.Reportf(occ.declarationPos,
+ "variable '%s' is only used in the if-statement (%s); consider using short syntax",
+ varName, pass.Fset.Position(occ.ifStmtPos))
+ }
+ }
+ })
+ return nil, nil
+}
+
+func (nom namedOccurrenceMap) checkStatement(stmt ast.Stmt, ifPos token.Pos) {
+ switch v := stmt.(type) {
+ case *ast.AssignStmt:
+ for _, el := range v.Rhs {
+ nom.checkExpression(el, ifPos)
+ }
+ if isAssign(v.Tok) {
+ for _, el := range v.Lhs {
+ nom.checkExpression(el, ifPos)
+ }
+ }
+ case *ast.DeferStmt:
+ for _, a := range v.Call.Args {
+ nom.checkExpression(a, ifPos)
+ }
+ case *ast.ExprStmt:
+ if callExpr, ok := v.X.(*ast.CallExpr); ok {
+ nom.checkExpression(callExpr, ifPos)
+ }
+ case *ast.ForStmt:
+ for _, el := range v.Body.List {
+ nom.checkStatement(el, ifPos)
+ }
+
+ if bexpr, ok := v.Cond.(*ast.BinaryExpr); ok {
+ nom.checkExpression(bexpr.X, ifPos)
+ nom.checkExpression(bexpr.Y, ifPos)
+ }
+
+ nom.checkStatement(v.Post, ifPos)
+ case *ast.GoStmt:
+ for _, a := range v.Call.Args {
+ nom.checkExpression(a, token.NoPos)
+ }
+ case *ast.IfStmt:
+ for _, el := range v.Body.List {
+ nom.checkStatement(el, v.If)
+ }
+
+ switch cond := v.Cond.(type) {
+ case *ast.BinaryExpr:
+ nom.checkExpression(cond.X, v.If)
+ nom.checkExpression(cond.Y, v.If)
+ case *ast.CallExpr:
+ nom.checkExpression(cond, v.If)
+ }
+
+ if init, ok := v.Init.(*ast.AssignStmt); ok {
+ for _, e := range init.Rhs {
+ nom.checkExpression(e, v.If)
+ }
+ }
+ case *ast.IncDecStmt:
+ nom.checkExpression(v.X, ifPos)
+ case *ast.RangeStmt:
+ nom.checkExpression(v.X, token.NoPos)
+ if v.Body != nil {
+ for _, e := range v.Body.List {
+ nom.checkStatement(e, ifPos)
+ }
+ }
+ case *ast.ReturnStmt:
+ for _, r := range v.Results {
+ nom.checkExpression(r, token.NoPos)
+ }
+ case *ast.SendStmt:
+ nom.checkExpression(v.Value, token.NoPos)
+ case *ast.SwitchStmt:
+ nom.checkExpression(v.Tag, token.NoPos)
+
+ for _, el := range v.Body.List {
+ clauses, ok := el.(*ast.CaseClause)
+ if !ok {
+ continue
+ }
+
+ for _, c := range clauses.List {
+ switch v := c.(type) {
+ case *ast.BinaryExpr:
+ nom.checkExpression(v.X, token.NoPos)
+ nom.checkExpression(v.Y, token.NoPos)
+ case *ast.Ident:
+ nom.checkExpression(v, token.NoPos)
+ }
+ }
+
+ for _, c := range clauses.Body {
+ if est, ok := c.(*ast.ExprStmt); ok {
+ nom.checkExpression(est.X, token.NoPos)
+ }
+
+ switch v := c.(type) {
+ case *ast.AssignStmt:
+ for _, el := range v.Rhs {
+ nom.checkExpression(el, token.NoPos)
+ }
+ case *ast.ExprStmt:
+ nom.checkExpression(v.X, token.NoPos)
+ }
+ }
+ }
+ }
+}
+
+func (nom namedOccurrenceMap) checkExpression(candidate ast.Expr, ifPos token.Pos) {
+ switch v := candidate.(type) {
+ case *ast.BinaryExpr:
+ nom.checkExpression(v.X, ifPos)
+ case *ast.CallExpr:
+ for _, arg := range v.Args {
+ nom.checkExpression(arg, ifPos)
+ }
+ if fun, ok := v.Fun.(*ast.SelectorExpr); ok {
+ nom.checkExpression(fun.X, ifPos)
+ }
+ case *ast.CompositeLit:
+ for _, el := range v.Elts {
+ kv, ok := el.(*ast.KeyValueExpr)
+ if !ok {
+ continue
+ }
+ if ident, ok := kv.Key.(*ast.Ident); ok {
+ nom.checkExpression(ident, ifPos)
+ }
+ if ident, ok := kv.Value.(*ast.Ident); ok {
+ nom.checkExpression(ident, ifPos)
+ }
+ }
+ case *ast.FuncLit:
+ for _, el := range v.Body.List {
+ nom.checkStatement(el, ifPos)
+ }
+ case *ast.Ident:
+ if nom[v.Name].isEmponymousKey(ifPos) {
+ return
+ }
+
+ scopeMarker1 := nom[v.Name].getScopeMarkerForPosition(v.Pos())
+
+ delete(nom[v.Name], scopeMarker1)
+
+ for k := range nom {
+ for scopeMarker2 := range nom[k] {
+ if scopeMarker1 == scopeMarker2 {
+ delete(nom[k], scopeMarker2)
+ }
+ }
+ }
+ case *ast.IndexExpr:
+ nom.checkExpression(v.X, ifPos)
+ switch index := v.Index.(type) {
+ case *ast.BinaryExpr:
+ nom.checkExpression(index.X, ifPos)
+ case *ast.Ident:
+ nom.checkExpression(index, ifPos)
+ }
+ case *ast.SelectorExpr:
+ nom.checkExpression(v.X, ifPos)
+ case *ast.SliceExpr:
+ nom.checkExpression(v.High, ifPos)
+ nom.checkExpression(v.Low, ifPos)
+ nom.checkExpression(v.X, ifPos)
+ case *ast.TypeAssertExpr:
+ nom.checkExpression(v.X, ifPos)
+ case *ast.UnaryExpr:
+ nom.checkExpression(v.X, ifPos)
+ }
+}
+
+func isAssign(tok token.Token) bool {
+ return (tok == token.ASSIGN ||
+ tok == token.ADD_ASSIGN || tok == token.SUB_ASSIGN ||
+ tok == token.MUL_ASSIGN || tok == token.QUO_ASSIGN || tok == token.REM_ASSIGN ||
+ tok == token.AND_ASSIGN || tok == token.OR_ASSIGN || tok == token.XOR_ASSIGN || tok == token.AND_NOT_ASSIGN ||
+ tok == token.SHL_ASSIGN || tok == token.SHR_ASSIGN)
+}
diff --git a/vendor/github.com/esimonov/ifshort/pkg/analyzer/occurrences.go b/vendor/github.com/esimonov/ifshort/pkg/analyzer/occurrences.go
new file mode 100644
index 000000000..34224c93a
--- /dev/null
+++ b/vendor/github.com/esimonov/ifshort/pkg/analyzer/occurrences.go
@@ -0,0 +1,259 @@
+package analyzer
+
+import (
+ "go/ast"
+ "go/token"
+ "time"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+// occurrence is a variable occurrence.
+type occurrence struct {
+ declarationPos token.Pos
+ ifStmtPos token.Pos
+}
+
+func (occ *occurrence) isComplete() bool {
+ return occ.ifStmtPos != token.NoPos && occ.declarationPos != token.NoPos
+}
+
+// scopeMarkeredOccurences is a map of scope markers to variable occurrences.
+type scopeMarkeredOccurences map[int64]occurrence
+
+func (smo scopeMarkeredOccurences) getGreatestMarker() int64 {
+ var maxScopeMarker int64
+
+ for marker := range smo {
+ if marker > maxScopeMarker {
+ maxScopeMarker = marker
+ }
+ }
+ return maxScopeMarker
+}
+
+// find scope marker of the greatest token.Pos that is smaller than provided.
+func (smo scopeMarkeredOccurences) getScopeMarkerForPosition(pos token.Pos) int64 {
+ var m int64
+ var foundPos token.Pos
+
+ for marker, occ := range smo {
+ if occ.declarationPos < pos && occ.declarationPos >= foundPos {
+ m = marker
+ foundPos = occ.declarationPos
+ }
+ }
+ return m
+}
+
+func (smo scopeMarkeredOccurences) isEmponymousKey(pos token.Pos) bool {
+ if pos == token.NoPos {
+ return false
+ }
+
+ for _, occ := range smo {
+ if occ.ifStmtPos == pos {
+ return true
+ }
+ }
+ return false
+}
+
+// namedOccurrenceMap is a map of variable names to scopeMarkeredOccurences.
+type namedOccurrenceMap map[string]scopeMarkeredOccurences
+
+func getNamedOccurrenceMap(fdecl *ast.FuncDecl, pass *analysis.Pass) namedOccurrenceMap {
+ nom := namedOccurrenceMap(map[string]scopeMarkeredOccurences{})
+
+ if fdecl == nil || fdecl.Body == nil {
+ return nom
+ }
+
+ for _, stmt := range fdecl.Body.List {
+ switch v := stmt.(type) {
+ case *ast.AssignStmt:
+ nom.addFromAssignment(pass, v)
+ case *ast.IfStmt:
+ nom.addFromCondition(v)
+ nom.addFromIfClause(v)
+ nom.addFromElseClause(v)
+ }
+ }
+
+ candidates := namedOccurrenceMap(map[string]scopeMarkeredOccurences{})
+
+ for varName, markeredOccs := range nom {
+ for marker, occ := range markeredOccs {
+ if !occ.isComplete() && !nom.isFoundByScopeMarker(marker) {
+ continue
+ }
+ if _, ok := candidates[varName]; !ok {
+ candidates[varName] = scopeMarkeredOccurences{
+ marker: occ,
+ }
+ } else {
+ candidates[varName][marker] = occ
+ }
+ }
+ }
+ return candidates
+}
+
+func (nom namedOccurrenceMap) isFoundByScopeMarker(scopeMarker int64) bool {
+ var i int
+
+ for _, markeredOccs := range nom {
+ for marker := range markeredOccs {
+ if marker == scopeMarker {
+ i++
+ }
+ }
+ }
+ return i >= 2
+}
+
+func (nom namedOccurrenceMap) addFromAssignment(pass *analysis.Pass, assignment *ast.AssignStmt) {
+ if assignment.Tok != token.DEFINE {
+ return
+ }
+
+ scopeMarker := time.Now().UnixNano()
+
+ for i, el := range assignment.Lhs {
+ ident, ok := el.(*ast.Ident)
+ if !ok {
+ continue
+ }
+
+ if ident.Name == "_" || ident.Obj == nil || isUnshortenableAssignment(ident.Obj.Decl) {
+ continue
+ }
+
+ if markeredOccs, ok := nom[ident.Name]; ok {
+ markeredOccs[scopeMarker] = occurrence{
+ declarationPos: ident.Pos(),
+ }
+ nom[ident.Name] = markeredOccs
+ } else {
+ newOcc := occurrence{}
+ if areFlagSettingsSatisfied(pass, assignment, i) {
+ newOcc.declarationPos = ident.Pos()
+ }
+ nom[ident.Name] = scopeMarkeredOccurences{scopeMarker: newOcc}
+ }
+ }
+}
+
+func isUnshortenableAssignment(decl interface{}) bool {
+ assign, ok := decl.(*ast.AssignStmt)
+ if !ok {
+ return false
+ }
+
+ for _, el := range assign.Rhs {
+ u, ok := el.(*ast.UnaryExpr)
+ if !ok {
+ continue
+ }
+
+ if u.Op == token.AND {
+ if _, ok := u.X.(*ast.CompositeLit); ok {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+func areFlagSettingsSatisfied(pass *analysis.Pass, assignment *ast.AssignStmt, i int) bool {
+ lh := assignment.Lhs[i]
+ rh := assignment.Rhs[len(assignment.Rhs)-1]
+
+ if len(assignment.Rhs) == len(assignment.Lhs) {
+ rh = assignment.Rhs[i]
+ }
+
+ if pass.Fset.Position(rh.End()).Line-pass.Fset.Position(rh.Pos()).Line > maxDeclLines {
+ return false
+ }
+ if int(rh.End()-lh.Pos()) > maxDeclChars {
+ return false
+ }
+ return true
+}
+
+func (nom namedOccurrenceMap) addFromCondition(stmt *ast.IfStmt) {
+ switch v := stmt.Cond.(type) {
+ case *ast.BinaryExpr:
+ for _, v := range [2]ast.Expr{v.X, v.Y} {
+ switch e := v.(type) {
+ case *ast.Ident:
+ nom.addFromIdent(stmt.If, e)
+ case *ast.SelectorExpr:
+ nom.addFromIdent(stmt.If, e.X)
+ }
+ }
+ case *ast.Ident:
+ nom.addFromIdent(stmt.If, v)
+ case *ast.CallExpr:
+ for _, a := range v.Args {
+ switch e := a.(type) {
+ case *ast.Ident:
+ nom.addFromIdent(stmt.If, e)
+ case *ast.CallExpr:
+ nom.addFromCallExpr(stmt.If, e)
+ }
+ }
+ }
+}
+
+func (nom namedOccurrenceMap) addFromIfClause(stmt *ast.IfStmt) {
+ nom.addFromBlockStmt(stmt.Body, stmt.If)
+}
+
+func (nom namedOccurrenceMap) addFromElseClause(stmt *ast.IfStmt) {
+ nom.addFromBlockStmt(stmt.Else, stmt.If)
+}
+
+func (nom namedOccurrenceMap) addFromBlockStmt(stmt ast.Stmt, ifPos token.Pos) {
+ blockStmt, ok := stmt.(*ast.BlockStmt)
+ if !ok {
+ return
+ }
+
+ for _, el := range blockStmt.List {
+ exptStmt, ok := el.(*ast.ExprStmt)
+ if !ok {
+ continue
+ }
+
+ if callExpr, ok := exptStmt.X.(*ast.CallExpr); ok {
+ nom.addFromCallExpr(ifPos, callExpr)
+ }
+ }
+}
+
+func (nom namedOccurrenceMap) addFromCallExpr(ifPos token.Pos, callExpr *ast.CallExpr) {
+ for _, arg := range callExpr.Args {
+ nom.addFromIdent(ifPos, arg)
+ }
+}
+
+func (nom namedOccurrenceMap) addFromIdent(ifPos token.Pos, v ast.Expr) {
+ ident, ok := v.(*ast.Ident)
+ if !ok {
+ return
+ }
+
+ if markeredOccs, ok := nom[ident.Name]; ok {
+ marker := nom[ident.Name].getGreatestMarker()
+
+ occ := markeredOccs[marker]
+ if occ.isComplete() {
+ return
+ }
+
+ occ.ifStmtPos = ifPos
+ nom[ident.Name][marker] = occ
+ }
+}