github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/testutils/lint/passes/nocopy/nocopy.go (about) 1 // Copyright 2020 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 // Package nocopy defines an Analyzer that detects invalid uses of util.NoCopy. 12 package nocopy 13 14 import ( 15 "go/ast" 16 17 "golang.org/x/tools/go/analysis" 18 "golang.org/x/tools/go/analysis/passes/inspect" 19 "golang.org/x/tools/go/ast/inspector" 20 ) 21 22 // Doc documents this pass. 23 const Doc = `check for invalid uses of util.NoCopy` 24 25 // Analyzer defines this pass. 26 var Analyzer = &analysis.Analyzer{ 27 Name: "nocopy", 28 Doc: Doc, 29 Requires: []*analysis.Analyzer{inspect.Analyzer}, 30 Run: run, 31 } 32 33 const noCopyType = "github.com/cockroachdb/cockroach/pkg/util.NoCopy" 34 35 // nocopy ensures that the util.NoCopy type is not misused. Specifically, it 36 // ensures that the type is always embedded without a name as the first field in 37 // a parent struct like: 38 // 39 // type s struct { 40 // _ util.NoCopy 41 // ... 42 // } 43 // 44 // We lint against including the type in other positions in structs both for 45 // uniformity and because it can have runtime performance effects. Specifically, 46 // if util.NoCopy is included as the last field in a parent struct then it will 47 // increase the size of the parent struct even though util.NoCopy is zero-sized. 48 // This is explained in detail in https://github.com/golang/go/issues/9401 and 49 // is demonstrated in https://play.golang.org/p/jwB2Az5owcm. 50 func run(pass *analysis.Pass) (interface{}, error) { 51 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 52 inspect.Preorder([]ast.Node{ 53 (*ast.StructType)(nil), 54 }, func(n ast.Node) { 55 str := n.(*ast.StructType) 56 if str.Fields == nil { 57 return 58 } 59 for i, f := range str.Fields.List { 60 tv, ok := pass.TypesInfo.Types[f.Type] 61 if !ok { 62 continue 63 } 64 if tv.Type.String() != noCopyType { 65 continue 66 } 67 switch { 68 case i != 0: 69 pass.Reportf(f.Pos(), "Illegal use of util.NoCopy - must be first field in struct") 70 case len(f.Names) == 0: 71 pass.Reportf(f.Pos(), "Illegal use of util.NoCopy - should not be embedded") 72 case len(f.Names) > 1: 73 pass.Reportf(f.Pos(), "Illegal use of util.NoCopy - should be included only once") 74 case f.Names[0].Name != "_": 75 pass.Reportf(f.Pos(), "Illegal use of util.NoCopy - should be unnamed") 76 default: 77 // Valid use. 78 } 79 } 80 }) 81 return nil, nil 82 }