diff options
| author | Taras Madan <tarasmadan@google.com> | 2025-01-22 16:07:17 +0100 |
|---|---|---|
| committer | Taras Madan <tarasmadan@google.com> | 2025-01-23 10:42:36 +0000 |
| commit | 7b4377ad9d8a7205416df8d6217ef2b010f89481 (patch) | |
| tree | e6fec4fd12ff807a16d847923f501075bf71d16c /vendor/github.com/ghostiam | |
| parent | 475a4c203afb8b7d3af51c4fd32bb170ff32a45e (diff) | |
vendor: delete
Diffstat (limited to 'vendor/github.com/ghostiam')
| -rw-r--r-- | vendor/github.com/ghostiam/protogetter/.goreleaser.yaml | 24 | ||||
| -rw-r--r-- | vendor/github.com/ghostiam/protogetter/LICENSE | 21 | ||||
| -rw-r--r-- | vendor/github.com/ghostiam/protogetter/Makefile | 9 | ||||
| -rw-r--r-- | vendor/github.com/ghostiam/protogetter/README.md | 73 | ||||
| -rw-r--r-- | vendor/github.com/ghostiam/protogetter/posfilter.go | 65 | ||||
| -rw-r--r-- | vendor/github.com/ghostiam/protogetter/processor.go | 351 | ||||
| -rw-r--r-- | vendor/github.com/ghostiam/protogetter/protogetter.go | 279 |
7 files changed, 0 insertions, 822 deletions
diff --git a/vendor/github.com/ghostiam/protogetter/.goreleaser.yaml b/vendor/github.com/ghostiam/protogetter/.goreleaser.yaml deleted file mode 100644 index a70d0fb00..000000000 --- a/vendor/github.com/ghostiam/protogetter/.goreleaser.yaml +++ /dev/null @@ -1,24 +0,0 @@ -before: - hooks: - - go mod tidy -builds: - - id: protogetter - main: ./cmd/protogetter - binary: protogetter - env: - - CGO_ENABLED=0 - goos: - - linux - - windows - - darwin -checksum: - name_template: 'checksums.txt' -snapshot: - name_template: "{{ incpatch .Version }}-next" -changelog: - sort: asc - filters: - exclude: - - '^docs:' - - '^test:' - - '^ci:'
\ No newline at end of file diff --git a/vendor/github.com/ghostiam/protogetter/LICENSE b/vendor/github.com/ghostiam/protogetter/LICENSE deleted file mode 100644 index b4449661b..000000000 --- a/vendor/github.com/ghostiam/protogetter/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023 Vladislav Fursov (GhostIAm) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.
\ No newline at end of file diff --git a/vendor/github.com/ghostiam/protogetter/Makefile b/vendor/github.com/ghostiam/protogetter/Makefile deleted file mode 100644 index 4c2a62af1..000000000 --- a/vendor/github.com/ghostiam/protogetter/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -.PHONY: test -test: - $(MAKE) -C testdata vendor - go test -v ./... - -.PHONY: install -install: - go install ./cmd/protogetter - @echo "Installed in $(shell which protogetter)" diff --git a/vendor/github.com/ghostiam/protogetter/README.md b/vendor/github.com/ghostiam/protogetter/README.md deleted file mode 100644 index c033e9597..000000000 --- a/vendor/github.com/ghostiam/protogetter/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# Protogetter -Welcome to the Protogetter project! - -## Overview -Protogetter is a linter developed specifically for Go programmers working with nested `protobuf` types.\ -It's designed to aid developers in preventing `invalid memory address or nil pointer dereference` errors arising from direct access of nested `protobuf` fields. - -When working with `protobuf`, it's quite common to have complex structures where a message field is contained within another message, which itself can be part of another message, and so on. -If these fields are accessed directly and some field in the call chain will not be initialized, it can result in application panic. - -Protogetter addresses this issue by suggesting use of getter methods for field access. - -## How does it work? -Protogetter analyzes your Go code and helps detect direct `protobuf` field accesses that could give rise to panic.\ -The linter suggests using getters: -```go -m.GetFoo().GetBar().GetBaz() -``` -instead of direct field access: -```go -m.Foo.Bar.Baz -``` - -And you will then only need to perform a nil check after the final call: -```go -if m.GetFoo().GetBar().GetBaz() != nil { - // Do something with m.GetFoo().GetBar().GetBaz() -} -``` -instead of: -```go -if m.Foo != nil { - if m.Foo.Bar != nil { - if m.Foo.Bar.Baz != nil { - // Do something with m.Foo.Bar.Baz - } - } -} -``` - -or use zero values: - -```go -// If one of the methods returns `nil` we will receive 0 instead of panic. -v := m.GetFoo().GetBar().GetBaz().GetInt() -``` - -instead of panic: - -```go -// If at least one structure in the chains is not initialized, we will get a panic. -v := m.Foo.Bar.Baz.Int -``` - -which simplifies the code and makes it more reliable. - -## Installation - -```bash -go install github.com/ghostiam/protogetter/cmd/protogetter@latest -``` - -## Usage - -To run the linter: -```bash -protogetter ./... -``` - -Or to apply suggested fixes directly: -```bash -protogetter --fix ./... -``` diff --git a/vendor/github.com/ghostiam/protogetter/posfilter.go b/vendor/github.com/ghostiam/protogetter/posfilter.go deleted file mode 100644 index 82075ccb1..000000000 --- a/vendor/github.com/ghostiam/protogetter/posfilter.go +++ /dev/null @@ -1,65 +0,0 @@ -package protogetter - -import ( - "go/token" -) - -type PosFilter struct { - positions map[token.Pos]struct{} - alreadyReplaced map[string]map[int][2]int // map[filename][line][start, end] -} - -func NewPosFilter() *PosFilter { - return &PosFilter{ - positions: make(map[token.Pos]struct{}), - alreadyReplaced: make(map[string]map[int][2]int), - } -} - -func (f *PosFilter) IsFiltered(pos token.Pos) bool { - _, ok := f.positions[pos] - return ok -} - -func (f *PosFilter) AddPos(pos token.Pos) { - f.positions[pos] = struct{}{} -} - -func (f *PosFilter) IsAlreadyReplaced(fset *token.FileSet, pos, end token.Pos) bool { - filePos := fset.Position(pos) - fileEnd := fset.Position(end) - - lines, ok := f.alreadyReplaced[filePos.Filename] - if !ok { - return false - } - - lineRange, ok := lines[filePos.Line] - if !ok { - return false - } - - if lineRange[0] <= filePos.Offset && fileEnd.Offset <= lineRange[1] { - return true - } - - return false -} - -func (f *PosFilter) AddAlreadyReplaced(fset *token.FileSet, pos, end token.Pos) { - filePos := fset.Position(pos) - fileEnd := fset.Position(end) - - lines, ok := f.alreadyReplaced[filePos.Filename] - if !ok { - lines = make(map[int][2]int) - f.alreadyReplaced[filePos.Filename] = lines - } - - lineRange, ok := lines[filePos.Line] - if ok && lineRange[0] <= filePos.Offset && fileEnd.Offset <= lineRange[1] { - return - } - - lines[filePos.Line] = [2]int{filePos.Offset, fileEnd.Offset} -} diff --git a/vendor/github.com/ghostiam/protogetter/processor.go b/vendor/github.com/ghostiam/protogetter/processor.go deleted file mode 100644 index 44f346e85..000000000 --- a/vendor/github.com/ghostiam/protogetter/processor.go +++ /dev/null @@ -1,351 +0,0 @@ -package protogetter - -import ( - "fmt" - "go/ast" - "go/token" - "go/types" - "reflect" - "strings" -) - -type processor struct { - info *types.Info - filter *PosFilter - cfg *Config - - to strings.Builder - from strings.Builder - err error -} - -func Process(info *types.Info, filter *PosFilter, n ast.Node, cfg *Config) (*Result, error) { - p := &processor{ - info: info, - filter: filter, - cfg: cfg, - } - - return p.process(n) -} - -func (c *processor) process(n ast.Node) (*Result, error) { - switch x := n.(type) { - case *ast.AssignStmt: - // Skip any assignment to the field. - for _, s := range x.Lhs { - c.filter.AddPos(s.Pos()) - - if se, ok := s.(*ast.StarExpr); ok { - c.filter.AddPos(se.X.Pos()) - } - } - - case *ast.IncDecStmt: - // Skip any increment/decrement to the field. - c.filter.AddPos(x.X.Pos()) - - case *ast.UnaryExpr: - if x.Op == token.AND { - // Skip all expressions when the field is used as a pointer. - // Because this is not direct reading, but most likely writing by pointer (for example like sql.Scan). - c.filter.AddPos(x.X.Pos()) - } - - case *ast.CallExpr: - if !c.cfg.ReplaceFirstArgInAppend && len(x.Args) > 0 { - if v, ok := x.Fun.(*ast.Ident); ok && v.Name == "append" { - // Skip first argument of append function. - c.filter.AddPos(x.Args[0].Pos()) - break - } - } - - f, ok := x.Fun.(*ast.SelectorExpr) - if !ok { - return &Result{}, nil - } - - if !isProtoMessage(c.info, f.X) { - return &Result{}, nil - } - - c.processInner(x) - - case *ast.SelectorExpr: - if !isProtoMessage(c.info, x.X) { - // If the selector is not on a proto message, skip it. - return &Result{}, nil - } - - c.processInner(x) - - case *ast.StarExpr: - f, ok := x.X.(*ast.SelectorExpr) - if !ok { - return &Result{}, nil - } - - if !isProtoMessage(c.info, f.X) { - return &Result{}, nil - } - - // proto2 generates fields as pointers. Hence, the indirection - // must be removed when generating the fix for the case. - // The `*` is retained in `c.from`, but excluded from the fix - // present in the `c.to`. - c.writeFrom("*") - c.processInner(x.X) - - case *ast.BinaryExpr: - // Check if the expression is a comparison. - if x.Op != token.EQL && x.Op != token.NEQ { - return &Result{}, nil - } - - // Check if one of the operands is nil. - - xIdent, xOk := x.X.(*ast.Ident) - yIdent, yOk := x.Y.(*ast.Ident) - - xIsNil := xOk && xIdent.Name == "nil" - yIsNil := yOk && yIdent.Name == "nil" - - if !xIsNil && !yIsNil { - return &Result{}, nil - } - - // Extract the non-nil operand for further checks - - var expr ast.Expr - if xIsNil { - expr = x.Y - } else { - expr = x.X - } - - se, ok := expr.(*ast.SelectorExpr) - if !ok { - return &Result{}, nil - } - - if !isProtoMessage(c.info, se.X) { - return &Result{}, nil - } - - // Check if the Getter function of the protobuf message returns a pointer. - hasPointer, ok := getterResultHasPointer(c.info, se.X, se.Sel.Name) - if !ok || hasPointer { - return &Result{}, nil - } - - c.filter.AddPos(x.X.Pos()) - - default: - return nil, fmt.Errorf("not implemented for type: %s (%s)", reflect.TypeOf(x), formatNode(n)) - } - - if c.err != nil { - return nil, c.err - } - - return &Result{ - From: c.from.String(), - To: c.to.String(), - }, nil -} - -func (c *processor) processInner(expr ast.Expr) { - switch x := expr.(type) { - case *ast.Ident: - c.write(x.Name) - - case *ast.BasicLit: - c.write(x.Value) - - case *ast.UnaryExpr: - if x.Op == token.AND { - c.write(formatNode(x)) - return - } - - c.write(x.Op.String()) - c.processInner(x.X) - - case *ast.SelectorExpr: - c.processInner(x.X) - c.write(".") - - // If getter exists, use it. - if methodIsExists(c.info, x.X, "Get"+x.Sel.Name) { - c.writeFrom(x.Sel.Name) - c.writeTo("Get" + x.Sel.Name + "()") - return - } - - // If the selector is not a proto-message or the method has already been called, we leave it unchanged. - // This approach is significantly more efficient than verifying the presence of methods in all cases. - c.write(x.Sel.Name) - - case *ast.CallExpr: - c.processInner(x.Fun) - c.write("(") - for i, arg := range x.Args { - if i > 0 { - c.write(",") - } - c.processInner(arg) - } - c.write(")") - - case *ast.IndexExpr: - c.processInner(x.X) - c.write("[") - c.processInner(x.Index) - c.write("]") - - case *ast.BinaryExpr: - c.processInner(x.X) - c.write(x.Op.String()) - c.processInner(x.Y) - - case *ast.ParenExpr: - c.write("(") - c.processInner(x.X) - c.write(")") - - case *ast.StarExpr: - c.write("*") - c.processInner(x.X) - - case *ast.CompositeLit, *ast.TypeAssertExpr, *ast.ArrayType, *ast.FuncLit, *ast.SliceExpr: - // Process the node as is. - c.write(formatNode(x)) - - default: - c.err = fmt.Errorf("processInner: not implemented for type: %s", reflect.TypeOf(x)) - } -} - -func (c *processor) write(s string) { - c.writeTo(s) - c.writeFrom(s) -} - -func (c *processor) writeTo(s string) { - c.to.WriteString(s) -} - -func (c *processor) writeFrom(s string) { - c.from.WriteString(s) -} - -// Result contains source code (from) and suggested change (to) -type Result struct { - From string - To string -} - -func (r *Result) Skipped() bool { - // If from and to are the same, skip it. - return r.From == r.To -} - -func isProtoMessage(info *types.Info, expr ast.Expr) bool { - // First, we are checking for the presence of the ProtoReflect method which is currently being generated - // and corresponds to v2 version. - // https://pkg.go.dev/google.golang.org/protobuf@v1.31.0/proto#Message - const protoV2Method = "ProtoReflect" - ok := methodIsExists(info, expr, protoV2Method) - if ok { - return true - } - - // Afterwards, we are checking the ProtoMessage method. All the structures that implement the proto.Message interface - // have a ProtoMessage method and are proto-structures. This interface has been generated since version 1.0.0 and - // continues to exist for compatibility. - // https://pkg.go.dev/github.com/golang/protobuf/proto?utm_source=godoc#Message - const protoV1Method = "ProtoMessage" - ok = methodIsExists(info, expr, protoV1Method) - if ok { - // Since there is a protoc-gen-gogo generator that implements the proto.Message interface, but may not generate - // getters or generate from without checking for nil, so even if getters exist, we skip them. - const protocGenGoGoMethod = "MarshalToSizedBuffer" - return !methodIsExists(info, expr, protocGenGoGoMethod) - } - - return false -} - -func typesNamed(info *types.Info, x ast.Expr) (*types.Named, bool) { - if info == nil { - return nil, false - } - - t := info.TypeOf(x) - if t == nil { - return nil, false - } - - ptr, ok := t.Underlying().(*types.Pointer) - if ok { - t = ptr.Elem() - } - - named, ok := t.(*types.Named) - if !ok { - return nil, false - } - - return named, true -} - -func methodIsExists(info *types.Info, x ast.Expr, name string) bool { - named, ok := typesNamed(info, x) - if !ok { - return false - } - - for i := 0; i < named.NumMethods(); i++ { - if named.Method(i).Name() == name { - return true - } - } - - return false -} - -func getterResultHasPointer(info *types.Info, x ast.Expr, name string) (hasPointer, ok bool) { - named, ok := typesNamed(info, x) - if !ok { - return false, false - } - - for i := 0; i < named.NumMethods(); i++ { - method := named.Method(i) - if method.Name() != "Get"+name { - continue - } - - var sig *types.Signature - sig, ok = method.Type().(*types.Signature) - if !ok { - return false, false - } - - results := sig.Results() - if results.Len() == 0 { - return false, false - } - - firstType := results.At(0) - _, ok = firstType.Type().(*types.Pointer) - if !ok { - return false, true - } - - return true, true - } - - return false, false -} diff --git a/vendor/github.com/ghostiam/protogetter/protogetter.go b/vendor/github.com/ghostiam/protogetter/protogetter.go deleted file mode 100644 index 31eee8572..000000000 --- a/vendor/github.com/ghostiam/protogetter/protogetter.go +++ /dev/null @@ -1,279 +0,0 @@ -package protogetter - -import ( - "bytes" - "flag" - "fmt" - "go/ast" - "go/format" - "go/token" - "log" - "path/filepath" - "strings" - - "github.com/gobwas/glob" - "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/ast/inspector" -) - -type Mode int - -const ( - StandaloneMode Mode = iota - GolangciLintMode -) - -const msgFormat = "avoid direct access to proto field %s, use %s instead" - -func NewAnalyzer(cfg *Config) *analysis.Analyzer { - if cfg == nil { - cfg = &Config{} - } - - return &analysis.Analyzer{ - Name: "protogetter", - Doc: "Reports direct reads from proto message fields when getters should be used", - Flags: flags(cfg), - Run: func(pass *analysis.Pass) (any, error) { - _, err := Run(pass, cfg) - return nil, err - }, - } -} - -func flags(opts *Config) flag.FlagSet { - fs := flag.NewFlagSet("protogetter", flag.ContinueOnError) - - fs.Func("skip-generated-by", "skip files generated with the given prefixes", func(s string) error { - for _, prefix := range strings.Split(s, ",") { - opts.SkipGeneratedBy = append(opts.SkipGeneratedBy, prefix) - } - return nil - }) - fs.Func("skip-files", "skip files with the given glob patterns", func(s string) error { - for _, pattern := range strings.Split(s, ",") { - opts.SkipFiles = append(opts.SkipFiles, pattern) - } - return nil - }) - fs.BoolVar(&opts.SkipAnyGenerated, "skip-any-generated", false, "skip any generated files") - - return *fs -} - -type Config struct { - Mode Mode // Zero value is StandaloneMode. - SkipGeneratedBy []string - SkipFiles []string - SkipAnyGenerated bool - ReplaceFirstArgInAppend bool -} - -func Run(pass *analysis.Pass, cfg *Config) ([]Issue, error) { - skipGeneratedBy := make([]string, 0, len(cfg.SkipGeneratedBy)+3) - // Always skip files generated by protoc-gen-go, protoc-gen-go-grpc and protoc-gen-grpc-gateway. - skipGeneratedBy = append(skipGeneratedBy, "protoc-gen-go", "protoc-gen-go-grpc", "protoc-gen-grpc-gateway") - for _, s := range cfg.SkipGeneratedBy { - s = strings.TrimSpace(s) - if s == "" { - continue - } - skipGeneratedBy = append(skipGeneratedBy, s) - } - - skipFilesGlobPatterns := make([]glob.Glob, 0, len(cfg.SkipFiles)) - for _, s := range cfg.SkipFiles { - s = strings.TrimSpace(s) - if s == "" { - continue - } - - compile, err := glob.Compile(s) - if err != nil { - return nil, fmt.Errorf("invalid glob pattern: %w", err) - } - - skipFilesGlobPatterns = append(skipFilesGlobPatterns, compile) - } - - nodeTypes := []ast.Node{ - (*ast.AssignStmt)(nil), - (*ast.BinaryExpr)(nil), - (*ast.CallExpr)(nil), - (*ast.SelectorExpr)(nil), - (*ast.StarExpr)(nil), - (*ast.IncDecStmt)(nil), - (*ast.UnaryExpr)(nil), - } - - // Skip filtered files. - var files []*ast.File - for _, f := range pass.Files { - if skipGeneratedFile(f, skipGeneratedBy, cfg.SkipAnyGenerated) { - continue - } - - if skipFilesByGlob(pass.Fset.File(f.Pos()).Name(), skipFilesGlobPatterns) { - continue - } - - files = append(files, f) - - // ast.Print(pass.Fset, f) - } - - ins := inspector.New(files) - - var issues []Issue - - filter := NewPosFilter() - ins.Preorder(nodeTypes, func(node ast.Node) { - report := analyse(pass, filter, node, cfg) - if report == nil { - return - } - - switch cfg.Mode { - case StandaloneMode: - pass.Report(report.ToDiagReport()) - case GolangciLintMode: - issues = append(issues, report.ToIssue(pass.Fset)) - } - }) - - return issues, nil -} - -func analyse(pass *analysis.Pass, filter *PosFilter, n ast.Node, cfg *Config) *Report { - // fmt.Printf("\n>>> check: %s\n", formatNode(n)) - // ast.Print(pass.Fset, n) - if filter.IsFiltered(n.Pos()) { - // fmt.Printf(">>> filtered\n") - return nil - } - - result, err := Process(pass.TypesInfo, filter, n, cfg) - if err != nil { - pass.Report(analysis.Diagnostic{ - Pos: n.Pos(), - End: n.End(), - Message: fmt.Sprintf("error: %v", err), - }) - - return nil - } - - // If existing in filter, skip it. - if filter.IsFiltered(n.Pos()) { - return nil - } - - if result.Skipped() { - return nil - } - - // If the expression has already been replaced, skip it. - if filter.IsAlreadyReplaced(pass.Fset, n.Pos(), n.End()) { - return nil - } - // Add the expression to the filter. - filter.AddAlreadyReplaced(pass.Fset, n.Pos(), n.End()) - - return &Report{ - node: n, - result: result, - } -} - -// Issue is used to integrate with golangci-lint's inline auto fix. -type Issue struct { - Pos token.Position - Message string - InlineFix InlineFix -} - -type InlineFix struct { - StartCol int // zero-based - Length int - NewString string -} - -type Report struct { - node ast.Node - result *Result -} - -func (r *Report) ToDiagReport() analysis.Diagnostic { - msg := fmt.Sprintf(msgFormat, r.result.From, r.result.To) - - return analysis.Diagnostic{ - Pos: r.node.Pos(), - End: r.node.End(), - Message: msg, - SuggestedFixes: []analysis.SuggestedFix{ - { - Message: msg, - TextEdits: []analysis.TextEdit{ - { - Pos: r.node.Pos(), - End: r.node.End(), - NewText: []byte(r.result.To), - }, - }, - }, - }, - } -} - -func (r *Report) ToIssue(fset *token.FileSet) Issue { - msg := fmt.Sprintf(msgFormat, r.result.From, r.result.To) - return Issue{ - Pos: fset.Position(r.node.Pos()), - Message: msg, - InlineFix: InlineFix{ - StartCol: fset.Position(r.node.Pos()).Column - 1, - Length: len(r.result.From), - NewString: r.result.To, - }, - } -} - -func skipGeneratedFile(f *ast.File, prefixes []string, skipAny bool) bool { - if len(f.Comments) == 0 { - return false - } - firstComment := f.Comments[0].Text() - - // https://golang.org/s/generatedcode - if skipAny && strings.HasPrefix(firstComment, "Code generated") { - return true - } - - for _, prefix := range prefixes { - if strings.HasPrefix(firstComment, "Code generated by "+prefix) { - return true - } - } - - return false -} - -func skipFilesByGlob(filename string, patterns []glob.Glob) bool { - for _, pattern := range patterns { - if pattern.Match(filename) || pattern.Match(filepath.Base(filename)) { - return true - } - } - - return false -} - -func formatNode(node ast.Node) string { - buf := new(bytes.Buffer) - if err := format.Node(buf, token.NewFileSet(), node); err != nil { - log.Printf("Error formatting expression: %v", err) - return "" - } - - return buf.String() -} |
