]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: add commentMap and test
authorRobert Griesemer <gri@golang.org>
Thu, 8 Dec 2022 16:29:14 +0000 (08:29 -0800)
committerGopher Robot <gobot@golang.org>
Tue, 17 Jan 2023 19:53:49 +0000 (19:53 +0000)
This adds the (adjusted) syntax.CommentMap function and corresponding
test to the types_test package so that we can use it for collecting
ERROR comments in the next CL.

For #51006.

Change-Id: I63ce96e7394c28c02d5a292250586cc49c1f6e19
Reviewed-on: https://go-review.googlesource.com/c/go/+/456125
Reviewed-by: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>

src/go/types/commentMap_test.go [new file with mode: 0644]

diff --git a/src/go/types/commentMap_test.go b/src/go/types/commentMap_test.go
new file mode 100644 (file)
index 0000000..ef6017a
--- /dev/null
@@ -0,0 +1,103 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types_test
+
+import (
+       "fmt"
+       "go/scanner"
+       "go/token"
+       "regexp"
+       "strings"
+       "testing"
+)
+
+type comment struct {
+       line, col int // comment position
+       text string   // comment text, excluding "//", "/*", or "*/"
+}
+
+// commentMap collects all comments in the given src with comment text
+// that matches the supplied regular expression rx and returns them as
+// []comment lists in a map indexed by line number. The comment text is
+// the comment with any comment markers ("//", "/*", or "*/") stripped.
+// The position for each comment is the position of the token immediately
+// preceding the comment, with all comments that are on the same line
+// collected in a slice, in source order. If there is no preceding token
+// (the matching comment appears at the beginning of the file), then the
+// recorded position is unknown (line, col = 0, 0).
+// If there are no matching comments, the result is nil.
+func commentMap(src []byte, rx *regexp.Regexp) (res map[int][]comment) {
+       fset := token.NewFileSet()
+       file := fset.AddFile("", -1, len(src))
+
+       var s scanner.Scanner
+       s.Init(file, src, nil, scanner.ScanComments)
+       var prev token.Pos // position of last non-comment, non-semicolon token
+
+       for {
+               pos, tok, lit := s.Scan()
+               switch tok {
+               case token.EOF:
+                       return
+               case token.COMMENT:
+                       if lit[1] == '*' {
+                               lit = lit[:len(lit)-2] // strip trailing */
+                       }
+                       lit = lit[2:] // strip leading // or /*
+                       if rx.MatchString(lit) {
+                               p := fset.Position(prev)
+                               err := comment{p.Line, p.Column, lit}
+                               if res == nil {
+                                       res = make(map[int][]comment)
+                               }
+                               res[p.Line] = append(res[p.Line], err)
+                       }
+               case token.SEMICOLON:
+                       // ignore automatically inserted semicolon
+                       if lit == "\n" {
+                               continue
+                       }
+                       fallthrough
+               default:
+                       prev = pos
+               }
+       }
+}
+
+func TestCommentMap(t *testing.T) {
+       const src = `/* ERROR "0:0" */ /* ERROR "0:0" */ // ERROR "0:0"
+// ERROR "0:0"
+x /* ERROR "3:1" */                // ignore automatically inserted semicolon here
+/* ERROR "3:1" */                  // position of x on previous line
+   x /* ERROR "5:4" */ ;           // do not ignore this semicolon
+/* ERROR "5:24" */                 // position of ; on previous line
+       package /* ERROR "7:2" */  // indented with tab
+        import  /* ERROR "8:9" */  // indented with blanks
+`
+       m := commentMap([]byte(src), regexp.MustCompile("^ ERROR "))
+       found := 0 // number of errors found
+       for line, errlist := range m {
+               for _, err := range errlist {
+                       if err.line != line {
+                               t.Errorf("%v: got map line %d; want %d", err, err.line, line)
+                               continue
+                       }
+                       // err.line == line
+
+                       got := strings.TrimSpace(err.text[len(" ERROR "):])
+                       want := fmt.Sprintf(`"%d:%d"`, line, err.col)
+                       if got != want {
+                               t.Errorf("%v: got msg %q; want %q", err, got, want)
+                               continue
+                       }
+                       found++
+               }
+       }
+
+       want := strings.Count(src, " ERROR ")
+       if found != want {
+               t.Errorf("commentMap got %d errors; want %d", found, want)
+       }
+}