Skip to content

Commit

Permalink
feature: modify existed comments if necessary (#16)
Browse files Browse the repository at this point in the history
feature: modify existed comments if necessary

- Add the missed name prefix to the existed comment
- Make existed comment to fit the template
- Works well in multi-line comment
- Take care of the marker comment

Co-authored-by: bennhuang <bennhuang@tencent.com>
  • Loading branch information
Bin-Huang and bennhuang authored Jun 10, 2022
1 parent cd36607 commit 29e0a6b
Show file tree
Hide file tree
Showing 4 changed files with 306 additions and 6 deletions.
45 changes: 45 additions & 0 deletions helper.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"go/ast"
"go/scanner"
"os"
"strings"
Expand All @@ -26,3 +27,47 @@ func walkFunc(path string, fi os.FileInfo, err error) error {

return nil
}

func isLineComment(comment *ast.CommentGroup) bool {
if comment == nil {
return false
}
if len(comment.List) == 0 {
return false
}
head := comment.List[0].Text
head = strings.TrimSpace(head)
return strings.HasPrefix(head, "//")
}

func hasCommentPrefix(comment *ast.CommentGroup, prefix string) bool {
return strings.HasPrefix(strings.TrimSpace(comment.Text()), prefix)
}

func appendCommentGroup(list []*ast.CommentGroup, item *ast.CommentGroup) []*ast.CommentGroup {
ret := []*ast.CommentGroup{}
hasInsert := false
for _, group := range list {
if group.Pos() < item.Pos() {
ret = append(ret, group)
continue
}
if group.Pos() == item.Pos() {
ret = append(ret, item)
hasInsert = true
continue
}
if group.Pos() > item.Pos() {
if !hasInsert {
ret = append(ret, item)
hasInsert = true
}
ret = append(ret, group)
continue
}
}
if !hasInsert {
ret = append(ret, item)
}
return ret
}
55 changes: 49 additions & 6 deletions parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ func parseFile(fset *token.FileSet, filePath, template string) (af *ast.File, mo
}

commentTemplate := commentBase + template
numComments := len(af.Comments)

originalCommentSign := ""
for _, c := range af.Comments {
originalCommentSign += c.Text()
}

cmap := ast.NewCommentMap(fset, af, af.Comments)

skipped := make(map[ast.Node]bool)
Expand All @@ -37,7 +42,7 @@ func parseFile(fset *token.FileSet, filePath, template string) (af *ast.File, mo
return true
}
addFuncDeclComment(typ, commentTemplate)
cmap[typ] = []*ast.CommentGroup{typ.Doc}
cmap[typ] = appendCommentGroup(cmap[typ], typ.Doc)

case *ast.DeclStmt:
skipped[typ.Decl] = true
Expand All @@ -54,7 +59,7 @@ func parseFile(fset *token.FileSet, filePath, template string) (af *ast.File, mo
continue
}
addParenValueSpecComment(vs, commentTemplate)
cmap[vs] = []*ast.CommentGroup{vs.Doc}
cmap[vs] = appendCommentGroup(cmap[vs], vs.Doc)
}
return true
}
Expand All @@ -80,14 +85,20 @@ func parseFile(fset *token.FileSet, filePath, template string) (af *ast.File, mo
default:
return true
}
cmap[typ] = []*ast.CommentGroup{typ.Doc}
cmap[typ] = appendCommentGroup(cmap[typ], typ.Doc)
}
return true
})

// Rebuild comments
af.Comments = cmap.Filter(af).Comments()
modified = len(af.Comments) > numComments

currentCommentSign := ""
for _, c := range af.Comments {
currentCommentSign += c.Text()
}

modified = currentCommentSign != originalCommentSign
return
}

Expand All @@ -99,8 +110,12 @@ func addFuncDeclComment(fd *ast.FuncDecl, commentTemplate string) {
pos = fd.Doc.Pos()
}
fd.Doc = &ast.CommentGroup{List: []*ast.Comment{{Slash: pos, Text: text}}}
return
}
if fd.Doc != nil && isLineComment(fd.Doc) && !hasCommentPrefix(fd.Doc, fd.Name.Name) {
modifyComment(fd.Doc, fd.Name.Name)
return
}

}

func addValueSpecComment(gd *ast.GenDecl, vs *ast.ValueSpec, commentTemplate string) {
Expand All @@ -111,6 +126,11 @@ func addValueSpecComment(gd *ast.GenDecl, vs *ast.ValueSpec, commentTemplate str
pos = gd.Doc.Pos()
}
gd.Doc = &ast.CommentGroup{List: []*ast.Comment{{Slash: pos, Text: text}}}
return
}
if gd.Doc != nil && isLineComment(gd.Doc) && !hasCommentPrefix(gd.Doc, vs.Names[0].Name) {
modifyComment(gd.Doc, vs.Names[0].Name)
return
}
}

Expand All @@ -123,6 +143,11 @@ func addParenValueSpecComment(vs *ast.ValueSpec, commentTemplate string) {
pos = vs.Doc.Pos()
}
vs.Doc = &ast.CommentGroup{List: []*ast.Comment{{Slash: pos, Text: text}}}
return
}
if vs.Doc != nil && isLineComment(vs.Doc) && !hasCommentPrefix(vs.Doc, vs.Names[0].Name) {
modifyComment(vs.Doc, vs.Names[0].Name)
return
}
}

Expand All @@ -134,5 +159,23 @@ func addTypeSpecComment(gd *ast.GenDecl, ts *ast.TypeSpec, commentTemplate strin
pos = gd.Doc.Pos()
}
gd.Doc = &ast.CommentGroup{List: []*ast.Comment{{Slash: pos, Text: text}}}
return
}
if gd.Doc != nil && isLineComment(gd.Doc) && !hasCommentPrefix(gd.Doc, ts.Name.Name) {
modifyComment(gd.Doc, ts.Name.Name)
return
}
}

func modifyComment(comment *ast.CommentGroup, prefix string) {
commentTemplate := commentBase + *template
first := comment.List[0].Text
if strings.HasPrefix(first, "//") && !strings.HasPrefix(first, "// ") {
text := fmt.Sprintf(commentTemplate, prefix)
comment.List = append([]*ast.Comment{{Text: text, Slash: comment.Pos()}}, comment.List...)
return
}
first = strings.TrimPrefix(first, "// ")
first = fmt.Sprintf(commentBase+"%s", prefix, first)
comment.List[0].Text = first
}
109 changes: 109 additions & 0 deletions parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,114 @@ func a() {
log.Println(LogAll)
}`

const existed = `package p
// global comments should never be deleted
// something
import "embed"
// global comment 1
// global comment 2
// global comment 3
// ============= function =============
// FuncWithExistedComment1 ...
func FuncWithExistedComment1() {
}
// FuncWithExistedComment2 ...
func FuncWithExistedComment2() {
// this comments should never be deleted
}
// FuncWithExistedComment3 something
func FuncWithExistedComment3() {
}
// FuncWithExistedComment4 multi-line comments
// something
func FuncWithExistedComment4() {
}
/*
something
*/
func FuncWithExistedComment5() {
}
// ============= value =============
// ValueWithExistedComment1 existed comment
var ValueWithExistedComment1 = 1
// ValueWithExistedComment2 existed comment with spaces
var ValueWithExistedComment2 = 1
// ValueWithExistedComment3 multi-line comments
// something
var ValueWithExistedComment3 = 1
/*
should't change C style comment
*/
var ValueWithExistedComment4 = 1
// ============= paren value =============
// ParenValueWithExistedComment1 existed comment
const (
ParenValueWithExistedComment1 = 1
// ParenValueWithExistedComment2 something
ParenValueWithExistedComment2 = 1
)
// ParenValueWithExistedComment3 multi-line comments
// something
const (
ParenValueWithExistedComment3 = 1
// ParenValueWithExistedComment2 something
ParenValueWithExistedComment4 = 1
)
// ============= type =============
// TypeWithExistedComment1 existed comment
type TypeWithExistedComment1 int
// TypeWithExistedComment2 existed comment with spaces
type TypeWithExistedComment2 int
// TypeWithExistedComment3 multi-line comments
// something
type TypeWithExistedComment3 int
/*
should't change C style comment
*/
type TypeWithExistedComment4 int
// ============= marker comment =============
// Embed ...
//go:embed dont_modify_this_comment.txt
//go:embed image/*
var Embed embed.FS
// Embed something
//go:embed dont_modify_this_comment.txt
var Embed embed.FS
// Generate ...
//go:generate goyacc -o gopher.go -p parser gopher.y
func Generate() {
}
// ============= end =============
`

func Test_parseFile(t *testing.T) {
parseFileTests := []struct {
path string
Expand All @@ -126,6 +234,7 @@ func Test_parseFile(t *testing.T) {
{"testdata/parenthesis.go", parenSrc, true, false},
{"testdata/invalid_file.go", "", false, true},
{"testdata/issue7.go", issue7, false, false},
{"testdata/existed.go", existed, true, false},
}

for _, tc := range parseFileTests {
Expand Down
103 changes: 103 additions & 0 deletions testdata/existed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package p

// global comments should never be deleted
// something

import "embed"

// global comment 1

// global comment 2
// global comment 3

// ============= function =============

// FuncWithExistedComment1
func FuncWithExistedComment1() {
}

func FuncWithExistedComment2() {
// this comments should never be deleted
}

// something
func FuncWithExistedComment3() {
}

// multi-line comments
// something
func FuncWithExistedComment4() {
}

/*
something
*/
func FuncWithExistedComment5() {
}

// ============= value =============

// existed comment
var ValueWithExistedComment1 = 1

// existed comment with spaces
var ValueWithExistedComment2 = 1

// multi-line comments
// something
var ValueWithExistedComment3 = 1

/*
should't change C style comment
*/
var ValueWithExistedComment4 = 1

// ============= paren value =============

// existed comment
const (
ParenValueWithExistedComment1 = 1
// ParenValueWithExistedComment2 something
ParenValueWithExistedComment2 = 1
)

// multi-line comments
// something
const (
ParenValueWithExistedComment3 = 1
// ParenValueWithExistedComment2 something
ParenValueWithExistedComment4 = 1
)

// ============= type =============

// existed comment
type TypeWithExistedComment1 int

// existed comment with spaces
type TypeWithExistedComment2 int

// multi-line comments
// something
type TypeWithExistedComment3 int

/*
should't change C style comment
*/
type TypeWithExistedComment4 int

// ============= marker comment =============

//go:embed dont_modify_this_comment.txt
//go:embed image/*
var Embed embed.FS

// something
//go:embed dont_modify_this_comment.txt
var Embed embed.FS

//go:generate goyacc -o gopher.go -p parser gopher.y
func Generate() {
}

// ============= end =============

0 comments on commit 29e0a6b

Please sign in to comment.