]> Cypherpunks repositories - gostls13.git/commitdiff
go/ast: drop //directive comments from doc.Text
authorRuss Cox <rsc@golang.org>
Sat, 21 Mar 2020 12:23:13 +0000 (08:23 -0400)
committerRuss Cox <rsc@golang.org>
Wed, 29 Apr 2020 19:02:32 +0000 (19:02 +0000)
This allows writing

// F does a thing.
//go:noinline
func F()

without the //go:noinline or other directive (such as //line)
ending up looking like extra words in the doc comment.

Fixes #37974.

Change-Id: Ic738d72802cc2fa448f7633915e7126d2f76d8ca
Reviewed-on: https://go-review.googlesource.com/c/go/+/224737
Reviewed-by: Robert Griesemer <gri@golang.org>
src/go/ast/ast.go
src/go/ast/ast_test.go

index b5b13b29083b244e40794832f0f3a6aa7ba90207..81c64589d043f272d6c9145f013622b010c9ee82 100644 (file)
@@ -87,10 +87,10 @@ func stripTrailingWhitespace(s string) string {
 
 // Text returns the text of the comment.
 // Comment markers (//, /*, and */), the first space of a line comment, and
-// leading and trailing empty lines are removed. Multiple empty lines are
-// reduced to one, and trailing space on lines is trimmed. Unless the result
-// is empty, it is newline-terminated.
-//
+// leading and trailing empty lines are removed.
+// Comment directives like "//line" and "//go:noinline" are also removed.
+// Multiple empty lines are reduced to one, and trailing space on lines is trimmed.
+// Unless the result is empty, it is newline-terminated.
 func (g *CommentGroup) Text() string {
        if g == nil {
                return ""
@@ -108,9 +108,18 @@ func (g *CommentGroup) Text() string {
                case '/':
                        //-style comment (no newline at the end)
                        c = c[2:]
-                       // strip first space - required for Example tests
-                       if len(c) > 0 && c[0] == ' ' {
+                       if len(c) == 0 {
+                               // empty line
+                               break
+                       }
+                       if c[0] == ' ' {
+                               // strip first space - required for Example tests
                                c = c[1:]
+                               break
+                       }
+                       if isDirective(c) {
+                               // Ignore //go:noinline, //line, and so on.
+                               continue
                        }
                case '*':
                        /*-style comment */
@@ -145,6 +154,32 @@ func (g *CommentGroup) Text() string {
        return strings.Join(lines, "\n")
 }
 
+// isDirective reports whether c is a comment directive.
+func isDirective(c string) bool {
+       // "//line " is a line directive.
+       // (The // has been removed.)
+       if strings.HasPrefix(c, "line ") {
+               return true
+       }
+
+       // "//[a-z0-9]+:[a-z0-9]"
+       // (The // has been removed.)
+       colon := strings.Index(c, ":")
+       if colon <= 0 || colon+1 >= len(c) {
+               return false
+       }
+       for i := 0; i <= colon+1; i++ {
+               if i == colon {
+                       continue
+               }
+               b := c[i]
+               if !('a' <= b && b <= 'z' || '0' <= b && b <= '9') {
+                       return false
+               }
+       }
+       return true
+}
+
 // ----------------------------------------------------------------------------
 // Expressions and types
 
index 1a6a283f232bb706287c6aa004fb27af2d67f4ff..71b2d6ca4b80eb52322f127f9e356ded92697eb1 100644 (file)
@@ -33,6 +33,9 @@ var comments = []struct {
        {[]string{"/* Foo*/", "/*\n*/", "//", "/*\n*/", "// Bar"}, " Foo\n\nBar\n"},
        {[]string{"/* Foo*/", "// Bar"}, " Foo\nBar\n"},
        {[]string{"/* Foo\n Bar*/"}, " Foo\n Bar\n"},
+
+       {[]string{"// foo", "//go:noinline", "// bar", "//:baz"}, "foo\nbar\n:baz\n"},
+       {[]string{"// foo", "//lint123:ignore", "// bar"}, "foo\nbar\n"},
 }
 
 func TestCommentText(t *testing.T) {
@@ -48,3 +51,29 @@ func TestCommentText(t *testing.T) {
                }
        }
 }
+
+var isDirectiveTests = []struct {
+       in string
+       ok bool
+}{
+       {"abc", false},
+       {"go:inline", true},
+       {"Go:inline", false},
+       {"go:Inline", false},
+       {":inline", false},
+       {"lint:ignore", true},
+       {"lint:1234", true},
+       {"1234:lint", true},
+       {"go: inline", false},
+       {"go:", false},
+       {"go:*", false},
+       {"go:x*", true},
+}
+
+func TestIsDirective(t *testing.T) {
+       for _, tt := range isDirectiveTests {
+               if ok := isDirective(tt.in); ok != tt.ok {
+                       t.Errorf("isDirective(%q) = %v, want %v", tt.in, ok, tt.ok)
+               }
+       }
+}