refactor cmd
This commit is contained in:
parent
7e07f1ca26
commit
12086ef6b6
2
Makefile
2
Makefile
@ -7,7 +7,7 @@ fmt:
|
|||||||
|
|
||||||
build:
|
build:
|
||||||
go generate ./...
|
go generate ./...
|
||||||
go build
|
go build ./cmd/...
|
||||||
|
|
||||||
run:
|
run:
|
||||||
./php-parser -d go $(PHPFILE)
|
./php-parser -d go $(PHPFILE)
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/z7zmey/php-parser/pkg/ast/traverser"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@ -13,15 +13,14 @@ import (
|
|||||||
|
|
||||||
"github.com/pkg/profile"
|
"github.com/pkg/profile"
|
||||||
"github.com/yookoala/realpath"
|
"github.com/yookoala/realpath"
|
||||||
"github.com/z7zmey/php-parser/parser"
|
"github.com/z7zmey/php-parser/pkg/parser"
|
||||||
"github.com/z7zmey/php-parser/printer"
|
"github.com/z7zmey/php-parser/pkg/ast/visitor"
|
||||||
"github.com/z7zmey/php-parser/visitor"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
var phpVersion string
|
var phpVersion string
|
||||||
var dumpType string
|
|
||||||
var profiler string
|
var profiler string
|
||||||
|
var dump *bool
|
||||||
var withFreeFloating *bool
|
var withFreeFloating *bool
|
||||||
var showResolvedNs *bool
|
var showResolvedNs *bool
|
||||||
var printBack *bool
|
var printBack *bool
|
||||||
@ -42,7 +41,7 @@ func main() {
|
|||||||
showResolvedNs = flag.Bool("r", false, "resolve names")
|
showResolvedNs = flag.Bool("r", false, "resolve names")
|
||||||
printBack = flag.Bool("pb", false, "print AST back into the parsed file")
|
printBack = flag.Bool("pb", false, "print AST back into the parsed file")
|
||||||
printPath = flag.Bool("p", false, "print filepath")
|
printPath = flag.Bool("p", false, "print filepath")
|
||||||
flag.StringVar(&dumpType, "d", "", "dump format: [custom, go, json, pretty_json]")
|
dump = flag.Bool("d", false, "dump")
|
||||||
flag.StringVar(&profiler, "prof", "", "start profiler: [cpu, mem, trace]")
|
flag.StringVar(&profiler, "prof", "", "start profiler: [cpu, mem, trace]")
|
||||||
flag.StringVar(&phpVersion, "phpver", "7.4", "php version")
|
flag.StringVar(&phpVersion, "phpver", "7.4", "php version")
|
||||||
|
|
||||||
@ -115,7 +114,7 @@ func parserWorker(fileCh <-chan *file, r chan<- result) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if *withFreeFloating {
|
if *withFreeFloating {
|
||||||
parserWorker.WithFreeFloating()
|
parserWorker.WithTokens()
|
||||||
}
|
}
|
||||||
|
|
||||||
parserWorker.Parse()
|
parserWorker.Parse()
|
||||||
@ -143,44 +142,26 @@ func printerWorker(r <-chan result) {
|
|||||||
fmt.Fprintf(os.Stdout, "==> %s\n", e)
|
fmt.Fprintf(os.Stdout, "==> %s\n", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
if *printBack {
|
//if *printBack {
|
||||||
o := bytes.NewBuffer([]byte{})
|
// o := bytes.NewBuffer([]byte{})
|
||||||
p := printer.NewPrinter(o)
|
// p := printer.NewPrinter(o)
|
||||||
p.Print(res.parser.GetRootNode())
|
// p.Print(res.parser.GetRootNode())
|
||||||
|
//
|
||||||
|
// err := ioutil.WriteFile(res.path, o.Bytes(), 0644)
|
||||||
|
// checkErr(err)
|
||||||
|
//}
|
||||||
|
|
||||||
err := ioutil.WriteFile(res.path, o.Bytes(), 0644)
|
|
||||||
checkErr(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var nsResolver *visitor.NamespaceResolver
|
|
||||||
if *showResolvedNs {
|
if *showResolvedNs {
|
||||||
nsResolver = visitor.NewNamespaceResolver()
|
v := visitor.NewNamespaceResolver()
|
||||||
res.parser.GetRootNode().Walk(nsResolver)
|
t := traverser.NewDFS(v)
|
||||||
|
t.Traverse(res.parser.GetRootNode())
|
||||||
|
fmt.Printf("%+v", v.ResolvedNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch dumpType {
|
if *dump == true {
|
||||||
case "custom":
|
v := visitor.NewDump(os.Stdout)
|
||||||
dumper := &visitor.Dumper{
|
t := traverser.NewDFS(v)
|
||||||
Writer: os.Stdout,
|
t.Traverse(res.parser.GetRootNode())
|
||||||
Indent: "| ",
|
|
||||||
NsResolver: nsResolver,
|
|
||||||
}
|
|
||||||
res.parser.GetRootNode().Walk(dumper)
|
|
||||||
case "json":
|
|
||||||
dumper := &visitor.JsonDumper{
|
|
||||||
Writer: os.Stdout,
|
|
||||||
NsResolver: nsResolver,
|
|
||||||
}
|
|
||||||
res.parser.GetRootNode().Walk(dumper)
|
|
||||||
case "pretty_json":
|
|
||||||
dumper := &visitor.PrettyJsonDumper{
|
|
||||||
Writer: os.Stdout,
|
|
||||||
NsResolver: nsResolver,
|
|
||||||
}
|
|
||||||
res.parser.GetRootNode().Walk(dumper)
|
|
||||||
case "go":
|
|
||||||
dumper := &visitor.GoDumper{Writer: os.Stdout}
|
|
||||||
res.parser.GetRootNode().Walk(dumper)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Done()
|
wg.Done()
|
File diff suppressed because it is too large
Load Diff
@ -117,7 +117,7 @@ func (v *Dump) Identifier(n *ast.Identifier) {
|
|||||||
v.printIndentIfNotSingle(v.indent - 1)
|
v.printIndentIfNotSingle(v.indent - 1)
|
||||||
v.print("&ast.Identifier{\n")
|
v.print("&ast.Identifier{\n")
|
||||||
|
|
||||||
v.printIndentIfNotSingle(v.indent)
|
v.printIndent(v.indent)
|
||||||
v.print(fmt.Sprintf("Value: %q,\n", n.Value))
|
v.print(fmt.Sprintf("Value: %q,\n", n.Value))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,7 +335,7 @@ func (v *Dump) StmtInlineHtml(n *ast.StmtInlineHtml) {
|
|||||||
v.printIndentIfNotSingle(v.indent - 1)
|
v.printIndentIfNotSingle(v.indent - 1)
|
||||||
v.print("&ast.StmtInlineHtml{\n")
|
v.print("&ast.StmtInlineHtml{\n")
|
||||||
|
|
||||||
v.printIndentIfNotSingle(v.indent)
|
v.printIndent(v.indent)
|
||||||
v.print(fmt.Sprintf("Value: %q,\n", n.Value))
|
v.print(fmt.Sprintf("Value: %q,\n", n.Value))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -953,7 +953,7 @@ func (v *Dump) ScalarDnumber(n *ast.ScalarDnumber) {
|
|||||||
v.printIndentIfNotSingle(v.indent - 1)
|
v.printIndentIfNotSingle(v.indent - 1)
|
||||||
v.print("&ast.ScalarDnumber{\n")
|
v.print("&ast.ScalarDnumber{\n")
|
||||||
|
|
||||||
v.printIndentIfNotSingle(v.indent)
|
v.printIndent(v.indent)
|
||||||
v.print(fmt.Sprintf("Value: %q,\n", n.Value))
|
v.print(fmt.Sprintf("Value: %q,\n", n.Value))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -966,7 +966,7 @@ func (v *Dump) ScalarEncapsedStringPart(n *ast.ScalarEncapsedStringPart) {
|
|||||||
v.printIndentIfNotSingle(v.indent - 1)
|
v.printIndentIfNotSingle(v.indent - 1)
|
||||||
v.print("&ast.ScalarEncapsedStringPart{\n")
|
v.print("&ast.ScalarEncapsedStringPart{\n")
|
||||||
|
|
||||||
v.printIndentIfNotSingle(v.indent)
|
v.printIndent(v.indent)
|
||||||
v.print(fmt.Sprintf("Value: %q,\n", n.Value))
|
v.print(fmt.Sprintf("Value: %q,\n", n.Value))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -974,7 +974,7 @@ func (v *Dump) ScalarHeredoc(n *ast.ScalarHeredoc) {
|
|||||||
v.printIndentIfNotSingle(v.indent - 1)
|
v.printIndentIfNotSingle(v.indent - 1)
|
||||||
v.print("&ast.ScalarHeredoc{\n")
|
v.print("&ast.ScalarHeredoc{\n")
|
||||||
|
|
||||||
v.printIndentIfNotSingle(v.indent)
|
v.printIndent(v.indent)
|
||||||
v.print(fmt.Sprintf("Label: %q,\n", n.Label))
|
v.print(fmt.Sprintf("Label: %q,\n", n.Label))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -982,7 +982,7 @@ func (v *Dump) ScalarLnumber(n *ast.ScalarLnumber) {
|
|||||||
v.printIndentIfNotSingle(v.indent - 1)
|
v.printIndentIfNotSingle(v.indent - 1)
|
||||||
v.print("&ast.ScalarLnumber{\n")
|
v.print("&ast.ScalarLnumber{\n")
|
||||||
|
|
||||||
v.printIndentIfNotSingle(v.indent)
|
v.printIndent(v.indent)
|
||||||
v.print(fmt.Sprintf("Value: %q,\n", n.Value))
|
v.print(fmt.Sprintf("Value: %q,\n", n.Value))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -990,7 +990,7 @@ func (v *Dump) ScalarMagicConstant(n *ast.ScalarMagicConstant) {
|
|||||||
v.printIndentIfNotSingle(v.indent - 1)
|
v.printIndentIfNotSingle(v.indent - 1)
|
||||||
v.print("&ast.ScalarMagicConstant{\n")
|
v.print("&ast.ScalarMagicConstant{\n")
|
||||||
|
|
||||||
v.printIndentIfNotSingle(v.indent)
|
v.printIndent(v.indent)
|
||||||
v.print(fmt.Sprintf("Value: %q,\n", n.Value))
|
v.print(fmt.Sprintf("Value: %q,\n", n.Value))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -998,6 +998,29 @@ func (v *Dump) ScalarString(n *ast.ScalarString) {
|
|||||||
v.printIndentIfNotSingle(v.indent - 1)
|
v.printIndentIfNotSingle(v.indent - 1)
|
||||||
v.print("&ast.ScalarString{\n")
|
v.print("&ast.ScalarString{\n")
|
||||||
|
|
||||||
v.printIndentIfNotSingle(v.indent)
|
v.printIndent(v.indent)
|
||||||
|
v.print(fmt.Sprintf("Value: %q,\n", n.Value))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Dump) NameName(_ *ast.NameName) {
|
||||||
|
v.printIndentIfNotSingle(v.indent - 1)
|
||||||
|
v.print("&ast.NameName{\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Dump) NameFullyQualified(_ *ast.NameFullyQualified) {
|
||||||
|
v.printIndentIfNotSingle(v.indent - 1)
|
||||||
|
v.print("&ast.NameFullyQualified{\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Dump) NameRelative(_ *ast.NameRelative) {
|
||||||
|
v.printIndentIfNotSingle(v.indent - 1)
|
||||||
|
v.print("&ast.NameRelative{\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Dump) NameNamePart(n *ast.NameNamePart) {
|
||||||
|
v.printIndentIfNotSingle(v.indent - 1)
|
||||||
|
v.print("&ast.NameNamePart{\n")
|
||||||
|
|
||||||
|
v.printIndent(v.indent)
|
||||||
v.print(fmt.Sprintf("Value: %q,\n", n.Value))
|
v.print(fmt.Sprintf("Value: %q,\n", n.Value))
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ func ExampleDump() {
|
|||||||
Var: &ast.ExprVariable{},
|
Var: &ast.ExprVariable{},
|
||||||
},
|
},
|
||||||
&ast.StmtInlineHtml{
|
&ast.StmtInlineHtml{
|
||||||
Value: "foo",
|
Value: []byte("foo"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
399
pkg/ast/visitor/namespace_resolver.go
Normal file
399
pkg/ast/visitor/namespace_resolver.go
Normal file
@ -0,0 +1,399 @@
|
|||||||
|
// Package visitor contains walker.visitor implementations
|
||||||
|
package visitor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/z7zmey/php-parser/pkg/ast"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NamespaceResolver visitor
|
||||||
|
type NamespaceResolver struct {
|
||||||
|
Null
|
||||||
|
Namespace *Namespace
|
||||||
|
ResolvedNames map[ast.Vertex]string
|
||||||
|
|
||||||
|
goDeep bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNamespaceResolver NamespaceResolver type constructor
|
||||||
|
func NewNamespaceResolver() *NamespaceResolver {
|
||||||
|
return &NamespaceResolver{
|
||||||
|
Namespace: NewNamespace(""),
|
||||||
|
ResolvedNames: map[ast.Vertex]string{},
|
||||||
|
goDeep: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) EnterNode(n ast.Vertex) bool {
|
||||||
|
n.Accept(nsr)
|
||||||
|
|
||||||
|
if !nsr.goDeep {
|
||||||
|
nsr.goDeep = true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) StmtNamespace(n *ast.StmtNamespace) {
|
||||||
|
if n.NamespaceName == nil {
|
||||||
|
nsr.Namespace = NewNamespace("")
|
||||||
|
} else {
|
||||||
|
NSParts := n.NamespaceName.(*ast.NameName).Parts
|
||||||
|
nsr.Namespace = NewNamespace(concatNameParts(NSParts))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) StmtUseList(n *ast.StmtUseList) {
|
||||||
|
useType := ""
|
||||||
|
if n.UseType != nil {
|
||||||
|
useType = string(n.UseType.(*ast.Identifier).Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, nn := range n.Uses {
|
||||||
|
nsr.AddAlias(useType, nn, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
nsr.goDeep = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) StmtGroupUse(n *ast.StmtGroupUse) {
|
||||||
|
useType := ""
|
||||||
|
if n.UseType != nil {
|
||||||
|
useType = string(n.UseType.(*ast.Identifier).Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, nn := range n.UseList {
|
||||||
|
nsr.AddAlias(useType, nn, n.Prefix.(*ast.NameName).Parts)
|
||||||
|
}
|
||||||
|
|
||||||
|
nsr.goDeep = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) StmtClass(n *ast.StmtClass) {
|
||||||
|
if n.Extends != nil {
|
||||||
|
nsr.ResolveName(n.Extends.ClassName, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.Implements != nil {
|
||||||
|
for _, interfaceName := range n.Implements.InterfaceNames {
|
||||||
|
nsr.ResolveName(interfaceName, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.ClassName != nil {
|
||||||
|
nsr.AddNamespacedName(n, string(n.ClassName.(*ast.Identifier).Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) StmtInterface(n *ast.StmtInterface) {
|
||||||
|
if n.Extends != nil {
|
||||||
|
for _, interfaceName := range n.Extends.InterfaceNames {
|
||||||
|
nsr.ResolveName(interfaceName, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsr.AddNamespacedName(n, string(n.InterfaceName.(*ast.Identifier).Value))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) StmtTrait(n *ast.StmtTrait) {
|
||||||
|
nsr.AddNamespacedName(n, string(n.TraitName.(*ast.Identifier).Value))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) StmtFunction(n *ast.StmtFunction) {
|
||||||
|
nsr.AddNamespacedName(n, string(n.FunctionName.(*ast.Identifier).Value))
|
||||||
|
|
||||||
|
for _, parameter := range n.Params {
|
||||||
|
nsr.ResolveType(parameter.(*ast.Parameter).Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.ReturnType != nil {
|
||||||
|
nsr.ResolveType(n.ReturnType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) StmtClassMethod(n *ast.StmtClassMethod) {
|
||||||
|
for _, parameter := range n.Params {
|
||||||
|
nsr.ResolveType(parameter.(*ast.Parameter).Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.ReturnType != nil {
|
||||||
|
nsr.ResolveType(n.ReturnType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) ExprClosure(n *ast.ExprClosure) {
|
||||||
|
for _, parameter := range n.Params {
|
||||||
|
nsr.ResolveType(parameter.(*ast.Parameter).Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.ReturnType != nil {
|
||||||
|
nsr.ResolveType(n.ReturnType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) StmtConstList(n *ast.StmtConstList) {
|
||||||
|
for _, constant := range n.Consts {
|
||||||
|
nsr.AddNamespacedName(constant, string(constant.(*ast.StmtConstant).ConstantName.(*ast.Identifier).Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) ExprStaticCall(n *ast.ExprStaticCall) {
|
||||||
|
nsr.ResolveName(n.Class, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) ExprStaticPropertyFetch(n *ast.ExprStaticPropertyFetch) {
|
||||||
|
nsr.ResolveName(n.Class, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) ExprClassConstFetch(n *ast.ExprClassConstFetch) {
|
||||||
|
nsr.ResolveName(n.Class, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) ExprNew(n *ast.ExprNew) {
|
||||||
|
nsr.ResolveName(n.Class, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) ExprInstanceOf(n *ast.ExprInstanceOf) {
|
||||||
|
nsr.ResolveName(n.Class, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) StmtCatch(n *ast.StmtCatch) {
|
||||||
|
for _, t := range n.Types {
|
||||||
|
nsr.ResolveName(t, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) ExprFunctionCall(n *ast.ExprFunctionCall) {
|
||||||
|
nsr.ResolveName(n.Function, "function")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) ExprConstFetch(n *ast.ExprConstFetch) {
|
||||||
|
nsr.ResolveName(n.Const, "const")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsr *NamespaceResolver) StmtTraitUse(n *ast.StmtTraitUse) {
|
||||||
|
for _, t := range n.Traits {
|
||||||
|
nsr.ResolveName(t, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
if adaptationList, ok := n.TraitAdaptationList.(*ast.StmtTraitAdaptationList); ok {
|
||||||
|
for _, a := range adaptationList.Adaptations {
|
||||||
|
switch aa := a.(type) {
|
||||||
|
case *ast.StmtTraitUsePrecedence:
|
||||||
|
refTrait := aa.Ref.(*ast.StmtTraitMethodRef).Trait
|
||||||
|
if refTrait != nil {
|
||||||
|
nsr.ResolveName(refTrait, "")
|
||||||
|
}
|
||||||
|
for _, insteadOf := range aa.Insteadof {
|
||||||
|
nsr.ResolveName(insteadOf, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
case *ast.StmtTraitUseAlias:
|
||||||
|
refTrait := aa.Ref.(*ast.StmtTraitMethodRef).Trait
|
||||||
|
if refTrait != nil {
|
||||||
|
nsr.ResolveName(refTrait, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LeaveNode is invoked after node process
|
||||||
|
func (nsr *NamespaceResolver) LeaveNode(n ast.Vertex) {
|
||||||
|
switch nn := n.(type) {
|
||||||
|
case *ast.StmtNamespace:
|
||||||
|
if nn.Stmts != nil {
|
||||||
|
nsr.Namespace = NewNamespace("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddAlias adds a new alias
|
||||||
|
func (nsr *NamespaceResolver) AddAlias(useType string, nn ast.Vertex, prefix []ast.Vertex) {
|
||||||
|
switch use := nn.(type) {
|
||||||
|
case *ast.StmtUse:
|
||||||
|
if use.UseType != nil {
|
||||||
|
useType = string(use.UseType.(*ast.Identifier).Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
useNameParts := use.Use.(*ast.NameName).Parts
|
||||||
|
var alias string
|
||||||
|
if use.Alias == nil {
|
||||||
|
alias = string(useNameParts[len(useNameParts)-1].(*ast.NameNamePart).Value)
|
||||||
|
} else {
|
||||||
|
alias = string(use.Alias.(*ast.Identifier).Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
nsr.Namespace.AddAlias(useType, concatNameParts(prefix, useNameParts), alias)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddNamespacedName adds namespaced name by node
|
||||||
|
func (nsr *NamespaceResolver) AddNamespacedName(nn ast.Vertex, nodeName string) {
|
||||||
|
if nsr.Namespace.Namespace == "" {
|
||||||
|
nsr.ResolvedNames[nn] = nodeName
|
||||||
|
} else {
|
||||||
|
nsr.ResolvedNames[nn] = nsr.Namespace.Namespace + "\\" + nodeName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveName adds a resolved fully qualified name by node
|
||||||
|
func (nsr *NamespaceResolver) ResolveName(nameNode ast.Vertex, aliasType string) {
|
||||||
|
resolved, err := nsr.Namespace.ResolveName(nameNode, aliasType)
|
||||||
|
if err == nil {
|
||||||
|
nsr.ResolvedNames[nameNode] = resolved
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveType adds a resolved fully qualified type name
|
||||||
|
func (nsr *NamespaceResolver) ResolveType(n ast.Vertex) {
|
||||||
|
switch nn := n.(type) {
|
||||||
|
case *ast.Nullable:
|
||||||
|
nsr.ResolveType(nn.Expr)
|
||||||
|
case *ast.NameName:
|
||||||
|
nsr.ResolveName(n, "")
|
||||||
|
case *ast.NameRelative:
|
||||||
|
nsr.ResolveName(n, "")
|
||||||
|
case *ast.NameFullyQualified:
|
||||||
|
nsr.ResolveName(n, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace context
|
||||||
|
type Namespace struct {
|
||||||
|
Namespace string
|
||||||
|
Aliases map[string]map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNamespace constructor
|
||||||
|
func NewNamespace(NSName string) *Namespace {
|
||||||
|
return &Namespace{
|
||||||
|
Namespace: NSName,
|
||||||
|
Aliases: map[string]map[string]string{
|
||||||
|
"": {},
|
||||||
|
"const": {},
|
||||||
|
"function": {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddAlias adds a new alias
|
||||||
|
func (ns *Namespace) AddAlias(aliasType string, aliasName string, alias string) {
|
||||||
|
aliasType = strings.ToLower(aliasType)
|
||||||
|
|
||||||
|
if aliasType == "const" {
|
||||||
|
ns.Aliases[aliasType][alias] = aliasName
|
||||||
|
} else {
|
||||||
|
ns.Aliases[aliasType][strings.ToLower(alias)] = aliasName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveName returns a resolved fully qualified name
|
||||||
|
func (ns *Namespace) ResolveName(nameNode ast.Vertex, aliasType string) (string, error) {
|
||||||
|
switch n := nameNode.(type) {
|
||||||
|
case *ast.NameFullyQualified:
|
||||||
|
// Fully qualifid name is already resolved
|
||||||
|
return concatNameParts(n.Parts), nil
|
||||||
|
|
||||||
|
case *ast.NameRelative:
|
||||||
|
if ns.Namespace == "" {
|
||||||
|
return concatNameParts(n.Parts), nil
|
||||||
|
}
|
||||||
|
return ns.Namespace + "\\" + concatNameParts(n.Parts), nil
|
||||||
|
|
||||||
|
case *ast.NameName:
|
||||||
|
if aliasType == "const" && len(n.Parts) == 1 {
|
||||||
|
part := strings.ToLower(string(n.Parts[0].(*ast.NameNamePart).Value))
|
||||||
|
if part == "true" || part == "false" || part == "null" {
|
||||||
|
return part, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if aliasType == "" && len(n.Parts) == 1 {
|
||||||
|
part := strings.ToLower(string(n.Parts[0].(*ast.NameNamePart).Value))
|
||||||
|
|
||||||
|
switch part {
|
||||||
|
case "self":
|
||||||
|
fallthrough
|
||||||
|
case "static":
|
||||||
|
fallthrough
|
||||||
|
case "parent":
|
||||||
|
fallthrough
|
||||||
|
case "int":
|
||||||
|
fallthrough
|
||||||
|
case "float":
|
||||||
|
fallthrough
|
||||||
|
case "bool":
|
||||||
|
fallthrough
|
||||||
|
case "string":
|
||||||
|
fallthrough
|
||||||
|
case "void":
|
||||||
|
fallthrough
|
||||||
|
case "iterable":
|
||||||
|
fallthrough
|
||||||
|
case "object":
|
||||||
|
return part, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aliasName, err := ns.ResolveAlias(nameNode, aliasType)
|
||||||
|
if err != nil {
|
||||||
|
// resolve as relative name if alias not found
|
||||||
|
if ns.Namespace == "" {
|
||||||
|
return concatNameParts(n.Parts), nil
|
||||||
|
}
|
||||||
|
return ns.Namespace + "\\" + concatNameParts(n.Parts), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(n.Parts) > 1 {
|
||||||
|
// if name qualified, replace first part by alias
|
||||||
|
return aliasName + "\\" + concatNameParts(n.Parts[1:]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return aliasName, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New("must be instance of name.Names")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveAlias returns alias or error if not found
|
||||||
|
func (ns *Namespace) ResolveAlias(nameNode ast.Vertex, aliasType string) (string, error) {
|
||||||
|
aliasType = strings.ToLower(aliasType)
|
||||||
|
nameParts := nameNode.(*ast.NameName).Parts
|
||||||
|
|
||||||
|
firstPartStr := string(nameParts[0].(*ast.NameNamePart).Value)
|
||||||
|
|
||||||
|
if len(nameParts) > 1 { // resolve aliases for qualified names, always against class alias type
|
||||||
|
firstPartStr = strings.ToLower(firstPartStr)
|
||||||
|
aliasType = ""
|
||||||
|
} else {
|
||||||
|
if aliasType != "const" { // constants are case-sensitive
|
||||||
|
firstPartStr = strings.ToLower(firstPartStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aliasName, ok := ns.Aliases[aliasType][firstPartStr]
|
||||||
|
if !ok {
|
||||||
|
return "", errors.New("Not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return aliasName, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func concatNameParts(parts ...[]ast.Vertex) string {
|
||||||
|
str := ""
|
||||||
|
|
||||||
|
for _, p := range parts {
|
||||||
|
for _, n := range p {
|
||||||
|
if str == "" {
|
||||||
|
str = string(n.(*ast.NameNamePart).Value)
|
||||||
|
} else {
|
||||||
|
str = str + "\\" + string(n.(*ast.NameNamePart).Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
986
pkg/ast/visitor/namespace_resolver_test.go
Normal file
986
pkg/ast/visitor/namespace_resolver_test.go
Normal file
@ -0,0 +1,986 @@
|
|||||||
|
package visitor_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gotest.tools/assert"
|
||||||
|
|
||||||
|
"github.com/z7zmey/php-parser/pkg/ast"
|
||||||
|
"github.com/z7zmey/php-parser/pkg/ast/traverser"
|
||||||
|
"github.com/z7zmey/php-parser/pkg/ast/visitor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestResolveStaticCall(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameBC := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}, &ast.NameNamePart{Value: []byte("C")}}}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtUseList{
|
||||||
|
Uses: []ast.Vertex{
|
||||||
|
&ast.StmtUse{
|
||||||
|
Use: nameAB,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.ExprStaticCall{
|
||||||
|
Class: nameBC,
|
||||||
|
Call: &ast.Identifier{Value: []byte("foo")},
|
||||||
|
ArgumentList: &ast.ArgumentList{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
nameBC: "A\\B\\C",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveStaticPropertyFetch(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameBC := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}, &ast.NameNamePart{Value: []byte("C")}}}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtUseList{
|
||||||
|
Uses: []ast.Vertex{
|
||||||
|
&ast.StmtUse{
|
||||||
|
Use: nameAB,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.ExprStaticPropertyFetch{
|
||||||
|
Class: nameBC,
|
||||||
|
Property: &ast.Identifier{Value: []byte("foo")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
nameBC: "A\\B\\C",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveClassConstFetch(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameBC := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}, &ast.NameNamePart{Value: []byte("C")}}}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtUseList{
|
||||||
|
Uses: []ast.Vertex{
|
||||||
|
&ast.StmtUse{
|
||||||
|
Use: nameAB,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.ExprClassConstFetch{
|
||||||
|
Class: nameBC,
|
||||||
|
ConstantName: &ast.Identifier{Value: []byte("FOO")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
nameBC: "A\\B\\C",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveNew(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameBC := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}, &ast.NameNamePart{Value: []byte("C")}}}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtUseList{
|
||||||
|
Uses: []ast.Vertex{
|
||||||
|
&ast.StmtUse{
|
||||||
|
Use: nameAB,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.ExprNew{
|
||||||
|
Class: nameBC,
|
||||||
|
ArgumentList: &ast.ArgumentList{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
nameBC: "A\\B\\C",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveInstanceOf(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameBC := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}, &ast.NameNamePart{Value: []byte("C")}}}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtUseList{
|
||||||
|
Uses: []ast.Vertex{
|
||||||
|
&ast.StmtUse{
|
||||||
|
Use: nameAB,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.ExprInstanceOf{
|
||||||
|
Expr: &ast.ExprVariable{VarName: &ast.Identifier{Value: []byte("foo")}},
|
||||||
|
Class: nameBC,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
nameBC: "A\\B\\C",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveInstanceCatch(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameBC := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}, &ast.NameNamePart{Value: []byte("C")}}}
|
||||||
|
|
||||||
|
nameDE := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("D")}, &ast.NameNamePart{Value: []byte("E")}}}
|
||||||
|
nameF := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("F")}}}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtUseList{
|
||||||
|
Uses: []ast.Vertex{
|
||||||
|
&ast.StmtUse{
|
||||||
|
Use: nameAB,
|
||||||
|
},
|
||||||
|
&ast.StmtUse{
|
||||||
|
Use: nameDE,
|
||||||
|
Alias: &ast.Identifier{Value: []byte("F")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.StmtTry{
|
||||||
|
Stmts: []ast.Vertex{},
|
||||||
|
Catches: []ast.Vertex{
|
||||||
|
&ast.StmtCatch{
|
||||||
|
Types: []ast.Vertex{
|
||||||
|
nameBC,
|
||||||
|
nameF,
|
||||||
|
},
|
||||||
|
Var: &ast.ExprVariable{VarName: &ast.Identifier{Value: []byte("foo")}},
|
||||||
|
Stmts: []ast.Vertex{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
nameBC: "A\\B\\C",
|
||||||
|
nameF: "D\\E",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveFunctionCall(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtUseList{
|
||||||
|
UseType: &ast.Identifier{Value: []byte("function")},
|
||||||
|
Uses: []ast.Vertex{
|
||||||
|
&ast.StmtUse{
|
||||||
|
Use: nameAB,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.ExprFunctionCall{
|
||||||
|
Function: nameB,
|
||||||
|
ArgumentList: &ast.ArgumentList{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
nameB: "A\\B",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveConstFetch(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtUseList{
|
||||||
|
UseType: &ast.Identifier{Value: []byte("const")},
|
||||||
|
Uses: []ast.Vertex{
|
||||||
|
&ast.StmtUse{
|
||||||
|
Use: nameAB,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.ExprConstFetch{
|
||||||
|
Const: nameB,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
nameB: "A\\B",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveGroupUse(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameBD := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}, &ast.NameNamePart{Value: []byte("D")}}}
|
||||||
|
nameE := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("E")}}}
|
||||||
|
nameC := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("C")}}}
|
||||||
|
nameF := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("F")}}}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtGroupUse{
|
||||||
|
Prefix: nameAB,
|
||||||
|
UseList: []ast.Vertex{
|
||||||
|
&ast.StmtUse{
|
||||||
|
UseType: &ast.Identifier{Value: []byte("Function")},
|
||||||
|
Use: nameF,
|
||||||
|
},
|
||||||
|
&ast.StmtUse{
|
||||||
|
UseType: &ast.Identifier{Value: []byte("const")},
|
||||||
|
Use: nameC,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.StmtGroupUse{
|
||||||
|
Prefix: nameBD,
|
||||||
|
UseType: &ast.Identifier{Value: []byte("Function")},
|
||||||
|
UseList: []ast.Vertex{
|
||||||
|
&ast.StmtUse{
|
||||||
|
Use: nameE,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.ExprConstFetch{
|
||||||
|
Const: nameC,
|
||||||
|
},
|
||||||
|
&ast.ExprFunctionCall{
|
||||||
|
Function: nameF,
|
||||||
|
ArgumentList: &ast.ArgumentList{},
|
||||||
|
},
|
||||||
|
&ast.ExprFunctionCall{
|
||||||
|
Function: nameE,
|
||||||
|
ArgumentList: &ast.ArgumentList{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
nameC: "A\\B\\C",
|
||||||
|
nameF: "A\\B\\F",
|
||||||
|
nameE: "B\\D\\E",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveTraitUse(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameD := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("D")}}}
|
||||||
|
|
||||||
|
fullyQualifiedNameB := &ast.NameFullyQualified{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
fullyQualifiedNameBC := &ast.NameFullyQualified{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}, &ast.NameNamePart{Value: []byte("C")}}}
|
||||||
|
relativeNameB := &ast.NameRelative{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
relativeNameBC := &ast.NameRelative{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}, &ast.NameNamePart{Value: []byte("C")}}}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtUseList{
|
||||||
|
Uses: []ast.Vertex{
|
||||||
|
&ast.StmtUse{
|
||||||
|
Use: nameAB,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.StmtTraitUse{
|
||||||
|
Traits: []ast.Vertex{
|
||||||
|
nameB,
|
||||||
|
relativeNameB,
|
||||||
|
},
|
||||||
|
TraitAdaptationList: &ast.StmtTraitAdaptationList{
|
||||||
|
Adaptations: []ast.Vertex{
|
||||||
|
&ast.StmtTraitUsePrecedence{
|
||||||
|
Ref: &ast.StmtTraitMethodRef{
|
||||||
|
Trait: fullyQualifiedNameB,
|
||||||
|
Method: &ast.Identifier{Value: []byte("foo")},
|
||||||
|
},
|
||||||
|
Insteadof: []ast.Vertex{fullyQualifiedNameBC},
|
||||||
|
},
|
||||||
|
&ast.StmtTraitUseAlias{
|
||||||
|
Ref: &ast.StmtTraitMethodRef{
|
||||||
|
Trait: relativeNameBC,
|
||||||
|
Method: &ast.Identifier{Value: []byte("foo")},
|
||||||
|
},
|
||||||
|
Alias: &ast.Identifier{Value: []byte("bar")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.StmtTraitUse{
|
||||||
|
Traits: []ast.Vertex{
|
||||||
|
nameD,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
nameB: "A\\B",
|
||||||
|
nameD: "D",
|
||||||
|
relativeNameB: "B",
|
||||||
|
fullyQualifiedNameB: "B",
|
||||||
|
fullyQualifiedNameBC: "B\\C",
|
||||||
|
relativeNameBC: "B\\C",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveClassName(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameBC := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}, &ast.NameNamePart{Value: []byte("C")}}}
|
||||||
|
|
||||||
|
class := &ast.StmtClass{
|
||||||
|
ClassName: &ast.Identifier{Value: []byte("A")},
|
||||||
|
Extends: &ast.StmtClassExtends{
|
||||||
|
ClassName: nameAB,
|
||||||
|
},
|
||||||
|
Implements: &ast.StmtClassImplements{
|
||||||
|
InterfaceNames: []ast.Vertex{
|
||||||
|
nameBC,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
class,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
class: "A",
|
||||||
|
nameAB: "A\\B",
|
||||||
|
nameBC: "B\\C",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveInterfaceName(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameBC := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}, &ast.NameNamePart{Value: []byte("C")}}}
|
||||||
|
|
||||||
|
interfaceNode := &ast.StmtInterface{
|
||||||
|
InterfaceName: &ast.Identifier{Value: []byte("A")},
|
||||||
|
Extends: &ast.StmtInterfaceExtends{
|
||||||
|
InterfaceNames: []ast.Vertex{
|
||||||
|
nameAB,
|
||||||
|
nameBC,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
interfaceNode,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
interfaceNode: "A",
|
||||||
|
nameAB: "A\\B",
|
||||||
|
nameBC: "B\\C",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveTraitName(t *testing.T) {
|
||||||
|
traitNode := &ast.StmtTrait{
|
||||||
|
TraitName: &ast.Identifier{Value: []byte("A")},
|
||||||
|
Stmts: []ast.Vertex{},
|
||||||
|
}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
traitNode,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
traitNode: "A",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveFunctionName(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameBC := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}, &ast.NameNamePart{Value: []byte("C")}}}
|
||||||
|
|
||||||
|
functionNode := &ast.StmtFunction{
|
||||||
|
ReturnsRef: false,
|
||||||
|
FunctionName: &ast.Identifier{Value: []byte("A")},
|
||||||
|
Params: []ast.Vertex{
|
||||||
|
&ast.Parameter{
|
||||||
|
ByRef: false,
|
||||||
|
Variadic: false,
|
||||||
|
Type: nameAB,
|
||||||
|
Var: &ast.ExprVariable{VarName: &ast.Identifier{Value: []byte("foo")}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ReturnType: &ast.Nullable{Expr: nameBC},
|
||||||
|
Stmts: []ast.Vertex{},
|
||||||
|
}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
functionNode,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
functionNode: "A",
|
||||||
|
nameAB: "A\\B",
|
||||||
|
nameBC: "B\\C",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveMethodName(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameBC := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}, &ast.NameNamePart{Value: []byte("C")}}}
|
||||||
|
|
||||||
|
methodNode := &ast.StmtClassMethod{
|
||||||
|
ReturnsRef: false,
|
||||||
|
MethodName: &ast.Identifier{Value: []byte("A")},
|
||||||
|
Params: []ast.Vertex{
|
||||||
|
&ast.Parameter{
|
||||||
|
ByRef: false,
|
||||||
|
Variadic: false,
|
||||||
|
Type: nameAB,
|
||||||
|
Var: &ast.ExprVariable{VarName: &ast.Identifier{Value: []byte("foo")}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ReturnType: &ast.Nullable{Expr: nameBC},
|
||||||
|
Stmt: &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
nameAB: "A\\B",
|
||||||
|
nameBC: "B\\C",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(methodNode)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveClosureName(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
nameBC := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("B")}, &ast.NameNamePart{Value: []byte("C")}}}
|
||||||
|
|
||||||
|
closureNode := &ast.ExprClosure{
|
||||||
|
ReturnsRef: false,
|
||||||
|
Static: false,
|
||||||
|
Params: []ast.Vertex{
|
||||||
|
&ast.Parameter{
|
||||||
|
ByRef: false,
|
||||||
|
Variadic: false,
|
||||||
|
Type: nameAB,
|
||||||
|
Var: &ast.ExprVariable{VarName: &ast.Identifier{Value: []byte("foo")}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ClosureUse: nil,
|
||||||
|
ReturnType: &ast.Nullable{Expr: nameBC},
|
||||||
|
Stmts: []ast.Vertex{},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
nameAB: "A\\B",
|
||||||
|
nameBC: "B\\C",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(closureNode)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveConstantsName(t *testing.T) {
|
||||||
|
nameAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
|
||||||
|
constantB := &ast.StmtConstant{
|
||||||
|
ConstantName: &ast.Identifier{Value: []byte("B")},
|
||||||
|
Expr: &ast.ScalarLnumber{Value: []byte("1")},
|
||||||
|
}
|
||||||
|
constantC := &ast.StmtConstant{
|
||||||
|
ConstantName: &ast.Identifier{Value: []byte("C")},
|
||||||
|
Expr: &ast.ScalarLnumber{Value: []byte("1")},
|
||||||
|
}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtNamespace{
|
||||||
|
NamespaceName: nameAB,
|
||||||
|
},
|
||||||
|
&ast.StmtConstList{
|
||||||
|
Consts: []ast.Vertex{
|
||||||
|
constantB,
|
||||||
|
constantC,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
constantB: "A\\B\\B",
|
||||||
|
constantC: "A\\B\\C",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveNamespaces(t *testing.T) {
|
||||||
|
namespaceAB := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("B")}}}
|
||||||
|
namespaceCD := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("C")}, &ast.NameNamePart{Value: []byte("D")}}}
|
||||||
|
|
||||||
|
nameAC := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("A")}, &ast.NameNamePart{Value: []byte("C")}}}
|
||||||
|
nameCF := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("C")}, &ast.NameNamePart{Value: []byte("F")}}}
|
||||||
|
nameFG := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("F")}, &ast.NameNamePart{Value: []byte("G")}}}
|
||||||
|
relativeNameCE := &ast.NameRelative{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("C")}, &ast.NameNamePart{Value: []byte("E")}}}
|
||||||
|
|
||||||
|
constantB := &ast.StmtConstant{
|
||||||
|
ConstantName: &ast.Identifier{Value: []byte("B")},
|
||||||
|
Expr: &ast.ScalarLnumber{Value: []byte("1")},
|
||||||
|
}
|
||||||
|
constantC := &ast.StmtConstant{
|
||||||
|
ConstantName: &ast.Identifier{Value: []byte("C")},
|
||||||
|
Expr: &ast.ScalarLnumber{Value: []byte("1")},
|
||||||
|
}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtNamespace{
|
||||||
|
NamespaceName: namespaceAB,
|
||||||
|
},
|
||||||
|
&ast.StmtConstList{
|
||||||
|
Consts: []ast.Vertex{
|
||||||
|
constantB,
|
||||||
|
constantC,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.ExprStaticCall{
|
||||||
|
Class: nameFG,
|
||||||
|
Call: &ast.Identifier{Value: []byte("foo")},
|
||||||
|
ArgumentList: &ast.ArgumentList{},
|
||||||
|
},
|
||||||
|
&ast.StmtNamespace{
|
||||||
|
Stmts: []ast.Vertex{},
|
||||||
|
},
|
||||||
|
&ast.StmtNamespace{
|
||||||
|
NamespaceName: namespaceCD,
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtUseList{
|
||||||
|
Uses: []ast.Vertex{
|
||||||
|
&ast.StmtUse{
|
||||||
|
Use: nameAC,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.ExprStaticCall{
|
||||||
|
Class: relativeNameCE,
|
||||||
|
Call: &ast.Identifier{Value: []byte("foo")},
|
||||||
|
ArgumentList: &ast.ArgumentList{},
|
||||||
|
},
|
||||||
|
&ast.ExprStaticCall{
|
||||||
|
Class: nameCF,
|
||||||
|
Call: &ast.Identifier{Value: []byte("foo")},
|
||||||
|
ArgumentList: &ast.ArgumentList{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]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()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveStaticCallDinamicClassName(t *testing.T) {
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.ExprStaticCall{
|
||||||
|
Class: &ast.ExprVariable{VarName: &ast.Identifier{Value: []byte("foo")}},
|
||||||
|
Call: &ast.Identifier{Value: []byte("foo")},
|
||||||
|
ArgumentList: &ast.ArgumentList{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDoNotResolveReservedConstants(t *testing.T) {
|
||||||
|
namespaceName := &ast.NameName{Parts: []ast.Vertex{&ast.NameNamePart{Value: []byte("Foo")}}}
|
||||||
|
|
||||||
|
constantTrue := &ast.NameName{
|
||||||
|
Parts: []ast.Vertex{
|
||||||
|
&ast.NameNamePart{Value: []byte("True")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
constantFalse := &ast.NameName{
|
||||||
|
Parts: []ast.Vertex{
|
||||||
|
&ast.NameNamePart{Value: []byte("False")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
constantNull := &ast.NameName{
|
||||||
|
Parts: []ast.Vertex{
|
||||||
|
&ast.NameNamePart{Value: []byte("NULL")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtNamespace{
|
||||||
|
NamespaceName: namespaceName,
|
||||||
|
},
|
||||||
|
&ast.StmtExpression{
|
||||||
|
Expr: &ast.ExprConstFetch{
|
||||||
|
Const: constantTrue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.StmtExpression{
|
||||||
|
Expr: &ast.ExprConstFetch{
|
||||||
|
Const: constantFalse,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.StmtExpression{
|
||||||
|
Expr: &ast.ExprConstFetch{
|
||||||
|
Const: constantNull,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
constantTrue: "true",
|
||||||
|
constantFalse: "false",
|
||||||
|
constantNull: "null",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDoNotResolveReservedNames(t *testing.T) {
|
||||||
|
|
||||||
|
nameInt := &ast.NameName{
|
||||||
|
Parts: []ast.Vertex{
|
||||||
|
&ast.NameNamePart{Value: []byte("int")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
nameFloat := &ast.NameName{
|
||||||
|
Parts: []ast.Vertex{
|
||||||
|
&ast.NameNamePart{Value: []byte("float")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
nameBool := &ast.NameName{
|
||||||
|
Parts: []ast.Vertex{
|
||||||
|
&ast.NameNamePart{Value: []byte("bool")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
nameString := &ast.NameName{
|
||||||
|
Parts: []ast.Vertex{
|
||||||
|
&ast.NameNamePart{Value: []byte("string")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
nameVoid := &ast.NameName{
|
||||||
|
Parts: []ast.Vertex{
|
||||||
|
&ast.NameNamePart{Value: []byte("void")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
nameIterable := &ast.NameName{
|
||||||
|
Parts: []ast.Vertex{
|
||||||
|
&ast.NameNamePart{Value: []byte("iterable")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
nameObject := &ast.NameName{
|
||||||
|
Parts: []ast.Vertex{
|
||||||
|
&ast.NameNamePart{Value: []byte("object")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
function := &ast.StmtFunction{
|
||||||
|
FunctionName: &ast.Identifier{Value: []byte("bar")},
|
||||||
|
Params: []ast.Vertex{
|
||||||
|
&ast.Parameter{
|
||||||
|
Type: nameInt,
|
||||||
|
Var: &ast.ExprVariable{
|
||||||
|
VarName: &ast.Identifier{Value: []byte("Int")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.Parameter{
|
||||||
|
Type: nameFloat,
|
||||||
|
Var: &ast.ExprVariable{
|
||||||
|
VarName: &ast.Identifier{Value: []byte("Float")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.Parameter{
|
||||||
|
Type: nameBool,
|
||||||
|
Var: &ast.ExprVariable{
|
||||||
|
VarName: &ast.Identifier{Value: []byte("Bool")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.Parameter{
|
||||||
|
Type: nameString,
|
||||||
|
Var: &ast.ExprVariable{
|
||||||
|
VarName: &ast.Identifier{Value: []byte("String")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.Parameter{
|
||||||
|
Type: nameVoid,
|
||||||
|
Var: &ast.ExprVariable{
|
||||||
|
VarName: &ast.Identifier{Value: []byte("Void")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.Parameter{
|
||||||
|
Type: nameIterable,
|
||||||
|
Var: &ast.ExprVariable{
|
||||||
|
VarName: &ast.Identifier{Value: []byte("Iterable")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.Parameter{
|
||||||
|
Type: nameObject,
|
||||||
|
Var: &ast.ExprVariable{
|
||||||
|
VarName: &ast.Identifier{Value: []byte("Object")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtNamespace{
|
||||||
|
NamespaceName: &ast.NameName{
|
||||||
|
Parts: []ast.Vertex{
|
||||||
|
&ast.NameNamePart{Value: []byte("Foo")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
function,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
function: "Foo\\bar",
|
||||||
|
nameInt: "int",
|
||||||
|
nameFloat: "float",
|
||||||
|
nameBool: "bool",
|
||||||
|
nameString: "string",
|
||||||
|
nameVoid: "void",
|
||||||
|
nameIterable: "iterable",
|
||||||
|
nameObject: "object",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDoNotResolveReservedSpecialNames(t *testing.T) {
|
||||||
|
|
||||||
|
nameSelf := &ast.NameName{
|
||||||
|
Parts: []ast.Vertex{
|
||||||
|
&ast.NameNamePart{Value: []byte("Self")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
nameStatic := &ast.NameName{
|
||||||
|
Parts: []ast.Vertex{
|
||||||
|
&ast.NameNamePart{Value: []byte("Static")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
nameParent := &ast.NameName{
|
||||||
|
Parts: []ast.Vertex{
|
||||||
|
&ast.NameNamePart{Value: []byte("Parent")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cls := &ast.StmtClass{
|
||||||
|
ClassName: &ast.Identifier{Value: []byte("Bar")},
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtExpression{
|
||||||
|
Expr: &ast.ExprStaticCall{
|
||||||
|
Class: nameSelf,
|
||||||
|
Call: &ast.Identifier{Value: []byte("func")},
|
||||||
|
ArgumentList: &ast.ArgumentList{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.StmtExpression{
|
||||||
|
Expr: &ast.ExprStaticCall{
|
||||||
|
Class: nameStatic,
|
||||||
|
Call: &ast.Identifier{Value: []byte("func")},
|
||||||
|
ArgumentList: &ast.ArgumentList{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.StmtExpression{
|
||||||
|
Expr: &ast.ExprStaticCall{
|
||||||
|
Class: nameParent,
|
||||||
|
Call: &ast.Identifier{Value: []byte("func")},
|
||||||
|
ArgumentList: &ast.ArgumentList{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
stxTree := &ast.StmtStmtList{
|
||||||
|
Stmts: []ast.Vertex{
|
||||||
|
&ast.StmtNamespace{
|
||||||
|
NamespaceName: &ast.NameName{
|
||||||
|
Parts: []ast.Vertex{
|
||||||
|
&ast.NameNamePart{Value: []byte("Foo")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cls,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[ast.Vertex]string{
|
||||||
|
cls: "Foo\\Bar",
|
||||||
|
nameSelf: "self",
|
||||||
|
nameStatic: "static",
|
||||||
|
nameParent: "parent",
|
||||||
|
}
|
||||||
|
|
||||||
|
nsResolver := visitor.NewNamespaceResolver()
|
||||||
|
dfsTraverser := traverser.NewDFS(nsResolver)
|
||||||
|
dfsTraverser.Traverse(stxTree)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, expected, nsResolver.ResolvedNames)
|
||||||
|
}
|
@ -681,3 +681,19 @@ func (v *Null) ScalarMagicConstant(_ *ast.ScalarMagicConstant) {
|
|||||||
func (v *Null) ScalarString(_ *ast.ScalarString) {
|
func (v *Null) ScalarString(_ *ast.ScalarString) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Null) NameName(_ *ast.NameName) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Null) NameFullyQualified(_ *ast.NameFullyQualified) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Null) NameRelative(_ *ast.NameRelative) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Null) NameNamePart(_ *ast.NameNamePart) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user