|
|
@ -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,22 +253,26 @@ 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 loadProgram(path string, load loadedSource) error { |
|
|
|
func (l *loadVisitor) init() { |
|
|
|
l := &loadVisitor{ |
|
|
|
l.functions = make(map[string]ast.Node) |
|
|
|
functions: make(map[string]ast.Node), |
|
|
|
l.absImports = make(map[string]*element) |
|
|
|
absImports: make(map[string]*element), |
|
|
|
l.relImports = make(map[string]*element) |
|
|
|
relImports: make(map[string]*element), |
|
|
|
l.objFunc = make(map[*ast.Object]ast.Node) |
|
|
|
objFunc: make(map[*ast.Object]ast.Node), |
|
|
|
l.fset = token.NewFileSet() |
|
|
|
fset: token.NewFileSet(), |
|
|
|
l.scopes = make(map[*ast.BlockStmt]*ast.Scope) |
|
|
|
scopes: make(map[*ast.BlockStmt]*ast.Scope), |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func loadProgram(path string, load loadedSource) error { |
|
|
|
|
|
|
|
l := &loadVisitor{} |
|
|
|
|
|
|
|
l.init() |
|
|
|
|
|
|
|
|
|
|
|
pkgs, err := parser.ParseDir(l.fset, path, nil, parser.AllErrors) |
|
|
|
pkgs, err := parser.ParseDir(l.fset, path, nil, parser.AllErrors) |
|
|
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
@ -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 { |
|
|
@ -332,7 +337,7 @@ type visitor struct { |
|
|
|
arrays []*occurrence |
|
|
|
arrays []*occurrence |
|
|
|
lits []*occurrence |
|
|
|
lits []*occurrence |
|
|
|
fors []*occurrence |
|
|
|
fors []*occurrence |
|
|
|
callRep map[string]int |
|
|
|
callRepetition map[string]int |
|
|
|
oneTime bool |
|
|
|
oneTime bool |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -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,74 +392,84 @@ 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 |
|
|
|
} |
|
|
|
} |
|
|
|
fdef := lookupDefinitionObj(function, path, load) |
|
|
|
|
|
|
|
if fdef == nil && !allowedFun["builtin"]["*"] && !allowedFun["builtin"][function.name] { |
|
|
|
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 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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] { |
|
|
|
|
|
|
|
ast.Walk(v, funcNode) |
|
|
|
|
|
|
|
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.callRep { |
|
|
|
|
|
|
|
info.callRep[name] += v |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
walked[funcNode] = true |
|
|
|
if !definedLocally && !explicitlyAllowed { |
|
|
|
|
|
|
|
appendIllegalCall(function) |
|
|
|
|
|
|
|
return false |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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{ |
|
|
|
info.illegals = append(info.illegals, &illegal{ |
|
|
|
T: "illegal-access", |
|
|
|
T: "illegal-access", |
|
|
|
Name: pck + "." + fun.name, |
|
|
|
Name: pck + "." + fun.name, |
|
|
@ -462,34 +477,32 @@ func isAllowed(function *element, path string, load loadedSource, walked map[ast |
|
|
|
}) |
|
|
|
}) |
|
|
|
allowed = false |
|
|
|
allowed = false |
|
|
|
} |
|
|
|
} |
|
|
|
continue |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
newPath := filepath.Clean(path + "/" + importRelPath.name) |
|
|
|
absoluteImport := load[path].absImports[pck] |
|
|
|
newEl := newElement(fun.name) |
|
|
|
importExplicitlyAllowed := absoluteImport == nil || |
|
|
|
allowedSel := isAllowed(newEl, newPath, load, walked, info) |
|
|
|
allowedFun[absoluteImport.name][fun.name] || |
|
|
|
if !allowedSel { |
|
|
|
allowedFun[absoluteImport.name]["*"] |
|
|
|
info.illegals = append(info.illegals, &illegal{ |
|
|
|
|
|
|
|
T: "illegal-access", |
|
|
|
if !isRelativeImport && !importExplicitlyAllowed { |
|
|
|
Name: pck + "." + fun.name, |
|
|
|
appendIllegalAccess() |
|
|
|
Pos: load[path].fset.Position(fun.pos).String(), |
|
|
|
} 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] { |
|
|
@ -510,7 +523,7 @@ 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
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -522,66 +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
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: treat all the flags in this function
|
|
|
|
|
|
|
|
// For now, only --no-lit="{PATTERN}"
|
|
|
|
|
|
|
|
func parseFlags(args []string) *flags { |
|
|
|
|
|
|
|
f := &flags{} |
|
|
|
|
|
|
|
for _, v := range args { |
|
|
|
|
|
|
|
var flag []string |
|
|
|
|
|
|
|
if strings.Contains(v, "=") { |
|
|
|
|
|
|
|
flag = strings.Split(v, "=") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if flag == nil { |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if flag[0] == "--no-lit" { |
|
|
|
|
|
|
|
f.l.noLit = true |
|
|
|
|
|
|
|
f.l.pattern = flag[1] |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return f |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func removeAmount(s string) string { |
|
|
|
|
|
|
|
strRm := strings.TrimFunc(s, func(c rune) bool { |
|
|
|
|
|
|
|
return c >= '0' && c <= '9' || c == '#' |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
return strRm |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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", |
|
|
@ -625,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 |
|
|
@ -658,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 |
|
|
@ -743,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), |
|
|
|
} |
|
|
|
} |
|
|
@ -752,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 { |
|
|
@ -774,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 { |
|
|
@ -793,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: |
|
|
@ -854,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 |
|
|
|
} |
|
|
|
} |
|
|
|