github.com/nya3jp/tast@v0.0.0-20230601000426-85c8e4d83a9b/src/go.chromium.org/tast/core/cmd/tast-lint/internal/check/issue.go (about) 1 // Copyright 2018 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package check 6 7 import ( 8 "fmt" 9 "go/ast" 10 "go/token" 11 "sort" 12 "strings" 13 ) 14 15 // Issue holds an issue reported by the linter. 16 type Issue struct { 17 Pos token.Position 18 Msg string 19 Link string 20 Fixable bool 21 Warning bool 22 } 23 24 func (i *Issue) String() string { 25 return fmt.Sprintf("%s: %s", i.Pos, i.Msg) 26 } 27 28 // SortIssues sorts issues by file path and position. 29 func SortIssues(issues []*Issue) { 30 sort.Slice(issues, func(i, j int) bool { 31 pi := issues[i].Pos 32 pj := issues[j].Pos 33 if pi.Filename != pj.Filename { 34 return pi.Filename < pj.Filename 35 } 36 return pi.Offset < pj.Offset 37 }) 38 } 39 40 // DropIgnoredIssues drops all issues that are on the same lines as NOLINT comments. 41 // 42 // Specifically, an issue is dropped if its line number matches the starting line 43 // number of a comment group (see ast.CommentGroup) in f that contains "NOLINT". 44 // 45 // Filtering is performed at this level rather than while walking the AST for several reasons: 46 // - We want to avoid making each check look for NOLINT itself. 47 // - We can't just skip nodes that are on the same lines as NOLINT comments, since some issues are 48 // reported with different line numbers than the position of the node from which they were reported. 49 // For example, the Declarations function inspects testing.Test composite literal nodes, 50 // but the line numbers used in its issues correspond to Desc fields that contain errors. 51 // We expect test authors to place a NOLINT comment at the end of the line containing the Desc field, 52 // not on the line containing the beginning of the testing.Test literal. 53 func DropIgnoredIssues(issues []*Issue, fs *token.FileSet, f *ast.File) []*Issue { 54 nolintLineNums := make(map[int]struct{}) 55 for _, cg := range f.Comments { 56 if strings.Contains(cg.Text(), "NOLINT") { 57 lineNum := fs.File(cg.Pos()).Line(cg.Pos()) 58 nolintLineNums[lineNum] = struct{}{} 59 } 60 } 61 62 var kept []*Issue 63 for _, issue := range issues { 64 if _, ok := nolintLineNums[issue.Pos.Line]; !ok { 65 kept = append(kept, issue) 66 } 67 } 68 return kept 69 }