summaryrefslogtreecommitdiffhomepage
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/checkunsafe/BUILD13
-rw-r--r--tools/checkunsafe/check_unsafe.go56
-rw-r--r--tools/go_generics/defs.bzl4
-rw-r--r--tools/go_generics/generics.go16
-rw-r--r--tools/go_generics/generics_tests/anon/input.go46
-rw-r--r--tools/go_generics/generics_tests/anon/opts.txt1
-rw-r--r--tools/go_generics/generics_tests/anon/output/output.go42
-rw-r--r--tools/go_generics/globals/globals_visitor.go21
-rw-r--r--tools/nogo.js7
-rwxr-xr-xtools/run_tests.sh3
10 files changed, 199 insertions, 10 deletions
diff --git a/tools/checkunsafe/BUILD b/tools/checkunsafe/BUILD
new file mode 100644
index 000000000..d85c56131
--- /dev/null
+++ b/tools/checkunsafe/BUILD
@@ -0,0 +1,13 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_tool_library")
+
+package(licenses = ["notice"])
+
+go_tool_library(
+ name = "checkunsafe",
+ srcs = ["check_unsafe.go"],
+ importpath = "checkunsafe",
+ visibility = ["//visibility:public"],
+ deps = [
+ "@org_golang_x_tools//go/analysis:go_tool_library",
+ ],
+)
diff --git a/tools/checkunsafe/check_unsafe.go b/tools/checkunsafe/check_unsafe.go
new file mode 100644
index 000000000..4ccd7cc5a
--- /dev/null
+++ b/tools/checkunsafe/check_unsafe.go
@@ -0,0 +1,56 @@
+// 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 checkunsafe allows unsafe imports only in files named appropriately.
+package checkunsafe
+
+import (
+ "fmt"
+ "path"
+ "strconv"
+ "strings"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+// Analyzer defines the entrypoint.
+var Analyzer = &analysis.Analyzer{
+ Name: "checkunsafe",
+ Doc: "allows unsafe use only in specified files",
+ Run: run,
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ for _, f := range pass.Files {
+ for _, imp := range f.Imports {
+ // Is this an unsafe import?
+ pkg, err := strconv.Unquote(imp.Path.Value)
+ if err != nil || pkg != "unsafe" {
+ continue
+ }
+
+ // Extract the filename.
+ filename := pass.Fset.File(imp.Pos()).Name()
+
+ // Allow files named _unsafe.go or _test.go to opt out.
+ if strings.HasSuffix(filename, "_unsafe.go") || strings.HasSuffix(filename, "_test.go") {
+ continue
+ }
+
+ // Throw the error.
+ pass.Reportf(imp.Pos(), fmt.Sprintf("package unsafe imported by %s; must end with _unsafe.go", path.Base(filename)))
+ }
+ }
+ return nil, nil
+}
diff --git a/tools/go_generics/defs.bzl b/tools/go_generics/defs.bzl
index 999fb3426..c5be52ecd 100644
--- a/tools/go_generics/defs.bzl
+++ b/tools/go_generics/defs.bzl
@@ -93,6 +93,9 @@ def _go_template_instance_impl(ctx):
args += [("-c=%s=%s" % (p[0], p[1])) for p in ctx.attr.consts.items()]
args += [("-import=%s=%s" % (p[0], p[1])) for p in ctx.attr.imports.items()]
+ if ctx.attr.anon:
+ args += ["-anon"]
+
ctx.actions.run(
inputs = [template.file],
outputs = [output],
@@ -129,6 +132,7 @@ go_template_instance = rule(
"types": attr.string_dict(),
"consts": attr.string_dict(),
"imports": attr.string_dict(),
+ "anon": attr.bool(mandatory = False, default = False),
"package": attr.string(mandatory = True),
"out": attr.output(mandatory = True),
"_tool": attr.label(executable = True, cfg = "host", default = Label("//tools/go_generics")),
diff --git a/tools/go_generics/generics.go b/tools/go_generics/generics.go
index 4e5cc53a2..e9cc2c753 100644
--- a/tools/go_generics/generics.go
+++ b/tools/go_generics/generics.go
@@ -82,7 +82,12 @@
// Note that the second call to g() kept "b" as an argument because it refers to
// the local variable "b".
//
-// Unfortunately, go_generics does not handle anonymous fields with renamed types.
+// Note that go_generics can handle anonymous fields with renamed types if
+// -anon is passed in, however it does not perform strict checking on parameter
+// types that share the same name as the global type and therefore will rename
+// them as well.
+//
+// You can see an example in the tools/go_generics/generics_tests/interface test.
package main
import (
@@ -108,6 +113,7 @@ var (
prefix = flag.String("prefix", "", "`prefix` to add to each global symbol")
packageName = flag.String("p", "main", "output package `name`")
printAST = flag.Bool("ast", false, "prints the AST")
+ processAnon = flag.Bool("anon", false, "process anonymous fields")
types = make(mapValue)
consts = make(mapValue)
imports = make(mapValue)
@@ -222,12 +228,16 @@ func main() {
// Modify the state tag appropriately.
if m := stateTagRegexp.FindStringSubmatch(ident.Name); m != nil {
if t := identifierRegexp.FindStringSubmatch(m[2]); t != nil {
- ident.Name = m[1] + `state:".(` + t[1] + *prefix + t[2] + *suffix + t[3] + `)"` + m[3]
+ typeName := *prefix + t[2] + *suffix
+ if n, ok := types[t[2]]; ok {
+ typeName = n
+ }
+ ident.Name = m[1] + `state:".(` + t[1] + typeName + t[3] + `)"` + m[3]
}
}
}
}
- })
+ }, *processAnon)
// Remove the definition of all types that are being remapped.
set := make(typeSet)
diff --git a/tools/go_generics/generics_tests/anon/input.go b/tools/go_generics/generics_tests/anon/input.go
new file mode 100644
index 000000000..44086d522
--- /dev/null
+++ b/tools/go_generics/generics_tests/anon/input.go
@@ -0,0 +1,46 @@
+// 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 tests
+
+type T interface {
+ Apply(T) T
+}
+
+type Foo struct {
+ T
+ Bar map[string]T `json:"bar,omitempty"`
+}
+
+type Baz struct {
+ T someTypeNotT
+}
+
+func (f Foo) GetBar(name string) T {
+ b, ok := f.Bar[name]
+ if ok {
+ b = f.Apply(b)
+ } else {
+ b = f.T
+ }
+ return b
+}
+
+func foobar() {
+ a := Baz{}
+ a.T = 0 // should not be renamed, this is a limitation
+
+ b := otherpkg.UnrelatedType{}
+ b.T = 0 // should not be renamed, this is a limitation
+}
diff --git a/tools/go_generics/generics_tests/anon/opts.txt b/tools/go_generics/generics_tests/anon/opts.txt
new file mode 100644
index 000000000..a5e9d26de
--- /dev/null
+++ b/tools/go_generics/generics_tests/anon/opts.txt
@@ -0,0 +1 @@
+-t=T=Q -suffix=New -anon
diff --git a/tools/go_generics/generics_tests/anon/output/output.go b/tools/go_generics/generics_tests/anon/output/output.go
new file mode 100644
index 000000000..160cddf79
--- /dev/null
+++ b/tools/go_generics/generics_tests/anon/output/output.go
@@ -0,0 +1,42 @@
+// 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 main
+
+type FooNew struct {
+ Q
+ Bar map[string]Q `json:"bar,omitempty"`
+}
+
+type BazNew struct {
+ T someTypeNotT
+}
+
+func (f FooNew) GetBar(name string) Q {
+ b, ok := f.Bar[name]
+ if ok {
+ b = f.Apply(b)
+ } else {
+ b = f.Q
+ }
+ return b
+}
+
+func foobarNew() {
+ a := BazNew{}
+ a.Q = 0 // should not be renamed, this is a limitation
+
+ b := otherpkg.UnrelatedType{}
+ b.Q = 0 // should not be renamed, this is a limitation
+}
diff --git a/tools/go_generics/globals/globals_visitor.go b/tools/go_generics/globals/globals_visitor.go
index 7ae48c662..883f21ebe 100644
--- a/tools/go_generics/globals/globals_visitor.go
+++ b/tools/go_generics/globals/globals_visitor.go
@@ -47,6 +47,11 @@ type globalsVisitor struct {
// scope is the current scope as nodes are visited.
scope *scope
+
+ // processAnon indicates whether we should process anonymous struct fields.
+ // It does not perform strict checking on parameter types that share the same name
+ // as the global type and therefore will rename them as well.
+ processAnon bool
}
// unexpected is called when an unexpected node appears in the AST. It dumps
@@ -132,7 +137,7 @@ func (v *globalsVisitor) visitFields(l *ast.FieldList, kind SymKind) {
}
}
-// visitGenDecl is called when a generic declation is encountered, for example,
+// visitGenDecl is called when a generic declaration is encountered, for example,
// on variable, constant and type declarations. It adds all newly defined
// symbols to the current scope and reports them if the current scope is the
// global one.
@@ -307,6 +312,9 @@ func (v *globalsVisitor) visitExpr(ge ast.Expr) {
case *ast.SelectorExpr:
v.visitExpr(e.X)
+ if v.processAnon {
+ v.visitExpr(e.Sel)
+ }
case *ast.SliceExpr:
v.visitExpr(e.X)
@@ -490,7 +498,7 @@ func (v *globalsVisitor) visitBlockStmt(s *ast.BlockStmt) {
v.popScope()
}
-// visitFuncDecl is called when a function or method declation is encountered.
+// visitFuncDecl is called when a function or method declaration is encountered.
// it creates a new scope for the function [optional] receiver, parameters and
// results, and visits all children nodes.
func (v *globalsVisitor) visitFuncDecl(d *ast.FuncDecl) {
@@ -577,11 +585,12 @@ func (v *globalsVisitor) visit() {
//
// The function f() is allowed to modify the identifier, for example, to rename
// uses of global references.
-func Visit(fset *token.FileSet, file *ast.File, f func(*ast.Ident, SymKind)) {
+func Visit(fset *token.FileSet, file *ast.File, f func(*ast.Ident, SymKind), processAnon bool) {
v := globalsVisitor{
- fset: fset,
- file: file,
- f: f,
+ fset: fset,
+ file: file,
+ f: f,
+ processAnon: processAnon,
}
v.visit()
diff --git a/tools/nogo.js b/tools/nogo.js
new file mode 100644
index 000000000..fc0a4d1f0
--- /dev/null
+++ b/tools/nogo.js
@@ -0,0 +1,7 @@
+{
+ "checkunsafe": {
+ "exclude_files": {
+ "/external/": "not subject to constraint"
+ }
+ }
+}
diff --git a/tools/run_tests.sh b/tools/run_tests.sh
index d1669b343..483b9cb50 100755
--- a/tools/run_tests.sh
+++ b/tools/run_tests.sh
@@ -45,7 +45,8 @@ readonly TEST_PACKAGES=("//pkg/..." "//runsc/..." "//tools/...")
#######################
# Install the latest version of Bazel and log the version.
-(which use_bazel.sh && use_bazel.sh latest) || which bazel
+# FIXME(b/137285694): Unable to build runsc with bazel 0.28.0.
+(which use_bazel.sh && use_bazel.sh 0.27.1) || which bazel
bazel version
# Load the kvm module.