Repository: VKCOM/noverify
Pull request #1140 (2021-09-02 10:27:34)

linter: improved and enabled `deprecated` checkers
`deprecated` checker is divided into two `deprecated`
and `deprecatedUntagged`, where the first will be
triggered if there is a description for @deprecated,
and the second if there is none.


Patch:
diff --git a/docs/checkers_doc.md b/docs/checkers_doc.md
index bfa22fd..886ab74 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 |
 | ------------ | ------------------------- | -------------------------- | ------------------ |
-| 97           | 84                        | 13                         | 12                 |
+| 98           | 85                        | 13                         | 12                 |
 
 ## Table of contents
  - Enabled by default
@@ -26,6 +26,7 @@
    - [`constCase` checker (autofixable)](#constcase-checker)
    - [`countUse` checker (autofixable)](#countuse-checker)
    - [`deadCode` checker](#deadcode-checker)
+   - [`deprecated` checker](#deprecated-checker)
    - [`discardExpr` checker](#discardexpr-checker)
    - [`discardVar` checker](#discardvar-checker)
    - [`dupArrayKeys` checker](#duparraykeys-checker)
@@ -63,9 +64,6 @@
    - [`paramClobber` checker](#paramclobber-checker)
    - [`parentConstructor` checker](#parentconstructor-checker)
    - [`parentNotFound` checker](#parentnotfound-checker)
-   - [`phpdocLint` checker](#phpdoclint-checker)
-   - [`phpdocRef` checker](#phpdocref-checker)
-   - [`phpdocType` checker](#phpdoctype-checker)
    - [`precedence` checker](#precedence-checker)
    - [`printf` checker](#printf-checker)
    - [`redundantGlobal` checker](#redundantglobal-checker)
@@ -100,7 +98,7 @@
    - [`arrayAccess` checker](#arrayaccess-checker)
    - [`classMembersOrder` checker](#classmembersorder-checker)
    - [`complexity` checker](#complexity-checker)
-   - [`deprecated` checker](#deprecated-checker)
+   - [`deprecatedUntagged` checker](#deprecateduntagged-checker)
    - [`errorSilence` checker](#errorsilence-checker)
    - [`langDeprecated` checker](#langdeprecated-checker)
    - [`missingPhpdoc` checker](#missingphpdoc-checker)
@@ -501,6 +499,34 @@ thisFunctionAlwaysExits();
 <p><br></p>
 
 
+### `deprecated` checker
+
+#### Description
+
+Report usages of deprecated symbols.
+
+#### Non-compliant code:
+```php
+/**
+ * @deprecated Use g() instead
+ */
+function f() {}
+
+f();
+```
+
+#### Compliant code:
+```php
+/**
+ * @deprecated Use g() instead
+ */
+function f() {}
+
+g();
+```
+<p><br></p>
+
+
 ### `discardExpr` checker
 
 #### Description
@@ -1240,6 +1266,7 @@ class Foo extends Bar {
 ```
 <p><br></p>
 
+
 ### `parentNotFound` checker
 
 #### Description
@@ -1266,59 +1293,6 @@ class Foo extends Boo {
 <p><br></p>
 
 
-### `phpdocLint` checker
-
-#### Description
-
-Report malformed PHPDoc comments.
-
-#### Non-compliant code:
-```php
-@property $foo // Property type is missing.
-```
-
-#### Compliant code:
-```php
-@property Foo $foo
-```
-<p><br></p>
-
-
-### `phpdocRef` checker
-
-#### Description
-
-Report invalid symbol references inside PHPDoc.
-
-#### Non-compliant code:
-```php
-@see MyClass
-```
-
-#### Compliant code:
-```php
-@see \Foo\MyClass
-```
-<p><br></p>
-
-
-### `phpdocType` checker
-
-#### Description
-
-Report potential issues in PHPDoc types.
-
-#### Non-compliant code:
-```php
-@var []int $xs
-```
-
-#### Compliant code:
-```php
-@var int[] $xs
-```
-<p><br></p>
-
 ### `precedence` checker
 
 #### Description
@@ -1977,20 +1951,30 @@ function checkRights() {
 <p><br></p>
 
 
-### `deprecated` checker
+### `deprecatedUntagged` checker
 
 #### Description
 
-Report usages of deprecated symbols.
+Report usages of deprecated symbols if the `@deprecated` tag has no description (see `deprecated` check).
 
 #### Non-compliant code:
 ```php
-ereg($pat, $s) // The ereg function has been deprecated.
+/**
+ * @deprecated
+ */
+function f() {}
+
+f();
 ```
 
 #### Compliant code:
 ```php
-preg_match($pat, $s)
+/**
+ * @deprecated
+ */
+function f() {}
+
+g();
 ```
 <p><br></p>
 
diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go
index 04e402d..fbe8954 100644
--- a/src/linter/block_linter.go
+++ b/src/linter/block_linter.go
@@ -933,7 +933,7 @@ func (b *blockLinter) checkDeprecatedFunctionCall(e *ir.FunctionCallExpr, call *
 		return
 	}
 
-	b.report(e.Function, LevelNotice, "deprecated", "Call to deprecated function %s", utils.NameNodeToString(e.Function))
+	b.report(e.Function, LevelNotice, "deprecatedUntagged", "Call to deprecated function %s", utils.NameNodeToString(e.Function))
 }
 
 func (b *blockLinter) checkFunctionAvailability(e *ir.FunctionCallExpr, call *funcCallInfo) {
@@ -1186,7 +1186,7 @@ func (b *blockLinter) checkMethodCall(e *ir.MethodCallExpr) {
 			b.report(e.Method, LevelNotice, "deprecated", "Call to deprecated method {%s}->%s() (%s)",
 				call.methodCallerType, call.methodName, call.info.Doc.DeprecationNote)
 		} else {
-			b.report(e.Method, LevelNotice, "deprecated", "Call to deprecated method {%s}->%s()",
+			b.report(e.Method, LevelNotice, "deprecatedUntagged", "Call to deprecated method {%s}->%s()",
 				call.methodCallerType, call.methodName)
 		}
 	}
@@ -1226,7 +1226,7 @@ func (b *blockLinter) checkStaticCall(e *ir.StaticCallExpr) {
 			b.report(e.Call, LevelNotice, "deprecated", "Call to deprecated static method %s::%s() (%s)",
 				call.className, call.methodName, call.methodInfo.Info.Doc.DeprecationNote)
 		} else {
-			b.report(e.Call, LevelNotice, "deprecated", "Call to deprecated static method %s::%s()",
+			b.report(e.Call, LevelNotice, "deprecatedUntagged", "Call to deprecated static method %s::%s()",
 				call.className, call.methodName)
 		}
 	}
diff --git a/src/linter/report.go b/src/linter/report.go
index e4947a5..18ed89f 100644
--- a/src/linter/report.go
+++ b/src/linter/report.go
@@ -531,11 +531,40 @@ case INC:
 
 		{
 			Name:     "deprecated",
-			Default:  false, // Experimental
+			Default:  true,
 			Quickfix: false,
 			Comment:  `Report usages of deprecated symbols.`,
-			Before:   `ereg($pat, $s) // The ereg function has been deprecated.`,
-			After:    `preg_match($pat, $s)`,
+			Before: `/**
+ * @deprecated Use g() instead
+ */
+function f() {}
+
+f();`,
+			After: `/**
+ * @deprecated Use g() instead
+ */
+function f() {}
+
+g();`,
+		},
+
+		{
+			Name:     "deprecatedUntagged",
+			Default:  false,
+			Quickfix: false,
+			Comment:  "Report usages of deprecated symbols if the `@deprecated` tag has no description (see `deprecated` check).",
+			Before: `/**
+ * @deprecated
+ */
+function f() {}
+
+f();`,
+			After: `/**
+ * @deprecated
+ */
+function f() {}
+
+g();`,
 		},
 
 		{


Test patch:
diff --git a/src/tests/checkers/deprecated_test.go b/src/tests/checkers/deprecated_test.go
new file mode 100644
index 0000000..091e737
--- /dev/null
+++ b/src/tests/checkers/deprecated_test.go
@@ -0,0 +1,73 @@
+package checkers
+
+import (
+	"testing"
+
+	"github.com/VKCOM/noverify/src/linttest"
+)
+
+func TestDeprecatedWithoutText(t *testing.T) {
+	test := linttest.NewSuite(t)
+	test.AddFile(`<?php
+class WithoutText {
+  /**
+   * @deprecated
+   */
+  public function method() {}
+
+  /**
+   * @deprecated
+   */
+  public static function staticMethod() {}
+}
+
+/**
+ * @deprecated
+ */
+function funcWithoutText() {}
+
+funcWithoutText();
+(new WithoutText)->method();
+WithoutText::staticMethod();
+
+`)
+	test.Expect = []string{
+		"Call to deprecated function funcWithoutText",
+		"Call to deprecated method {\\WithoutText}->method()",
+		"Call to deprecated static method \\WithoutText::staticMethod()",
+	}
+	test.RunAndMatch()
+}
+
+func TestDeprecatedWithText(t *testing.T) {
+	test := linttest.NewSuite(t)
+	test.AddFile(`<?php
+class WithText {
+  /**
+   * @deprecated use method2() instead
+   */
+  public function method() {}
+
+  /**
+   * @deprecated use staticMethod2() instead
+   */
+  public static function staticMethod() {}
+}
+
+/**
+ * @deprecated use funcWithText2() instead
+ */
+function funcWithText() {}
+
+funcWithText();
+(new WithText)->method();
+WithText::staticMethod();
+
+`)
+	test.Expect = []string{
+		"Call to deprecated function funcWithText (use funcWithText2() instead)",
+		"Call to deprecated method {\\WithText}->method() (use method2() instead)",
+		"Call to deprecated static method \\WithText::staticMethod() (use staticMethod2() instead)",
+	}
+	test.RunAndMatch()
+}
diff --git a/src/tests/golden/testdata/flysystem/golden.txt b/src/tests/golden/testdata/flysystem/golden.txt
index 45b17c6..9378e75 100644
--- a/src/tests/golden/testdata/flysystem/golden.txt
+++ b/src/tests/golden/testdata/flysystem/golden.txt
@@ -88,7 +88,7 @@ WARNING unused: Variable $e is unused (use $_ to ignore this inspection or speci
 WARNING unused: Variable $e is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/flysystem/src/MountManager.php:275
         } catch (PluginNotFoundException $e) {
                                          ^^
-MAYBE   deprecated: Call to deprecated method {\League\Flysystem\FilesystemInterface}->get() at testdata/flysystem/src/MountManager.php:646
+MAYBE   deprecatedUntagged: Call to deprecated method {\League\Flysystem\FilesystemInterface}->get() at testdata/flysystem/src/MountManager.php:646
         return $this->getFilesystem($prefix)->get($path);
                                               ^^^
 WARNING unused: Variable $e is unused (use $_ to ignore this inspection or specify --unused-var-regex flag) at testdata/flysystem/src/Plugin/ForcedCopy.php:33