mirror of
				https://github.com/mgechev/revive.git
				synced 2025-10-30 23:37:49 +02:00 
			
		
		
		
	Add unchecked-type-assertion (#889)
Co-authored-by: Dirk Faust <d.faust@mittwald.de>
This commit is contained in:
		| @@ -464,6 +464,7 @@ List of all available rules. The rules ported from `golint` are left unchanged a | |||||||
| | [`context-keys-type`](./RULES_DESCRIPTIONS.md#context-key-types)   |  n/a   | Disallows the usage of basic types in `context.WithValue`.       |   yes    |  yes  | | | [`context-keys-type`](./RULES_DESCRIPTIONS.md#context-key-types)   |  n/a   | Disallows the usage of basic types in `context.WithValue`.       |   yes    |  yes  | | ||||||
| | [`time-equal`](./RULES_DESCRIPTIONS.md#time-equal)         |  n/a   | Suggests to use `time.Time.Equal` instead of `==` and `!=` for equality check time.                 |   no    |  yes  | | | [`time-equal`](./RULES_DESCRIPTIONS.md#time-equal)         |  n/a   | Suggests to use `time.Time.Equal` instead of `==` and `!=` for equality check time.                 |   no    |  yes  | | ||||||
| | [`time-naming`](./RULES_DESCRIPTIONS.md#time-naming)         |  n/a   | Conventions around the naming of time variables.                 |   yes    |  yes  | | | [`time-naming`](./RULES_DESCRIPTIONS.md#time-naming)         |  n/a   | Conventions around the naming of time variables.                 |   yes    |  yes  | | ||||||
|  | | [`unchecked-type-assertions`](./RULES_DESCRIPTIONS.md#unchecked-type-assertions)         |  n/a   | Disallows type assertions without checking the result.                 |   no    |  yes  | | ||||||
| | [`var-declaration`](./RULES_DESCRIPTIONS.md#var-declaration)     |  n/a   | Reduces redundancies around variable declaration.                |   yes    |  yes  | | | [`var-declaration`](./RULES_DESCRIPTIONS.md#var-declaration)     |  n/a   | Reduces redundancies around variable declaration.                |   yes    |  yes  | | ||||||
| | [`unexported-return`](./RULES_DESCRIPTIONS.md#unexported-return)   |  n/a   | Warns when a public return is from unexported type.              |   yes    |  yes  | | | [`unexported-return`](./RULES_DESCRIPTIONS.md#unexported-return)   |  n/a   | Warns when a public return is from unexported type.              |   yes    |  yes  | | ||||||
| | [`errorf`](./RULES_DESCRIPTIONS.md#errorf)              |  n/a   | Should replace `errors.New(fmt.Sprintf())` with `fmt.Errorf()`   |   yes    |  yes  | | | [`errorf`](./RULES_DESCRIPTIONS.md#errorf)              |  n/a   | Should replace `errors.New(fmt.Sprintf())` with `fmt.Errorf()`   |   yes    |  yes  | | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ List of all available rules. | |||||||
|   - [string-format](#string-format) |   - [string-format](#string-format) | ||||||
|   - [superfluous-else](#superfluous-else) |   - [superfluous-else](#superfluous-else) | ||||||
|   - [time-equal](#time-equal) |   - [time-equal](#time-equal) | ||||||
|  |   - [unchecked-type-assertion](#unchecked-type-assertion) | ||||||
|   - [time-naming](#time-naming) |   - [time-naming](#time-naming) | ||||||
|   - [var-naming](#var-naming) |   - [var-naming](#var-naming) | ||||||
|   - [var-declaration](#var-declaration) |   - [var-declaration](#var-declaration) | ||||||
| @@ -170,8 +171,8 @@ Example: | |||||||
| [rule.cognitive-complexity] | [rule.cognitive-complexity] | ||||||
|   arguments =[7] |   arguments =[7] | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ## comment-spacings | ## comment-spacings | ||||||
|  |  | ||||||
| _Description_: Spots comments of the form: | _Description_: Spots comments of the form: | ||||||
| ```go | ```go | ||||||
| //This is a malformed comment: no space between // and the start of the sentence | //This is a malformed comment: no space between // and the start of the sentence | ||||||
| @@ -683,6 +684,26 @@ _Description_: Using unit-specific suffix like "Secs", "Mins", ... when naming v | |||||||
|  |  | ||||||
| _Configuration_: N/A | _Configuration_: N/A | ||||||
|  |  | ||||||
|  | ## unchecked-type-assertion | ||||||
|  |  | ||||||
|  | _Description_: This rule checks whether a type assertion result is checked (the `ok` value), preventing unexpected `panic`s. | ||||||
|  |  | ||||||
|  | _Configuration_: list of key-value-pair-map (`[]map[string]any`). | ||||||
|  |  | ||||||
|  | - `acceptIgnoredAssertionResult` : (bool) default `false`, set it to `true` to accept ignored type assertion results like this: | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | foo, _ := bar(.*Baz). | ||||||
|  | //   ^ | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Example: | ||||||
|  |  | ||||||
|  | ```yaml | ||||||
|  | [rule.unchecked-type-assertion] | ||||||
|  | arguments = [{acceptIgnoredAssertionResult=true}] | ||||||
|  | ``` | ||||||
|  |  | ||||||
| ## var-naming | ## var-naming | ||||||
|  |  | ||||||
| _Description_: This rule warns when [initialism](https://github.com/golang/go/wiki/CodeReviewComments#initialisms), [variable](https://github.com/golang/go/wiki/CodeReviewComments#variable-names) or [package](https://github.com/golang/go/wiki/CodeReviewComments#package-names) naming conventions are not followed. | _Description_: This rule warns when [initialism](https://github.com/golang/go/wiki/CodeReviewComments#initialisms), [variable](https://github.com/golang/go/wiki/CodeReviewComments#variable-names) or [package](https://github.com/golang/go/wiki/CodeReviewComments#package-names) naming conventions are not followed. | ||||||
|   | |||||||
| @@ -80,6 +80,7 @@ var allRules = append([]lint.Rule{ | |||||||
| 	&rule.FunctionLength{}, | 	&rule.FunctionLength{}, | ||||||
| 	&rule.NestedStructs{}, | 	&rule.NestedStructs{}, | ||||||
| 	&rule.UselessBreak{}, | 	&rule.UselessBreak{}, | ||||||
|  | 	&rule.UncheckedTypeAssertionRule{}, | ||||||
| 	&rule.TimeEqualRule{}, | 	&rule.TimeEqualRule{}, | ||||||
| 	&rule.BannedCharsRule{}, | 	&rule.BannedCharsRule{}, | ||||||
| 	&rule.OptimizeOperandsOrderRule{}, | 	&rule.OptimizeOperandsOrderRule{}, | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							| @@ -1,7 +1,5 @@ | |||||||
| github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= | github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= | ||||||
| github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= | github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= | ||||||
| github.com/chavacava/garif v0.0.0-20230608123814-4bd63c2919ab h1:5JxePczlyGAtj6R1MUEFZ/UFud6FfsOejq7xLC2ZIb0= |  | ||||||
| github.com/chavacava/garif v0.0.0-20230608123814-4bd63c2919ab/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww= |  | ||||||
| github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc= | github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc= | ||||||
| github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww= | github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww= | ||||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
|   | |||||||
							
								
								
									
										196
									
								
								rule/unchecked-type-assertion.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								rule/unchecked-type-assertion.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,196 @@ | |||||||
|  | package rule | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"go/ast" | ||||||
|  | 	"sync" | ||||||
|  |  | ||||||
|  | 	"github.com/mgechev/revive/lint" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	ruleUTAMessagePanic   = "type assertion will panic if not matched" | ||||||
|  | 	ruleUTAMessageIgnored = "type assertion result ignored" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // UncheckedTypeAssertionRule lints missing or ignored `ok`-value in danymic type casts. | ||||||
|  | type UncheckedTypeAssertionRule struct { | ||||||
|  | 	sync.Mutex | ||||||
|  | 	acceptIgnoredAssertionResult bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (u *UncheckedTypeAssertionRule) configure(arguments lint.Arguments) { | ||||||
|  | 	u.Lock() | ||||||
|  | 	defer u.Unlock() | ||||||
|  |  | ||||||
|  | 	if len(arguments) == 0 { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	args, ok := arguments[0].(map[string]any) | ||||||
|  | 	if !ok { | ||||||
|  | 		panic("Unable to get arguments. Expected object of key-value-pairs.") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for k, v := range args { | ||||||
|  | 		switch k { | ||||||
|  | 		case "acceptIgnoredAssertionResult": | ||||||
|  | 			u.acceptIgnoredAssertionResult, ok = v.(bool) | ||||||
|  | 			if !ok { | ||||||
|  | 				panic(fmt.Sprintf("Unable to parse argument '%s'. Expected boolean.", k)) | ||||||
|  | 			} | ||||||
|  | 		default: | ||||||
|  | 			panic(fmt.Sprintf("Unknown argument: %s", k)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Apply applies the rule to given file. | ||||||
|  | func (u *UncheckedTypeAssertionRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure { | ||||||
|  | 	u.configure(args) | ||||||
|  |  | ||||||
|  | 	var failures []lint.Failure | ||||||
|  |  | ||||||
|  | 	walker := &lintUnchekedTypeAssertion{ | ||||||
|  | 		pkg: file.Pkg, | ||||||
|  | 		onFailure: func(failure lint.Failure) { | ||||||
|  | 			failures = append(failures, failure) | ||||||
|  | 		}, | ||||||
|  | 		acceptIgnoredTypeAssertionResult: u.acceptIgnoredAssertionResult, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	file.Pkg.TypeCheck() | ||||||
|  | 	ast.Walk(walker, file.AST) | ||||||
|  |  | ||||||
|  | 	return failures | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Name returns the rule name. | ||||||
|  | func (*UncheckedTypeAssertionRule) Name() string { | ||||||
|  | 	return "unchecked-type-assertion" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type lintUnchekedTypeAssertion struct { | ||||||
|  | 	pkg                              *lint.Package | ||||||
|  | 	onFailure                        func(lint.Failure) | ||||||
|  | 	acceptIgnoredTypeAssertionResult bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func isIgnored(e ast.Expr) bool { | ||||||
|  | 	ident, ok := e.(*ast.Ident) | ||||||
|  | 	if !ok { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ident.Name == "_" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func isTypeSwitch(e *ast.TypeAssertExpr) bool { | ||||||
|  | 	return e.Type == nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *lintUnchekedTypeAssertion) requireNoTypeAssert(expr ast.Expr) { | ||||||
|  | 	e, ok := expr.(*ast.TypeAssertExpr) | ||||||
|  | 	if ok && !isTypeSwitch(e) { | ||||||
|  | 		w.addFailure(e, ruleUTAMessagePanic) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *lintUnchekedTypeAssertion) handleIfStmt(n *ast.IfStmt) { | ||||||
|  | 	ifCondition, ok := n.Cond.(*ast.BinaryExpr) | ||||||
|  | 	if !ok { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	w.requireNoTypeAssert(ifCondition.X) | ||||||
|  | 	w.requireNoTypeAssert(ifCondition.Y) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *lintUnchekedTypeAssertion) requireBinaryExpressionWithoutTypeAssertion(expr ast.Expr) { | ||||||
|  | 	binaryExpr, ok := expr.(*ast.BinaryExpr) | ||||||
|  | 	if ok { | ||||||
|  | 		w.requireNoTypeAssert(binaryExpr.X) | ||||||
|  | 		w.requireNoTypeAssert(binaryExpr.Y) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *lintUnchekedTypeAssertion) handleCaseClause(n *ast.CaseClause) { | ||||||
|  | 	for _, expr := range n.List { | ||||||
|  | 		w.requireNoTypeAssert(expr) | ||||||
|  | 		w.requireBinaryExpressionWithoutTypeAssertion(expr) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *lintUnchekedTypeAssertion) handleSwitch(n *ast.SwitchStmt) { | ||||||
|  | 	w.requireNoTypeAssert(n.Tag) | ||||||
|  | 	w.requireBinaryExpressionWithoutTypeAssertion(n.Tag) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *lintUnchekedTypeAssertion) handleAssignment(n *ast.AssignStmt) { | ||||||
|  | 	if len(n.Rhs) == 0 { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	e, ok := n.Rhs[0].(*ast.TypeAssertExpr) | ||||||
|  | 	if !ok || e == nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if isTypeSwitch(e) { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if len(n.Lhs) == 1 { | ||||||
|  | 		w.addFailure(e, ruleUTAMessagePanic) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !w.acceptIgnoredTypeAssertionResult && len(n.Lhs) == 2 && isIgnored(n.Lhs[1]) { | ||||||
|  | 		w.addFailure(e, ruleUTAMessageIgnored) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // handles "return foo(.*bar)" - one of them is enough to fail as golang does not forward the type cast tuples in return statements | ||||||
|  | func (w *lintUnchekedTypeAssertion) handleReturn(n *ast.ReturnStmt) { | ||||||
|  | 	for _, r := range n.Results { | ||||||
|  | 		w.requireNoTypeAssert(r) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *lintUnchekedTypeAssertion) handleRange(n *ast.RangeStmt) { | ||||||
|  | 	w.requireNoTypeAssert(n.X) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *lintUnchekedTypeAssertion) handleChannelSend(n *ast.SendStmt) { | ||||||
|  | 	w.requireNoTypeAssert(n.Value) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *lintUnchekedTypeAssertion) Visit(node ast.Node) ast.Visitor { | ||||||
|  | 	switch n := node.(type) { | ||||||
|  | 	case *ast.RangeStmt: | ||||||
|  | 		w.handleRange(n) | ||||||
|  | 	case *ast.SwitchStmt: | ||||||
|  | 		w.handleSwitch(n) | ||||||
|  | 	case *ast.ReturnStmt: | ||||||
|  | 		w.handleReturn(n) | ||||||
|  | 	case *ast.AssignStmt: | ||||||
|  | 		w.handleAssignment(n) | ||||||
|  | 	case *ast.IfStmt: | ||||||
|  | 		w.handleIfStmt(n) | ||||||
|  | 	case *ast.CaseClause: | ||||||
|  | 		w.handleCaseClause(n) | ||||||
|  | 	case *ast.SendStmt: | ||||||
|  | 		w.handleChannelSend(n) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return w | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *lintUnchekedTypeAssertion) addFailure(n *ast.TypeAssertExpr, why string) { | ||||||
|  | 	s := fmt.Sprintf("type cast result is unchecked in %v - %s", gofmt(n), why) | ||||||
|  | 	w.onFailure(lint.Failure{ | ||||||
|  | 		Category:   "bad practice", | ||||||
|  | 		Confidence: 1, | ||||||
|  | 		Node:       n, | ||||||
|  | 		Failure:    s, | ||||||
|  | 	}) | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								test/unchecked_type_assertion_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								test/unchecked_type_assertion_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | package test | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  |  | ||||||
|  | 	"github.com/mgechev/revive/lint" | ||||||
|  | 	"github.com/mgechev/revive/rule" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestUncheckedDynamicCast(t *testing.T) { | ||||||
|  | 	testRule(t, "unchecked-type-assertion", &rule.UncheckedTypeAssertionRule{}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestUncheckedDynamicCastWithAcceptIgnored(t *testing.T) { | ||||||
|  | 	args := []any{map[string]any{ | ||||||
|  | 		"acceptIgnoredAssertionResult": true, | ||||||
|  | 	}} | ||||||
|  |  | ||||||
|  | 	testRule(t, "unchecked-type-assertion-accept-ignored", &rule.UncheckedTypeAssertionRule{}, &lint.RuleConfig{Arguments: args}) | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								testdata/unchecked-type-assertion-accept-ignored.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								testdata/unchecked-type-assertion-accept-ignored.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | package fixtures | ||||||
|  |  | ||||||
|  | var foo any = "foo" | ||||||
|  |  | ||||||
|  | func handleIgnoredIsOKByConfig() { | ||||||
|  | 	// No lint here bacuse `acceptIgnoredAssertionResult` is set to `true` | ||||||
|  | 	r, _ := foo.(int) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleSkippedStillFails() { | ||||||
|  | 	r := foo.(int) // MATCH /type cast result is unchecked in foo.(int) - type assertion will panic if not matched/ | ||||||
|  | } | ||||||
							
								
								
									
										108
									
								
								testdata/unchecked-type-assertion.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								testdata/unchecked-type-assertion.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | |||||||
|  | package fixtures | ||||||
|  |  | ||||||
|  | import "fmt" | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	foo  any = "foo" | ||||||
|  | 	bars     = []any{1, 42, "some", "thing"} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func handleIgnored() { | ||||||
|  | 	r, _ := foo.(int) // MATCH /type cast result is unchecked in foo.(int) - type assertion result ignored/ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleSkipped() { | ||||||
|  | 	r := foo.(int) // MATCH /type cast result is unchecked in foo.(int) - type assertion will panic if not matched/ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleReturn() int { | ||||||
|  | 	return foo.(int) // MATCH /type cast result is unchecked in foo.(int) - type assertion will panic if not matched/ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleSwitch() { | ||||||
|  | 	switch foo.(int) { // MATCH /type cast result is unchecked in foo.(int) - type assertion will panic if not matched/ | ||||||
|  | 	case 0: | ||||||
|  | 	case 1: | ||||||
|  | 		// | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleRange() { | ||||||
|  | 	var some any = bars | ||||||
|  | 	for _, x := range some.([]string) { // MATCH /type cast result is unchecked in some.([]string) - type assertion will panic if not matched/ | ||||||
|  | 		fmt.Println(x) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleTypeSwitch() { | ||||||
|  | 	// Should not be a lint | ||||||
|  | 	switch foo.(type) { | ||||||
|  | 	case string: | ||||||
|  | 	case int: | ||||||
|  | 		// | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleTypeSwitchWithAssignment() { | ||||||
|  | 	// Should not be a lint | ||||||
|  | 	switch n := foo.(type) { | ||||||
|  | 	case string: | ||||||
|  | 	case int: | ||||||
|  | 		// | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleTypeComparison() { | ||||||
|  | 	if foo.(int) == 1 { // MATCH /type cast result is unchecked in foo.(int) - type assertion will panic if not matched/ | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleTypeComparisonReverse() { | ||||||
|  | 	if 1 == foo.(int) { // MATCH /type cast result is unchecked in foo.(int) - type assertion will panic if not matched/ | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleTypeAssignmentComparison() { | ||||||
|  | 	var value any | ||||||
|  | 	value = 42 // int | ||||||
|  |  | ||||||
|  | 	if v := value.(int); v == 42 { // MATCH /type cast result is unchecked in value.(int) - type assertion will panic if not matched/ | ||||||
|  | 		fmt.Printf("Value is an integer: %d\n", v) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleSwitchComparison() { | ||||||
|  | 	switch foo.(int) == 1 { // MATCH /type cast result is unchecked in foo.(int) - type assertion will panic if not matched/ | ||||||
|  | 	case true: | ||||||
|  | 	case false: | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleSwitchComparisonReverse() { | ||||||
|  | 	switch 1 == foo.(int) { // MATCH /type cast result is unchecked in foo.(int) - type assertion will panic if not matched/ | ||||||
|  | 	case true: | ||||||
|  | 	case false: | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleInnerSwitchAssertion() { | ||||||
|  | 	switch { | ||||||
|  | 	case foo.(int) == 1: // MATCH /type cast result is unchecked in foo.(int) - type assertion will panic if not matched/ | ||||||
|  | 	case bar.(int) == 1: // MATCH /type cast result is unchecked in bar.(int) - type assertion will panic if not matched/ | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleInnerSwitchAssertionReverse() { | ||||||
|  | 	switch { | ||||||
|  | 	case 1 == foo.(int): // MATCH /type cast result is unchecked in foo.(int) - type assertion will panic if not matched/ | ||||||
|  | 	case 1 == bar.(int): // MATCH /type cast result is unchecked in bar.(int) - type assertion will panic if not matched/ | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleChannelWrite() { | ||||||
|  | 	c := make(chan any) | ||||||
|  | 	var a any = "foo" | ||||||
|  | 	c <- a.(int) // MATCH /type cast result is unchecked in a.(int) - type assertion will panic if not matched/ | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user