Skip to content

Commit

Permalink
wip: try parsing comments out of regex
Browse files Browse the repository at this point in the history
This doesn't actually work yet
  • Loading branch information
craigfurman committed Nov 28, 2021
1 parent e2bbe2f commit b51de3b
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 23 deletions.
8 changes: 4 additions & 4 deletions forbidigo/forbidigo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ func foo() {
})

t.Run("displays custom messages", func(t *testing.T) {
linter, _ := NewLinter([]string{`#[Please don't use this!]fmt\.Printf`})
linter, _ := NewLinter([]string{`fmt\.Printf(# Please don't use this!)?`})
expectIssues(t, linter, `
package bar
package bar
func foo() {
func foo() {
fmt.Printf("here i am")
}`, "use of `fmt.Printf` forbidden by pattern `fmt\\.Printf` at testing.go:5:2: Please don't use this!")
}`, "use of `fmt.Printf` forbidden by pattern `fmt\\.Printf` at testing.go:5:2: Please don't use this!")
})

t.Run("it doesn't require a package on the identifier", func(t *testing.T) {
Expand Down
41 changes: 29 additions & 12 deletions forbidigo/patterns.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,46 @@ package forbidigo
import (
"fmt"
"regexp"
"regexp/syntax"
"strings"
)

var ptrnWithMsg = regexp.MustCompile(`(#\[(?P<msg>[^\]]+)\])?(?P<pattern>.+)`)

type pattern struct {
pattern *regexp.Regexp
msg string
}

func parse(ptrn string) (*pattern, error) {
p := &pattern{}
matches := ptrnWithMsg.FindStringSubmatch(ptrn)
for i, name := range ptrnWithMsg.SubexpNames() {
if name == "msg" {
p.msg = matches[i]
} else if name == "pattern" {
re, err := regexp.Compile(matches[i])
if err != nil {
return nil, fmt.Errorf("unable to compile pattern `%s`: %s", matches[i], err)
}
p.pattern = re
parsedPattern, err := syntax.Parse(ptrn, syntax.Perl)
if err != nil {
return nil, fmt.Errorf("unable to parse pattern: %s: %s", ptrn, err)
}
if len(parsedPattern.Sub) == 0 {
p.pattern, err = regexp.Compile(parsedPattern.String())
if err != nil {
return nil, fmt.Errorf("unable to compile pattern: %s: %s", ptrn, err)
}
return p, nil
}
p.pattern, err = regexp.Compile(parsedPattern.Sub[0].String())
if err != nil {
return nil, fmt.Errorf("unable to compile pattern: %s: %s", ptrn, err)
}
if len(parsedPattern.Sub) < 2 {
return p, nil
}
msgPattern := deepestSubmatch(parsedPattern).String()
p.msg = strings.TrimSpace(strings.TrimPrefix(msgPattern, "#"))

return p, nil
}

func deepestSubmatch(expr *syntax.Regexp) *syntax.Regexp {
for {
if len(expr.Sub) == 0 {
return expr
}
expr = expr.Sub[len(expr.Sub)-1]
}
}
11 changes: 4 additions & 7 deletions forbidigo/patterns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,13 @@ func TestParseValidPattern(t *testing.T) {
assert.Equal(t, `fmt\.Errorf`, ptrn.pattern.String())
}

func TestParseValidPatternThatUsesSquareBrackets(t *testing.T) {
ptrn, err := parse(`[f]mt\.Errorf`)
require.Nil(t, err)
assert.Equal(t, `[f]mt\.Errorf`, ptrn.pattern.String())
}

func TestParseValidPatternWithCustomMessage(t *testing.T) {
ptrn, err := parse(`#[Please don't use this!]fmt\.Println`)
ptrn, err := parse(`fmt\.Println(# Please don't use this!)?`)
require.Nil(t, err)

// Remove custom message from pattern so as not to duplicate it in the output.
assert.Equal(t, `fmt\.Println`, ptrn.pattern.String())

assert.Equal(t, "Please don't use this!", ptrn.msg)
}

Expand Down

0 comments on commit b51de3b

Please sign in to comment.