...

Source file src/github.com/gogo/protobuf/plugin/defaultcheck/defaultcheck.go

Documentation: github.com/gogo/protobuf/plugin/defaultcheck

     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  }
   134  

View as plain text