Repository: VKCOM/noverify
Pull request #1083 (2021-08-16 14:33:58)

linter: added `reverseAssign` checker
For example:

```php
$a =- 100;
// or
$a =+ 100;
```


Patch:
diff --git a/docs/checkers_doc.md b/docs/checkers_doc.md
index d9a6d75..ed7a38c 100644
--- a/docs/checkers_doc.md
+++ b/docs/checkers_doc.md
@@ -4,7 +4,7 @@
 
 | Total checks | Checks enabled by default | Disabled checks by default | Autofixable checks |
 | ------------ | ------------------------- | -------------------------- | ------------------ |
-| 87           | 77                        | 10                         | 12                 |
+| 88           | 78                        | 10                         | 12                 |
 ## Table of contents
  - Enabled by default
    - [`accessLevel` checker](#accesslevel-checker)
@@ -68,6 +68,7 @@
    - [`regexpSyntax` checker](#regexpsyntax-checker)
    - [`regexpVet` checker](#regexpvet-checker)
    - [`returnAssign` checker](#returnassign-checker)
+   - [`reverseAssign` checker](#reverseassign-checker)
    - [`selfAssign` checker](#selfassign-checker)
    - [`stdInterface` checker](#stdinterface-checker)
    - [`strangeCast` checker](#strangecast-checker)
@@ -1340,6 +1341,24 @@ return $a;
 <p><br></p>
 
 
+### `reverseAssign` checker
+
+#### Description
+
+Report a reverse assign with unary plus or minus.
+
+#### Non-compliant code:
+```php
+$a =+ 100;
+```
+
+#### Compliant code:
+```php
+$a += 100;
+```
+<p><br></p>
+
+
 ### `selfAssign` checker
 
 #### Description
diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go
index 8cb4963..5db1fce 100644
--- a/src/linter/block_linter.go
+++ b/src/linter/block_linter.go
@@ -311,6 +311,41 @@ func (b *blockLinter) checkCoalesceExpr(n *ir.CoalesceExpr) {
 
 func (b *blockLinter) checkAssign(a *ir.Assign) {
 	b.checkVoidType(a.Expr)
+
+	var sign byte
+	switch a.Expr.(type) {
+	case *ir.UnaryPlusExpr:
+		sign = '+'
+	case *ir.UnaryMinusExpr:
+		sign = '-'
+	default:
+		return
+	}
+
+	// Get sign token.
+	signTkn := ir.GetFirstToken(a.Expr)
+
+	// $a= 100;
+	//   |
+	//   - Free floating empty.
+	//
+	// $a = 100;
+	//    |
+	//    - Free floating contain space.
+	containsSpaceBeforeAssign := len(a.EqualTkn.FreeFloating) != 0
+
+	// $a =+ 100;
+	//     |
+	//     - Free floating empty.
+	//
+	// $a = +100;
+	//      |
+	//      - Free floating contain space.
+	containsSpaceBeforeSign := len(signTkn.FreeFloating) != 0
+
+	if !containsSpaceBeforeSign && containsSpaceBeforeAssign {
+		b.report(a, LevelWarning, "reverseAssign", "Possible there should be '%c='", sign)
+	}
 }
 
 func (b *blockLinter) checkTryStmt(s *ir.TryStmt) {
diff --git a/src/linter/report.go b/src/linter/report.go
index e307a0a..d850a5e 100644
--- a/src/linter/report.go
+++ b/src/linter/report.go
@@ -900,6 +900,15 @@ function main(): void {
 			Before:   `$x.""`,
 			After:    `(string)$x`,
 		},
+
+		{
+			Name:     "reverseAssign",
+			Default:  true,
+			Quickfix: false,
+			Comment:  `Report a reverse assign with unary plus or minus.`,
+			Before:   `$a =+ 100;`,
+			After:    `$a += 100;`,
+		},
 	}
 
 	for _, info := range allChecks {


Test patch:
diff --git a/src/tests/inline/testdata/checkers/reverseAssign.php b/src/tests/inline/testdata/checkers/reverseAssign.php
new file mode 100644
index 0000000..dfa06fc
--- /dev/null
+++ b/src/tests/inline/testdata/checkers/reverseAssign.php
@@ -0,0 +1,21 @@
+<?php
+
+function reverseAssign($b) {
+    $a = 100;
+
+    $a += $b; // ok
+    $a =+ $b; // want `Possible there should be '+='`
+    $a =+$b;  // want `Possible there should be '+='`
+    $a=+$b;   // ok
+    $a= +$b;  // ok
+    $a = +$b; // ok
+
+    $a -= $b; // ok
+    $a =- $b; // want `Possible there should be '-='`
+    $a =-$b;  // want `Possible there should be '-='`
+    $a=-$b;   // ok
+    $a= -$b;  // ok
+    $a = -$b; // ok
+
+    echo $a;
+}