woodpecker/vendor/github.com/gostaticanalysis/comment/comment.go
Lukas c28f7cb29f
Add golangci-lint (#502)
Initial part of #435
2021-11-14 21:01:54 +01:00

147 lines
3.8 KiB
Go

package comment
import (
"go/ast"
"go/token"
"strings"
)
// Maps is slice of ast.CommentMap.
type Maps []ast.CommentMap
// New creates new a CommentMap slice from specified files.
func New(fset *token.FileSet, files []*ast.File) Maps {
maps := make(Maps, len(files))
for i := range files {
maps[i] = ast.NewCommentMap(fset, files[i], files[i].Comments)
}
return maps
}
// Comments returns correspond a CommentGroup slice to specified AST node.
func (maps Maps) Comments(n ast.Node) []*ast.CommentGroup {
for i := range maps {
if maps[i][n] != nil {
return maps[i][n]
}
}
return nil
}
// CommentsByPos returns correspond a CommentGroup slice to specified pos.
func (maps Maps) CommentsByPos(pos token.Pos) []*ast.CommentGroup {
for i := range maps {
for n, cgs := range maps[i] {
if n.Pos() == pos {
return cgs
}
}
}
return nil
}
// Annotated checks either specified AST node is annotated or not.
func (maps Maps) Annotated(n ast.Node, annotation string) bool {
for _, cg := range maps.Comments(n) {
if strings.HasPrefix(strings.TrimSpace(cg.Text()), annotation) {
return true
}
}
return false
}
// Ignore checks either specified AST node is ignored by the check.
// It follows staticcheck style as the below.
// //lint:ignore Check1[,Check2,...,CheckN] reason
func (maps Maps) Ignore(n ast.Node, check string) bool {
for _, cg := range maps.Comments(n) {
if hasIgnoreCheck(cg, check) {
return true
}
}
return false
}
// IgnorePos checks either specified postion of AST node is ignored by the check.
// It follows staticcheck style as the below.
// //lint:ignore Check1[,Check2,...,CheckN] reason
func (maps Maps) IgnorePos(pos token.Pos, check string) bool {
for _, cg := range maps.CommentsByPos(pos) {
if hasIgnoreCheck(cg, check) {
return true
}
}
return false
}
// Deprecated: This function does not work with multiple files.
// CommentsByPosLine can be used instead of CommentsByLine.
//
// CommentsByLine returns correspond a CommentGroup slice to specified line.
func (maps Maps) CommentsByLine(fset *token.FileSet, line int) []*ast.CommentGroup {
for i := range maps {
for n, cgs := range maps[i] {
l := fset.File(n.Pos()).Line(n.Pos())
if l == line {
return cgs
}
}
}
return nil
}
// CommentsByPosLine returns correspond a CommentGroup slice to specified line.
func (maps Maps) CommentsByPosLine(fset *token.FileSet, pos token.Pos) []*ast.CommentGroup {
f1 := fset.File(pos)
for i := range maps {
for n, cgs := range maps[i] {
f2 := fset.File(n.Pos())
if f1 != f2 {
// different file
continue
}
if f1.Line(pos) == f2.Line(n.Pos()) {
return cgs
}
}
}
return nil
}
// IgnoreLine checks either specified lineof AST node is ignored by the check.
// It follows staticcheck style as the below.
// //lint:ignore Check1[,Check2,...,CheckN] reason
func (maps Maps) IgnoreLine(fset *token.FileSet, line int, check string) bool {
for _, cg := range maps.CommentsByLine(fset, line) {
if hasIgnoreCheck(cg, check) {
return true
}
}
return false
}
// hasIgnoreCheck returns true if the provided CommentGroup starts with a comment
// of the form "//lint:ignore Check1[,Check2,...,CheckN] reason" and one of the
// checks matches the provided check. The *ast.CommentGroup is checked directly
// rather than using "cg.Text()" because, starting in Go 1.15, the "cg.Text()" call
// no longer returns directive-style comments (see https://github.com/golang/go/issues/37974).
func hasIgnoreCheck(cg *ast.CommentGroup, check string) bool {
if !strings.HasPrefix(cg.List[0].Text, "//") {
return false
}
s := strings.TrimSpace(cg.List[0].Text[2:])
txt := strings.Split(s, " ")
if len(txt) < 3 || txt[0] != "lint:ignore" {
return false
}
checks := strings.Split(txt[1], ",")
for i := range checks {
if check == checks[i] {
return true
}
}
return false
}