// Copyright 2019 The gVisor Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package nogo import ( "go/token" "path/filepath" "regexp" "strings" "golang.org/x/tools/go/analysis" ) type matcher interface { ShouldReport(d analysis.Diagnostic, fs *token.FileSet) bool } // pathRegexps excludes explicit paths. type pathRegexps struct { expr []*regexp.Regexp whitelist bool } // buildRegexps builds a list of regular expressions. // // This will panic on error. func buildRegexps(prefix string, args ...string) []*regexp.Regexp { result := make([]*regexp.Regexp, 0, len(args)) for _, arg := range args { result = append(result, regexp.MustCompile(filepath.Join(prefix, arg))) } return result } // ShouldReport implements matcher.ShouldReport. func (p *pathRegexps) ShouldReport(d analysis.Diagnostic, fs *token.FileSet) bool { fullPos := fs.Position(d.Pos).String() for _, path := range p.expr { if path.MatchString(fullPos) { return p.whitelist } } return !p.whitelist } // internalExcluded excludes specific internal paths. func internalExcluded(paths ...string) *pathRegexps { return &pathRegexps{ expr: buildRegexps(internalPrefix, paths...), whitelist: false, } } // excludedExcluded excludes specific external paths. func externalExcluded(paths ...string) *pathRegexps { return &pathRegexps{ expr: buildRegexps(externalPrefix, paths...), whitelist: false, } } // internalMatches returns a path matcher for internal packages. func internalMatches() *pathRegexps { return &pathRegexps{ expr: buildRegexps(internalPrefix, ".*"), whitelist: true, } } // resultExcluded excludes explicit message contents. type resultExcluded []string // ShouldReport implements matcher.ShouldReport. func (r resultExcluded) ShouldReport(d analysis.Diagnostic, _ *token.FileSet) bool { for _, str := range r { if strings.Contains(d.Message, str) { return false } } return true // Not excluded. } // andMatcher is a composite matcher. type andMatcher struct { first matcher second matcher } // ShouldReport implements matcher.ShouldReport. func (a *andMatcher) ShouldReport(d analysis.Diagnostic, fs *token.FileSet) bool { return a.first.ShouldReport(d, fs) && a.second.ShouldReport(d, fs) } // and is a syntactic convension for andMatcher. func and(first matcher, second matcher) *andMatcher { return &andMatcher{ first: first, second: second, } } // anyMatcher matches everything. type anyMatcher struct{} // ShouldReport implements matcher.ShouldReport. func (anyMatcher) ShouldReport(analysis.Diagnostic, *token.FileSet) bool { return true } // alwaysMatches returns an anyMatcher instance. func alwaysMatches() anyMatcher { return anyMatcher{} } // neverMatcher will never match. type neverMatcher struct{} // ShouldReport implements matcher.ShouldReport. func (neverMatcher) ShouldReport(analysis.Diagnostic, *token.FileSet) bool { return false } // disableMatches returns a neverMatcher instance. func disableMatches() neverMatcher { return neverMatcher{} }