github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/staticcheck/sa1102/sa1102.go (about)

     1  package sa1102
     2  
     3  import (
     4  	"go/ast"
     5  	"go/types"
     6  
     7  	"github.com/amarpal/go-tools/analysis/lint"
     8  
     9  	"golang.org/x/tools/go/analysis"
    10  )
    11  
    12  var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
    13  	Analyzer: &analysis.Analyzer{
    14  		Name:     "SA1102",
    15  		Run:      run,
    16  		Requires: []*analysis.Analyzer{},
    17  	},
    18  	Doc: &lint.Documentation{
    19  		Title:    "log.Fatalln should not be called in package not named `main`",
    20  		Text:     `log.Fatalln calls os.Exit(1) which is unexpected in packages not named 'main'`,
    21  		Since:    "Unreleased",
    22  		Severity: lint.SeverityWarning,
    23  	},
    24  })
    25  
    26  var Analyzer = SCAnalyzer.Analyzer
    27  
    28  func run(pass *analysis.Pass) (interface{}, error) {
    29  	// Check if the package name is 'main'. If it is, then do nothing.
    30  	if pass.Pkg.Name() == "main" {
    31  		return nil, nil
    32  	}
    33  	// Inspect the nodes in the AST.
    34  	for _, file := range pass.Files {
    35  		ast.Inspect(file, func(n ast.Node) bool {
    36  			// Look for call expressions (e.g., function calls).
    37  			call, ok := n.(*ast.CallExpr)
    38  			if !ok {
    39  				return true // continue to next node
    40  			}
    41  			// Check if the call is a function call.
    42  			fun, ok := call.Fun.(*ast.SelectorExpr)
    43  			if !ok {
    44  				return true
    45  			}
    46  			// Check if the function is 'Fatalln' and from the 'log' package.
    47  			if fun.Sel.Name == "Fatalln" {
    48  				pkgIdent, ok := fun.X.(*ast.Ident)
    49  				if !ok {
    50  					return true
    51  				}
    52  				obj := pass.TypesInfo.Uses[pkgIdent]
    53  				pkgName, ok := obj.(*types.PkgName)
    54  				if ok && pkgName.Imported().Path() == "log" {
    55  					pass.Reportf(call.Pos(), "use of log.Fatalln in package not named 'main'")
    56  				}
    57  			}
    58  			return true
    59  		})
    60  	}
    61  	return nil, nil
    62  }