gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/tools/nogo/check/analyzers.go (about)

     1  // Copyright 2019 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package check
    16  
    17  import (
    18  	"encoding/gob"
    19  	"io"
    20  	"reflect"
    21  
    22  	"golang.org/x/tools/go/analysis"
    23  	"golang.org/x/tools/go/analysis/passes/asmdecl"
    24  	"golang.org/x/tools/go/analysis/passes/assign"
    25  	"golang.org/x/tools/go/analysis/passes/atomic"
    26  	"golang.org/x/tools/go/analysis/passes/bools"
    27  	"golang.org/x/tools/go/analysis/passes/buildtag"
    28  	"golang.org/x/tools/go/analysis/passes/cgocall"
    29  	"golang.org/x/tools/go/analysis/passes/composite"
    30  	"golang.org/x/tools/go/analysis/passes/copylock"
    31  	"golang.org/x/tools/go/analysis/passes/errorsas"
    32  	"golang.org/x/tools/go/analysis/passes/httpresponse"
    33  	"golang.org/x/tools/go/analysis/passes/loopclosure"
    34  	"golang.org/x/tools/go/analysis/passes/lostcancel"
    35  	"golang.org/x/tools/go/analysis/passes/nilfunc"
    36  	"golang.org/x/tools/go/analysis/passes/nilness"
    37  	"golang.org/x/tools/go/analysis/passes/printf"
    38  	"golang.org/x/tools/go/analysis/passes/shadow"
    39  	"golang.org/x/tools/go/analysis/passes/shift"
    40  	"golang.org/x/tools/go/analysis/passes/stdmethods"
    41  	"golang.org/x/tools/go/analysis/passes/stringintconv"
    42  	"golang.org/x/tools/go/analysis/passes/structtag"
    43  	"golang.org/x/tools/go/analysis/passes/tests"
    44  	"golang.org/x/tools/go/analysis/passes/unmarshal"
    45  	"golang.org/x/tools/go/analysis/passes/unreachable"
    46  	"golang.org/x/tools/go/analysis/passes/unsafeptr"
    47  	"golang.org/x/tools/go/analysis/passes/unusedresult"
    48  	"honnef.co/go/tools/staticcheck"
    49  	"honnef.co/go/tools/stylecheck"
    50  
    51  	"gvisor.dev/gvisor/tools/checkaligned"
    52  	"gvisor.dev/gvisor/tools/checkconst"
    53  	"gvisor.dev/gvisor/tools/checkescape"
    54  	"gvisor.dev/gvisor/tools/checklinkname"
    55  	"gvisor.dev/gvisor/tools/checklocks"
    56  	"gvisor.dev/gvisor/tools/checkunsafe"
    57  )
    58  
    59  // binaryAnalyzer is a special class of analyzer which supports an additional
    60  // operation to run an analyzer with the object binary data.
    61  type binaryAnalyzer interface {
    62  	// Run runs the analyzer with the given binary data.
    63  	Run(*analysis.Pass, io.Reader) (any, error)
    64  }
    65  
    66  // analyzer is a simple analysis.Analyzer interface.
    67  //
    68  // This is implemented by plainAnalyzer, and is used to allow calls to
    69  // non-standard analyzers (e.g. checkescape, which requires the objdump output
    70  // in addition to the existing pass information).
    71  type analyzer interface {
    72  	Legacy() *analysis.Analyzer
    73  }
    74  
    75  // plainAnalyzer implements analyzer.
    76  type plainAnalyzer struct {
    77  	*analysis.Analyzer
    78  }
    79  
    80  // Legacy implements analyzer.Legacy.
    81  func (pa *plainAnalyzer) Legacy() *analysis.Analyzer {
    82  	return pa.Analyzer
    83  }
    84  
    85  var (
    86  	// allAnalyzers is a list of all available analyzers.
    87  	//
    88  	// This is guaranteed to be complete closure around the dependency
    89  	// graph of all analyzers (via the "Requires" attribute, below).
    90  	// Therefore, to map an *analysis.Analyzer to a runner, you may safely
    91  	// use "findAnalyzer".
    92  	allAnalyzers = make(map[*analysis.Analyzer]analyzer)
    93  
    94  	// allFactTypes is a list of all fact types, useful as a filter.
    95  	allFactTypes = make(map[reflect.Type]bool)
    96  )
    97  
    98  // findAnalyzer maps orig to an analyzer instance.
    99  //
   100  // This is guaranteed to work provided allAnalyzers is made into a transitive
   101  // closure of all known analyzers (see init).
   102  func findAnalyzer(orig *analysis.Analyzer) analyzer {
   103  	return allAnalyzers[orig]
   104  }
   105  
   106  // registerFactType registers an analysis.Fact.
   107  func registerFactType(f analysis.Fact) {
   108  	// Already registered?
   109  	t := reflect.TypeOf(f)
   110  	if _, ok := allFactTypes[t]; ok {
   111  		return
   112  	}
   113  
   114  	// Register the type.
   115  	gob.Register(f)
   116  	allFactTypes[t] = true
   117  }
   118  
   119  // register recursively registers an analyzer.
   120  func register(a analyzer) {
   121  	// Already registered?
   122  	if _, ok := allAnalyzers[a.Legacy()]; ok {
   123  		return
   124  	}
   125  
   126  	// Register all fact types.
   127  	for _, f := range a.Legacy().FactTypes {
   128  		registerFactType(f)
   129  	}
   130  
   131  	// Register dependencies.
   132  	for _, orig := range a.Legacy().Requires {
   133  		if findAnalyzer(orig) == nil {
   134  			register(&plainAnalyzer{orig})
   135  		}
   136  	}
   137  
   138  	// Save the analyzer.
   139  	allAnalyzers[a.Legacy()] = a
   140  }
   141  
   142  func init() {
   143  	// Standard & internal analyzers.
   144  	register(&plainAnalyzer{asmdecl.Analyzer})
   145  	register(&plainAnalyzer{assign.Analyzer})
   146  	register(&plainAnalyzer{atomic.Analyzer})
   147  	register(&plainAnalyzer{bools.Analyzer})
   148  	register(&plainAnalyzer{buildtag.Analyzer})
   149  	register(&plainAnalyzer{cgocall.Analyzer})
   150  	register(&plainAnalyzer{composite.Analyzer})
   151  	register(&plainAnalyzer{copylock.Analyzer})
   152  	register(&plainAnalyzer{errorsas.Analyzer})
   153  	register(&plainAnalyzer{httpresponse.Analyzer})
   154  	register(&plainAnalyzer{loopclosure.Analyzer})
   155  	register(&plainAnalyzer{lostcancel.Analyzer})
   156  	register(&plainAnalyzer{nilfunc.Analyzer})
   157  	register(&plainAnalyzer{nilness.Analyzer})
   158  	register(&plainAnalyzer{printf.Analyzer})
   159  	register(&plainAnalyzer{shift.Analyzer})
   160  	register(&plainAnalyzer{stdmethods.Analyzer})
   161  	register(&plainAnalyzer{stringintconv.Analyzer})
   162  	register(&plainAnalyzer{shadow.Analyzer})
   163  	register(&plainAnalyzer{structtag.Analyzer})
   164  	register(&plainAnalyzer{tests.Analyzer})
   165  	register(&plainAnalyzer{unmarshal.Analyzer})
   166  	register(&plainAnalyzer{unreachable.Analyzer})
   167  	register(&plainAnalyzer{unsafeptr.Analyzer})
   168  	register(&plainAnalyzer{unusedresult.Analyzer})
   169  	register(checkescape.Analyzer)
   170  	register(&plainAnalyzer{checkconst.Analyzer})
   171  	register(&plainAnalyzer{checkunsafe.Analyzer})
   172  	register(&plainAnalyzer{checklinkname.Analyzer})
   173  	register(&plainAnalyzer{checklocks.Analyzer})
   174  	register(&plainAnalyzer{checkaligned.Analyzer})
   175  
   176  	// Add all staticcheck analyzers.
   177  	for _, a := range staticcheck.Analyzers {
   178  		register(&plainAnalyzer{a.Analyzer})
   179  	}
   180  
   181  	// Add all stylecheck analyzers.
   182  	for _, a := range stylecheck.Analyzers {
   183  		register(&plainAnalyzer{a.Analyzer})
   184  	}
   185  }