Skip to content

Commit

Permalink
fix stdlibpkg.$_ pattern compilation
Browse files Browse the repository at this point in the history
  • Loading branch information
quasilyte committed Dec 22, 2021
1 parent ba25d0f commit 9075ea2
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 51 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ci-lint:
$(GOPATH_DIR)/bin/golangci-lint run ./...
go install github.com/quasilyte/go-consistent@latest
$(GOPATH_DIR)/bin/go-consistent . ./internal/... ./nodetag/... ./filters/...
cd ./cmd/gogrep && $(GOPATH_DIR)/bin/go-consistent ./...
cd ./cmd/gogrep && GOPROXY=direct go mod tidy && $(GOPATH_DIR)/bin/go-consistent ./...
@echo "everything is OK"

lint:
Expand Down
2 changes: 1 addition & 1 deletion compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ func (c *compiler) compileCallExpr(n *ast.CallExpr) {
func (c *compiler) compileSymbol(fn ast.Expr) {
if c.config.WithTypes {
if e, ok := fn.(*ast.SelectorExpr); ok {
if ident, ok := e.X.(*ast.Ident); ok && stdinfo.Packages[ident.Name] != "" {
if ident, ok := e.X.(*ast.Ident); ok && stdinfo.Packages[ident.Name] != "" && !isWildName(e.Sel.Name) {
c.emitInst(instruction{
op: opSimpleSelectorExpr,
valueIndex: c.internString(e.Sel, e.Sel.String()),
Expand Down
113 changes: 64 additions & 49 deletions compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,39 @@ type compileTest struct {
output []string
}

func runCompileTest(t *testing.T, i int, test compileTest, withTypes bool) {
t.Helper()
t.Run(fmt.Sprintf("test%d", i), func(t *testing.T) {
isStrict := func(s string) bool {
return strings.HasPrefix(s, "STRICT ")
}
unwrapPattern := func(s string) string {
s = strings.TrimPrefix(s, "STRICT ")
return s
}

strict := isStrict(test.input)
input := unwrapPattern(test.input)
want := test.output
fset := token.NewFileSet()
config := CompileConfig{Fset: fset, Src: input, Strict: strict, WithTypes: withTypes}
p, _, err := Compile(config)
if err != nil {
t.Errorf("compile `%s`: %v", input, err)
return
}
have := formatProgram(p.m.prog)
if diff := cmp.Diff(have, want); diff != "" {
t.Errorf("compile `%s` (+want -have):\n%s", input, diff)
fmt.Printf("Output:\n")
for _, line := range have {
fmt.Printf("`%s`,\n", line)
}
return
}
})
}

func compileTestsFromMap(m map[string][]string) []compileTest {
result := make([]compileTest, 0, len(m))
for input, output := range m {
Expand Down Expand Up @@ -370,27 +403,25 @@ func TestCompileWildcard(t *testing.T) {
})

for i := range tests {
test := tests[i]
t.Run(fmt.Sprintf("test%d", i), func(t *testing.T) {
input := test.input
want := test.output
fset := token.NewFileSet()
config := CompileConfig{Fset: fset, Src: input}
p, _, err := Compile(config)
if err != nil {
t.Errorf("compile `%s`: %v", input, err)
return
}
have := formatProgram(p.m.prog)
if diff := cmp.Diff(have, want); diff != "" {
t.Errorf("compile `%s` (+want -have):\n%s", input, diff)
fmt.Printf("Output:\n")
for _, line := range have {
fmt.Printf("`%s`,\n", line)
}
return
}
})
runCompileTest(t, i, tests[i], false)
}
}

func TestCompileWildcardWithTypes(t *testing.T) {
tests := compileTestsFromMap(map[string][]string{
`fmt.$_($*_)`: {
`CallExpr`,
` • SelectorExpr`,
` • • Node`,
` • • Ident fmt`,
` • ArgList`,
` • • NodeSeq`,
` • • End`,
},
})

for i := range tests {
runCompileTest(t, i, tests[i], true)
}
}

Expand Down Expand Up @@ -765,9 +796,17 @@ func TestCompile(t *testing.T) {
`goto l`: {`SimpleLabeledBranchStmt goto l`},

`foo: x`: {
`SimpleLabeledStmt foo`,
` • ExprStmt`,
` • • Ident x`,
`KeyValueExpr`,
` • Ident foo`,
` • Ident x`,
},

`{foo: x}`: {
`BlockStmt`,
` • SimpleLabeledStmt foo`,
` • • ExprStmt`,
` • • • Ident x`,
` • End`,
},

`x = y`: {
Expand Down Expand Up @@ -1010,31 +1049,7 @@ func TestCompile(t *testing.T) {
})

for i := range tests {
test := tests[i]
t.Run(fmt.Sprintf("test%d", i), func(t *testing.T) {
input := test.input
want := test.output
fset := token.NewFileSet()
n := testParseNode(t, fset, input)
var c compiler
c.config = CompileConfig{Fset: fset, WithTypes: true}
info := newPatternInfo()
p, err := c.Compile(n, &info)
if err != nil {
t.Errorf("compile `%s`: %v", input, err)
return
}

have := formatProgram(p)
if diff := cmp.Diff(have, want); diff != "" {
t.Errorf("compile `%s` (+want -have):\n%s", input, diff)
fmt.Printf("Output:\n")
for _, line := range have {
fmt.Printf("`%s`,\n", line)
}
return
}
})
runCompileTest(t, i, tests[i], true)
}
}

Expand Down
67 changes: 67 additions & 0 deletions match_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,79 @@ package gogrep
import (
"fmt"
"go/ast"
"go/importer"
"go/parser"
"go/token"
"go/types"
"strings"
"testing"
)

// FIXME: find test case duplicates.

func TestMatchWithTypes(t *testing.T) {
tests := []struct {
pat string
numMatches int
}{
{`fmt.Sprintf($*_)`, 2},
{`fmt.$_($*_)`, 2},
}

fileSrc := `package example
import (
"fmt"
)
func testFunc(format string, args []interface{}) {
_ = fmt.Sprintf("%d", 1)
_ = fmt.Sprintf(format, args...)
}
`
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "file.go", fileSrc, 0)
if err != nil {
t.Fatal(err)
}
typesInfo := &types.Info{
Types: make(map[ast.Expr]types.TypeAndValue),
Defs: make(map[*ast.Ident]types.Object),
Uses: make(map[*ast.Ident]types.Object),
}
typechecker := &types.Config{
Importer: importer.Default(),
}
_, err = typechecker.Check("example", fset, []*ast.File{f}, typesInfo)
if err != nil {
t.Fatal(err)
}

for i := range tests {
test := tests[i]
t.Run(fmt.Sprintf("test%d", i), func(t *testing.T) {
state := NewMatcherState()
state.Types = typesInfo
fset := token.NewFileSet()
testPattern := test.pat
config := CompileConfig{Fset: fset, Src: testPattern, WithTypes: true}
pat, _, err := Compile(config)
if err != nil {
t.Errorf("compile `%s`: %v", test.pat, err)
return
}
matches := 0
testAllMatches(pat, &state, f, func(m MatchData) {
matches++
})
if matches != test.numMatches {
t.Errorf("test `%s`:\nhave: %v\nwant: %v",
test.pat, matches, test.numMatches)
}
})
}
}

func TestMatch(t *testing.T) {
strict := func(s string) string {
return "STRICT " + s
Expand Down Expand Up @@ -147,6 +213,7 @@ func TestMatch(t *testing.T) {
{`fmt.Sprintf($_, $args...)`, 0, `fmt.Sprintf(f)`},
{`fmt.Sprintf($_, $args...)`, 0, `fmt.Sprintf(f, a, b)`},
{`fmt.Sprintf($_, $args)`, 0, `fmt.Sprintf(f, a...)`},
{`$fmt.$_($*_)`, 1, `fmt.Sprintf("%d", 1)`},

// Selector expr.
{`$x.Field`, 1, `a.Field`},
Expand Down

0 comments on commit 9075ea2

Please sign in to comment.