Isaev Denis 95ec0cf21e
dramatically reduce memory usage ()
Run all linters per package. It allows unloading package data when it's
processed. It dramatically reduces memory (and CPU because of GC) usage.

Relates: 
2019-09-30 16:19:41 +03:00

131 lines
3.1 KiB
Go

package golinters
import (
"fmt"
"go/token"
"strings"
"sync"
"github.com/golangci/misspell"
"golang.org/x/tools/go/analysis"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/result"
)
func runMisspellOnFile(fileName string, r *misspell.Replacer, lintCtx *linter.Context) ([]result.Issue, error) {
var res []result.Issue
fileContent, err := lintCtx.FileCache.GetFileBytes(fileName)
if err != nil {
return nil, fmt.Errorf("can't get file %s contents: %s", fileName, err)
}
// use r.Replace, not r.ReplaceGo because r.ReplaceGo doesn't find
// issues inside strings: it searches only inside comments. r.Replace
// searches all words: it treats input as a plain text. A standalone misspell
// tool uses r.Replace by default.
_, diffs := r.Replace(string(fileContent))
for _, diff := range diffs {
text := fmt.Sprintf("`%s` is a misspelling of `%s`", diff.Original, diff.Corrected)
pos := token.Position{
Filename: fileName,
Line: diff.Line,
Column: diff.Column + 1,
}
replacement := &result.Replacement{
Inline: &result.InlineFix{
StartCol: diff.Column,
Length: len(diff.Original),
NewString: diff.Corrected,
},
}
res = append(res, result.Issue{
Pos: pos,
Text: text,
FromLinter: misspellName,
Replacement: replacement,
})
}
return res, nil
}
const misspellName = "misspell"
func NewMisspell() *goanalysis.Linter {
var mu sync.Mutex
var resIssues []result.Issue
var ruleErr error
analyzer := &analysis.Analyzer{
Name: goanalysis.TheOnlyAnalyzerName,
Doc: goanalysis.TheOnlyanalyzerDoc,
}
return goanalysis.NewLinter(
misspellName,
"Finds commonly misspelled English words in comments",
[]*analysis.Analyzer{analyzer},
nil,
).WithContextSetter(func(lintCtx *linter.Context) {
r := misspell.Replacer{
Replacements: misspell.DictMain,
}
// Figure out regional variations
settings := lintCtx.Settings().Misspell
locale := settings.Locale
switch strings.ToUpper(locale) {
case "":
// nothing
case "US":
r.AddRuleList(misspell.DictAmerican)
case "UK", "GB":
r.AddRuleList(misspell.DictBritish)
case "NZ", "AU", "CA":
ruleErr = fmt.Errorf("unknown locale: %q", locale)
}
if ruleErr == nil {
if len(settings.IgnoreWords) != 0 {
r.RemoveRule(settings.IgnoreWords)
}
r.Compile()
}
analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
if ruleErr != nil {
return nil, ruleErr
}
var fileNames []string
for _, f := range pass.Files {
pos := pass.Fset.Position(f.Pos())
fileNames = append(fileNames, pos.Filename)
}
var res []result.Issue
for _, f := range fileNames {
issues, err := runMisspellOnFile(f, &r, lintCtx)
if err != nil {
return nil, err
}
res = append(res, issues...)
}
if len(res) == 0 {
return nil, nil
}
mu.Lock()
resIssues = append(resIssues, res...)
mu.Unlock()
return nil, nil
}
}).WithIssuesReporter(func(*linter.Context) []result.Issue {
return resIssues
}).WithLoadMode(goanalysis.LoadModeSyntax)
}