Skip to content

Commit

Permalink
fix: report all TODOs in a multi-line comment (#721)
Browse files Browse the repository at this point in the history
Signed-off-by: Ian Lewis <ianmlewis@gmail.com>
  • Loading branch information
Ian Lewis authored Sep 22, 2023
1 parent 0832830 commit 82cfc85
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 30 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Support for CoffeeScript was added.

### Fixed

- All TODOs in a multi-line comment are now reported
([#721](https://github.com/ianlewis/todos/pull/721)).

### Changed

- The language of each file is now determined by it's file name in most
Expand Down
78 changes: 48 additions & 30 deletions internal/todos/todos.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ type CommentScanner interface {

// TODOScanner scans for TODO comments.
type TODOScanner struct {
next *TODO
next []*TODO
s CommentScanner
lineMatch []*regexp.Regexp
multilineMatch *regexp.Regexp
Expand Down Expand Up @@ -145,48 +145,63 @@ func NewTODOScanner(s CommentScanner, config *Config) *TODOScanner {

// Scan scans for the next TODO.
func (t *TODOScanner) Scan() bool {
if len(t.next) > 0 {
t.next = t.next[1:]
if len(t.next) > 0 {
return true
}
}

for t.s.Scan() {
next := t.s.Next()

match := t.findMatch(next)
if next.Multiline {
matches := t.findMultilineMatches(next)
t.next = append(t.next, matches...)
return true
}

match := t.findLineMatch(next)
if match != nil {
t.next = match
t.next = append(t.next, match)
return true
}
}
return false
}

// findMatch returns the TODO type, the full TODO line, the label, message, and
// the line number it was found on or zero if it was not found.
func (t *TODOScanner) findMatch(c *scanner.Comment) *TODO {
if c.Multiline {
for i, line := range strings.Split(c.Text, "\n") {
match := t.multilineMatch.FindAllStringSubmatch(line, 1)
if len(match) != 0 && len(match[0]) > 2 && match[0][2] != "" {
label := match[0][5]
if label == "" {
label = match[0][6]
}

message := match[0][4]
if message == "" {
message = match[0][7]
}

return &TODO{
Type: match[0][2],
Text: strings.TrimSpace(line),
Label: strings.TrimSpace(label),
Message: strings.TrimSpace(message),
// Add the line relative to the file.
Line: c.Line + i,
CommentLine: c.Line,
}
// findMultilineMatch returns the TODO for the comment if it was found.
func (t *TODOScanner) findMultilineMatches(c *scanner.Comment) []*TODO {
var matches []*TODO
for i, line := range strings.Split(c.Text, "\n") {
match := t.multilineMatch.FindAllStringSubmatch(line, 1)
if len(match) != 0 && len(match[0]) > 2 && match[0][2] != "" {
label := match[0][5]
if label == "" {
label = match[0][6]
}

message := match[0][4]
if message == "" {
message = match[0][7]
}

matches = append(matches, &TODO{
Type: match[0][2],
Text: strings.TrimSpace(line),
Label: strings.TrimSpace(label),
Message: strings.TrimSpace(message),
// Add the line relative to the file.
Line: c.Line + i,
CommentLine: c.Line,
})
}
}
return matches
}

// findLineMatch returns the TODO for the comment if it was found.
func (t *TODOScanner) findLineMatch(c *scanner.Comment) *TODO {
for _, lnMatch := range t.lineMatch {
match := lnMatch.FindAllStringSubmatch(c.Text, 1)
if len(match) != 0 && len(match[0]) > 2 && match[0][2] != "" {
Expand Down Expand Up @@ -217,7 +232,10 @@ func (t *TODOScanner) findMatch(c *scanner.Comment) *TODO {

// Next returns the next TODO.
func (t *TODOScanner) Next() *TODO {
return t.next
if len(t.next) > 0 {
return t.next[0]
}
return nil
}

// Err returns the first error encountered.
Expand Down
40 changes: 40 additions & 0 deletions internal/todos/todos_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,46 @@ func TestTODOScanner(t *testing.T) {
},
},
},
"multiline_comments_multiple_todos.go": {
s: &testScanner{
comments: []*scanner.Comment{
{
Text: "// package comment",
Line: 1,
},
{
Text: "/*\nfoo\nTODO(github.com/foo/bar/issues1): foo\nTODO: second task\n */",
Line: 5,
Multiline: true,
},
{
Text: "// godoc ",
Line: 9,
},
},
},
config: &Config{
Types: []string{"TODO"},
},
expected: []*TODO{
{
Type: "TODO",
Text: "TODO(github.com/foo/bar/issues1): foo",
Label: "github.com/foo/bar/issues1",
Message: "foo",
Line: 7,
CommentLine: 5,
},
{
Type: "TODO",
Text: "TODO: second task",
Label: "",
Message: "second task",
Line: 8,
CommentLine: 5,
},
},
},
"multiline_comments_javadoc.go": {
s: &testScanner{
comments: []*scanner.Comment{
Expand Down

0 comments on commit 82cfc85

Please # to comment.