github.com/blend/go-sdk@v1.20240719.1/profanity/generics.go (about) 1 /* 2 3 Copyright (c) 2024 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package profanity 9 10 import ( 11 "go/ast" 12 "go/parser" 13 "go/token" 14 "path/filepath" 15 ) 16 17 var ( 18 _ Rule = (*NoGenericDecls)(nil) 19 ) 20 21 // NoGenericDecls returns a profanity error if a generic function or type declaration exists 22 type NoGenericDecls struct { 23 Enabled bool `yaml:"enabled"` 24 } 25 26 // Validate implements validation for the rule. 27 func (ngd NoGenericDecls) Validate() error { 28 return nil 29 } 30 31 // Check implements Rule. 32 func (ngd NoGenericDecls) Check(filename string, contents []byte) RuleResult { 33 if !ngd.Enabled { 34 return RuleResult{OK: true} 35 } 36 if filepath.Ext(filename) != ".go" { 37 return RuleResult{OK: true} 38 } 39 40 fset := token.NewFileSet() 41 fileAst, err := parser.ParseFile(fset, filename, contents, parser.AllErrors|parser.ParseComments) 42 if err != nil { 43 return RuleResult{Err: err} 44 } 45 46 var result *RuleResult 47 ast.Inspect(fileAst, func(n ast.Node) bool { 48 if n == nil { 49 return false 50 } 51 if result != nil { 52 return false 53 } 54 switch nt := n.(type) { 55 case *ast.FuncType: 56 if nt.TypeParams != nil { 57 result = &RuleResult{ 58 File: filename, 59 Line: fset.Position(nt.TypeParams.Pos()).Line, 60 Message: "Type params present on function declaration", 61 } 62 return false 63 } 64 case *ast.TypeSpec: 65 if nt.TypeParams != nil { 66 result = &RuleResult{ 67 File: filename, 68 Line: fset.Position(nt.TypeParams.Pos()).Line, 69 Message: "Type params present on type declaration", 70 } 71 return false 72 } 73 case *ast.InterfaceType: 74 if nt.Methods != nil { 75 for _, i := range nt.Methods.List { 76 if i == nil { 77 continue 78 } 79 ast.Inspect(i, func(n ast.Node) bool { 80 if n == nil { 81 return false 82 } 83 if result != nil { 84 return false 85 } 86 switch nt := n.(type) { 87 case *ast.BinaryExpr: 88 if nt.Op == token.OR { 89 result = &RuleResult{ 90 File: filename, 91 Line: fset.Position(nt.Pos()).Line, 92 Message: "Union present in interface", 93 } 94 return false 95 } 96 case *ast.UnaryExpr: 97 if nt.Op == token.TILDE { 98 result = &RuleResult{ 99 File: filename, 100 Line: fset.Position(nt.Pos()).Line, 101 Message: "Underlying type operator present in interface", 102 } 103 return false 104 } 105 } 106 return true 107 }) 108 } 109 } 110 return false 111 } 112 return true 113 }) 114 if result != nil { 115 return *result 116 } 117 return RuleResult{OK: true} 118 } 119 120 // Strings implements fmt.Stringer. 121 func (ngd NoGenericDecls) String() string { 122 return "generic declarations" 123 }