github.com/gogo/protobuf@v1.3.2/plugin/defaultcheck/defaultcheck.go (about) 1 // Protocol Buffers for Go with Gadgets 2 // 3 // Copyright (c) 2013, The GoGo Authors. All rights reserved. 4 // http://github.com/gogo/protobuf 5 // 6 // Redistribution and use in source and binary forms, with or without 7 // modification, are permitted provided that the following conditions are 8 // met: 9 // 10 // * Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // * Redistributions in binary form must reproduce the above 13 // copyright notice, this list of conditions and the following disclaimer 14 // in the documentation and/or other materials provided with the 15 // distribution. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 /* 30 The defaultcheck plugin is used to check whether nullable is not used incorrectly. 31 For instance: 32 An error is caused if a nullable field: 33 - has a default value, 34 - is an enum which does not start at zero, 35 - is used for an extension, 36 - is used for a native proto3 type, 37 - is used for a repeated native type. 38 39 An error is also caused if a field with a default value is used in a message: 40 - which is a face. 41 - without getters. 42 43 It is enabled by the following extensions: 44 45 - nullable 46 47 For incorrect usage of nullable with tests see: 48 49 github.com/gogo/protobuf/test/nullableconflict 50 51 */ 52 package defaultcheck 53 54 import ( 55 "fmt" 56 "github.com/gogo/protobuf/gogoproto" 57 "github.com/gogo/protobuf/protoc-gen-gogo/generator" 58 "os" 59 ) 60 61 type plugin struct { 62 *generator.Generator 63 } 64 65 func NewPlugin() *plugin { 66 return &plugin{} 67 } 68 69 func (p *plugin) Name() string { 70 return "defaultcheck" 71 } 72 73 func (p *plugin) Init(g *generator.Generator) { 74 p.Generator = g 75 } 76 77 func (p *plugin) Generate(file *generator.FileDescriptor) { 78 proto3 := gogoproto.IsProto3(file.FileDescriptorProto) 79 for _, msg := range file.Messages() { 80 getters := gogoproto.HasGoGetters(file.FileDescriptorProto, msg.DescriptorProto) 81 face := gogoproto.IsFace(file.FileDescriptorProto, msg.DescriptorProto) 82 for _, field := range msg.GetField() { 83 if len(field.GetDefaultValue()) > 0 { 84 if !getters { 85 fmt.Fprintf(os.Stderr, "ERROR: field %v.%v cannot have a default value and not have a getter method", generator.CamelCase(*msg.Name), generator.CamelCase(*field.Name)) 86 os.Exit(1) 87 } 88 if face { 89 fmt.Fprintf(os.Stderr, "ERROR: field %v.%v cannot have a default value be in a face", generator.CamelCase(*msg.Name), generator.CamelCase(*field.Name)) 90 os.Exit(1) 91 } 92 } 93 if gogoproto.IsNullable(field) { 94 continue 95 } 96 if len(field.GetDefaultValue()) > 0 { 97 fmt.Fprintf(os.Stderr, "ERROR: field %v.%v cannot be non-nullable and have a default value", generator.CamelCase(*msg.Name), generator.CamelCase(*field.Name)) 98 os.Exit(1) 99 } 100 if !field.IsMessage() && !gogoproto.IsCustomType(field) { 101 if field.IsRepeated() { 102 fmt.Fprintf(os.Stderr, "WARNING: field %v.%v is a repeated non-nullable native type, nullable=false has no effect\n", generator.CamelCase(*msg.Name), generator.CamelCase(*field.Name)) 103 } else if proto3 { 104 fmt.Fprintf(os.Stderr, "ERROR: field %v.%v is a native type and in proto3 syntax with nullable=false there exists conflicting implementations when encoding zero values", generator.CamelCase(*msg.Name), generator.CamelCase(*field.Name)) 105 os.Exit(1) 106 } 107 if field.IsBytes() { 108 fmt.Fprintf(os.Stderr, "WARNING: field %v.%v is a non-nullable bytes type, nullable=false has no effect\n", generator.CamelCase(*msg.Name), generator.CamelCase(*field.Name)) 109 } 110 } 111 if !field.IsEnum() { 112 continue 113 } 114 enum := p.ObjectNamed(field.GetTypeName()).(*generator.EnumDescriptor) 115 if len(enum.Value) == 0 || enum.Value[0].GetNumber() != 0 { 116 fmt.Fprintf(os.Stderr, "ERROR: field %v.%v cannot be non-nullable and be an enum type %v which does not start with zero", generator.CamelCase(*msg.Name), generator.CamelCase(*field.Name), enum.GetName()) 117 os.Exit(1) 118 } 119 } 120 } 121 for _, e := range file.GetExtension() { 122 if !gogoproto.IsNullable(e) { 123 fmt.Fprintf(os.Stderr, "ERROR: extended field %v cannot be nullable %v", generator.CamelCase(e.GetName()), generator.CamelCase(*e.Name)) 124 os.Exit(1) 125 } 126 } 127 } 128 129 func (p *plugin) GenerateImports(*generator.FileDescriptor) {} 130 131 func init() { 132 generator.RegisterPlugin(NewPlugin()) 133 }