package rule import ( "go/ast" "github.com/mgechev/revive/lint" ) // BlankImportsRule lints given else constructs. type BlankImportsRule struct{} // Apply applies the rule to given file. func (r *BlankImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure fileAst := file.AST walker := lintBlankImports{ file: file, fileAst: fileAst, onFailure: func(failure lint.Failure) { failures = append(failures, failure) }, } ast.Walk(walker, fileAst) return failures } // Name returns the rule name. func (r *BlankImportsRule) Name() string { return "blank-imports" } type lintBlankImports struct { fileAst *ast.File file *lint.File onFailure func(lint.Failure) } func (w lintBlankImports) Visit(_ ast.Node) ast.Visitor { // In package main and in tests, we don't complain about blank imports. if w.file.Pkg.IsMain() || w.file.IsTest() { return nil } // The first element of each contiguous group of blank imports should have // an explanatory comment of some kind. for i, imp := range w.fileAst.Imports { pos := w.file.ToPosition(imp.Pos()) if !isBlank(imp.Name) { continue // Ignore non-blank imports. } if i > 0 { prev := w.fileAst.Imports[i-1] prevPos := w.file.ToPosition(prev.Pos()) if isBlank(prev.Name) && prevPos.Line+1 == pos.Line { continue // A subsequent blank in a group. } } // This is the first blank import of a group. if imp.Doc == nil && imp.Comment == nil { w.onFailure(lint.Failure{ Node: imp, Failure: "a blank import should be only in a main or test package, or have a comment justifying it", Confidence: 1, Category: "imports", }) } } return nil }