Repository: mgechev/revive

Issue:
rule to detect unnecessary conditionals
Patterns like 

```go
if cond {
  return true
} else {
  return false
}
```

and 

```go
if cond {
  id = true
} else {
  id = false
}
```

can be replaced by

```go
return cond
```

and 

```go
id = cond
```

respectively.

**This issue is a proposal to create a rule that detects these patterns and propose a simplification.**

A draft version of the rule detects things like:

`github.com/Azure/go-ntlmssp/negotiator.go:23:9: replace this conditional by: domainNeeded = !(strings.Contains(user, "@"))`
```go
if strings.Contains(user, "@") {
	domainNeeded = false
} else {
	domainNeeded = true
}
```

`k8s.io/component-base/cli/flag/tristate.go:70:2: replace this conditional by: return t == True`
```go
if t == True {
	return true
} else {
	return false
}
```

`github.com/open-policy-agent/opa/internal/cidr/merge/merge.go:145:3: replace this conditional by: overflow = ip[i] == 0 && previousIP[i] == 255`

```go
if ip[i] == 0 && previousIP[i] == 255 {
	overflow = true
} else {
	overflow = false
}
```

Somme other outputs from the draft of the rule:

```
gitea/routers/api/v1/repo/pull.go:351:2: replace this conditional by: patch = !(ctx.PathParam("diffType") == "diff")
github.com/Azure/go-amqp/internal/encoding/types.go:1663:4: replace this conditional by: aa[i] = !(value == 0)
github.com/Azure/go-ntlmssp/negotiator.go:23:9: replace this conditional by: domainNeeded = !(strings.Contains(user, "@"))
github.com/arangodb/go-driver/context.go:349:3: replace this conditional by: *cs.DirtyReadFlag = dirtyRead != ""
github.com/go-playground/validator/v10/baked_in.go:2680:5: replace this conditional by: return strings.HasSuffix(field.String(), string(os.PathSeparator))
github.com/google/pprof/profile/proto.go:361:2: replace this conditional by: *x = !(int64(b.u64) == 0)
github.com/jcmturner/gokrb5/v8/credentials/ccache.go:169:2: replace this conditional by: cred.IsSKey = !(ik == 0)
github.com/jcmturner/gokrb5/v8/credentials/ccache.go:326:9: replace this conditional by: endian = (0x78 & 0xff) == (bp[0] & 0xff)
github.com/jcmturner/gokrb5/v8/keytab/keytab.go:514:9: replace this conditional by: endian = (0x78 & 0xff) == (bp[0] & 0xff)
github.com/jmespath/go-jmespath/util.go:92:2: replace this conditional by: stepValueNegative = step < 0
github.com/oliveagle/jsonpath/jsonpath.go:686:3: replace this conditional by: return err == nil
github.com/open-policy-agent/opa/internal/cidr/merge/merge.go:145:3: replace this conditional by: overflow = ip[i] == 0 && previousIP[i] == 255
k8s.io/component-base/cli/flag/tristate.go:70:2: replace this conditional by: return t == True
kubernetes/staging/src/k8s.io/kubectl/pkg/cmd/get/get.go:681:2: replace this conditional by: *outputObjects = isList
kubernetes/test/e2e/storage/drivers/csi-test/mock/service/controller.go:206:3: replace this conditional by: volRo = roVal == "true"
kubesphere/pkg/models/registries/registries.go:127:3: replace this conditional by: return !(strings.HasPrefix(serverAddress, "http://"))
```

(is a draft thus there is still some work to get simpler replacement propositions)




Discussion:

Solution patch:
diff --git a/README.md b/README.md
index 3e4b9bd..9f18dfb 100644
--- a/README.md
+++ b/README.md
@@ -591,6 +591,7 @@ List of all available rules. The rules ported from `golint` are left unchanged a
 | [`unexported-naming`](./RULES_DESCRIPTIONS.md#unexported-naming)          |  n/a   |  Warns on wrongly named un-exported symbols       |    no    |  no   |
 | [`unexported-return`](./RULES_DESCRIPTIONS.md#unexported-return)   |  n/a   | Warns when a public return is from unexported type.              |   yes    |  yes  |
 | [`unhandled-error`](./RULES_DESCRIPTIONS.md#unhandled-error)   | []string   | Warns on unhandled errors returned by function calls    |    no    |  yes   |
+| [`unnecessary-if`](./RULES_DESCRIPTIONS.md#unnecessary-if)    |  n/a   | Identifies `if-else` statements that can be replaced by simpler statements  |    no    |  no   |
 | [`unnecessary-format`](./RULES_DESCRIPTIONS.md#unnecessary-format)    |  n/a   | Identifies calls to formatting functions where the format string does not contain any formatting verbs          |    no    |  no   |
 | [`unnecessary-stmt`](./RULES_DESCRIPTIONS.md#unnecessary-stmt)    |  n/a   | Suggests removing or simplifying unnecessary statements          |    no    |  no   |
 | [`unreachable-code`](./RULES_DESCRIPTIONS.md#unreachable-code)    |  n/a   | Warns on unreachable code                                        |    no    |  no   |
diff --git a/RULES_DESCRIPTIONS.md b/RULES_DESCRIPTIONS.md
index bf39efb..817ae71 100644
--- a/RULES_DESCRIPTIONS.md
+++ b/RULES_DESCRIPTIONS.md
@@ -87,6 +87,7 @@ List of all available rules.
 - [unexported-naming](#unexported-naming)
 - [unexported-return](#unexported-return)
 - [unhandled-error](#unhandled-error)
+- [unnecessary-if](#unnecessary-if)
 - [unnecessary-format](#unnecessary-format)
 - [unnecessary-stmt](#unnecessary-stmt)
 - [unreachable-code](#unreachable-code)
@@ -1293,6 +1294,7 @@ The list of [supported tags](https://go.dev/wiki/Well-known-struct-tags):
 | ------------- | ------------------------------------------------------------------------ |
 | `asn1`         | <https://pkg.go.dev/encoding/asn1>                                      |
 | `bson`         | <https://pkg.go.dev/go.mongodb.org/mongo-driver/bson>                   |
+| `cbor`         | <https://pkg.go.dev/github.com/fxamacker/cbor/v2>                   |
 | `datastore`    | <https://pkg.go.dev/cloud.google.com/go/datastore>                      |
 | `default`      | The type of "default" must match the type of the field.                 |
 | `json`         | <https://pkg.go.dev/encoding/json>                                      |
@@ -1499,6 +1501,39 @@ arguments = [
 ]
 ```
 
+## unnecessary-if
+
+_Description_: Detects unnecessary `if-else` statements that return or assign a boolean value
+based on a condition and suggests a simplified, direct return or assignment.
+The `if-else` block is redundant because the condition itself is already a boolean expression.
+The simplified version is immediately clearer, more idiomatic, and reduces cognitive load for the reader.
+
+### Examples (unnecessary-if)
+
+```go
+if y <= 0 {
+  z = true
+} else {
+  z = false
+}
+
+if x > 10 {
+  return false
+} else {
+  return true
+}
+```
+
+Fixed code:
+
+```go
+z = y <= 0
+
+return x <= 10
+```
+
+_Configuration_: N/A
+
 ## unnecessary-format
 
 _Description_: This rule identifies calls to formatting functions where the format string does not contain any formatting verbs
diff --git a/config/config.go b/config/config.go
index d163308..ba97832 100644
--- a/config/config.go
+++ b/config/config.go
@@ -115,6 +115,7 @@ var allRules = append([]lint.Rule{
 	&rule.UnsecureURLSchemeRule{},
 	&rule.InefficientMapLookupRule{},
 	&rule.ForbiddenCallInWgGoRule{},
+	&rule.UnnecessaryIfRule{},
 }, defaultRules...)
 
 // allFormatters is a list of all available formatters to output the linting results.
diff --git a/rule/struct_tag.go b/rule/struct_tag.go
index 74528c5..02110bf 100644
--- a/rule/struct_tag.go
+++ b/rule/struct_tag.go
@@ -24,6 +24,7 @@ type tagKey string
 const (
 	keyASN1         tagKey = "asn1"
 	keyBSON         tagKey = "bson"
+	keyCbor         tagKey = "cbor"
 	keyCodec        tagKey = "codec"
 	keyDatastore    tagKey = "datastore"
 	keyDefault      tagKey = "default"
@@ -45,6 +46,7 @@ type tagChecker func(checkCtx *checkContext, tag *structtag.Tag, field *ast.Fiel
 var tagCheckers = map[tagKey]tagChecker{
 	keyASN1:         checkASN1Tag,
 	keyBSON:         checkBSONTag,
+	keyCbor:         checkCborTag,
 	keyCodec:        checkCodecTag,
 	keyDatastore:    checkDatastoreTag,
 	keyDefault:      checkDefaultTag,
@@ -385,6 +387,66 @@ func checkBSONTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (mes
 	return "", true
 }
 
+func checkCborTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (message string, succeeded bool) {
+	hasToArray := false
+	hasOmitEmptyOrZero := false
+	hasKeyAsInt := false
+
+	for _, opt := range tag.Options {
+		switch opt {
+		case "omitempty", "omitzero":
+			hasOmitEmptyOrZero = true
+		case "toarray":
+			if tag.Name != "" {
+				return `tag name for option "toarray" should be empty`, false
+			}
+			hasToArray = true
+		case "keyasint":
+			intKey, err := strconv.Atoi(tag.Name)
+			if err != nil {
+				return `tag name for option "keyasint" should be an integer`, false
+			}
+
+			_, ok := checkCtx.usedTagNbr[intKey]
+			if ok {
+				return fmt.Sprintf("duplicated integer key %d", intKey), false
+			}
+
+			checkCtx.usedTagNbr[intKey] = true
+			hasKeyAsInt = true
+			continue
+
+		default:
+			if !checkCtx.isUserDefined(keyCbor, opt) {
+				return fmt.Sprintf(msgUnknownOption, opt), false
+			}
+		}
+	}
+
+	// Check for duplicated tag names
+	if tag.Name != "" {
+		_, ok := checkCtx.usedTagName[tag.Name]
+		if ok {
+			return fmt.Sprintf("duplicated tag name %s", tag.Name), false
+		}
+		checkCtx.usedTagName[tag.Name] = true
+	}
+
+	// Check for integer tag names without keyasint option
+	if !hasKeyAsInt {
+		_, err := strconv.Atoi(tag.Name)
+		if err == nil {
+			return `integer tag names are only allowed in presence of "keyasint" option`, false
+		}
+	}
+
+	if hasToArray && hasOmitEmptyOrZero {
+		return `options "omitempty" and "omitzero" are ignored in presence of "toarray" option`, false
+	}
+
+	return "", true
+}
+
 const structTagCodecSpecialField = "_struct"
 
 func checkCodecTag(checkCtx *checkContext, tag *structtag.Tag, field *ast.Field) (message string, succeeded bool) {
@@ -843,6 +905,7 @@ var validateSingleOptions = map[string]struct{}{
 	"multibyte":                     {},
 	"number":                        {},
 	"numeric":                       {},
+	"omitempty":                     {},
 	"port":                          {},
 	"postcode_iso3166_alpha2":       {},
 	"postcode_iso3166_alpha2_field": {},
diff --git a/rule/unnecessary_if.go b/rule/unnecessary_if.go
new file mode 100644
index 0000000..f2f8174
--- /dev/null
+++ b/rule/unnecessary_if.go
@@ -0,0 +1,202 @@
+package rule
+
+import (
+	"fmt"
+	"go/ast"
+	"go/token"
+
+	"github.com/mgechev/revive/internal/astutils"
+	"github.com/mgechev/revive/lint"
+)
+
+// UnnecessaryIfRule warns on if...else statements that can be replaced by simpler expressions.
+type UnnecessaryIfRule struct{}
+
+// Apply applies the rule to given file.
+func (*UnnecessaryIfRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+	var failures []lint.Failure
+
+	onFailure := func(failure lint.Failure) {
+		failures = append(failures, failure)
+	}
+
+	w := &lintUnnecessaryIf{onFailure: onFailure}
+	for _, decl := range file.AST.Decls {
+		fn, ok := decl.(*ast.FuncDecl)
+		if !ok || fn.Body == nil {
+			continue
+		}
+
+		ast.Walk(w, fn.Body)
+	}
+
+	return failures
+}
+
+// Name returns the rule name.
+func (*UnnecessaryIfRule) Name() string {
+	return "unnecessary-if"
+}
+
+type lintUnnecessaryIf struct {
+	onFailure func(lint.Failure)
+}
+
+// Visit walks the AST looking for if statements of the form:
+//
+// if cond { return <bool literal> } else { return <bool literal> }
+//
+// or
+//
+// if cond { <idX> = <bool literal> } else { <idX> = <bool literal> }.
+func (w *lintUnnecessaryIf) Visit(node ast.Node) ast.Visitor {
+	ifStmt, ok := node.(*ast.IfStmt)
+	if !ok {
+		return w // not an if statement
+	}
+
+	//          if without else    or if with initialization
+	mustSkip := ifStmt.Else == nil || ifStmt.Init != nil
+	if mustSkip {
+		return w
+	}
+
+	elseBranch, ok := ifStmt.Else.(*ast.BlockStmt)
+	if !ok { // if-else-if construction
+		return w // the rule only copes with single if...else statements
+	}
+
+	thenStmts := ifStmt.Body.List
+	elseStmts := elseBranch.List
+	if len(thenStmts) != 1 || len(elseStmts) != 1 {
+		return w // then and else branches do not have just one statement
+	}
+
+	replacement := ""
+	thenBool := false
+	switch thenStmt := thenStmts[0].(type) {
+	case *ast.ReturnStmt:
+		replacement, thenBool = w.replacementForReturnStmt(thenStmt, elseStmts)
+	case *ast.AssignStmt:
+		replacement, thenBool = w.replacementForAssignmentStmt(thenStmt, elseStmts)
+	default:
+		return w // the then branch is neither a return nor an assignment
+	}
+
+	if replacement == "" {
+		return w // no replacement found
+	}
+
+	cond := w.condAsString(ifStmt.Cond, !thenBool)
+	msg := "replace this conditional by: " + replacement + " " + cond
+
+	w.onFailure(lint.Failure{
+		Confidence: 1.0,
+		Node:       ifStmt,
+		Category:   lint.FailureCategoryLogic,
+		Failure:    msg,
+	})
+
+	return nil
+}
+
+var relationalOppositeOf = map[token.Token]token.Token{
+	token.EQL: token.NEQ, // == !=
+	token.GEQ: token.LSS, // >= <
+	token.GTR: token.LEQ, // > <=
+	token.LEQ: token.GTR, // <= >
+	token.LSS: token.GEQ, // < >=
+	token.NEQ: token.EQL, // != ==
+}
+
+// condAsString yields the string representation of the given condition expression.
+// The method will try to minimize the negations in the resulting expression.
+func (*lintUnnecessaryIf) condAsString(cond ast.Expr, mustNegate bool) string {
+	result := astutils.GoFmt(cond)
+
+	if mustNegate {
+		result = "!(" + result + ")" // naive negation
+
+		// check if we can build a simpler expression
+		if binExp, ok := cond.(*ast.BinaryExpr); ok {
+			originalOp := binExp.Op
+			opposite, ok := relationalOppositeOf[originalOp]
+			if ok {
+				binExp.Op = opposite
+				result = astutils.GoFmt(binExp) // replace initial result by a simpler one
+				binExp.Op = originalOp
+			}
+		}
+	}
+
+	return result
+}
+
+// replacementForAssignmentStmt returns a replacement statement != ""
+// iff both then and else statements are of the form <idX> = <bool literal>
+// If the replacement != "" then the second return value is the Boolean value
+// of <bool literal> in the then-side assignment, false otherwise.
+func (w *lintUnnecessaryIf) replacementForAssignmentStmt(thenStmt *ast.AssignStmt, elseStmts []ast.Stmt) (replacement string, thenBool bool) {
+	thenBoolStr, ok := w.isSingleBooleanLiteral(thenStmt.Rhs)
+	if !ok {
+		return "", false
+	}
+
+	thenLHS := astutils.GoFmt(thenStmt.Lhs[0])
+
+	elseStmt, ok := elseStmts[0].(*ast.AssignStmt)
+	if !ok {
+		return "", false
+	}
+
+	elseLHS := astutils.GoFmt(elseStmt.Lhs[0])
+	if thenLHS != elseLHS {
+		return "", false
+	}
+
+	_, ok = w.isSingleBooleanLiteral(elseStmt.Rhs)
+	if !ok {
+		return "", false
+	}
+
+	return fmt.Sprintf("%s %s", thenLHS, thenStmt.Tok.String()), thenBoolStr == "true"
+}
+
+// replacementForReturnStmt returns a replacement statement != ""
+// iff both then and else statements are of the form return <bool literal>
+// If the replacement != "" then the second return value is the string representation
+// of <bool literal> in the then-side assignment, "" otherwise.
+func (w *lintUnnecessaryIf) replacementForReturnStmt(thenStmt *ast.ReturnStmt, elseStmts []ast.Stmt) (replacement string, thenBool bool) {
+	thenBoolStr, ok := w.isSingleBooleanLiteral(thenStmt.Results)
+	if !ok {
+		return "", false
+	}
+
+	elseStmt, ok := elseStmts[0].(*ast.ReturnStmt)
+	if !ok {
+		return "", false
+	}
+
+	_, ok = w.isSingleBooleanLiteral(elseStmt.Results)
+	if !ok {
+		return "", false
+	}
+
+	return "return", thenBoolStr == "true"
+}
+
+// isSingleBooleanLiteral returns the string representation of <bool literal> and true
+// if the given list of expressions has exactly one element and that element is a bool literal (true or false),
+// otherwise it returns "" and false.
+func (*lintUnnecessaryIf) isSingleBooleanLiteral(exprs []ast.Expr) (string, bool) {
+	if len(exprs) != 1 {
+		return "", false
+	}
+
+	ident, ok := exprs[0].(*ast.Ident)
+	if !ok {
+		return "", false
+	}
+
+	return ident.Name, (ident.Name == "true" || ident.Name == "false")
+}



Test patch:
diff --git a/test/struct_tag_test.go b/test/struct_tag_test.go
index dce3c61..5f521de 100644
--- a/test/struct_tag_test.go
+++ b/test/struct_tag_test.go
@@ -23,6 +23,7 @@ func TestStructTagWithUserOptions(t *testing.T) {
 			"toml,unknown",
 			"spanner,mySpannerOption",
 			"codec,myCodecOption",
+			"cbor,myCborOption",
 		},
 	})
 }
diff --git a/test/unnecessary_if_test.go b/test/unnecessary_if_test.go
new file mode 100644
index 0000000..f6712b0
--- /dev/null
+++ b/test/unnecessary_if_test.go
@@ -0,0 +1,12 @@
+package test
+
+import (
+	"testing"
+
+	"github.com/mgechev/revive/lint"
+	"github.com/mgechev/revive/rule"
+)
+
+func TestUnnecessaryIf(t *testing.T) {
+	testRule(t, "unnecessary_if", &rule.UnnecessaryIfRule{}, &lint.RuleConfig{})
+}
diff --git a/testdata/struct_tag.go b/testdata/struct_tag.go
index 1fc551f..f6b70f8 100644
--- a/testdata/struct_tag.go
+++ b/testdata/struct_tag.go
@@ -156,6 +156,7 @@ type MapStruct struct {
 }
 
 type ValidateUser struct {
+	Id          string `validate:"omitempty,min=3,max=32"`
 	Username    string `validate:"required,min=3,max=32"`
 	Email       string `validate:"required,email"`
 	Password    string `validate:"required,min=8,max=32"`
@@ -214,3 +215,24 @@ type TestDuplicatedCodecTags struct {
 	B       int      `codec:"field_a"` // MATCH /duplicated tag name "field_a" in codec tag/
 	C       int      `codec:"field_c"`
 }
+
+type Cbor struct {
+	RepeatedStr string `cbor:"errors"`
+	Repeated    string `cbor:"1,keyasint"`
+	Useless     string `cbor:"-,omitempty"`              // MATCH /useless option omitempty for ignored field in cbor tag/
+	Inputs      string `cbor:",keyasint"`                // MATCH /tag name for option "keyasint" should be an integer in cbor tag/
+	Outputs     string `cbor:"inputs,keyasint"`          // MATCH /tag name for option "keyasint" should be an integer in cbor tag/
+	Errors      string `cbor:"errors,optempty,keyasint"` // MATCH /unknown option "optempty" in cbor tag/
+	Inputs2     string `cbor:"-10,omitempty"`            // MATCH /integer tag names are only allowed in presence of "keyasint" option in cbor tag/
+	Outputs2    string `cbor:"-12,toarray"`              // MATCH /tag name for option "toarray" should be empty in cbor tag/
+	RepeatedInt string `cbor:"1,keyasint"`               // MATCH /duplicated integer key 1 in cbor tag/
+	RepeatedStr string `cbor:"errors,omitempty"`         // MATCH /duplicated tag name errors in cbor tag/
+	Useless     string `cbor:",toarray,omitempty"`       // MATCH /options "omitempty" and "omitzero" are ignored in presence of "toarray" option in cbor tag/
+	Useless2    string `cbor:",omitzero,toarray"`        // MATCH /options "omitempty" and "omitzero" are ignored in presence of "toarray" option in cbor tag/
+	// OK
+	InputsOk   string `cbor:"8,keyasint"`
+	OutputsOk  string `cbor:"-100,keyasint"`
+	ErrorsOk   string `cbor:"-1,keyasint"`
+	InputsOk2  string `cbor:"inputs,omitempty"`
+	OutputsOk2 string `cbor:",toarray"`
+}
diff --git a/testdata/struct_tag_user_options.go b/testdata/struct_tag_user_options.go
index a60fa3d..6f3f520 100644
--- a/testdata/struct_tag_user_options.go
+++ b/testdata/struct_tag_user_options.go
@@ -102,3 +102,11 @@ type CodecUserOptions struct {
 	ID   int    `codec:"user_id,myCodecOption"`
 	Name string `codec:"full_name,unknownOption"` // MATCH /unknown option "unknownOption" in codec tag/
 }
+
+type CborUserOptions struct {
+	InputsOk   string `cbor:"8,keyasint,myCborOption"`
+	OutputsOk  string `cbor:"-100,keyasint,unknownOption"` // MATCH /unknown option "unknownOption" in cbor tag/
+	ErrorsOk   string `cbor:"-1,keyasint"`
+	InputsOk2  string `cbor:"inputs,omitempty"`
+	OutputsOk2 string `cbor:",toarray"`
+}
diff --git a/testdata/unnecessary_if.go b/testdata/unnecessary_if.go
new file mode 100644
index 0000000..4862449
--- /dev/null
+++ b/testdata/unnecessary_if.go
@@ -0,0 +1,153 @@
+package fixtures
+
+func unnecessaryIf() bool {
+	var cond bool
+	var id bool
+
+	// test return replacements
+	if cond { // MATCH /replace this conditional by: return cond/
+		return true
+	} else {
+		return false
+	}
+
+	if cond { // MATCH /replace this conditional by: return !(cond)/
+		return false
+	} else {
+		return true
+	}
+
+	// test assignment replacements
+	if cond { // MATCH /replace this conditional by: id = cond/
+		id = true
+	} else {
+		id = false
+	}
+
+	if cond { // MATCH /replace this conditional by: id = !(cond)/
+		id = false
+	} else {
+		id = true
+	}
+
+	// test suggestions for (in)equalities
+	//// assignments
+	if cond == id { // MATCH /replace this conditional by: id = cond == id/
+		id = true
+	} else {
+		id = false
+	}
+
+	if cond == id { // MATCH /replace this conditional by: id = cond != id/
+		id = false
+	} else {
+		id = true
+	}
+
+	if cond != id { // MATCH /replace this conditional by: id = cond != id/
+		id = true
+	} else {
+		id = false
+	}
+
+	if cond != id { // MATCH /replace this conditional by: id = cond == id/
+		id = false
+	} else {
+		id = true
+	}
+
+	//// return
+	if cond == id { // MATCH /replace this conditional by: return cond == id/
+		return true
+	} else {
+		return false
+	}
+
+	if cond == id { // MATCH /replace this conditional by: return cond != id/
+		return false
+	} else {
+		return true
+	}
+
+	if cond != id { // MATCH /replace this conditional by: return cond != id/
+		return true
+	} else {
+		return false
+	}
+
+	if cond != id { // MATCH /replace this conditional by: return cond == id/
+		return false
+	} else {
+		return true
+	}
+
+	//// assignments
+	if cond <= id { // MATCH /replace this conditional by: id = cond <= id/
+		id = true
+	} else {
+		id = false
+	}
+
+	if cond <= id { // MATCH /replace this conditional by: id = cond > id/
+		id = false
+	} else {
+		id = true
+	}
+
+	if cond >= id { // MATCH /replace this conditional by: id = cond >= id/
+		id = true
+	} else {
+		id = false
+	}
+
+	if cond >= id { // MATCH /replace this conditional by: id = cond < id/
+		id = false
+	} else {
+		id = true
+	}
+
+	if cond > id { // MATCH /replace this conditional by: id = cond > id/
+		id = true
+	} else {
+		id = false
+	}
+
+	if cond > id { // MATCH /replace this conditional by: id = cond <= id/
+		id = false
+	} else {
+		id = true
+	}
+
+	if cond < id { // MATCH /replace this conditional by: id = cond < id/
+		id = true
+	} else {
+		id = false
+	}
+
+	if cond < id { // MATCH /replace this conditional by: id = cond >= id/
+		id = false
+	} else {
+		id = true
+	}
+
+	if (something > 0) && (!id) || (something+10 <= 0) { // MATCH /replace this conditional by: id = !((something > 0) && (!id) || (something+10 <= 0))/
+		id = false
+	} else {
+		id = true
+	}
+
+	// conditionals with initialization
+	if cond := false; cond {
+		return true
+	} else {
+		return false
+	}
+
+	if cond := false; cond {
+		id = true
+	} else {
+		id = false
+	}
+
+	return id == id
+}