diff --git a/.gitignore b/.gitignore
index fdd1235b0..bb3b410fc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,5 @@ src/cmd/stubs/phpstorm-stubs/
y.output
.idea
vendor
+dev
+src/tests/golden/testdata/quickfix/*.fix
diff --git a/example/custom/custom_test.go b/example/custom/custom_test.go
index 082a15b3a..3b2e5e41b 100644
--- a/example/custom/custom_test.go
+++ b/example/custom/custom_test.go
@@ -11,6 +11,7 @@ func TestAssignmentAsExpression(t *testing.T) {
addCheckers(test.Config())
test.AddFile(`')`,
},
+ {
+ Name: "notStrictTypes",
+ Default: true,
+ Quickfix: true,
+ Comment: "Report strict_types value is not 1 in declare section.",
+ Before: `declare(strict_types = 0);`,
+ After: `declare(strict_types = 1);`,
+ },
+
+ {
+ Name: "noDeclareSection",
+ Default: true,
+ Quickfix: true,
+ Comment: "Report declare(strict_types=1) has not been set.",
+ Before: ` `,
+ After: `declare(strict_types = 1);`,
+ },
+
{
Name: "emptyStmt",
Default: true,
@@ -1185,8 +1203,8 @@ func DiffReports(gitRepo string, diffArgs []string, changesList []git.Change, ch
}
}
- old := reportListToMap(oldList)
- new := reportListToMap(newList)
+ oldReportMap := reportListToMap(oldList)
+ newReportMap := reportListToMap(newList)
changes := gitChangesToMap(changesList)
var mu sync.Mutex
@@ -1196,7 +1214,7 @@ func DiffReports(gitRepo string, diffArgs []string, changesList []git.Change, ch
limitCh := make(chan struct{}, maxConcurrency)
- for filename, list := range new {
+ for filename, list := range newReportMap {
wg.Add(1)
go func(filename string, list []*Report) {
limitCh <- struct{}{}
@@ -1212,7 +1230,7 @@ func DiffReports(gitRepo string, diffArgs []string, changesList []git.Change, ch
oldName = filename // full diff mode
}
- reports, err := diffReportsList(gitRepo, ignoreCommits, diffArgs, filename, c, old[oldName], list)
+ reports, err := diffReportsList(gitRepo, ignoreCommits, diffArgs, filename, c, oldReportMap[oldName], list)
if err != nil {
mu.Lock()
resErr = err
@@ -1266,8 +1284,8 @@ func diffReportsList(gitRepo string, ignoreCommits map[string]struct{}, diffArgs
}
}
- old, oldMaxLine := reportListToPerLineMap(oldList)
- new, newMaxLine := reportListToPerLineMap(newList)
+ oldPerLineMap, oldMaxLine := reportListToPerLineMap(oldList)
+ newPerLineMap, newMaxLine := reportListToPerLineMap(newList)
var maxLine = oldMaxLine
if newMaxLine > maxLine {
@@ -1284,17 +1302,17 @@ func diffReportsList(gitRepo string, ignoreCommits map[string]struct{}, diffArgs
// just deletion
if ok && ch.new.HaveRange && ch.new.Range == 0 {
oldLine = ch.old.To
- newLine-- // cancel the increment of newLine, because code was deleted, no new lines added
+ newLine-- // cancel the increment of newLine, because code was deleted, no newPerLineMap lines added
continue
}
- res = maybeAppendReports(res, new, old, newLine, oldLine, blame, ignoreCommits)
+ res = maybeAppendReports(res, newPerLineMap, oldPerLineMap, newLine, oldLine, blame, ignoreCommits)
if ok {
oldLine = 0 // all changes and additions must be checked
for j := newLine + 1; j <= ch.new.To; j++ {
newLine = j
- res = maybeAppendReports(res, new, old, newLine, oldLine, blame, ignoreCommits)
+ res = maybeAppendReports(res, newPerLineMap, oldPerLineMap, newLine, oldLine, blame, ignoreCommits)
}
oldLine = ch.old.To
}
diff --git a/src/linter/root.go b/src/linter/root.go
index 3c23699ac..414e23c3f 100644
--- a/src/linter/root.go
+++ b/src/linter/root.go
@@ -69,10 +69,12 @@ type rootWalker struct {
// name matches the pattern and @linter disable was encountered
// strictTypes is true if file contains `declare(strict_types=1)`.
- strictTypes bool
- strictMixed bool
+ strictTypes bool
+ strictMixed bool
+ declareSection bool
- reports []*Report
+ reports []*Report
+ quickfix *QuickFixGenerator
config *Config
@@ -141,7 +143,12 @@ func (d *rootWalker) EnterNode(n ir.Node) (res bool) {
}
if c.ConstantName.Value == "strict_types" {
v, ok := c.Expr.(*ir.Lnumber)
- if ok && v.Value == "1" {
+ if !ok {
+ continue
+ }
+
+ d.declareSection = true
+ if v.Value == "1" {
d.strictTypes = true
}
}
diff --git a/src/linter/worker.go b/src/linter/worker.go
index 6cfa8c5a0..8e7beb7cd 100644
--- a/src/linter/worker.go
+++ b/src/linter/worker.go
@@ -315,6 +315,11 @@ func (w *Worker) analyzeFile(file *workspace.File, rootNode *ir.Root) (*rootWalk
}
walker.afterLeaveFile()
+ if !walker.declareSection {
+ walker.Report(rootNode, LevelWarning, "noDeclareSection", "Missed declare(strict_types=1) directive")
+ walker.addQuickFix("notStrictTypes", walker.quickfix.CreateDeclareStrictTypes(rootNode))
+ }
+
if len(walker.ctx.fixes) != 0 {
needApplyFixes := !file.AutoGenerated() || w.config.CheckAutoGenerated
diff --git a/src/tests/checkers/anon_class_test.go b/src/tests/checkers/anon_class_test.go
index 654a9d9fb..8f5951a69 100644
--- a/src/tests/checkers/anon_class_test.go
+++ b/src/tests/checkers/anon_class_test.go
@@ -8,6 +8,7 @@ import (
func TestSimpleAnonClass(t *testing.T) {
linttest.SimpleNegativeTest(t, `func2()->func3();
func TestAnonClassWithConstructor(t *testing.T) {
linttest.SimpleNegativeTest(t, ` $v) {
$_ = [$k, $v];
@@ -178,6 +188,7 @@ $_ = [$x]; // Bad
func TestForeachSimplify(t *testing.T) {
test := linttest.NewSuite(t)
test.AddFile(` $y];
}
@@ -593,6 +613,7 @@ foreach ([[1, 2, 3, 4]] as list($x, $y,,$z)) {
func TestArgsCount(t *testing.T) {
test := linttest.NewSuite(t)
test.AddFile(` 1, "\xa" => 2];
`)
test.Expect = []string{`Duplicate array key "\n"`}
@@ -1326,6 +1386,7 @@ $_ = ["\n" => 1, "\xa" => 2];
func TestDuplicateArrayKeyGood(t *testing.T) {
linttest.SimpleNegativeTest(t, ` 1,
"'" => 1,
@@ -1336,6 +1397,7 @@ $valid_quotes = [
func TestDuplicateArrayKey(t *testing.T) {
test := linttest.NewSuite(t)
test.AddFile(` 'something',
@@ -1351,6 +1413,7 @@ function test() {
func TestDuplicateArrayKeyWithBoolConstants(t *testing.T) {
test := linttest.NewSuite(t)
test.AddFile(` 1, true => 2];
func TestDuplicateArrayKeyWithConstants(t *testing.T) {
test := linttest.NewSuite(t)
test.AddFile(`loadHTML('field = $x; }
@@ -44,6 +46,7 @@ echo $v->field;
func TestIndexingOrderTraits(t *testing.T) {
test := linttest.NewSuite(t)
test.AddNamedFile("/foo/A.php", `field = $x; }
@@ -76,11 +80,13 @@ echo $v->field;
func TestIndexingOrderFuncs(t *testing.T) {
test := linttest.NewSuite(t)
test.AddNamedFile("/foo/A.php", `acceptThis($foo);
func TestMagicGetChaining(t *testing.T) {
linttest.SimpleNegativeTest(t, `foo->bar->method();
func TestNonPublicMagicMethods(t *testing.T) {
test := linttest.NewSuite(t)
test.AddFile(`create() as $item) {
func TestDerivedLateStaticBinding(t *testing.T) {
linttest.SimpleNegativeTest(t, `onlyInDerived();
func TestStaticResolutionInsideSameClass(t *testing.T) {
test := linttest.NewSuite(t)
test.AddFile(`name();
@@ -1002,6 +1030,7 @@ function fn4($f4) {
func TestInstanceOfElseif1(t *testing.T) {
linttest.SimpleNegativeTest(t, `[0-9])~', $s);
preg_match('~(?[0-9])~', $s);
@@ -27,6 +28,7 @@ func TestRESimplifyMixed(t *testing.T) {
test := linttest.NewSuite(t)
test.LoadStubs = []string{`stubs/phpstorm-stubs/pcre/pcre.php`}
test.AddFile(` x
function ungroup($s) {
preg_match('/(?:x)/', $s);
@@ -146,6 +149,7 @@ func TestRESimplifyChangeDelim(t *testing.T) {
test := linttest.NewSuite(t)
test.LoadStubs = []string{`stubs/phpstorm-stubs/pcre/pcre.php`}
test.AddFile(`good6['y']->value;
func TestShapeReturn(t *testing.T) {
linttest.SimpleNegativeTest(t, `next->next;
func TestTuple(t *testing.T) {
linttest.SimpleNegativeTest(t, `', 'a', 'A']);
}
@@ -40,6 +42,7 @@ func TestStripTagsString1(t *testing.T) {
test := linttest.NewSuite(t)
test.LoadStubs = []string{"stubs/phpstorm-stubs/standard/standard_1.php"}
test.AddFile(`');
}
@@ -58,6 +61,7 @@ func TestStripTagsString2(t *testing.T) {
test := linttest.NewSuite(t)
test.LoadStubs = []string{"stubs/phpstorm-stubs/standard/standard_1.php"}
test.AddFile(`
');
}
diff --git a/src/tests/checkers/trait_test.go b/src/tests/checkers/trait_test.go
index 884e37274..167d820bf 100644
--- a/src/tests/checkers/trait_test.go
+++ b/src/tests/checkers/trait_test.go
@@ -9,6 +9,7 @@ import (
func TestTraitSingleton(t *testing.T) {
// See #533.
linttest.SimpleNegativeTest(t, ` 1, 'b' => 2, 'c' => 3];
if (array_key_exists('z', $array)) { // 2
diff --git a/src/tests/golden/testdata/quickfix/complexExamples.php.fix.expected b/src/tests/golden/testdata/quickfix/complexExamples.php.fix.expected
index 503b05611..3ed4c9e56 100644
--- a/src/tests/golden/testdata/quickfix/complexExamples.php.fix.expected
+++ b/src/tests/golden/testdata/quickfix/complexExamples.php.fix.expected
@@ -1,5 +1,6 @@
sum(); // actual PHP prints 6
func TestIssue209_2(t *testing.T) {
test := linttest.NewSuite(t)
test.AddFile(` 1, "\n" => 2];
`)
}
diff --git a/src/tests/regression/issue6_test.go b/src/tests/regression/issue6_test.go
index cad278d7a..128505fae 100644
--- a/src/tests/regression/issue6_test.go
+++ b/src/tests/regression/issue6_test.go
@@ -8,7 +8,8 @@ import (
func TestIssue6(t *testing.T) {
linttest.SimpleNegativeTest(t, `