diff --git a/node/name/n_fully_qualified.go b/node/name/n_fully_qualified.go index e215dd1..eeed26d 100644 --- a/node/name/n_fully_qualified.go +++ b/node/name/n_fully_qualified.go @@ -40,3 +40,8 @@ func (n *FullyQualified) Walk(v walker.Visitor) { v.LeaveNode(n) } + +// GetParts returns the name parts +func (n *FullyQualified) GetParts() []node.Node { + return n.Parts +} diff --git a/node/name/n_name.go b/node/name/n_name.go index a1f68aa..bace418 100644 --- a/node/name/n_name.go +++ b/node/name/n_name.go @@ -40,3 +40,8 @@ func (n *Name) Walk(v walker.Visitor) { v.LeaveNode(n) } + +// GetParts returns the name parts +func (n *Name) GetParts() []node.Node { + return n.Parts +} diff --git a/node/name/n_relative.go b/node/name/n_relative.go index 451febf..262d96c 100644 --- a/node/name/n_relative.go +++ b/node/name/n_relative.go @@ -40,3 +40,8 @@ func (n *Relative) Walk(v walker.Visitor) { v.LeaveNode(n) } + +// GetParts returns the name parts +func (n *Relative) GetParts() []node.Node { + return n.Parts +} diff --git a/node/name/names.go b/node/name/names.go new file mode 100644 index 0000000..e7140ad --- /dev/null +++ b/node/name/names.go @@ -0,0 +1,11 @@ +package name + +import ( + "github.com/z7zmey/php-parser/node" +) + +// Names is generalizing the Name types +type Names interface { + node.Node + GetParts() []node.Node +} diff --git a/node/name/t_name_test.go b/node/name/t_name_test.go index d14087c..8bf1b9d 100644 --- a/node/name/t_name_test.go +++ b/node/name/t_name_test.go @@ -96,3 +96,18 @@ func TestRelative(t *testing.T) { actual, _, _ = php5.Parse(bytes.NewBufferString(src), "test.php") assertEqual(t, expected, actual) } + +func TestNamePartsGetter(t *testing.T) { + expected := []node.Node{ + &name.NamePart{Value: "a"}, + &name.NamePart{Value: "b"}, + } + + plainName := &name.Name{Parts: expected} + relativeName := &name.Relative{Parts: expected} + fullyQualifiedName := &name.FullyQualified{Parts: expected} + + assertEqual(t, expected, plainName.GetParts()) + assertEqual(t, expected, relativeName.GetParts()) + assertEqual(t, expected, fullyQualifiedName.GetParts()) +} diff --git a/visitor/NsResolver.go b/visitor/NsResolver.go index 8fa7fe5..a8d2520 100644 --- a/visitor/NsResolver.go +++ b/visitor/NsResolver.go @@ -29,11 +29,13 @@ func concatNameParts(parts ...[]node.Node) string { return str } +// Namespace context type Namespace struct { Namespace string Aliases map[string]map[string]string } +// NewNamespace constructor func NewNamespace(NSName string) *Namespace { return &Namespace{ Namespace: NSName, @@ -45,6 +47,7 @@ func NewNamespace(NSName string) *Namespace { } } +// AddAlias adds a new alias func (ns *Namespace) AddAlias(aliasType string, aliasName string, alias string) { aliasType = strings.ToLower(aliasType) @@ -55,21 +58,25 @@ func (ns *Namespace) AddAlias(aliasType string, aliasName string, alias string) } } -func (ns *Namespace) resolveName(nameNode node.Node, aliasType string) string { +// ResolveName returns a resolved fully qualified name +func (ns *Namespace) ResolveName(nameNode node.Node, aliasType string) string { switch n := nameNode.(type) { case *name.FullyQualified: + // Fully qualifid name is already resolved return concatNameParts(n.Parts) case *name.Relative: return ns.Namespace + "\\" + concatNameParts(n.Parts) case *name.Name: - aliasName, err := ns.resolveAlias(nameNode, aliasType) + aliasName, err := ns.ResolveAlias(nameNode, aliasType) if err != nil { + // resolve as relative name if alias not found return ns.Namespace + "\\" + concatNameParts(n.Parts) } if len(n.Parts) > 1 { + // if name qualified, replace first part by alias return aliasName + "\\" + concatNameParts(n.Parts[1:]) } @@ -79,7 +86,8 @@ func (ns *Namespace) resolveName(nameNode node.Node, aliasType string) string { panic("invalid nameNode variable type") } -func (ns *Namespace) resolveAlias(nameNode node.Node, aliasType string) (string, error) { +// ResolveAlias returns alias or error if not found +func (ns *Namespace) ResolveAlias(nameNode node.Node, aliasType string) (string, error) { aliasType = strings.ToLower(aliasType) nameParts := nameNode.(*name.Name).Parts @@ -102,6 +110,7 @@ func (ns *Namespace) resolveAlias(nameNode node.Node, aliasType string) (string, return aliasName, nil } +// NsResolver visitor type NsResolver struct { Namespace *Namespace ResolvedNames map[node.Node]string @@ -154,130 +163,106 @@ func (nsr *NsResolver) EnterNode(w walker.Walkable) bool { case *stmt.Class: if n.Extends != nil { - nsr.resolveName(n.Extends, "") + nsr.ResolveName(n.Extends, "") } for _, interfaceName := range n.Implements { - nsr.resolveName(interfaceName, "") + nsr.ResolveName(interfaceName, "") } - nsr.addNamespacedName(n, n.ClassName.(*node.Identifier).Value) + nsr.AddNamespacedName(n, n.ClassName.(*node.Identifier).Value) case *stmt.Interface: for _, interfaceName := range n.Extends { - nsr.resolveName(interfaceName, "") + nsr.ResolveName(interfaceName, "") } - nsr.addNamespacedName(n, n.InterfaceName.(*node.Identifier).Value) + nsr.AddNamespacedName(n, n.InterfaceName.(*node.Identifier).Value) case *stmt.Trait: - nsr.addNamespacedName(n, n.TraitName.(*node.Identifier).Value) + nsr.AddNamespacedName(n, n.TraitName.(*node.Identifier).Value) case *stmt.Function: - nsr.addNamespacedName(n, n.FunctionName.(*node.Identifier).Value) + nsr.AddNamespacedName(n, n.FunctionName.(*node.Identifier).Value) for _, parameter := range n.Params { - nsr.resolveType(parameter.(*node.Parameter).VariableType) + nsr.ResolveType(parameter.(*node.Parameter).VariableType) } if n.ReturnType != nil { - nsr.resolveType(n.ReturnType) + nsr.ResolveType(n.ReturnType) } case *stmt.ClassMethod: for _, parameter := range n.Params { - nsr.resolveType(parameter.(*node.Parameter).VariableType) + nsr.ResolveType(parameter.(*node.Parameter).VariableType) } if n.ReturnType != nil { - nsr.resolveType(n.ReturnType) + nsr.ResolveType(n.ReturnType) } case *expr.Closure: for _, parameter := range n.Params { - nsr.resolveType(parameter.(*node.Parameter).VariableType) + nsr.ResolveType(parameter.(*node.Parameter).VariableType) } if n.ReturnType != nil { - nsr.resolveType(n.ReturnType) + nsr.ResolveType(n.ReturnType) } case *stmt.ConstList: for _, constant := range n.Consts { - nsr.addNamespacedName(constant, constant.(*stmt.Constant).ConstantName.(*node.Identifier).Value) + nsr.AddNamespacedName(constant, constant.(*stmt.Constant).ConstantName.(*node.Identifier).Value) } case *expr.StaticCall: - switch nn := n.Class.(type) { - case *name.Name: - nsr.resolveName(nn, "") - case *name.Relative: - nsr.resolveName(nn, "") - case *name.FullyQualified: - nsr.resolveName(nn, "") + clsName, ok := n.Class.(name.Names) + if ok { + nsr.ResolveName(clsName, "") } case *expr.StaticPropertyFetch: - switch nn := n.Class.(type) { - case *name.Name: - nsr.resolveName(nn, "") - case *name.Relative: - nsr.resolveName(nn, "") - case *name.FullyQualified: - nsr.resolveName(nn, "") + clsName, ok := n.Class.(name.Names) + if ok { + nsr.ResolveName(clsName, "") } case *expr.ClassConstFetch: - switch nn := n.Class.(type) { - case *name.Name: - nsr.resolveName(nn, "") - case *name.Relative: - nsr.resolveName(nn, "") - case *name.FullyQualified: - nsr.resolveName(nn, "") + clsName, ok := n.Class.(name.Names) + if ok { + nsr.ResolveName(clsName, "") } case *expr.New: - switch nn := n.Class.(type) { - case *name.Name: - nsr.resolveName(nn, "") - case *name.Relative: - nsr.resolveName(nn, "") - case *name.FullyQualified: - nsr.resolveName(nn, "") + clsName, ok := n.Class.(name.Names) + if ok { + nsr.ResolveName(clsName, "") } case *expr.InstanceOf: - switch nn := n.Class.(type) { - case *name.Name: - nsr.resolveName(nn, "") - case *name.Relative: - nsr.resolveName(nn, "") - case *name.FullyQualified: - nsr.resolveName(nn, "") + clsName, ok := n.Class.(name.Names) + if ok { + nsr.ResolveName(clsName, "") } case *stmt.Catch: for _, t := range n.Types { - nsr.resolveName(t, "") + nsr.ResolveName(t, "") } case *expr.FunctionCall: - switch nn := n.Function.(type) { - case *name.Name: - nsr.resolveName(nn, "function") - case *name.Relative: - nsr.resolveName(nn, "function") - case *name.FullyQualified: - nsr.resolveName(nn, "function") + funcName, ok := n.Function.(name.Names) + if ok { + nsr.ResolveName(funcName, "function") } case *expr.ConstFetch: - nsr.resolveName(n.Constant, "const") + nsr.ResolveName(n.Constant, "const") case *stmt.TraitUse: for _, t := range n.Traits { - nsr.resolveName(t, "") + nsr.ResolveName(t, "") } for _, a := range n.Adaptations { @@ -285,16 +270,16 @@ func (nsr *NsResolver) EnterNode(w walker.Walkable) bool { case *stmt.TraitUsePrecedence: refTrait := aa.Ref.(*stmt.TraitMethodRef).Trait if refTrait != nil { - nsr.resolveName(refTrait, "") + nsr.ResolveName(refTrait, "") } for _, insteadOf := range aa.Insteadof { - nsr.resolveName(insteadOf, "") + nsr.ResolveName(insteadOf, "") } case *stmt.TraitUseAlias: refTrait := aa.Ref.(*stmt.TraitMethodRef).Trait if refTrait != nil { - nsr.resolveName(refTrait, "") + nsr.ResolveName(refTrait, "") } } } @@ -319,6 +304,7 @@ func (nsr *NsResolver) LeaveNode(w walker.Walkable) { } } +// AddAlias adds a new alias func (nsr *NsResolver) AddAlias(useType string, nn node.Node, prefix []node.Node) { switch use := nn.(type) { case *stmt.Use: @@ -338,7 +324,8 @@ func (nsr *NsResolver) AddAlias(useType string, nn node.Node, prefix []node.Node } } -func (nsr *NsResolver) addNamespacedName(nn node.Node, nodeName string) { +// AddNamespacedName adds namespaced name by node +func (nsr *NsResolver) AddNamespacedName(nn node.Node, nodeName string) { if nsr.Namespace.Namespace == "" { nsr.ResolvedNames[nn] = nodeName } else { @@ -346,19 +333,17 @@ func (nsr *NsResolver) addNamespacedName(nn node.Node, nodeName string) { } } -func (nsr *NsResolver) resolveName(nameNode node.Node, aliasType string) { - nsr.ResolvedNames[nameNode] = nsr.Namespace.resolveName(nameNode, aliasType) +// ResolveName adds a resolved fully qualified name by node +func (nsr *NsResolver) ResolveName(nameNode node.Node, aliasType string) { + nsr.ResolvedNames[nameNode] = nsr.Namespace.ResolveName(nameNode, aliasType) } -func (nsr *NsResolver) resolveType(n node.Node) { +// ResolveType adds a resolved fully qualified type name +func (nsr *NsResolver) ResolveType(n node.Node) { switch nn := n.(type) { case *node.Nullable: - nsr.resolveType(nn.Expr) - case *name.Name: - nsr.resolveName(n, "") - case *name.Relative: - nsr.resolveName(n, "") - case *name.FullyQualified: - nsr.resolveName(n, "") + nsr.ResolveType(nn.Expr) + case name.Names: + nsr.ResolveName(n, "") } }