src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

qf1006.go (1607B)


      1 package qf1006
      2 
      3 import (
      4 	"go/ast"
      5 	"go/token"
      6 
      7 	"honnef.co/go/tools/analysis/code"
      8 	"honnef.co/go/tools/analysis/edit"
      9 	"honnef.co/go/tools/analysis/lint"
     10 	"honnef.co/go/tools/analysis/report"
     11 	"honnef.co/go/tools/go/ast/astutil"
     12 	"honnef.co/go/tools/pattern"
     13 
     14 	"golang.org/x/tools/go/analysis"
     15 )
     16 
     17 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
     18 	Analyzer: &analysis.Analyzer{
     19 		Name:     "QF1006",
     20 		Run:      run,
     21 		Requires: code.RequiredAnalyzers,
     22 	},
     23 	Doc: &lint.RawDocumentation{
     24 		Title: `Lift \'if\'+\'break\' into loop condition`,
     25 		Before: `
     26 for {
     27     if done {
     28         break
     29     }
     30     ...
     31 }`,
     32 
     33 		After: `
     34 for !done {
     35     ...
     36 }`,
     37 		Since:    "2021.1",
     38 		Severity: lint.SeverityHint,
     39 	},
     40 })
     41 
     42 var Analyzer = SCAnalyzer.Analyzer
     43 
     44 var checkForLoopIfBreak = pattern.MustParse(`(ForStmt nil nil nil if@(IfStmt nil cond (BranchStmt "BREAK" nil) nil):_)`)
     45 
     46 func run(pass *analysis.Pass) (any, error) {
     47 	for node, m := range code.Matches(pass, checkForLoopIfBreak) {
     48 		pos := node.Pos() + token.Pos(len("for"))
     49 		r := astutil.NegateDeMorgan(m.State["cond"].(ast.Expr), false)
     50 
     51 		// FIXME(dh): we're leaving behind an empty line when we
     52 		// delete the old if statement. However, we can't just delete
     53 		// an additional character, in case there closing curly brace
     54 		// is followed by a comment, or Windows newlines.
     55 		report.Report(pass, m.State["if"].(ast.Node), "could lift into loop condition",
     56 			report.Fixes(edit.Fix("Lift into loop condition",
     57 				edit.ReplaceWithString(edit.Range{pos, pos}, " "+report.Render(pass, r)),
     58 				edit.Delete(m.State["if"].(ast.Node)))))
     59 	}
     60 	return nil, nil
     61 }