github.com/chenfeining/golangci-lint@v1.0.2-0.20230730162517-14c6c67868df/pkg/golinters/maligned.go (about)

     1  package golinters
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	malignedAPI "github.com/golangci/maligned"
     8  	"golang.org/x/tools/go/analysis"
     9  
    10  	"github.com/chenfeining/golangci-lint/pkg/config"
    11  	"github.com/chenfeining/golangci-lint/pkg/golinters/goanalysis"
    12  	"github.com/chenfeining/golangci-lint/pkg/lint/linter"
    13  	"github.com/chenfeining/golangci-lint/pkg/result"
    14  )
    15  
    16  const malignedName = "maligned"
    17  
    18  //nolint:dupl
    19  func NewMaligned(settings *config.MalignedSettings) *goanalysis.Linter {
    20  	var mu sync.Mutex
    21  	var res []goanalysis.Issue
    22  
    23  	analyzer := &analysis.Analyzer{
    24  		Name: malignedName,
    25  		Doc:  goanalysis.TheOnlyanalyzerDoc,
    26  		Run: func(pass *analysis.Pass) (any, error) {
    27  			issues := runMaligned(pass, settings)
    28  
    29  			if len(issues) == 0 {
    30  				return nil, nil
    31  			}
    32  
    33  			mu.Lock()
    34  			res = append(res, issues...)
    35  			mu.Unlock()
    36  
    37  			return nil, nil
    38  		},
    39  	}
    40  
    41  	return goanalysis.NewLinter(
    42  		malignedName,
    43  		"Tool to detect Go structs that would take less memory if their fields were sorted",
    44  		[]*analysis.Analyzer{analyzer},
    45  		nil,
    46  	).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
    47  		return res
    48  	}).WithLoadMode(goanalysis.LoadModeTypesInfo)
    49  }
    50  
    51  func runMaligned(pass *analysis.Pass, settings *config.MalignedSettings) []goanalysis.Issue {
    52  	prog := goanalysis.MakeFakeLoaderProgram(pass)
    53  
    54  	malignedIssues := malignedAPI.Run(prog)
    55  	if len(malignedIssues) == 0 {
    56  		return nil
    57  	}
    58  
    59  	issues := make([]goanalysis.Issue, 0, len(malignedIssues))
    60  	for _, i := range malignedIssues {
    61  		text := fmt.Sprintf("struct of size %d bytes could be of size %d bytes", i.OldSize, i.NewSize)
    62  		if settings.SuggestNewOrder {
    63  			text += fmt.Sprintf(":\n%s", formatCodeBlock(i.NewStructDef, nil))
    64  		}
    65  
    66  		issues = append(issues, goanalysis.NewIssue(&result.Issue{
    67  			Pos:        i.Pos,
    68  			Text:       text,
    69  			FromLinter: malignedName,
    70  		}, pass))
    71  	}
    72  
    73  	return issues
    74  }