visitor package tests

This commit is contained in:
z7zmey 2018-02-27 23:38:05 +02:00
parent a517a62f4c
commit e19df2783d
5 changed files with 829 additions and 34 deletions

View File

@ -8322,7 +8322,8 @@ yyrule124: // \?\?
} }
yyrule125: // (#|[/][/]).*{NEW_LINE} yyrule125: // (#|[/][/]).*{NEW_LINE}
{ {
lval.Token(l.newToken(l.Token())) // return T_COMMENT; // TODO: handle ?> lval.Token(l.newToken(l.Token()))
l.addComment(comment.NewPlainComment(string(l.TokenBytes(nil)))) // return T_COMMENT; // TODO: handle ?>
goto yystate0 goto yystate0
} }
yyrule126: // ([/][*])|([/][*][*]) yyrule126: // ([/][*])|([/][*][*])

View File

@ -247,7 +247,7 @@ NEW_LINE (\r|\n|\r\n)
<PHP>\<\< lval.Token(l.newToken(l.Token())); return T_SL <PHP>\<\< lval.Token(l.newToken(l.Token())); return T_SL
<PHP>\>\> lval.Token(l.newToken(l.Token())); return T_SR <PHP>\>\> lval.Token(l.newToken(l.Token())); return T_SR
<PHP>\?\? lval.Token(l.newToken(l.Token())); return T_COALESCE <PHP>\?\? lval.Token(l.newToken(l.Token())); return T_COALESCE
<PHP>(#|[/][/]).*{NEW_LINE} lval.Token(l.newToken(l.Token()));// return T_COMMENT; // TODO: handle ?> <PHP>(#|[/][/]).*{NEW_LINE} lval.Token(l.newToken(l.Token())); l.addComment(comment.NewPlainComment(string(l.TokenBytes(nil))))// return T_COMMENT; // TODO: handle ?>
<PHP>([/][*])|([/][*][*]) <PHP>([/][*])|([/][*][*])
tb := l.Token() tb := l.Token()
is_doc_comment := false is_doc_comment := false

79
visitor/dumper_test.go Normal file
View File

@ -0,0 +1,79 @@
// Package visitor contains walker.visitor implementations
package visitor_test
import (
"bytes"
"github.com/z7zmey/php-parser/php7"
"github.com/z7zmey/php-parser/visitor"
)
func ExampleDumper() {
src := `<?php
namespace Foo {
class Bar {
public function FunctionName(Type $var = null)
{
// some comment
$var;
}
}
}`
nodes, comments, positions := php7.Parse(bytes.NewBufferString(src), "test.php")
dumper := visitor.Dumper{
Indent: "| ",
Comments: comments,
Positions: positions,
}
nodes.Walk(dumper)
// Output:
//| *stmt.StmtList Pos{Line: 3-11 Pos: 10-143}
//| "Stmts":
//| *stmt.Namespace Pos{Line: 3-11 Pos: 10-143}
//| "NamespaceName":
//| *name.Name Pos{Line: 3-3 Pos: 20-22}
//| "Parts":
//| *name.NamePart Pos{Line: 3-3 Pos: 20-22} map[Value:Foo]
//| "Stmts":
//| *stmt.Class Pos{Line: 4-10 Pos: 29-139} map[PhpDocComment:]
//| "ClassName":
//| *node.Identifier Pos{Line: 4-4 Pos: 35-37} map[Value:Bar]
//| "Stmts":
//| *stmt.ClassMethod Pos{Line: 5-9 Pos: 45-134} map[ReturnsRef:false PhpDocComment:]
//| "MethodName":
//| *node.Identifier Pos{Line: 5-5 Pos: 61-72} map[Value:FunctionName]
//| "Modifiers":
//| *node.Identifier Pos{Line: 5-5 Pos: 45-50} map[Value:public]
//| "Params":
//| *node.Parameter Pos{Line: 5-5 Pos: 74-89} map[ByRef:false Variadic:false]
//| "VariableType":
//| *name.Name Pos{Line: 5-5 Pos: 74-77}
//| "Parts":
//| *name.NamePart Pos{Line: 5-5 Pos: 74-77} map[Value:Type]
//| "Variable":
//| *expr.Variable Pos{Line: 5-5 Pos: 79-82}
//| "VarName":
//| *node.Identifier Pos{Line: 5-5 Pos: 79-82} map[Value:$var]
//| "DefaultValue":
//| *expr.ConstFetch Pos{Line: 5-5 Pos: 86-89}
//| "Constant":
//| *name.Name Pos{Line: 5-5 Pos: 86-89}
//| "Parts":
//| *name.NamePart Pos{Line: 5-5 Pos: 86-89} map[Value:null]
//| "Stmts":
//| *stmt.Expression Pos{Line: 8-8 Pos: 124-128}
//| Comments:
//| "// some comment\n"
//| "Expr":
//| *expr.Variable Pos{Line: 8-8 Pos: 124-127}
//| Comments:
//| "// some comment\n"
//| "VarName":
//| *node.Identifier Pos{Line: 8-8 Pos: 124-127} map[Value:$var]
//| Comments:
//| "// some comment\n"
}

View File

@ -120,34 +120,19 @@ func (nsr *NamespaceResolver) EnterNode(w walker.Walkable) bool {
} }
case *expr.StaticCall: case *expr.StaticCall:
clsName, ok := n.Class.(name.Names) nsr.ResolveName(n.Class, "")
if ok {
nsr.ResolveName(clsName, "")
}
case *expr.StaticPropertyFetch: case *expr.StaticPropertyFetch:
clsName, ok := n.Class.(name.Names) nsr.ResolveName(n.Class, "")
if ok {
nsr.ResolveName(clsName, "")
}
case *expr.ClassConstFetch: case *expr.ClassConstFetch:
clsName, ok := n.Class.(name.Names) nsr.ResolveName(n.Class, "")
if ok {
nsr.ResolveName(clsName, "")
}
case *expr.New: case *expr.New:
clsName, ok := n.Class.(name.Names) nsr.ResolveName(n.Class, "")
if ok {
nsr.ResolveName(clsName, "")
}
case *expr.InstanceOf: case *expr.InstanceOf:
clsName, ok := n.Class.(name.Names) nsr.ResolveName(n.Class, "")
if ok {
nsr.ResolveName(clsName, "")
}
case *stmt.Catch: case *stmt.Catch:
for _, t := range n.Types { for _, t := range n.Types {
@ -155,10 +140,7 @@ func (nsr *NamespaceResolver) EnterNode(w walker.Walkable) bool {
} }
case *expr.FunctionCall: case *expr.FunctionCall:
funcName, ok := n.Function.(name.Names) nsr.ResolveName(n.Function, "function")
if ok {
nsr.ResolveName(funcName, "function")
}
case *expr.ConstFetch: case *expr.ConstFetch:
nsr.ResolveName(n.Constant, "const") nsr.ResolveName(n.Constant, "const")
@ -238,7 +220,10 @@ func (nsr *NamespaceResolver) AddNamespacedName(nn node.Node, nodeName string) {
// ResolveName adds a resolved fully qualified name by node // ResolveName adds a resolved fully qualified name by node
func (nsr *NamespaceResolver) ResolveName(nameNode node.Node, aliasType string) { func (nsr *NamespaceResolver) ResolveName(nameNode node.Node, aliasType string) {
nsr.ResolvedNames[nameNode] = nsr.Namespace.ResolveName(nameNode, aliasType) resolved, err := nsr.Namespace.ResolveName(nameNode, aliasType)
if err == nil {
nsr.ResolvedNames[nameNode] = resolved
}
} }
// ResolveType adds a resolved fully qualified type name // ResolveType adds a resolved fully qualified type name
@ -281,31 +266,37 @@ func (ns *Namespace) AddAlias(aliasType string, aliasName string, alias string)
} }
// ResolveName returns a resolved fully qualified name // ResolveName returns a resolved fully qualified name
func (ns *Namespace) ResolveName(nameNode node.Node, aliasType string) string { func (ns *Namespace) ResolveName(nameNode node.Node, aliasType string) (string, error) {
switch n := nameNode.(type) { switch n := nameNode.(type) {
case *name.FullyQualified: case *name.FullyQualified:
// Fully qualifid name is already resolved // Fully qualifid name is already resolved
return concatNameParts(n.Parts) return concatNameParts(n.Parts), nil
case *name.Relative: case *name.Relative:
return ns.Namespace + "\\" + concatNameParts(n.Parts) if ns.Namespace == "" {
return concatNameParts(n.Parts), nil
}
return ns.Namespace + "\\" + concatNameParts(n.Parts), nil
case *name.Name: case *name.Name:
aliasName, err := ns.ResolveAlias(nameNode, aliasType) aliasName, err := ns.ResolveAlias(nameNode, aliasType)
if err != nil { if err != nil {
// resolve as relative name if alias not found // resolve as relative name if alias not found
return ns.Namespace + "\\" + concatNameParts(n.Parts) if ns.Namespace == "" {
return concatNameParts(n.Parts), nil
}
return ns.Namespace + "\\" + concatNameParts(n.Parts), nil
} }
if len(n.Parts) > 1 { if len(n.Parts) > 1 {
// if name qualified, replace first part by alias // if name qualified, replace first part by alias
return aliasName + "\\" + concatNameParts(n.Parts[1:]) return aliasName + "\\" + concatNameParts(n.Parts[1:]), nil
} }
return aliasName return aliasName, nil
} }
panic("invalid nameNode variable type") return "", errors.New("must be instance of name.Names")
} }
// ResolveAlias returns alias or error if not found // ResolveAlias returns alias or error if not found

View File

@ -0,0 +1,724 @@
// Package visitor contains walker.visitor implementations
package visitor_test
import (
"reflect"
"testing"
"github.com/kylelemons/godebug/pretty"
"github.com/z7zmey/php-parser/node/scalar"
"github.com/z7zmey/php-parser/node/expr"
"github.com/z7zmey/php-parser/visitor"
"github.com/z7zmey/php-parser/node/stmt"
"github.com/z7zmey/php-parser/node"
"github.com/z7zmey/php-parser/node/name"
)
func assertEqual(t *testing.T, expected interface{}, actual interface{}) {
if !reflect.DeepEqual(expected, actual) {
diff := pretty.Compare(expected, actual)
if diff != "" {
t.Errorf("diff: (-expected +actual)\n%s", diff)
} else {
t.Errorf("expected and actual are not equal\n")
}
}
}
func TestResolveStaticCall(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
ast := &stmt.StmtList{
Stmts: []node.Node{
&stmt.UseList{
Uses: []node.Node{
&stmt.Use{
Use: nameAB,
},
},
},
&expr.StaticCall{
Class: nameBC,
Call: &node.Identifier{Value: "foo"},
Arguments: []node.Node{},
},
},
}
expected := map[node.Node]string{
nameBC: "A\\B\\C",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveStaticPropertyFetch(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
ast := &stmt.StmtList{
Stmts: []node.Node{
&stmt.UseList{
Uses: []node.Node{
&stmt.Use{
Use: nameAB,
},
},
},
&expr.StaticPropertyFetch{
Class: nameBC,
Property: &node.Identifier{Value: "$foo"},
},
},
}
expected := map[node.Node]string{
nameBC: "A\\B\\C",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveClassConstFetch(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
ast := &stmt.StmtList{
Stmts: []node.Node{
&stmt.UseList{
Uses: []node.Node{
&stmt.Use{
Use: nameAB,
},
},
},
&expr.ClassConstFetch{
Class: nameBC,
ConstantName: &node.Identifier{Value: "FOO"},
},
},
}
expected := map[node.Node]string{
nameBC: "A\\B\\C",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveNew(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
ast := &stmt.StmtList{
Stmts: []node.Node{
&stmt.UseList{
Uses: []node.Node{
&stmt.Use{
Use: nameAB,
},
},
},
&expr.New{
Class: nameBC,
Arguments: []node.Node{},
},
},
}
expected := map[node.Node]string{
nameBC: "A\\B\\C",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveInstanceOf(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
ast := &stmt.StmtList{
Stmts: []node.Node{
&stmt.UseList{
Uses: []node.Node{
&stmt.Use{
Use: nameAB,
},
},
},
&expr.InstanceOf{
Expr: &expr.Variable{VarName: &node.Identifier{Value: "$foo"}},
Class: nameBC,
},
},
}
expected := map[node.Node]string{
nameBC: "A\\B\\C",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveInstanceCatch(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
nameDE := &name.Name{Parts: []node.Node{&name.NamePart{Value: "D"}, &name.NamePart{Value: "E"}}}
nameF := &name.Name{Parts: []node.Node{&name.NamePart{Value: "F"}}}
ast := &stmt.StmtList{
Stmts: []node.Node{
&stmt.UseList{
Uses: []node.Node{
&stmt.Use{
Use: nameAB,
},
&stmt.Use{
Use: nameDE,
Alias: &node.Identifier{Value: "F"},
},
},
},
&stmt.Try{
Stmts: []node.Node{},
Catches: []node.Node{
&stmt.Catch{
Types: []node.Node{
nameBC,
nameF,
},
Variable: &expr.Variable{VarName: &node.Identifier{Value: "$foo"}},
Stmts: []node.Node{},
},
},
},
},
}
expected := map[node.Node]string{
nameBC: "A\\B\\C",
nameF: "D\\E",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveFunctionCall(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
nameB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}}}
ast := &stmt.StmtList{
Stmts: []node.Node{
&stmt.UseList{
UseType: &node.Identifier{Value: "function"},
Uses: []node.Node{
&stmt.Use{
Use: nameAB,
},
},
},
&expr.FunctionCall{
Function: nameB,
Arguments: []node.Node{},
},
},
}
expected := map[node.Node]string{
nameB: "A\\B",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveConstFetch(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
nameB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}}}
ast := &stmt.StmtList{
Stmts: []node.Node{
&stmt.UseList{
UseType: &node.Identifier{Value: "const"},
Uses: []node.Node{
&stmt.Use{
Use: nameAB,
},
},
},
&expr.ConstFetch{
Constant: nameB,
},
},
}
expected := map[node.Node]string{
nameB: "A\\B",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveGroupUse(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
nameBD := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "D"}}}
nameE := &name.Name{Parts: []node.Node{&name.NamePart{Value: "E"}}}
nameC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "C"}}}
nameF := &name.Name{Parts: []node.Node{&name.NamePart{Value: "F"}}}
ast := &stmt.StmtList{
Stmts: []node.Node{
&stmt.GroupUse{
Prefix: nameAB,
UseList: []node.Node{
&stmt.Use{
UseType: &node.Identifier{Value: "Function"},
Use: nameF,
},
&stmt.Use{
UseType: &node.Identifier{Value: "const"},
Use: nameC,
},
},
},
&stmt.GroupUse{
Prefix: nameBD,
UseType: &node.Identifier{Value: "Function"},
UseList: []node.Node{
&stmt.Use{
Use: nameE,
},
},
},
&expr.ConstFetch{
Constant: nameC,
},
&expr.FunctionCall{
Function: nameF,
Arguments: []node.Node{},
},
&expr.FunctionCall{
Function: nameE,
Arguments: []node.Node{},
},
},
}
expected := map[node.Node]string{
nameC: "A\\B\\C",
nameF: "A\\B\\F",
nameE: "B\\D\\E",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveTraitUse(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
nameB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}}}
fullyQualifiedNameB := &name.FullyQualified{Parts: []node.Node{&name.NamePart{Value: "B"}}}
fullyQualifiedNameBC := &name.FullyQualified{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
relativeNameB := &name.Relative{Parts: []node.Node{&name.NamePart{Value: "B"}}}
relativeNameBC := &name.Relative{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
ast := &stmt.StmtList{
Stmts: []node.Node{
&stmt.UseList{
Uses: []node.Node{
&stmt.Use{
Use: nameAB,
},
},
},
&stmt.TraitUse{
Traits: []node.Node{
nameB,
relativeNameB,
},
Adaptations: []node.Node{
&stmt.TraitUsePrecedence{
Ref: &stmt.TraitMethodRef{
Trait: fullyQualifiedNameB,
Method: &node.Identifier{Value: "foo"},
},
Insteadof: []node.Node{fullyQualifiedNameBC},
},
&stmt.TraitUseAlias{
Ref: &stmt.TraitMethodRef{
Trait: relativeNameBC,
Method: &node.Identifier{Value: "foo"},
},
Alias: &node.Identifier{Value: "bar"},
},
},
},
},
}
expected := map[node.Node]string{
nameB: "A\\B",
relativeNameB: "B",
fullyQualifiedNameB: "B",
fullyQualifiedNameBC: "B\\C",
relativeNameBC: "B\\C",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveClassName(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
class := &stmt.Class{
PhpDocComment: "",
ClassName: &node.Identifier{Value: "A"},
Extends: nameAB,
Implements: []node.Node{
nameBC,
},
}
ast := &stmt.StmtList{
Stmts: []node.Node{
class,
},
}
expected := map[node.Node]string{
class: "A",
nameAB: "A\\B",
nameBC: "B\\C",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveInterfaceName(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
interfaceNode := &stmt.Interface{
PhpDocComment: "",
InterfaceName: &node.Identifier{Value: "A"},
Extends: []node.Node{
nameAB,
nameBC,
},
}
ast := &stmt.StmtList{
Stmts: []node.Node{
interfaceNode,
},
}
expected := map[node.Node]string{
interfaceNode: "A",
nameAB: "A\\B",
nameBC: "B\\C",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveTraitName(t *testing.T) {
traitNode := &stmt.Trait{
PhpDocComment: "",
TraitName: &node.Identifier{Value: "A"},
Stmts: []node.Node{},
}
ast := &stmt.StmtList{
Stmts: []node.Node{
traitNode,
},
}
expected := map[node.Node]string{
traitNode: "A",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveFunctionName(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
functionNode := &stmt.Function{
ReturnsRef: false,
PhpDocComment: "",
FunctionName: &node.Identifier{Value: "A"},
Params: []node.Node{
&node.Parameter{
ByRef: false,
Variadic: false,
VariableType: nameAB,
Variable: &expr.Variable{VarName: &node.Identifier{Value: "$foo"}},
},
},
ReturnType: &node.Nullable{Expr: nameBC},
Stmts: []node.Node{},
}
ast := &stmt.StmtList{
Stmts: []node.Node{
functionNode,
},
}
expected := map[node.Node]string{
functionNode: "A",
nameAB: "A\\B",
nameBC: "B\\C",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveMethodName(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
methodNode := &stmt.ClassMethod{
ReturnsRef: false,
PhpDocComment: "",
MethodName: &node.Identifier{Value: "A"},
Params: []node.Node{
&node.Parameter{
ByRef: false,
Variadic: false,
VariableType: nameAB,
Variable: &expr.Variable{VarName: &node.Identifier{Value: "$foo"}},
},
},
ReturnType: &node.Nullable{Expr: nameBC},
Stmts: []node.Node{},
}
expected := map[node.Node]string{
nameAB: "A\\B",
nameBC: "B\\C",
}
nsResolver := visitor.NewNamespaceResolver()
methodNode.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveClosureName(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
nameBC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "B"}, &name.NamePart{Value: "C"}}}
closureNode := &expr.Closure{
ReturnsRef: false,
Static: false,
PhpDocComment: "",
Params: []node.Node{
&node.Parameter{
ByRef: false,
Variadic: false,
VariableType: nameAB,
Variable: &expr.Variable{VarName: &node.Identifier{Value: "$foo"}},
},
},
ReturnType: &node.Nullable{Expr: nameBC},
Stmts: []node.Node{},
}
expected := map[node.Node]string{
nameAB: "A\\B",
nameBC: "B\\C",
}
nsResolver := visitor.NewNamespaceResolver()
closureNode.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveConstantsName(t *testing.T) {
nameAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
constantB := &stmt.Constant{
PhpDocComment: "",
ConstantName: &node.Identifier{Value: "B"},
Expr: &scalar.Lnumber{Value: "1"},
}
constantC := &stmt.Constant{
PhpDocComment: "",
ConstantName: &node.Identifier{Value: "C"},
Expr: &scalar.Lnumber{Value: "1"},
}
ast := &stmt.StmtList{
Stmts: []node.Node{
&stmt.Namespace{
NamespaceName: nameAB,
},
&stmt.ConstList{
Consts: []node.Node{
constantB,
constantC,
},
},
},
}
expected := map[node.Node]string{
constantB: "A\\B\\B",
constantC: "A\\B\\C",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveNamespaces(t *testing.T) {
namespaceAB := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "B"}}}
namespaceCD := &name.Name{Parts: []node.Node{&name.NamePart{Value: "C"}, &name.NamePart{Value: "D"}}}
nameAC := &name.Name{Parts: []node.Node{&name.NamePart{Value: "A"}, &name.NamePart{Value: "C"}}}
nameCF := &name.Name{Parts: []node.Node{&name.NamePart{Value: "C"}, &name.NamePart{Value: "F"}}}
nameFG := &name.Name{Parts: []node.Node{&name.NamePart{Value: "F"}, &name.NamePart{Value: "G"}}}
relativeNameCE := &name.Relative{Parts: []node.Node{&name.NamePart{Value: "C"}, &name.NamePart{Value: "E"}}}
constantB := &stmt.Constant{
PhpDocComment: "",
ConstantName: &node.Identifier{Value: "B"},
Expr: &scalar.Lnumber{Value: "1"},
}
constantC := &stmt.Constant{
PhpDocComment: "",
ConstantName: &node.Identifier{Value: "C"},
Expr: &scalar.Lnumber{Value: "1"},
}
ast := &stmt.StmtList{
Stmts: []node.Node{
&stmt.Namespace{
NamespaceName: namespaceAB,
},
&stmt.ConstList{
Consts: []node.Node{
constantB,
constantC,
},
},
&expr.StaticCall{
Class: nameFG,
Call: &node.Identifier{Value: "foo"},
Arguments: []node.Node{},
},
&stmt.Namespace{
Stmts: []node.Node{},
},
&stmt.Namespace{
NamespaceName: namespaceCD,
Stmts: []node.Node{
&stmt.UseList{
Uses: []node.Node{
&stmt.Use{
Use: nameAC,
},
},
},
&expr.StaticCall{
Class: relativeNameCE,
Call: &node.Identifier{Value: "foo"},
Arguments: []node.Node{},
},
&expr.StaticCall{
Class: nameCF,
Call: &node.Identifier{Value: "foo"},
Arguments: []node.Node{},
},
},
},
},
}
expected := map[node.Node]string{
constantB: "A\\B\\B",
constantC: "A\\B\\C",
nameFG: "A\\B\\F\\G",
relativeNameCE: "C\\D\\C\\E",
nameCF: "A\\C\\F",
}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}
func TestResolveStaticCallDinamicClassName(t *testing.T) {
ast := &stmt.StmtList{
Stmts: []node.Node{
&expr.StaticCall{
Class: &expr.Variable{VarName: &node.Identifier{Value: "$foo"}},
Call: &node.Identifier{Value: "foo"},
Arguments: []node.Node{},
},
},
}
expected := map[node.Node]string{}
nsResolver := visitor.NewNamespaceResolver()
ast.Walk(nsResolver)
assertEqual(t, expected, nsResolver.ResolvedNames)
}