diff --git a/docs/checkers_doc.md b/docs/checkers_doc.md
index 166416b1..bb31729b 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 |
| ------------ | ------------------------- | -------------------------- | ------------------ |
-| 104 | 86 | 18 | 14 |
+| 105 | 87 | 18 | 14 |
## Table of contents
- Enabled by default
@@ -75,6 +75,7 @@
- [`stdInterface` checker](#stdinterface-checker)
- [`strangeCast` checker](#strangecast-checker)
- [`strictCmp` checker](#strictcmp-checker)
+ - [`stringInterpolationDeprecated` checker](#stringinterpolationdeprecated-checker)
- [`stripTags` checker](#striptags-checker)
- [`switchEmpty` checker](#switchempty-checker)
- [`switchSimplify` checker](#switchsimplify-checker)
@@ -1183,7 +1184,7 @@ interface Iface {
#### Description
-Report not nullable param can be null.
+Report not nullable param with explicit null default value.
#### Non-compliant code:
```php
@@ -1471,6 +1472,24 @@ in_array("what", $s, true)
+### `stringInterpolationDeprecated` checker
+
+#### Description
+
+Report deprecated string interpolation style
+
+#### Non-compliant code:
+```php
+${variable}
+```
+
+#### Compliant code:
+```php
+{$variable}
+```
+
+
+
### `stripTags` checker
#### Description
diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go
index 3f6cbd4f..11e11b2e 100644
--- a/src/linter/block_linter.go
+++ b/src/linter/block_linter.go
@@ -24,6 +24,10 @@ type blockLinter struct {
func (b *blockLinter) enterNode(n ir.Node) {
switch n := n.(type) {
+
+ case *ir.Encapsed:
+ b.checkStringInterpolationDeprecation(n)
+
case *ir.Assign:
b.checkAssign(n)
@@ -207,6 +211,18 @@ func (b *blockLinter) enterNode(n ir.Node) {
}
}
+func (b *blockLinter) checkStringInterpolationDeprecation(str *ir.Encapsed) {
+ for _, item := range str.Parts {
+ variable, ok := item.(*ir.SimpleVar)
+ if ok {
+ if variable.IdentifierTkn.Value[0] != '$' {
+ b.report(str, LevelWarning, "stringInterpolationDeprecated", "use {$variable} instead ${variable}")
+ break
+ }
+ }
+ }
+}
+
func (b *blockLinter) checkUnaryPlus(n *ir.UnaryPlusExpr) {
val := constfold.Eval(b.classParseState(), n.Expr)
if val.IsValid() {
diff --git a/src/linter/report.go b/src/linter/report.go
index b36363b9..97ad85b7 100644
--- a/src/linter/report.go
+++ b/src/linter/report.go
@@ -618,6 +618,15 @@ g();`,
}`,
},
+ {
+ Name: "stringInterpolationDeprecated",
+ Default: true,
+ Quickfix: false,
+ Comment: `Report deprecated string interpolation style`,
+ Before: `${variable}`,
+ After: `{$variable}`,
+ },
+
{
Name: "misspellName",
Default: true,
diff --git a/src/tests/checkers/string_interpolation_test.go b/src/tests/checkers/string_interpolation_test.go
new file mode 100644
index 00000000..3f895203
--- /dev/null
+++ b/src/tests/checkers/string_interpolation_test.go
@@ -0,0 +1,50 @@
+package checkers
+
+import (
+ "testing"
+
+ "github.com/VKCOM/noverify/src/linttest"
+)
+
+func TestInterpolationDeprecated1(t *testing.T) {
+ test := linttest.NewSuite(t)
+ test.AddFile(`