1
0
mirror of https://github.com/mgechev/revive.git synced 2025-03-23 21:19:26 +02:00
revive/linter/package.go
2018-01-23 17:14:23 -08:00

101 lines
2.2 KiB
Go

package linter
import (
"go/ast"
"go/token"
"go/types"
"sync"
"golang.org/x/tools/go/gcexportdata"
)
// Package represents a package in the project.
type Package struct {
fset *token.FileSet
files map[string]*File
TypesPkg *types.Package
TypesInfo *types.Info
// sortable is the set of types in the package that implement sort.Interface.
Sortable map[string]bool
// main is whether this is a "main" package.
main int
}
var newImporter = func(fset *token.FileSet) types.ImporterFrom {
return gcexportdata.NewImporter(fset, make(map[string]*types.Package))
}
var (
trueValue = 1
falseValue = 2
notSet = 3
)
// IsMain returns if that's the main package.
func (p *Package) IsMain() bool {
if p.main == trueValue {
return true
} else if p.main == falseValue {
return false
}
for _, f := range p.files {
if f.isMain() {
p.main = trueValue
return true
}
}
p.main = falseValue
return false
}
// TypeCheck performs type checking for given package.
func (p *Package) TypeCheck() error {
config := &types.Config{
// By setting a no-op error reporter, the type checker does as much work as possible.
Error: func(error) {},
Importer: newImporter(p.fset),
}
info := &types.Info{
Types: make(map[ast.Expr]types.TypeAndValue),
Defs: make(map[*ast.Ident]types.Object),
Uses: make(map[*ast.Ident]types.Object),
Scopes: make(map[ast.Node]*types.Scope),
}
var anyFile *File
var astFiles []*ast.File
for _, f := range p.files {
anyFile = f
astFiles = append(astFiles, f.AST)
}
typesPkg, err := config.Check(anyFile.AST.Name.Name, p.fset, astFiles, info)
// Remember the typechecking info, even if config.Check failed,
// since we will get partial information.
p.TypesPkg = typesPkg
p.TypesInfo = info
return err
}
// TypeOf returns the type of an expression.
func (p *Package) TypeOf(expr ast.Expr) types.Type {
if p.TypesInfo == nil {
return nil
}
return p.TypesInfo.TypeOf(expr)
}
func (p *Package) lint(rules []Rule, config RulesConfig, failures chan Failure) {
p.TypeCheck()
var wg sync.WaitGroup
for _, file := range p.files {
wg.Add(1)
go (func(file *File) {
file.lint(rules, config, failures)
defer wg.Done()
})(file)
}
wg.Wait()
close(failures)
}