mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 01:53:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			201 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Protocol Buffers for Go with Gadgets
 | 
						|
//
 | 
						|
// Copyright (c) 2013, The GoGo Authors. All rights reserved.
 | 
						|
// http://github.com/gogo/protobuf
 | 
						|
//
 | 
						|
// Redistribution and use in source and binary forms, with or without
 | 
						|
// modification, are permitted provided that the following conditions are
 | 
						|
// met:
 | 
						|
//
 | 
						|
//     * Redistributions of source code must retain the above copyright
 | 
						|
// notice, this list of conditions and the following disclaimer.
 | 
						|
//     * Redistributions in binary form must reproduce the above
 | 
						|
// copyright notice, this list of conditions and the following disclaimer
 | 
						|
// in the documentation and/or other materials provided with the
 | 
						|
// distribution.
 | 
						|
//
 | 
						|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
						|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
						|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
						|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
						|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
						|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
						|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
						|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
						|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
						|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
						|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 | 
						|
/*
 | 
						|
The embedcheck plugin is used to check whether embed is not used incorrectly.
 | 
						|
For instance:
 | 
						|
An embedded message has a generated string method, but the is a member of a message which does not.
 | 
						|
This causes a warning.
 | 
						|
An error is caused by a namespace conflict.
 | 
						|
 | 
						|
It is enabled by the following extensions:
 | 
						|
 | 
						|
  - embed
 | 
						|
  - embed_all
 | 
						|
 | 
						|
For incorrect usage of embed with tests see:
 | 
						|
 | 
						|
  github.com/gogo/protobuf/test/embedconflict
 | 
						|
 | 
						|
*/
 | 
						|
package embedcheck
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"os"
 | 
						|
 | 
						|
	"github.com/gogo/protobuf/gogoproto"
 | 
						|
	"github.com/gogo/protobuf/protoc-gen-gogo/generator"
 | 
						|
)
 | 
						|
 | 
						|
type plugin struct {
 | 
						|
	*generator.Generator
 | 
						|
}
 | 
						|
 | 
						|
func NewPlugin() *plugin {
 | 
						|
	return &plugin{}
 | 
						|
}
 | 
						|
 | 
						|
func (p *plugin) Name() string {
 | 
						|
	return "embedcheck"
 | 
						|
}
 | 
						|
 | 
						|
func (p *plugin) Init(g *generator.Generator) {
 | 
						|
	p.Generator = g
 | 
						|
}
 | 
						|
 | 
						|
var overwriters []map[string]gogoproto.EnableFunc = []map[string]gogoproto.EnableFunc{
 | 
						|
	{
 | 
						|
		"stringer": gogoproto.IsStringer,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"gostring": gogoproto.HasGoString,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"equal": gogoproto.HasEqual,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"verboseequal": gogoproto.HasVerboseEqual,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"size":       gogoproto.IsSizer,
 | 
						|
		"protosizer": gogoproto.IsProtoSizer,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"unmarshaler":        gogoproto.IsUnmarshaler,
 | 
						|
		"unsafe_unmarshaler": gogoproto.IsUnsafeUnmarshaler,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"marshaler":        gogoproto.IsMarshaler,
 | 
						|
		"unsafe_marshaler": gogoproto.IsUnsafeMarshaler,
 | 
						|
	},
 | 
						|
}
 | 
						|
 | 
						|
func (p *plugin) Generate(file *generator.FileDescriptor) {
 | 
						|
	for _, msg := range file.Messages() {
 | 
						|
		for _, os := range overwriters {
 | 
						|
			possible := true
 | 
						|
			for _, overwriter := range os {
 | 
						|
				if overwriter(file.FileDescriptorProto, msg.DescriptorProto) {
 | 
						|
					possible = false
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if possible {
 | 
						|
				p.checkOverwrite(msg, os)
 | 
						|
			}
 | 
						|
		}
 | 
						|
		p.checkNameSpace(msg)
 | 
						|
		for _, field := range msg.GetField() {
 | 
						|
			if gogoproto.IsEmbed(field) && gogoproto.IsCustomName(field) {
 | 
						|
				fmt.Fprintf(os.Stderr, "ERROR: field %v with custom name %v cannot be embedded", *field.Name, gogoproto.GetCustomName(field))
 | 
						|
				os.Exit(1)
 | 
						|
			}
 | 
						|
		}
 | 
						|
		p.checkRepeated(msg)
 | 
						|
	}
 | 
						|
	for _, e := range file.GetExtension() {
 | 
						|
		if gogoproto.IsEmbed(e) {
 | 
						|
			fmt.Fprintf(os.Stderr, "ERROR: extended field %v cannot be embedded", generator.CamelCase(*e.Name))
 | 
						|
			os.Exit(1)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (p *plugin) checkNameSpace(message *generator.Descriptor) map[string]bool {
 | 
						|
	ccTypeName := generator.CamelCaseSlice(message.TypeName())
 | 
						|
	names := make(map[string]bool)
 | 
						|
	for _, field := range message.Field {
 | 
						|
		fieldname := generator.CamelCase(*field.Name)
 | 
						|
		if field.IsMessage() && gogoproto.IsEmbed(field) {
 | 
						|
			desc := p.ObjectNamed(field.GetTypeName())
 | 
						|
			moreNames := p.checkNameSpace(desc.(*generator.Descriptor))
 | 
						|
			for another := range moreNames {
 | 
						|
				if names[another] {
 | 
						|
					fmt.Fprintf(os.Stderr, "ERROR: duplicate embedded fieldname %v in type %v\n", fieldname, ccTypeName)
 | 
						|
					os.Exit(1)
 | 
						|
				}
 | 
						|
				names[another] = true
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			if names[fieldname] {
 | 
						|
				fmt.Fprintf(os.Stderr, "ERROR: duplicate embedded fieldname %v in type %v\n", fieldname, ccTypeName)
 | 
						|
				os.Exit(1)
 | 
						|
			}
 | 
						|
			names[fieldname] = true
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return names
 | 
						|
}
 | 
						|
 | 
						|
func (p *plugin) checkOverwrite(message *generator.Descriptor, enablers map[string]gogoproto.EnableFunc) {
 | 
						|
	ccTypeName := generator.CamelCaseSlice(message.TypeName())
 | 
						|
	names := []string{}
 | 
						|
	for name := range enablers {
 | 
						|
		names = append(names, name)
 | 
						|
	}
 | 
						|
	for _, field := range message.Field {
 | 
						|
		if field.IsMessage() && gogoproto.IsEmbed(field) {
 | 
						|
			fieldname := generator.CamelCase(*field.Name)
 | 
						|
			desc := p.ObjectNamed(field.GetTypeName())
 | 
						|
			msg := desc.(*generator.Descriptor)
 | 
						|
			for errStr, enabled := range enablers {
 | 
						|
				if enabled(msg.File().FileDescriptorProto, msg.DescriptorProto) {
 | 
						|
					fmt.Fprintf(os.Stderr, "WARNING: found non-%v %v with embedded %v %v\n", names, ccTypeName, errStr, fieldname)
 | 
						|
				}
 | 
						|
			}
 | 
						|
			p.checkOverwrite(msg, enablers)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (p *plugin) checkRepeated(message *generator.Descriptor) {
 | 
						|
	ccTypeName := generator.CamelCaseSlice(message.TypeName())
 | 
						|
	for _, field := range message.Field {
 | 
						|
		if !gogoproto.IsEmbed(field) {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if field.IsBytes() {
 | 
						|
			fieldname := generator.CamelCase(*field.Name)
 | 
						|
			fmt.Fprintf(os.Stderr, "ERROR: found embedded bytes field %s in message %s\n", fieldname, ccTypeName)
 | 
						|
			os.Exit(1)
 | 
						|
		}
 | 
						|
		if !field.IsRepeated() {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		fieldname := generator.CamelCase(*field.Name)
 | 
						|
		fmt.Fprintf(os.Stderr, "ERROR: found repeated embedded field %s in message %s\n", fieldname, ccTypeName)
 | 
						|
		os.Exit(1)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (p *plugin) GenerateImports(*generator.FileDescriptor) {}
 | 
						|
 | 
						|
func init() {
 | 
						|
	generator.RegisterPlugin(NewPlugin())
 | 
						|
}
 |