1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
// Copyright 2012 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.
// To avoid a cyclic dependency with go/parser, this file is in a separate package.
package ast_test
import (
"fmt"
. "go/ast"
"go/parser"
"go/token"
"sort"
"strings"
"testing"
)
const src = `
// the very first comment
// package p
package p /* the name is p */
// imports
import (
"bytes" // bytes
"fmt" // fmt
"go/ast"
"go/parser"
)
// T
type T struct {
a, b, c int // associated with a, b, c
// associated with x, y
x, y float64 // float values
z complex128 // complex value
}
// also associated with T
// x
var x = 0 // x = 0
// also associated with x
// f1
func f1() {
/* associated with s1 */
s1()
// also associated with s1
// associated with s2
// also associated with s2
s2() // line comment for s2
}
// associated with f1
// also associated with f1
// associated with f2
// f2
func f2() {
}
func f3() {
i := 1 /* 1 */ + 2 // addition
_ = i
}
// the very last comment
`
// res maps a key of the form "line number: node type"
// to the associated comments' text.
var res = map[string]string{
" 5: *ast.File": "the very first comment\npackage p\n",
" 5: *ast.Ident": " the name is p\n",
" 8: *ast.GenDecl": "imports\n",
" 9: *ast.ImportSpec": "bytes\n",
"10: *ast.ImportSpec": "fmt\n",
"16: *ast.GenDecl": "T\nalso associated with T\n",
"17: *ast.Field": "associated with a, b, c\n",
"19: *ast.Field": "associated with x, y\nfloat values\n",
"20: *ast.Field": "complex value\n",
"25: *ast.GenDecl": "x\nx = 0\nalso associated with x\n",
"29: *ast.FuncDecl": "f1\nassociated with f1\nalso associated with f1\n",
"31: *ast.ExprStmt": " associated with s1\nalso associated with s1\n",
"37: *ast.ExprStmt": "associated with s2\nalso associated with s2\nline comment for s2\n",
"45: *ast.FuncDecl": "associated with f2\nf2\n",
"49: *ast.AssignStmt": "addition\n",
"49: *ast.BasicLit": " 1\n",
"50: *ast.Ident": "the very last comment\n",
}
func ctext(list []*CommentGroup) string {
var buf strings.Builder
for _, g := range list {
buf.WriteString(g.Text())
}
return buf.String()
}
func TestCommentMap(t *testing.T) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
if err != nil {
t.Fatal(err)
}
cmap := NewCommentMap(fset, f, f.Comments)
// very correct association of comments
for n, list := range cmap {
key := fmt.Sprintf("%2d: %T", fset.Position(n.Pos()).Line, n)
got := ctext(list)
want := res[key]
if got != want {
t.Errorf("%s: got %q; want %q", key, got, want)
}
}
// verify that no comments got lost
if n := len(cmap.Comments()); n != len(f.Comments) {
t.Errorf("got %d comment groups in map; want %d", n, len(f.Comments))
}
// support code to update test:
// set genMap to true to generate res map
const genMap = false
if genMap {
out := make([]string, 0, len(cmap))
for n, list := range cmap {
out = append(out, fmt.Sprintf("\t\"%2d: %T\":\t%q,", fset.Position(n.Pos()).Line, n, ctext(list)))
}
sort.Strings(out)
for _, s := range out {
fmt.Println(s)
}
}
}
func TestFilter(t *testing.T) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
if err != nil {
t.Fatal(err)
}
cmap := NewCommentMap(fset, f, f.Comments)
// delete variable declaration
for i, decl := range f.Decls {
if gen, ok := decl.(*GenDecl); ok && gen.Tok == token.VAR {
copy(f.Decls[i:], f.Decls[i+1:])
f.Decls = f.Decls[:len(f.Decls)-1]
break
}
}
// check if comments are filtered correctly
cc := cmap.Filter(f)
for n, list := range cc {
key := fmt.Sprintf("%2d: %T", fset.Position(n.Pos()).Line, n)
got := ctext(list)
want := res[key]
if key == "25: *ast.GenDecl" || got != want {
t.Errorf("%s: got %q; want %q", key, got, want)
}
}
}
|