package processors import ( "go/token" "path/filepath" "strings" "github.com/golangci/golangci-lint/pkg/logutils" "github.com/golangci/golangci-lint/pkg/lint/astcache" "github.com/golangci/golangci-lint/pkg/result" ) type posMapper func(pos token.Position) token.Position // FilenameUnadjuster is needed because a lot of linters use fset.Position(f.Pos()) // to get filename. And they return adjusted filename (e.g. *.qtpl) for an issue. We need // restore real .go filename to properly output it, parse it, etc. type FilenameUnadjuster struct { m map[string]posMapper // map from adjusted filename to position mapper: adjusted -> unadjusted position log logutils.Log loggedUnadjustments map[string]bool } var _ Processor = &FilenameUnadjuster{} func NewFilenameUnadjuster(cache *astcache.Cache, log logutils.Log) *FilenameUnadjuster { m := map[string]posMapper{} for _, f := range cache.GetAllValidFiles() { adjustedFilename := f.Fset.PositionFor(f.F.Pos(), true).Filename if adjustedFilename == "" { continue } unadjustedFilename := f.Fset.PositionFor(f.F.Pos(), false).Filename if unadjustedFilename == "" || unadjustedFilename == adjustedFilename { continue } if !strings.HasSuffix(unadjustedFilename, ".go") { continue // file.go -> /caches/cgo-xxx } f := f m[adjustedFilename] = func(adjustedPos token.Position) token.Position { tokenFile := f.Fset.File(f.F.Pos()) if tokenFile == nil { log.Warnf("Failed to get token file for %s", adjustedFilename) return adjustedPos } return f.Fset.PositionFor(tokenFile.Pos(adjustedPos.Offset), false) } } return &FilenameUnadjuster{ m: m, log: log, loggedUnadjustments: map[string]bool{}, } } func (p FilenameUnadjuster) Name() string { return "filename_unadjuster" } func (p *FilenameUnadjuster) Process(issues []result.Issue) ([]result.Issue, error) { return transformIssues(issues, func(i *result.Issue) *result.Issue { issueFilePath := i.FilePath() if !filepath.IsAbs(i.FilePath()) { absPath, err := filepath.Abs(i.FilePath()) if err != nil { p.log.Warnf("failed to build abs path for %q: %s", i.FilePath(), err) return i } issueFilePath = absPath } mapper := p.m[issueFilePath] if mapper == nil { return i } newI := *i newI.Pos = mapper(i.Pos) if !p.loggedUnadjustments[i.Pos.Filename] { p.log.Infof("Unadjusted from %v to %v", i.Pos, newI.Pos) p.loggedUnadjustments[i.Pos.Filename] = true } return &newI }), nil } func (FilenameUnadjuster) Finish() {}