summaryrefslogtreecommitdiffhomepage
path: root/tools/nogo
diff options
context:
space:
mode:
Diffstat (limited to 'tools/nogo')
-rw-r--r--tools/nogo/build.go8
-rw-r--r--tools/nogo/defs.bzl20
-rw-r--r--tools/nogo/matchers.go29
-rw-r--r--tools/nogo/nogo.go22
4 files changed, 51 insertions, 28 deletions
diff --git a/tools/nogo/build.go b/tools/nogo/build.go
index 1c0d08661..433d13738 100644
--- a/tools/nogo/build.go
+++ b/tools/nogo/build.go
@@ -31,6 +31,10 @@ var (
)
// findStdPkg needs to find the bundled standard library packages.
-func findStdPkg(path, GOOS, GOARCH string) (io.ReadCloser, error) {
- return os.Open(fmt.Sprintf("external/go_sdk/pkg/%s_%s/%s.a", GOOS, GOARCH, path))
+func (i *importer) findStdPkg(path string) (io.ReadCloser, error) {
+ if path == "C" {
+ // Cgo builds cannot be analyzed. Skip.
+ return nil, ErrSkip
+ }
+ return os.Open(fmt.Sprintf("external/go_sdk/pkg/%s_%s/%s.a", i.GOOS, i.GOARCH, path))
}
diff --git a/tools/nogo/defs.bzl b/tools/nogo/defs.bzl
index 6560b57c8..d399079c5 100644
--- a/tools/nogo/defs.bzl
+++ b/tools/nogo/defs.bzl
@@ -28,8 +28,10 @@ def _nogo_aspect_impl(target, ctx):
else:
return [NogoInfo()]
- # Construct the Go environment from the go_context.env dictionary.
- env_prefix = " ".join(["%s=%s" % (key, value) for (key, value) in go_context(ctx).env.items()])
+ go_ctx = go_context(ctx)
+
+ # Construct the Go environment from the go_ctx.env dictionary.
+ env_prefix = " ".join(["%s=%s" % (key, value) for (key, value) in go_ctx.env.items()])
# Start with all target files and srcs as input.
inputs = target.files.to_list() + srcs
@@ -45,7 +47,7 @@ def _nogo_aspect_impl(target, ctx):
"#!/bin/bash",
"%s %s tool objdump %s > %s\n" % (
env_prefix,
- go_context(ctx).go.path,
+ go_ctx.go.path,
[f.path for f in binaries if f.path.endswith(".a")][0],
disasm_file.path,
),
@@ -53,7 +55,7 @@ def _nogo_aspect_impl(target, ctx):
ctx.actions.run(
inputs = binaries,
outputs = [disasm_file],
- tools = go_context(ctx).runfiles,
+ tools = go_ctx.runfiles,
mnemonic = "GoObjdump",
progress_message = "Objdump %s" % target.label,
executable = dumper,
@@ -70,9 +72,11 @@ def _nogo_aspect_impl(target, ctx):
ImportPath = importpath,
GoFiles = [src.path for src in srcs if src.path.endswith(".go")],
NonGoFiles = [src.path for src in srcs if not src.path.endswith(".go")],
- GOOS = go_context(ctx).goos,
- GOARCH = go_context(ctx).goarch,
- Tags = go_context(ctx).tags,
+ # Google's internal build system needs a bit more help to find std.
+ StdZip = go_ctx.std_zip.short_path if hasattr(go_ctx, "std_zip") else "",
+ GOOS = go_ctx.goos,
+ GOARCH = go_ctx.goarch,
+ Tags = go_ctx.tags,
FactMap = {}, # Constructed below.
ImportMap = {}, # Constructed below.
FactOutput = facts.path,
@@ -110,7 +114,7 @@ def _nogo_aspect_impl(target, ctx):
ctx.actions.run(
inputs = inputs,
outputs = [facts],
- tools = go_context(ctx).runfiles,
+ tools = go_ctx.runfiles,
executable = ctx.files._nogo[0],
mnemonic = "GoStaticAnalysis",
progress_message = "Analyzing %s" % target.label,
diff --git a/tools/nogo/matchers.go b/tools/nogo/matchers.go
index bc5772303..57a250501 100644
--- a/tools/nogo/matchers.go
+++ b/tools/nogo/matchers.go
@@ -27,10 +27,15 @@ type matcher interface {
ShouldReport(d analysis.Diagnostic, fs *token.FileSet) bool
}
-// pathRegexps excludes explicit paths.
+// pathRegexps filters explicit paths.
type pathRegexps struct {
- expr []*regexp.Regexp
- whitelist bool
+ expr []*regexp.Regexp
+
+ // include, if true, indicates that paths matching any regexp in expr
+ // match.
+ //
+ // If false, paths matching no regexps in expr match.
+ include bool
}
// buildRegexps builds a list of regular expressions.
@@ -49,33 +54,33 @@ func (p *pathRegexps) ShouldReport(d analysis.Diagnostic, fs *token.FileSet) boo
fullPos := fs.Position(d.Pos).String()
for _, path := range p.expr {
if path.MatchString(fullPos) {
- return p.whitelist
+ return p.include
}
}
- return !p.whitelist
+ return !p.include
}
// internalExcluded excludes specific internal paths.
func internalExcluded(paths ...string) *pathRegexps {
return &pathRegexps{
- expr: buildRegexps(internalPrefix, paths...),
- whitelist: false,
+ expr: buildRegexps(internalPrefix, paths...),
+ include: false,
}
}
// excludedExcluded excludes specific external paths.
func externalExcluded(paths ...string) *pathRegexps {
return &pathRegexps{
- expr: buildRegexps(externalPrefix, paths...),
- whitelist: false,
+ expr: buildRegexps(externalPrefix, paths...),
+ include: false,
}
}
// internalMatches returns a path matcher for internal packages.
func internalMatches() *pathRegexps {
return &pathRegexps{
- expr: buildRegexps(internalPrefix, ".*"),
- whitelist: true,
+ expr: buildRegexps(internalPrefix, ".*"),
+ include: true,
}
}
@@ -89,7 +94,7 @@ func (r resultExcluded) ShouldReport(d analysis.Diagnostic, _ *token.FileSet) bo
return false
}
}
- return true // Not blacklisted.
+ return true // Not excluded.
}
// andMatcher is a composite matcher.
diff --git a/tools/nogo/nogo.go b/tools/nogo/nogo.go
index 203cdf688..ea1e97076 100644
--- a/tools/nogo/nogo.go
+++ b/tools/nogo/nogo.go
@@ -20,6 +20,7 @@ package nogo
import (
"encoding/json"
+ "errors"
"flag"
"fmt"
"go/ast"
@@ -54,6 +55,7 @@ type pkgConfig struct {
FactMap map[string]string
FactOutput string
Objdump string
+ StdZip string
}
// loadFacts finds and loads facts per FactMap.
@@ -89,8 +91,9 @@ func (c *pkgConfig) shouldInclude(path string) (bool, error) {
// pass when a given package is not available.
type importer struct {
pkgConfig
- fset *token.FileSet
- cache map[string]*types.Package
+ fset *token.FileSet
+ cache map[string]*types.Package
+ lastErr error
}
// Import implements types.Importer.Import.
@@ -109,12 +112,13 @@ func (i *importer) Import(path string) (*types.Package, error) {
if !ok {
// Not found in the import path. Attempt to find the package
// via the standard library.
- rc, err = findStdPkg(path, i.GOOS, i.GOARCH)
+ rc, err = i.findStdPkg(path)
} else {
// Open the file.
rc, err = os.Open(realPath)
}
if err != nil {
+ i.lastErr = err
return nil, err
}
defer rc.Close()
@@ -128,6 +132,9 @@ func (i *importer) Import(path string) (*types.Package, error) {
return gcexportdata.Read(r, i.fset, i.cache, path)
}
+// ErrSkip indicates the package should be skipped.
+var ErrSkip = errors.New("skipped")
+
// checkPackage runs all analyzers.
//
// The implementation was adapted from [1], which was in turn adpated from [2].
@@ -172,14 +179,14 @@ func checkPackage(config pkgConfig) ([]string, error) {
Selections: make(map[*ast.SelectorExpr]*types.Selection),
}
types, err := typeConfig.Check(config.ImportPath, imp.fset, syntax, typesInfo)
- if err != nil {
- return nil, fmt.Errorf("error checking types: %v", err)
+ if err != nil && imp.lastErr != ErrSkip {
+ return nil, fmt.Errorf("error checking types: %w", err)
}
// Load all package facts.
facts, err := facts.Decode(types, config.loadFacts)
if err != nil {
- return nil, fmt.Errorf("error decoding facts: %v", err)
+ return nil, fmt.Errorf("error decoding facts: %w", err)
}
// Set the binary global for use.
@@ -247,6 +254,9 @@ func checkPackage(config pkgConfig) ([]string, error) {
// Visit all analysis recursively.
for a, _ := range analyzerConfig {
+ if imp.lastErr == ErrSkip {
+ continue // No local analysis.
+ }
if err := visit(a); err != nil {
return nil, err // Already has context.
}