Browse Source

Improve readability, delete unused function plus minor fixes

pull/646/head
Augusto 4 years ago committed by xpetit
parent
commit
53ed2a1ab8
  1. 427
      rc/rc.go
  2. 2
      rc/rc_test.go

427
rc/rc.go

@ -18,14 +18,15 @@ import (
type strBoolMap map[string]bool type strBoolMap map[string]bool
func (a *strBoolMap) String() string { // Implementation of the flag.Value interface
var res string func (a *strBoolMap) String() (res string) {
for k, _ := range *a { for k, _ := range *a {
res += k res += k
} }
return res return res
} }
// Implementation of the flag.Value interface
func (a *strBoolMap) Set(str string) error { func (a *strBoolMap) Set(str string) error {
if *a == nil { if *a == nil {
*a = make(map[string]bool) *a = make(map[string]bool)
@ -37,12 +38,13 @@ func (a *strBoolMap) Set(str string) error {
return nil return nil
} }
// flag that groups a boolean value and a regular expression // Flag that groups a boolean value and a regular expression
type regexpFlag struct { type regexpFlag struct {
active bool active bool
reg *regexp.Regexp reg *regexp.Regexp
} }
// Implementation of the flag.Value interface
func (r *regexpFlag) String() string { func (r *regexpFlag) String() string {
if r.reg != nil { if r.reg != nil {
return r.reg.String() return r.reg.String()
@ -50,10 +52,10 @@ func (r *regexpFlag) String() string {
return "" return ""
} }
// Implementation of the flag.Value interface
func (r *regexpFlag) Set(s string) error { func (r *regexpFlag) Set(s string) error {
re := regexp.MustCompile(s)
r.active = true r.active = true
r.reg = re r.reg = regexp.MustCompile(s)
return nil return nil
} }
@ -101,7 +103,7 @@ func main() {
filename := goFile(flag.Args()) filename := goFile(flag.Args())
if filename == "" { if filename == "" {
fmt.Println("\tNo file to analyse") fmt.Println("\tNo file to analyze")
os.Exit(1) os.Exit(1)
} }
@ -123,7 +125,7 @@ func main() {
os.Exit(1) os.Exit(1)
} }
info := analyseProgram(filename, currentPath, load) info := analyzeProgram(filename, currentPath, load)
if info.illegals != nil { if info.illegals != nil {
fmt.Println("Cheating:") fmt.Println("Cheating:")
@ -143,42 +145,42 @@ func goFile(args []string) string {
// Returns the smallest block containing the position pos. It can // Returns the smallest block containing the position pos. It can
// return nil if `pos` is not inside any ast.BlockStmt // return nil if `pos` is not inside any ast.BlockStmt
func smallestBlock(pos token.Pos, blocks []*ast.BlockStmt) *ast.BlockStmt { func smallestBlock(pos token.Pos, blocks []*ast.BlockStmt) (minBlock *ast.BlockStmt) {
var minBlk *ast.BlockStmt
var minSize token.Pos var minSize token.Pos
for _, v := range blocks { for _, v := range blocks {
if pos > v.Pos() && pos < v.End() { if pos > v.Pos() && pos < v.End() {
size := v.End() - v.Pos() size := v.End() - v.Pos()
if minBlk == nil || size < minSize { if minBlock == nil || size < minSize {
minBlk = v minBlock = v
minSize = size minSize = size
} }
} }
} }
return minBlk return minBlock
} }
// Used to mark an ast.Object as a function parameter
type data struct { type data struct {
argument bool parameter bool
} }
func fillScope(funcDefs []*fDefInfo, scope *ast.Scope, scopes map[*ast.BlockStmt]*ast.Scope) { func fillScope(funcDefs []*function, scope *ast.Scope, scopes map[*ast.BlockStmt]*ast.Scope) {
for _, fun := range funcDefs { for _, fun := range funcDefs {
scope.Insert(fun.obj) scope.Insert(fun.obj)
for _, name := range fun.paramsFunc { for _, name := range fun.params {
obj := ast.NewObj(ast.Fun, name) obj := ast.NewObj(ast.Fun, name)
obj.Data = data{
data := data{ parameter: true,
argument: true,
} }
obj.Data = data
scopes[fun.body].Insert(obj) scopes[fun.body].Insert(obj)
} }
} }
} }
// Create the scopes for a BlockStmt contained inside another BlockStmt // Create the scopes for a BlockStmt contained inside another BlockStmt
func createChildScope(block *ast.BlockStmt, l *loadVisitor, scopes map[*ast.BlockStmt]*ast.Scope) { func createChildScope(
block *ast.BlockStmt,
l *loadVisitor, scopes map[*ast.BlockStmt]*ast.Scope) {
blocks := l.blocks blocks := l.blocks
// The smalles block containing the beggining of the block // The smalles block containing the beggining of the block
parentBlock := smallestBlock(block.Pos(), blocks) parentBlock := smallestBlock(block.Pos(), blocks)
@ -188,7 +190,7 @@ func createChildScope(block *ast.BlockStmt, l *loadVisitor, scopes map[*ast.Bloc
scopes[block] = ast.NewScope(scopes[parentBlock]) scopes[block] = ast.NewScope(scopes[parentBlock])
} }
// Returns true `block` is contained inside another block // Returns true if `block` is contained inside another ast.BlockStmt
func isContained(block *ast.BlockStmt, blocks []*ast.BlockStmt) bool { func isContained(block *ast.BlockStmt, blocks []*ast.BlockStmt) bool {
for _, v := range blocks { for _, v := range blocks {
if block == v { if block == v {
@ -203,30 +205,29 @@ func isContained(block *ast.BlockStmt, blocks []*ast.BlockStmt) bool {
// Creates all the scopes in the package // Creates all the scopes in the package
func createScopes(l *loadVisitor, pkgScope *ast.Scope) map[*ast.BlockStmt]*ast.Scope { func createScopes(l *loadVisitor, pkgScope *ast.Scope) map[*ast.BlockStmt]*ast.Scope {
blocks := l.blocks
scopes := make(map[*ast.BlockStmt]*ast.Scope) scopes := make(map[*ast.BlockStmt]*ast.Scope)
if blocks == nil { if l.blocks == nil {
return nil return nil
} }
for _, b := range blocks { for _, b := range l.blocks {
if !isContained(b, blocks) { if !isContained(b, l.blocks) {
scopes[b] = ast.NewScope(pkgScope) scopes[b] = ast.NewScope(pkgScope)
continue
} }
} }
for _, b := range blocks { for _, b := range l.blocks {
if scopes[b] != nil { if scopes[b] == nil {
continue createChildScope(b, l, scopes)
} }
createChildScope(b, l, scopes)
} }
return scopes return scopes
} }
type blockVisitor struct { type blockVisitor struct {
fdef []*fDefInfo // All functions defined in the scope in any funct []*function
// All functions defined in the scope in any
// way: as a funcDecl, GenDecl or AssigmentStmt // way: as a funcDecl, GenDecl or AssigmentStmt
oneBlock bool // Indicates if the visitor already encounter a oneBlock bool
// Indicates if the visitor already encounter a
// blockStmt // blockStmt
} }
@ -238,11 +239,11 @@ func (b *blockVisitor) Visit(n ast.Node) ast.Visitor {
} }
return b return b
case *ast.FuncDecl, *ast.GenDecl, *ast.AssignStmt: case *ast.FuncDecl, *ast.GenDecl, *ast.AssignStmt:
def := funcInfo(t) def := extractFunction(t)
if def == nil || def.obj == nil { if def == nil || def.obj == nil {
return b return b
} }
b.fdef = append(b.fdef, def) b.funct = append(b.funct, def)
return nil return nil
default: default:
return b return b
@ -252,21 +253,25 @@ func (b *blockVisitor) Visit(n ast.Node) ast.Visitor {
type loadedSource map[string]*loadVisitor type loadedSource map[string]*loadVisitor
// Returns information about the function defined in the block node // Returns information about the function defined in the block node
func defs(block ast.Node) []*fDefInfo { func functionsInfo(block ast.Node) []*function {
b := &blockVisitor{} b := &blockVisitor{}
ast.Walk(b, block) ast.Walk(b, block)
return b.fdef return b.funct
}
func (l *loadVisitor) init() {
l.functions = make(map[string]ast.Node)
l.absImports = make(map[string]*element)
l.relImports = make(map[string]*element)
l.objFunc = make(map[*ast.Object]ast.Node)
l.fset = token.NewFileSet()
l.scopes = make(map[*ast.BlockStmt]*ast.Scope)
} }
func loadProgram(path string, load loadedSource) error { func loadProgram(path string, load loadedSource) error {
l := &loadVisitor{ l := &loadVisitor{}
functions: make(map[string]ast.Node), l.init()
absImports: make(map[string]*element),
relImports: make(map[string]*element),
objFunc: make(map[*ast.Object]ast.Node),
fset: token.NewFileSet(),
scopes: make(map[*ast.BlockStmt]*ast.Scope),
}
pkgs, err := parser.ParseDir(l.fset, path, nil, parser.AllErrors) pkgs, err := parser.ParseDir(l.fset, path, nil, parser.AllErrors)
@ -277,30 +282,30 @@ func loadProgram(path string, load loadedSource) error {
for _, pkg := range pkgs { for _, pkg := range pkgs {
ast.Walk(l, pkg) ast.Walk(l, pkg)
l.pkgScope = ast.NewScope(nil) l.pkgScope = ast.NewScope(nil)
def := defs(pkg) functions := functionsInfo(pkg)
for _, v := range def { for _, f := range functions {
l.pkgScope.Insert(v.obj) l.pkgScope.Insert(f.obj)
} }
l.scopes = createScopes(l, l.pkgScope) l.scopes = createScopes(l, l.pkgScope)
fillScope(def, l.pkgScope, l.scopes) fillScope(functions, l.pkgScope, l.scopes)
for block, scope := range l.scopes { for block, scope := range l.scopes {
defs := defs(block) functions := functionsInfo(block)
fillScope(defs, scope, l.scopes) fillScope(functions, scope, l.scopes)
} }
load[path] = l load[path] = l
l.files = pkg.Files l.files = pkg.Files
} }
for _, v := range l.relImports { for _, relativePath := range l.relImports {
if load[v.name] == nil { if load[relativePath.name] == nil {
newPath := filepath.Clean(path + "/" + v.name) newPath := filepath.Clean(path + "/" + relativePath.name)
err = loadProgram(newPath, load) err = loadProgram(newPath, load)
if err != nil { if err != nil {
return err return err
} }
} }
} }
return err return nil
} }
func smallestScopeContaining(pos token.Pos, path string, load loadedSource) *ast.Scope { func smallestScopeContaining(pos token.Pos, path string, load loadedSource) *ast.Scope {
@ -326,14 +331,14 @@ func lookupDefinitionObj(el *element, path string, load loadedSource) *ast.Objec
} }
type visitor struct { type visitor struct {
fset *token.FileSet fset *token.FileSet
uses []*element uses []*element
selections map[string][]*element selections map[string][]*element
arrays []*occurrence arrays []*occurrence
lits []*occurrence lits []*occurrence
fors []*occurrence fors []*occurrence
callRep map[string]int callRepetition map[string]int
oneTime bool oneTime bool
} }
func (v *visitor) getPos(n ast.Node) string { func (v *visitor) getPos(n ast.Node) string {
@ -343,9 +348,9 @@ func (v *visitor) getPos(n ast.Node) string {
func (v *visitor) Visit(n ast.Node) ast.Visitor { func (v *visitor) Visit(n ast.Node) ast.Visitor {
switch t := n.(type) { switch t := n.(type) {
case *ast.FuncDecl, *ast.GenDecl, *ast.AssignStmt: case *ast.FuncDecl, *ast.GenDecl, *ast.AssignStmt:
//Avoids analysing a declaration inside a declaration //Avoids analyzing a declaration inside a declaration
//Since this is handle by the functions `isAllowed` //Since this is handle by the functions `isAllowed`
fdef := funcInfo(t) fdef := extractFunction(t)
if fdef == nil || fdef.obj == nil { if fdef == nil || fdef.obj == nil {
return v return v
} }
@ -378,7 +383,7 @@ func (v *visitor) Visit(n ast.Node) ast.Visitor {
name: fun.Name, name: fun.Name,
pos: fun.Pos(), pos: fun.Pos(),
}) })
v.callRep[fun.Name]++ v.callRepetition[fun.Name]++
} }
case *ast.SelectorExpr: case *ast.SelectorExpr:
@ -387,109 +392,117 @@ func (v *visitor) Visit(n ast.Node) ast.Visitor {
name: t.Sel.Name, name: t.Sel.Name,
pos: n.Pos(), pos: n.Pos(),
}) })
v.callRep[x.Name+"."+t.Sel.Name]++ v.callRepetition[x.Name+"."+t.Sel.Name]++
} }
} }
return v return v
} }
func (v *visitor) init(fset *token.FileSet) {
v.selections = make(map[string][]*element)
v.callRepetition = make(map[string]int)
v.fset = fset
}
func (info *info) add(v *visitor) {
info.fors = append(info.fors, v.fors...)
info.lits = append(info.lits, v.lits...)
info.arrays = append(info.arrays, v.arrays...)
for name, v := range v.callRepetition {
info.callRepetition[name] += v
}
}
// Returns the info structure with all the ocurrences of the element // Returns the info structure with all the ocurrences of the element
// of the analised in the project // of the analised in the project
func isAllowed(function *element, path string, load loadedSource, walked map[ast.Node]bool, info *info) bool { func isAllowed(function *element, path string, load loadedSource, walked map[ast.Node]bool, info *info) bool {
if walked == nil { functionObj := lookupDefinitionObj(function, path, load)
walked = make(map[ast.Node]bool) definedLocally := functionObj != nil
explicitlyAllowed := allowedFun["builtin"]["*"] || allowedFun["builtin"][function.name]
isFunctionParameter := func(function *ast.Object) bool {
arg, ok := function.Data.(data)
return ok && arg.parameter
}
DoesntCallMoreFunctions := func(functionDefinition ast.Node, v *visitor) bool {
if !walked[functionDefinition] {
ast.Walk(v, functionDefinition)
info.add(v)
walked[functionDefinition] = true
}
return v.uses == nil && v.selections == nil
} }
fdef := lookupDefinitionObj(function, path, load)
if fdef == nil && !allowedFun["builtin"]["*"] && !allowedFun["builtin"][function.name] { appendIllegalCall := func(function *element) {
info.illegals = append(info.illegals, &illegal{ info.illegals = append(info.illegals, &illegal{
T: "illegal-call", T: "illegal-call",
Name: function.name, Name: function.name,
Pos: load[path].fset.Position(function.pos).String(), Pos: load[path].fset.Position(function.pos).String(),
}) })
return false
}
if fdef == nil {
return true
}
if arg, ok := fdef.Data.(data); ok && arg.argument {
return true
}
funcNode := load[path].objFunc[fdef]
v := &visitor{
selections: make(map[string][]*element),
callRep: make(map[string]int),
fset: load[path].fset,
} }
if !walked[funcNode] { if !definedLocally && !explicitlyAllowed {
ast.Walk(v, funcNode) appendIllegalCall(function)
info.fors = append(info.fors, v.fors...) return false
info.lits = append(info.lits, v.lits...)
info.arrays = append(info.arrays, v.arrays...)
for name, v := range v.callRep {
info.callRep[name] += v
}
walked[funcNode] = true
} }
if v.uses == nil && v.selections == nil { functionDefinition := load[path].objFunc[functionObj]
v := &visitor{}
v.init(load[path].fset)
if explicitlyAllowed || isFunctionParameter(functionObj) ||
DoesntCallMoreFunctions(functionDefinition, v) {
return true return true
} }
allowed := true allowed := true
for _, use := range v.uses { for _, functionCall := range v.uses {
allowedUse := isAllowed(use, path, load, walked, info) if !isAllowed(functionCall, path, load, walked, info) {
if !allowedUse { appendIllegalCall(functionCall)
info.illegals = append(info.illegals, &illegal{ allowed = false
T: "illegal-call",
Name: use.name,
Pos: load[path].fset.Position(use.pos).String(),
})
} }
allowed = allowedUse && allowed
} }
for pck, funcNames := range v.selections { for pck, funcNames := range v.selections {
importRelPath := load[path].relImports[pck] pathToFunction := func() string { return load[path].relImports[pck].name }
isRelativeImport := load[path].relImports[pck] != nil
for _, fun := range funcNames { for _, fun := range funcNames {
if importRelPath == nil { appendIllegalAccess := func() {
absImp := load[path].absImports[pck]
if absImp != nil && !allowedFun[absImp.name][fun.name] && !allowedFun[absImp.name]["*"] {
// Add to the illegals array the import and selection
info.illegals = append(info.illegals, &illegal{
T: "illegal-access",
Name: pck + "." + fun.name,
Pos: load[path].fset.Position(fun.pos).String(),
})
allowed = false
}
continue
}
newPath := filepath.Clean(path + "/" + importRelPath.name)
newEl := newElement(fun.name)
allowedSel := isAllowed(newEl, newPath, load, walked, info)
if !allowedSel {
info.illegals = append(info.illegals, &illegal{ info.illegals = append(info.illegals, &illegal{
T: "illegal-access", T: "illegal-access",
Name: pck + "." + fun.name, Name: pck + "." + fun.name,
Pos: load[path].fset.Position(fun.pos).String(), Pos: load[path].fset.Position(fun.pos).String(),
}) })
allowed = false
}
absoluteImport := load[path].absImports[pck]
importExplicitlyAllowed := absoluteImport == nil ||
allowedFun[absoluteImport.name][fun.name] ||
allowedFun[absoluteImport.name]["*"]
if !isRelativeImport && !importExplicitlyAllowed {
appendIllegalAccess()
} else if isRelativeImport &&
!isAllowed(newElement(fun.name), filepath.Clean(path+"/"+pathToFunction()), load, walked, info) {
appendIllegalAccess()
} }
allowed = allowedSel && allowed
} }
} }
if !allowed { if !allowed {
info.illegals = append(info.illegals, &illegal{ info.illegals = append(info.illegals, &illegal{
T: "illegal-definition", T: "illegal-definition",
Name: fdef.Name, Name: functionObj.Name,
Pos: load[path].fset.Position(funcNode.Pos()).String(), Pos: load[path].fset.Position(functionDefinition.Pos()).String(),
}) })
} }
return allowed return allowed
} }
func removeRepetitions(slc []*illegal) []*illegal { func removeRepetitions(slc []*illegal) (result []*illegal) {
var result []*illegal
in := make(map[string]bool) in := make(map[string]bool)
for _, v := range slc { for _, v := range slc {
if in[v.Pos] { if in[v.Pos] {
@ -507,11 +520,11 @@ type occurrence struct {
} }
type info struct { type info struct {
arrays []*occurrence arrays []*occurrence
lits []*occurrence lits []*occurrence
fors []*occurrence fors []*occurrence
callRep map[string]int callRepetition map[string]int
illegals []*illegal // functions, selections that are not allowed illegals []*illegal // functions, selections that are not allowed
} }
func newElement(name string) *element { func newElement(name string) *element {
@ -522,65 +535,32 @@ func newElement(name string) *element {
} }
func analyseProgram(filename, path string, load loadedSource) *info { func analyzeProgram(filename, path string, load loadedSource) *info {
fset := load[path].fset fset := load[path].fset
file := load[path].files[filename] file := load[path].files[filename]
// Functions defined in the file functions := functionsInfo(file)
functions := defs(file)
info := &info{ info := &info{
callRep: make(map[string]int), callRepetition: make(map[string]int),
} }
info.illegals = append(info.illegals, analyseImports(file, fset, noRelativeImports)...) info.illegals = append(info.illegals, analyzeImports(file, fset, noRelativeImports)...)
walked := make(map[ast.Node]bool) walked := make(map[ast.Node]bool)
for _, v := range functions { for _, fun := range functions {
f := newElement(v.obj.Name) function := newElement(fun.obj.Name)
isAllowed(f, path, load, walked, info) isAllowed(function, path, load, walked, info)
} }
info.illegals = append(info.illegals, analyseLoops(info.fors, noFor)...) info.illegals = append(info.illegals, analyzeLoops(info.fors, noFor)...)
info.illegals = append(info.illegals, analyseArrayTypes(info.arrays, noArrays || noSlices, noTheseSlices)...) info.illegals = append(info.illegals, analyzeArrayTypes(info.arrays, noArrays || noSlices, noTheseSlices)...)
info.illegals = append(info.illegals, analyseLits(info.lits, noLit)...) info.illegals = append(info.illegals, analyzeLits(info.lits, noLit)...)
info.illegals = append(info.illegals, analyseRepetition(info.callRep, allowedRep)...) info.illegals = append(info.illegals, analyzeRepetition(info.callRepetition, allowedRep)...)
info.illegals = removeRepetitions(info.illegals) info.illegals = removeRepetitions(info.illegals)
return info return info
} }
type flags struct {
l struct { // flag for char or string literal
noLit bool // true -> unallows
pattern string // this pattern
}
}
func fillScope(funcDefs []*function, scope *ast.Scope, scopes map[*ast.BlockStmt]*ast.Scope) {
for _, fun := range funcDefs {
scope.Insert(fun.obj)
for _, name := range fun.params {
obj := ast.NewObj(ast.Fun, name)
obj.Data = data{
parameter: true,
}
scopes[fun.body].Insert(obj)
}
}
}
// Create the scopes for a BlockStmt contained inside another BlockStmt
func createChildScope(
block *ast.BlockStmt,
l *loadVisitor, scopes map[*ast.BlockStmt]*ast.Scope) {
blocks := l.blocks
// The smalles block containing the beggining of the block
parentBlock := smallestBlock(block.Pos(), blocks)
if scopes[parentBlock] == nil {
createChildScope(parentBlock, l, scopes)
}
scopes[block] = ast.NewScope(scopes[parentBlock])
}
func parseArgs(toAllow []string, builtins bool, casting bool) error { func parseArgs(toAllow []string, builtins bool, casting bool) error {
allowedFun["builtin"] = make(map[string]bool) allowedFun["builtin"] = make(map[string]bool)
predeclaredTypes := []string{"bool", "byte", "complex64", "complex128", predeclaredTypes := []string{"bool", "byte", "complex64", "complex128",
@ -624,7 +604,7 @@ func parseArgs(toAllow []string, builtins bool, casting bool) error {
funcName = spl[0] funcName = spl[0]
n, err := strconv.Atoi(spl[1]) n, err := strconv.Atoi(spl[1])
if err != nil { if err != nil {
return fmt.Errorf("After the '#' there should be a integer" + return fmt.Errorf("After the '#' there should be an integer" +
" representing the maximum number of allowed occurrences") " representing the maximum number of allowed occurrences")
} }
var prefix string var prefix string
@ -657,63 +637,56 @@ func printIllegals(illegals []*illegal) {
tbl.Print() tbl.Print()
} }
func analyseRepetition(callRep map[string]int, allowRep map[string]int) []*illegal { func analyzeRepetition(callRepetition map[string]int, allowRep map[string]int) (illegals []*illegal) {
var illegals []*illegal
for name, rep := range allowedRep { for name, rep := range allowedRep {
if callRep[name] > rep { if callRepetition[name] > rep {
diff := callRep[name] - rep diff := callRepetition[name] - rep
il := &illegal{ illegals = append(illegals, &illegal{
T: "illegal-amount", T: "illegal-amount",
Name: name + " exeding max repetitions by " + strconv.Itoa(diff), Name: name + " exeding max repetitions by " + strconv.Itoa(diff),
Pos: "all the project", Pos: "all the project",
} })
illegals = append(illegals, il)
} }
} }
return illegals return illegals
} }
func analyseLits(litOccu []*occurrence, noLit regexpFlag) []*illegal { func analyzeLits(litOccu []*occurrence, noLit regexpFlag) (illegals []*illegal) {
var illegals []*illegal
if noLit.active { if noLit.active {
for _, v := range litOccu { for _, v := range litOccu {
if noLit.reg.Match([]byte(v.name)) { if noLit.reg.Match([]byte(v.name)) {
il := &illegal{ illegals = append(illegals, &illegal{
T: "illegal-lit", T: "illegal-lit",
Name: v.name, Name: v.name,
Pos: v.pos, Pos: v.pos,
} })
illegals = append(illegals, il)
} }
} }
} }
return illegals return illegals
} }
func analyseArrayTypes(arrays []*occurrence, noArrays bool, noTheseSlices map[string]bool) []*illegal { func analyzeArrayTypes(arrays []*occurrence, noArrays bool, noTheseSlices map[string]bool) (illegals []*illegal) {
var illegals []*illegal
for _, v := range arrays { for _, v := range arrays {
if noArrays || noTheseSlices[v.name] { if noArrays || noTheseSlices[v.name] {
il := &illegal{ illegals = append(illegals, &illegal{
T: "illegal-slice", T: "illegal-slice",
Name: v.name, Name: v.name,
Pos: v.pos, Pos: v.pos,
} })
illegals = append(illegals, il)
} }
} }
return illegals return illegals
} }
func analyseLoops(fors []*occurrence, noFor bool) []*illegal {
var illegals []*illegal func analyzeLoops(fors []*occurrence, noFor bool) (illegals []*illegal) {
if noFor { if noFor {
for _, v := range fors { for _, v := range fors {
il := &illegal{ illegals = append(illegals, &illegal{
T: "illegal-loop", T: "illegal-loop",
Name: v.name, Name: v.name,
Pos: v.pos, Pos: v.pos,
} })
illegals = append(illegals, il)
} }
} }
return illegals return illegals
@ -742,8 +715,7 @@ func (i *importVisitor) Visit(n ast.Node) ast.Visitor {
return i return i
} }
func analyseImports(file ast.Node, fset *token.FileSet, noRelImp bool) []*illegal { func analyzeImports(file ast.Node, fset *token.FileSet, noRelImp bool) (illegals []*illegal) {
var il []*illegal
i := &importVisitor{ i := &importVisitor{
imports: make(map[string]*element), imports: make(map[string]*element),
} }
@ -751,14 +723,14 @@ func analyseImports(file ast.Node, fset *token.FileSet, noRelImp bool) []*illega
for _, path := range i.imports { for _, path := range i.imports {
isRelativeImport := isRelativeImport(path.name) isRelativeImport := isRelativeImport(path.name)
if (noRelativeImports && isRelativeImport) || (allowedFun[path.name] == nil && !isRelativeImport) { if (noRelativeImports && isRelativeImport) || (allowedFun[path.name] == nil && !isRelativeImport) {
il = append(il, &illegal{ illegals = append(illegals, &illegal{
T: "illegal-import", T: "illegal-import",
Name: path.name, Name: path.name,
Pos: fset.Position(path.pos).String(), Pos: fset.Position(path.pos).String(),
}) })
} }
} }
return il return illegals
} }
type element struct { type element struct {
@ -773,14 +745,15 @@ type loadVisitor struct {
fset *token.FileSet fset *token.FileSet
objFunc map[*ast.Object]ast.Node objFunc map[*ast.Object]ast.Node
blocks []*ast.BlockStmt blocks []*ast.BlockStmt
scopes map[*ast.BlockStmt]*ast.Scope // nil after the visit scopes map[*ast.BlockStmt]*ast.Scope
// nil after the visit
// used to keep the result of the createScope function // used to keep the result of the createScope function
pkgScope *ast.Scope pkgScope *ast.Scope
files map[string]*ast.File files map[string]*ast.File
} }
// Returns all the parameter of a function that identify a function // Returns all the parameter of a function that identify a function
func listParamFunc(params *ast.FieldList) []string { func functionsInTheParameters(params *ast.FieldList) []string {
var funcs []string var funcs []string
for _, param := range params.List { for _, param := range params.List {
if _, ok := param.Type.(*ast.FuncType); ok { if _, ok := param.Type.(*ast.FuncType); ok {
@ -792,50 +765,52 @@ func listParamFunc(params *ast.FieldList) []string {
return funcs return funcs
} }
type fDefInfo struct { type function struct {
obj *ast.Object // the object that represents a function obj *ast.Object // the ast.Object that represents a function
paramsFunc []string // the name of the parameter that represent params []string
// the name of the parameter that represent
// functions // functions
body *ast.BlockStmt body *ast.BlockStmt
} }
// Returns information about a node representing a function declaration // Returns information about a node representing a function declaration
func funcInfo(n ast.Node) *fDefInfo { func extractFunction(n ast.Node) *function {
fdef := &fDefInfo{} function := &function{}
switch t := n.(type) { switch t := n.(type) {
case *ast.FuncDecl: case *ast.FuncDecl:
fdef.obj = t.Name.Obj function.obj = t.Name.Obj
fdef.paramsFunc = listParamFunc(t.Type.Params) function.params = functionsInTheParameters(t.Type.Params)
fdef.body = t.Body function.body = t.Body
return fdef return function
case *ast.GenDecl: case *ast.GenDecl:
for _, v := range t.Specs { for _, v := range t.Specs {
if val, ok := v.(*ast.ValueSpec); ok { if val, ok := v.(*ast.ValueSpec); ok {
for i, value := range val.Values { for i, value := range val.Values {
if funcLit, ok := value.(*ast.FuncLit); ok { if funcLit, ok := value.(*ast.FuncLit); ok {
fdef.obj = val.Names[i].Obj function.obj = val.Names[i].Obj
fdef.paramsFunc = listParamFunc(funcLit.Type.Params) function.params = functionsInTheParameters(funcLit.Type.Params)
fdef.body = funcLit.Body function.body = funcLit.Body
} }
} }
} }
} }
return fdef return function
case *ast.AssignStmt: case *ast.AssignStmt:
for i, right := range t.Rhs { for i, right := range t.Rhs {
if funcLit, ok := right.(*ast.FuncLit); ok { if funcLit, ok := right.(*ast.FuncLit); ok {
if ident, ok := t.Lhs[i].(*ast.Ident); ok { if ident, ok := t.Lhs[i].(*ast.Ident); ok {
fdef.obj = ident.Obj function.obj = ident.Obj
fdef.paramsFunc = listParamFunc(funcLit.Type.Params) function.params = functionsInTheParameters(funcLit.Type.Params)
} }
} }
return fdef return function
} }
default: default:
return fdef return function
} }
return fdef return function
} }
func (l *loadVisitor) Visit(n ast.Node) ast.Visitor { func (l *loadVisitor) Visit(n ast.Node) ast.Visitor {
switch t := n.(type) { switch t := n.(type) {
case *ast.ImportSpec: case *ast.ImportSpec:
@ -853,11 +828,11 @@ func (l *loadVisitor) Visit(n ast.Node) ast.Visitor {
if isRelativeImport(path) { if isRelativeImport(path) {
l.relImports[name] = el l.relImports[name] = el
break } else {
l.absImports[name] = el
} }
l.absImports[name] = el
case *ast.FuncDecl, *ast.GenDecl, *ast.AssignStmt: case *ast.FuncDecl, *ast.GenDecl, *ast.AssignStmt:
fdef := funcInfo(t) fdef := extractFunction(t)
if fdef == nil || fdef.obj == nil { if fdef == nil || fdef.obj == nil {
return l return l
} }

2
rc/rc_test.go

@ -115,7 +115,7 @@ func TestFlags(t *testing.T) {
illegal-definition Length tests/testingWrapping.go:7:1 illegal-definition Length tests/testingWrapping.go:7:1
`, `,
`tests/testingWrapping.go len`: ``, `tests/testingWrapping.go len`: ``,
`tests/empty/empty len`: ` No file to analyse `tests/empty/empty len`: ` No file to analyze
`, `,
`tests/empty/empty.go tests/empty/empty`: ` tests/empty/empty.go:1:1: expected ';', found 'EOF' (and 2 more errors) `tests/empty/empty.go tests/empty/empty`: ` tests/empty/empty.go:1:1: expected ';', found 'EOF' (and 2 more errors)
`, `,

Loading…
Cancel
Save