393 lines
7.1 KiB
Go
393 lines
7.1 KiB
Go
package golang
|
|
|
|
import (
|
|
"go/ast"
|
|
"go/parser"
|
|
"go/token"
|
|
|
|
"github.com/golangci/dupl/syntax"
|
|
)
|
|
|
|
const (
|
|
BadNode = iota
|
|
File
|
|
ArrayType
|
|
AssignStmt
|
|
BasicLit
|
|
BinaryExpr
|
|
BlockStmt
|
|
BranchStmt
|
|
CallExpr
|
|
CaseClause
|
|
ChanType
|
|
CommClause
|
|
CompositeLit
|
|
DeclStmt
|
|
DeferStmt
|
|
Ellipsis
|
|
EmptyStmt
|
|
ExprStmt
|
|
Field
|
|
FieldList
|
|
ForStmt
|
|
FuncDecl
|
|
FuncLit
|
|
FuncType
|
|
GenDecl
|
|
GoStmt
|
|
Ident
|
|
IfStmt
|
|
IncDecStmt
|
|
IndexExpr
|
|
InterfaceType
|
|
KeyValueExpr
|
|
LabeledStmt
|
|
MapType
|
|
ParenExpr
|
|
RangeStmt
|
|
ReturnStmt
|
|
SelectStmt
|
|
SelectorExpr
|
|
SendStmt
|
|
SliceExpr
|
|
StarExpr
|
|
StructType
|
|
SwitchStmt
|
|
TypeAssertExpr
|
|
TypeSpec
|
|
TypeSwitchStmt
|
|
UnaryExpr
|
|
ValueSpec
|
|
)
|
|
|
|
// Parse the given file and return uniform syntax tree.
|
|
func Parse(filename string) (*syntax.Node, error) {
|
|
fset := token.NewFileSet()
|
|
file, err := parser.ParseFile(fset, filename, nil, 0)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
t := &transformer{
|
|
fileset: fset,
|
|
filename: filename,
|
|
}
|
|
return t.trans(file), nil
|
|
}
|
|
|
|
type transformer struct {
|
|
fileset *token.FileSet
|
|
filename string
|
|
}
|
|
|
|
// trans transforms given golang AST to uniform tree structure.
|
|
func (t *transformer) trans(node ast.Node) (o *syntax.Node) {
|
|
o = syntax.NewNode()
|
|
o.Filename = t.filename
|
|
st, end := node.Pos(), node.End()
|
|
o.Pos, o.End = t.fileset.File(st).Offset(st), t.fileset.File(end).Offset(end)
|
|
|
|
switch n := node.(type) {
|
|
case *ast.ArrayType:
|
|
o.Type = ArrayType
|
|
if n.Len != nil {
|
|
o.AddChildren(t.trans(n.Len))
|
|
}
|
|
o.AddChildren(t.trans(n.Elt))
|
|
|
|
case *ast.AssignStmt:
|
|
o.Type = AssignStmt
|
|
for _, e := range n.Rhs {
|
|
o.AddChildren(t.trans(e))
|
|
}
|
|
|
|
for _, e := range n.Lhs {
|
|
o.AddChildren(t.trans(e))
|
|
}
|
|
|
|
case *ast.BasicLit:
|
|
o.Type = BasicLit
|
|
|
|
case *ast.BinaryExpr:
|
|
o.Type = BinaryExpr
|
|
o.AddChildren(t.trans(n.X), t.trans(n.Y))
|
|
|
|
case *ast.BlockStmt:
|
|
o.Type = BlockStmt
|
|
for _, stmt := range n.List {
|
|
o.AddChildren(t.trans(stmt))
|
|
}
|
|
|
|
case *ast.BranchStmt:
|
|
o.Type = BranchStmt
|
|
if n.Label != nil {
|
|
o.AddChildren(t.trans(n.Label))
|
|
}
|
|
|
|
case *ast.CallExpr:
|
|
o.Type = CallExpr
|
|
o.AddChildren(t.trans(n.Fun))
|
|
for _, arg := range n.Args {
|
|
o.AddChildren(t.trans(arg))
|
|
}
|
|
|
|
case *ast.CaseClause:
|
|
o.Type = CaseClause
|
|
for _, e := range n.List {
|
|
o.AddChildren(t.trans(e))
|
|
}
|
|
for _, stmt := range n.Body {
|
|
o.AddChildren(t.trans(stmt))
|
|
}
|
|
|
|
case *ast.ChanType:
|
|
o.Type = ChanType
|
|
o.AddChildren(t.trans(n.Value))
|
|
|
|
case *ast.CommClause:
|
|
o.Type = CommClause
|
|
if n.Comm != nil {
|
|
o.AddChildren(t.trans(n.Comm))
|
|
}
|
|
for _, stmt := range n.Body {
|
|
o.AddChildren(t.trans(stmt))
|
|
}
|
|
|
|
case *ast.CompositeLit:
|
|
o.Type = CompositeLit
|
|
if n.Type != nil {
|
|
o.AddChildren(t.trans(n.Type))
|
|
}
|
|
for _, e := range n.Elts {
|
|
o.AddChildren(t.trans(e))
|
|
}
|
|
|
|
case *ast.DeclStmt:
|
|
o.Type = DeclStmt
|
|
o.AddChildren(t.trans(n.Decl))
|
|
|
|
case *ast.DeferStmt:
|
|
o.Type = DeferStmt
|
|
o.AddChildren(t.trans(n.Call))
|
|
|
|
case *ast.Ellipsis:
|
|
o.Type = Ellipsis
|
|
if n.Elt != nil {
|
|
o.AddChildren(t.trans(n.Elt))
|
|
}
|
|
|
|
case *ast.EmptyStmt:
|
|
o.Type = EmptyStmt
|
|
|
|
case *ast.ExprStmt:
|
|
o.Type = ExprStmt
|
|
o.AddChildren(t.trans(n.X))
|
|
|
|
case *ast.Field:
|
|
o.Type = Field
|
|
for _, name := range n.Names {
|
|
o.AddChildren(t.trans(name))
|
|
}
|
|
o.AddChildren(t.trans(n.Type))
|
|
|
|
case *ast.FieldList:
|
|
o.Type = FieldList
|
|
for _, field := range n.List {
|
|
o.AddChildren(t.trans(field))
|
|
}
|
|
|
|
case *ast.File:
|
|
o.Type = File
|
|
for _, decl := range n.Decls {
|
|
if genDecl, ok := decl.(*ast.GenDecl); ok && genDecl.Tok == token.IMPORT {
|
|
// skip import declarations
|
|
continue
|
|
}
|
|
o.AddChildren(t.trans(decl))
|
|
}
|
|
|
|
case *ast.ForStmt:
|
|
o.Type = ForStmt
|
|
if n.Init != nil {
|
|
o.AddChildren(t.trans(n.Init))
|
|
}
|
|
if n.Cond != nil {
|
|
o.AddChildren(t.trans(n.Cond))
|
|
}
|
|
if n.Post != nil {
|
|
o.AddChildren(t.trans(n.Post))
|
|
}
|
|
o.AddChildren(t.trans(n.Body))
|
|
|
|
case *ast.FuncDecl:
|
|
o.Type = FuncDecl
|
|
if n.Recv != nil {
|
|
o.AddChildren(t.trans(n.Recv))
|
|
}
|
|
o.AddChildren(t.trans(n.Name), t.trans(n.Type))
|
|
if n.Body != nil {
|
|
o.AddChildren(t.trans(n.Body))
|
|
}
|
|
|
|
case *ast.FuncLit:
|
|
o.Type = FuncLit
|
|
o.AddChildren(t.trans(n.Type), t.trans(n.Body))
|
|
|
|
case *ast.FuncType:
|
|
o.Type = FuncType
|
|
o.AddChildren(t.trans(n.Params))
|
|
if n.Results != nil {
|
|
o.AddChildren(t.trans(n.Results))
|
|
}
|
|
|
|
case *ast.GenDecl:
|
|
o.Type = GenDecl
|
|
for _, spec := range n.Specs {
|
|
o.AddChildren(t.trans(spec))
|
|
}
|
|
|
|
case *ast.GoStmt:
|
|
o.Type = GoStmt
|
|
o.AddChildren(t.trans(n.Call))
|
|
|
|
case *ast.Ident:
|
|
o.Type = Ident
|
|
|
|
case *ast.IfStmt:
|
|
o.Type = IfStmt
|
|
if n.Init != nil {
|
|
o.AddChildren(t.trans(n.Init))
|
|
}
|
|
o.AddChildren(t.trans(n.Cond), t.trans(n.Body))
|
|
if n.Else != nil {
|
|
o.AddChildren(t.trans(n.Else))
|
|
}
|
|
|
|
case *ast.IncDecStmt:
|
|
o.Type = IncDecStmt
|
|
o.AddChildren(t.trans(n.X))
|
|
|
|
case *ast.IndexExpr:
|
|
o.Type = IndexExpr
|
|
o.AddChildren(t.trans(n.X), t.trans(n.Index))
|
|
|
|
case *ast.InterfaceType:
|
|
o.Type = InterfaceType
|
|
o.AddChildren(t.trans(n.Methods))
|
|
|
|
case *ast.KeyValueExpr:
|
|
o.Type = KeyValueExpr
|
|
o.AddChildren(t.trans(n.Key), t.trans(n.Value))
|
|
|
|
case *ast.LabeledStmt:
|
|
o.Type = LabeledStmt
|
|
o.AddChildren(t.trans(n.Label), t.trans(n.Stmt))
|
|
|
|
case *ast.MapType:
|
|
o.Type = MapType
|
|
o.AddChildren(t.trans(n.Key), t.trans(n.Value))
|
|
|
|
case *ast.ParenExpr:
|
|
o.Type = ParenExpr
|
|
o.AddChildren(t.trans(n.X))
|
|
|
|
case *ast.RangeStmt:
|
|
o.Type = RangeStmt
|
|
if n.Key != nil {
|
|
o.AddChildren(t.trans(n.Key))
|
|
}
|
|
if n.Value != nil {
|
|
o.AddChildren(t.trans(n.Value))
|
|
}
|
|
o.AddChildren(t.trans(n.X), t.trans(n.Body))
|
|
|
|
case *ast.ReturnStmt:
|
|
o.Type = ReturnStmt
|
|
for _, e := range n.Results {
|
|
o.AddChildren(t.trans(e))
|
|
}
|
|
|
|
case *ast.SelectStmt:
|
|
o.Type = SelectStmt
|
|
o.AddChildren(t.trans(n.Body))
|
|
|
|
case *ast.SelectorExpr:
|
|
o.Type = SelectorExpr
|
|
o.AddChildren(t.trans(n.X), t.trans(n.Sel))
|
|
|
|
case *ast.SendStmt:
|
|
o.Type = SendStmt
|
|
o.AddChildren(t.trans(n.Chan), t.trans(n.Value))
|
|
|
|
case *ast.SliceExpr:
|
|
o.Type = SliceExpr
|
|
o.AddChildren(t.trans(n.X))
|
|
if n.Low != nil {
|
|
o.AddChildren(t.trans(n.Low))
|
|
}
|
|
if n.High != nil {
|
|
o.AddChildren(t.trans(n.High))
|
|
}
|
|
if n.Max != nil {
|
|
o.AddChildren(t.trans(n.Max))
|
|
}
|
|
|
|
case *ast.StarExpr:
|
|
o.Type = StarExpr
|
|
o.AddChildren(t.trans(n.X))
|
|
|
|
case *ast.StructType:
|
|
o.Type = StructType
|
|
o.AddChildren(t.trans(n.Fields))
|
|
|
|
case *ast.SwitchStmt:
|
|
o.Type = SwitchStmt
|
|
if n.Init != nil {
|
|
o.AddChildren(t.trans(n.Init))
|
|
}
|
|
if n.Tag != nil {
|
|
o.AddChildren(t.trans(n.Tag))
|
|
}
|
|
o.AddChildren(t.trans(n.Body))
|
|
|
|
case *ast.TypeAssertExpr:
|
|
o.Type = TypeAssertExpr
|
|
o.AddChildren(t.trans(n.X))
|
|
if n.Type != nil {
|
|
o.AddChildren(t.trans(n.Type))
|
|
}
|
|
|
|
case *ast.TypeSpec:
|
|
o.Type = TypeSpec
|
|
o.AddChildren(t.trans(n.Name), t.trans(n.Type))
|
|
|
|
case *ast.TypeSwitchStmt:
|
|
o.Type = TypeSwitchStmt
|
|
if n.Init != nil {
|
|
o.AddChildren(t.trans(n.Init))
|
|
}
|
|
o.AddChildren(t.trans(n.Assign), t.trans(n.Body))
|
|
|
|
case *ast.UnaryExpr:
|
|
o.Type = UnaryExpr
|
|
o.AddChildren(t.trans(n.X))
|
|
|
|
case *ast.ValueSpec:
|
|
o.Type = ValueSpec
|
|
for _, name := range n.Names {
|
|
o.AddChildren(t.trans(name))
|
|
}
|
|
if n.Type != nil {
|
|
o.AddChildren(t.trans(n.Type))
|
|
}
|
|
for _, val := range n.Values {
|
|
o.AddChildren(t.trans(val))
|
|
}
|
|
|
|
default:
|
|
o.Type = BadNode
|
|
|
|
}
|
|
|
|
return o
|
|
}
|