From 066f245867cf6afe8d7088e7b2c3167639be200f Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Mon, 4 Mar 2024 12:54:46 +0300 Subject: [PATCH 1/8] added new linter rule: declareStrictTypes can not be "0" added quickFix for declareStrictTypes added test --- src/linter/block_linter.go | 26 ++++++++++++++++++- src/linter/quickfix.go | 8 ++++++ src/linter/report.go | 9 +++++++ .../testdata/quickfix/declareStrictTypes.php | 6 +++++ .../declareStrictTypes.php.fix.expected | 6 +++++ 5 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/tests/golden/testdata/quickfix/declareStrictTypes.php create mode 100644 src/tests/golden/testdata/quickfix/declareStrictTypes.php.fix.expected diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index bd7bc368d..c0542c05b 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -57,6 +57,9 @@ func (b *blockLinter) enterNode(n ir.Node) { case *ir.ExpressionStmt: b.checkStmtExpression(n) + case *ir.DeclareStmt: + b.checkDeclareStrictTypes(n) + case *ir.ConstFetchExpr: b.checkConstFetch(n) @@ -547,7 +550,6 @@ func (b *blockLinter) checkNew(e *ir.NewExpr) { func (b *blockLinter) checkStmtExpression(s *ir.ExpressionStmt) { report := false - // All branches except default try to filter-out common // cases to reduce the number of type solving performed. if irutil.IsAssign(s.Expr) { @@ -1533,3 +1535,25 @@ func (b *blockLinter) classParseState() *meta.ClassParseState { func (b *blockLinter) metaInfo() *meta.Info { return b.walker.r.ctx.st.Info } + +func (b *blockLinter) checkDeclareStrictTypes(statement *ir.DeclareStmt) { + for _, i := range statement.Consts { + switch node := i.(type) { + case *ir.ConstantStmt: + if node.ConstantName.Value != "strict_types" { + return + } + value, ok := node.Expr.(*ir.Lnumber) + if !ok { + return + } + + if value.Value == "1" { + return + } + + b.report(statement, LevelError, "notStrictTypes", "strict_types value is not 1") + b.walker.r.addQuickFix("notStrictTypes", b.quickfix.StrictTypes(value)) + } + } +} diff --git a/src/linter/quickfix.go b/src/linter/quickfix.go index ef83aa8ad..36f7cc4e2 100644 --- a/src/linter/quickfix.go +++ b/src/linter/quickfix.go @@ -34,6 +34,14 @@ func (g *QuickFixGenerator) Array(arr *ir.ArrayExpr) quickfix.TextEdit { } } +func (g *QuickFixGenerator) StrictTypes(lnumber *ir.Lnumber) quickfix.TextEdit { + return quickfix.TextEdit{ + StartPos: lnumber.Position.StartPos, + EndPos: lnumber.Position.EndPos, + Replacement: "1", + } +} + func (g *QuickFixGenerator) NullForNotNullableProperty(prop *ir.PropertyStmt) quickfix.TextEdit { from := prop.Position.StartPos to := prop.Variable.Position.EndPos diff --git a/src/linter/report.go b/src/linter/report.go index d1914da36..faf624d04 100644 --- a/src/linter/report.go +++ b/src/linter/report.go @@ -25,6 +25,15 @@ func addBuiltinCheckers(reg *CheckersRegistry) { After: `$s = strip_tags($s, '
')`, }, + { + 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: "emptyStmt", Default: true, diff --git a/src/tests/golden/testdata/quickfix/declareStrictTypes.php b/src/tests/golden/testdata/quickfix/declareStrictTypes.php new file mode 100644 index 000000000..72d4c306e --- /dev/null +++ b/src/tests/golden/testdata/quickfix/declareStrictTypes.php @@ -0,0 +1,6 @@ + Date: Mon, 4 Mar 2024 13:20:58 +0300 Subject: [PATCH 2/8] refactoring --- src/linter/block_linter.go | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index c0542c05b..1fa947d83 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -1538,22 +1538,24 @@ func (b *blockLinter) metaInfo() *meta.Info { func (b *blockLinter) checkDeclareStrictTypes(statement *ir.DeclareStmt) { for _, i := range statement.Consts { - switch node := i.(type) { - case *ir.ConstantStmt: - if node.ConstantName.Value != "strict_types" { - return - } - value, ok := node.Expr.(*ir.Lnumber) - if !ok { - return - } + node, ok := i.(*ir.ConstantStmt) + if !ok { + return + } - if value.Value == "1" { - return - } + if node.ConstantName.Value != "strict_types" { + return + } + value, isNumber := node.Expr.(*ir.Lnumber) + if !isNumber { + return + } - b.report(statement, LevelError, "notStrictTypes", "strict_types value is not 1") - b.walker.r.addQuickFix("notStrictTypes", b.quickfix.StrictTypes(value)) + if value.Value == "1" { + return } + + b.report(statement, LevelError, "notStrictTypes", "strict_types value is not 1") + b.walker.r.addQuickFix("notStrictTypes", b.quickfix.StrictTypes(value)) } } From 38f190ade192ab57bb75e54474a9d882c299c710 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Tue, 5 Mar 2024 17:53:30 +0300 Subject: [PATCH 3/8] added new warning and QuickFix for it: lack of declare(strict_types=1) section new rules for .gitignore new tests refactored warnings --- .gitignore | 2 ++ src/ir/irutil/keyword.go | 2 ++ src/linter/block_linter.go | 7 ++++- src/linter/quickfix.go | 8 ++++++ src/linter/report.go | 27 ++++++++++++------- src/linter/root.go | 15 ++++++++--- src/linter/worker.go | 5 ++++ .../quickfix/arraySyntax.php.fix.expected | 1 + .../quickfix/binaryOp.php.fix.expected | 1 + .../quickfix/callSimplify.php.fix.expected | 1 + .../quickfix/complexExamples.php.fix.expected | 1 + .../quickfix/constCase.php.fix.expected | 1 + .../testdata/quickfix/declareStrictTypes.php | 2 +- .../declareStrictTypes.php.fix.expected | 2 +- .../quickfix/getTypeMisUse.php.fix.expected | 1 + .../quickfix/indexingSyntax.php.fix.expected | 1 + .../noDeclareStrictTypesSection_1.php | 4 +++ ...clareStrictTypesSection_1.php.fix.expected | 5 ++++ .../noDeclareStrictTypesSection_2.php | 5 ++++ ...clareStrictTypesSection_2.php.fix.expected | 6 +++++ .../quickfix/propNullDefault.php.fix.expected | 1 + .../quickfix/ternarySimplify.php.fix.expected | 1 + .../quickfix/trailingComma.php.fix.expected | 1 + .../quickfix/unaryRepeat.php.fix.expected | 1 + 24 files changed, 85 insertions(+), 16 deletions(-) create mode 100644 src/tests/golden/testdata/quickfix/noDeclareStrictTypesSection_1.php create mode 100644 src/tests/golden/testdata/quickfix/noDeclareStrictTypesSection_1.php.fix.expected create mode 100644 src/tests/golden/testdata/quickfix/noDeclareStrictTypesSection_2.php create mode 100644 src/tests/golden/testdata/quickfix/noDeclareStrictTypesSection_2.php.fix.expected 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/src/ir/irutil/keyword.go b/src/ir/irutil/keyword.go index 764104929..8cf454865 100644 --- a/src/ir/irutil/keyword.go +++ b/src/ir/irutil/keyword.go @@ -14,6 +14,8 @@ func Keywords(n ir.Node) []*token.Token { switch n := n.(type) { case *ir.FunctionStmt: return []*token.Token{n.FunctionTkn} + case *ir.DeclareStmt: + return []*token.Token{n.DeclareTkn} case *ir.DefaultStmt: return []*token.Token{n.DefaultTkn} case *ir.CaseStmt: diff --git a/src/linter/block_linter.go b/src/linter/block_linter.go index 1fa947d83..6b163b8ce 100644 --- a/src/linter/block_linter.go +++ b/src/linter/block_linter.go @@ -1537,6 +1537,10 @@ func (b *blockLinter) metaInfo() *meta.Info { } func (b *blockLinter) checkDeclareStrictTypes(statement *ir.DeclareStmt) { + if b.walker.r.strictTypes { + return + } + for _, i := range statement.Consts { node, ok := i.(*ir.ConstantStmt) if !ok { @@ -1546,6 +1550,7 @@ func (b *blockLinter) checkDeclareStrictTypes(statement *ir.DeclareStmt) { if node.ConstantName.Value != "strict_types" { return } + value, isNumber := node.Expr.(*ir.Lnumber) if !isNumber { return @@ -1555,7 +1560,7 @@ func (b *blockLinter) checkDeclareStrictTypes(statement *ir.DeclareStmt) { return } - b.report(statement, LevelError, "notStrictTypes", "strict_types value is not 1") + b.report(statement, LevelWarning, "notStrictTypes", "strict_types value is not 1") b.walker.r.addQuickFix("notStrictTypes", b.quickfix.StrictTypes(value)) } } diff --git a/src/linter/quickfix.go b/src/linter/quickfix.go index 36f7cc4e2..50d6d6204 100644 --- a/src/linter/quickfix.go +++ b/src/linter/quickfix.go @@ -42,6 +42,14 @@ func (g *QuickFixGenerator) StrictTypes(lnumber *ir.Lnumber) quickfix.TextEdit { } } +func (g *QuickFixGenerator) CreateDeclareStrictTypes(root *ir.Root) quickfix.TextEdit { + return quickfix.TextEdit{ + StartPos: root.Position.StartPos, + EndPos: root.Position.StartPos, + Replacement: "declare(strict_types=1);\n", + } +} + func (g *QuickFixGenerator) NullForNotNullableProperty(prop *ir.PropertyStmt) quickfix.TextEdit { from := prop.Position.StartPos to := prop.Variable.Position.EndPos diff --git a/src/linter/report.go b/src/linter/report.go index faf624d04..a9e831257 100644 --- a/src/linter/report.go +++ b/src/linter/report.go @@ -34,6 +34,15 @@ func addBuiltinCheckers(reg *CheckersRegistry) { 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, @@ -1194,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 @@ -1205,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{}{} @@ -1221,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 @@ -1275,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 { @@ -1293,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..382f3c01b 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", "You have no declare section with strict_types=1 argument") + walker.addQuickFix("notStrictTypes", walker.quickfix.CreateDeclareStrictTypes(rootNode)) + } + if len(walker.ctx.fixes) != 0 { needApplyFixes := !file.AutoGenerated() || w.config.CheckAutoGenerated diff --git a/src/tests/golden/testdata/quickfix/arraySyntax.php.fix.expected b/src/tests/golden/testdata/quickfix/arraySyntax.php.fix.expected index 4e4199df7..5a0d176c5 100644 --- a/src/tests/golden/testdata/quickfix/arraySyntax.php.fix.expected +++ b/src/tests/golden/testdata/quickfix/arraySyntax.php.fix.expected @@ -1,5 +1,6 @@ 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..15e87f4c4 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 @@ Date: Tue, 5 Mar 2024 18:24:26 +0300 Subject: [PATCH 4/8] Tests fix --- src/tests/golden/golden_test.go | 97 +++++++++++++++++++++++++++------ 1 file changed, 81 insertions(+), 16 deletions(-) diff --git a/src/tests/golden/golden_test.go b/src/tests/golden/golden_test.go index be5002069..4c83bc945 100644 --- a/src/tests/golden/golden_test.go +++ b/src/tests/golden/golden_test.go @@ -39,6 +39,8 @@ func TestGolden(t *testing.T) { Name: "embeddedrules", Disable: []string{ "deadCode", + "notStrictTypes", + "noDeclareSection", }, Deps: []string{ `stubs/phpstorm-stubs/pcre/pcre.php`, @@ -50,6 +52,8 @@ func TestGolden(t *testing.T) { Disable: []string{ "arraySyntax", "redundantCast", + "notStrictTypes", + "noDeclareSection", }, Deps: []string{ `stubs/phpstorm-stubs/pcre/pcre.php`, @@ -62,6 +66,10 @@ func TestGolden(t *testing.T) { { Name: "math", + Disable: []string{ + "notStrictTypes", + "noDeclareSection", + }, Deps: []string{ `stubs/phpstorm-stubs/pcre/pcre.php`, `stubs/phpstorm-stubs/gmp/gmp.php`, @@ -73,6 +81,10 @@ func TestGolden(t *testing.T) { { Name: "qrcode", + Disable: []string{ + "notStrictTypes", + "noDeclareSection", + }, Deps: []string{ `stubs/phpstorm-stubs/pcre/pcre.php`, `stubs/phpstorm-stubs/gd/gd.php`, @@ -81,6 +93,10 @@ func TestGolden(t *testing.T) { { Name: "ctype", + Disable: []string{ + "notStrictTypes", + "noDeclareSection", + }, Deps: []string{ `stubs/phpstorm-stubs/pcre/pcre.php`, }, @@ -88,14 +104,22 @@ func TestGolden(t *testing.T) { { Name: "idn", + Disable: []string{ + "notStrictTypes", + "noDeclareSection", + }, Deps: []string{ `stubs/phpstorm-stubs/mbstring/mbstring.php`, }, }, { - Name: "parsedown", - Disable: []string{"missingPhpdoc", "arraySyntax"}, + Name: "parsedown", + Disable: []string{"missingPhpdoc", + "arraySyntax", + "notStrictTypes", + "noDeclareSection", + }, Deps: []string{ `stubs/phpstorm-stubs/pcre/pcre.php`, `stubs/phpstorm-stubs/mbstring/mbstring.php`, @@ -103,16 +127,24 @@ func TestGolden(t *testing.T) { }, { - Name: "underscore", - Disable: []string{"missingPhpdoc"}, + Name: "underscore", + Disable: []string{ + "missingPhpdoc", + "notStrictTypes", + "noDeclareSection", + }, Deps: []string{ `stubs/phpstorm-stubs/pcre/pcre.php`, }, }, { - Name: "phprocksyd", - Disable: []string{"missingPhpdoc"}, + Name: "phprocksyd", + Disable: []string{ + "missingPhpdoc", + "notStrictTypes", + "noDeclareSection", + }, Deps: []string{ `stubs/phpstorm-stubs/standard/basic.php`, `stubs/phpstorm-stubs/pcntl/pcntl.php`, @@ -122,8 +154,12 @@ func TestGolden(t *testing.T) { }, { - Name: "flysystem", - Disable: []string{"redundantCast"}, + Name: "flysystem", + Disable: []string{ + "redundantCast", + "notStrictTypes", + "noDeclareSection", + }, Deps: []string{ `stubs/phpstorm-stubs/pcre/pcre.php`, `stubs/phpstorm-stubs/SPL/SPL.php`, @@ -139,8 +175,12 @@ func TestGolden(t *testing.T) { }, { - Name: "inflector", - Disable: []string{"missingPhpdoc"}, + Name: "inflector", + Disable: []string{ + "missingPhpdoc", + "notStrictTypes", + "noDeclareSection", + }, Deps: []string{ `stubs/phpstorm-stubs/pcre/pcre.php`, `stubs/phpstorm-stubs/SPL/SPL.php`, @@ -149,8 +189,12 @@ func TestGolden(t *testing.T) { }, { - Name: "options-resolver", - Disable: []string{"missingPhpdoc"}, + Name: "options-resolver", + Disable: []string{ + "missingPhpdoc", + "notStrictTypes", + "noDeclareSection", + }, Deps: []string{ `stubs/phpstorm-stubs/SPL/SPL.php`, `stubs/phpstorm-stubs/Reflection/Reflection.php`, @@ -162,8 +206,13 @@ func TestGolden(t *testing.T) { }, { - Name: "twitter-api-php", - Disable: []string{"missingPhpdoc", "arraySyntax"}, + Name: "twitter-api-php", + Disable: []string{ + "missingPhpdoc", + "arraySyntax", + "notStrictTypes", + "noDeclareSection", + }, Deps: []string{ `stubs/phpstorm-stubs/pcre/pcre.php`, `stubs/phpstorm-stubs/SPL/SPL.php`, @@ -176,22 +225,38 @@ func TestGolden(t *testing.T) { { Name: "output-test", + Disable: []string{ + "notStrictTypes", + "noDeclareSection", + }, }, { - Name: "gitignore-test", + Name: "gitignore-test", + Disable: []string{ + "notStrictTypes", + "noDeclareSection", + }, OnlyE2E: true, Gitignore: true, }, { - Name: "baseline-test", + Name: "baseline-test", + Disable: []string{ + "notStrictTypes", + "noDeclareSection", + }, OnlyE2E: true, Baseline: true, }, { Name: "phpdoc", + Disable: []string{ + "notStrictTypes", + "noDeclareSection", + }, }, } From 2fa39047c48449b544083550771dd0a42d9688e2 Mon Sep 17 00:00:00 2001 From: Richardas Kuchinskas Date: Wed, 6 Mar 2024 13:21:31 +0300 Subject: [PATCH 5/8] Fixed regression --- src/tests/regression/issue1071_test.go | 1 + src/tests/regression/issue11_test.go | 1 + src/tests/regression/issue128_test.go | 1 + src/tests/regression/issue16_test.go | 1 + src/tests/regression/issue170_test.go | 1 + src/tests/regression/issue182_test.go | 1 + src/tests/regression/issue183_test.go | 1 + src/tests/regression/issue1_test.go | 1 + src/tests/regression/issue209_test.go | 1 + src/tests/regression/issue252_test.go | 1 + src/tests/regression/issue26_test.go | 1 + src/tests/regression/issue283_test.go | 1 + src/tests/regression/issue288_test.go | 1 + src/tests/regression/issue289_test.go | 1 + src/tests/regression/issue2_test.go | 1 + src/tests/regression/issue327_test.go | 1 + src/tests/regression/issue362_test.go | 1 + src/tests/regression/issue375_test.go | 1 + src/tests/regression/issue37_test.go | 1 + src/tests/regression/issue387_test.go | 1 + src/tests/regression/issue390_test.go | 1 + src/tests/regression/issue3_test.go | 1 + src/tests/regression/issue497_test.go | 1 + src/tests/regression/issue547_test.go | 1 + src/tests/regression/issue548_test.go | 1 + src/tests/regression/issue556_test.go | 1 + src/tests/regression/issue673_test.go | 1 + src/tests/regression/issue6_test.go | 1 + src/tests/regression/issue778_test.go | 1 + src/tests/regression/issue78_test.go | 1 + src/tests/regression/issue8_test.go | 1 + src/tests/regression/issue989_test.go | 1 + src/tests/regression/pull236_test.go | 1 + 33 files changed, 33 insertions(+) diff --git a/src/tests/regression/issue1071_test.go b/src/tests/regression/issue1071_test.go index f18db4f42..da2d7c71c 100644 --- a/src/tests/regression/issue1071_test.go +++ b/src/tests/regression/issue1071_test.go @@ -13,6 +13,7 @@ func TestIssue1071FunctionWithBackSlash(t *testing.T) { "stubs/phpstorm-stubs/meta/.phpstorm.meta.php", } test.AddFile(` 1, "\n" => 2]; `) } diff --git a/src/tests/regression/issue6_test.go b/src/tests/regression/issue6_test.go index cad278d7a..e077b8f88 100644 --- a/src/tests/regression/issue6_test.go +++ b/src/tests/regression/issue6_test.go @@ -9,6 +9,7 @@ import ( func TestIssue6(t *testing.T) { linttest.SimpleNegativeTest(t, ` Date: Wed, 6 Mar 2024 16:26:33 +0300 Subject: [PATCH 6/8] Fixed tests (declare section) --- example/custom/custom_test.go | 1 + src/tests/checkers/anon_class_test.go | 8 ++ src/tests/checkers/arrow_functions_test.go | 3 + src/tests/checkers/basic_test.go | 117 ++++++++++++++++-- src/tests/checkers/catch_test.go | 10 ++ src/tests/checkers/closure_test.go | 3 + src/tests/checkers/codedup_test.go | 7 ++ src/tests/checkers/deprecated_test.go | 2 + src/tests/checkers/disable_inspection_test.go | 1 + src/tests/checkers/discard_expr_test.go | 4 + src/tests/checkers/emptystmt_test.go | 7 ++ src/tests/checkers/function_exists_test.go | 3 + src/tests/checkers/get_type_miss_use_test.go | 1 + src/tests/checkers/indexing_order_test.go | 6 + src/tests/checkers/kphp_test.go | 2 + src/tests/checkers/linter_suppress_test.go | 7 ++ src/tests/checkers/literal_type_test.go | 1 + src/tests/checkers/misspell_test.go | 4 + src/tests/checkers/oop_test.go | 39 ++++++ src/tests/checkers/paramClobber_test.go | 6 + src/tests/checkers/phpdoc_test.go | 13 ++ src/tests/checkers/printf_test.go | 2 + src/tests/checkers/regexpsimplify_test.go | 5 + src/tests/checkers/regexpvet_test.go | 3 + src/tests/checkers/relative_name_test.go | 3 + src/tests/checkers/shape_test.go | 6 + src/tests/checkers/strict_mixed_test.go | 2 + src/tests/checkers/stripTags_test.go | 4 + src/tests/checkers/trait_test.go | 1 + src/tests/checkers/trigger_error_test.go | 5 + src/tests/checkers/typehint_test.go | 1 + .../php8/deprecated_annotation_any.php | 1 + .../testdata/php8/param_available_any.php | 1 + .../testdata/php8/propertyPromotion_any.php | 1 + src/tests/regression/issue209_test.go | 1 + src/tests/regression/issue252_test.go | 1 + src/tests/regression/issue26_test.go | 3 + src/tests/regression/issue362_test.go | 1 + src/tests/regression/issue548_test.go | 4 + src/tests/regression/issue78_test.go | 2 + src/tests/regression/issue989_test.go | 3 + 41 files changed, 287 insertions(+), 8 deletions(-) diff --git a/example/custom/custom_test.go b/example/custom/custom_test.go index 082a15b3a..08c601c93 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(`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..0b2664391 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, `sum(); // actual PHP prints 6 func TestIssue209_2(t *testing.T) { test := linttest.NewSuite(t) test.AddFile(` Date: Wed, 6 Mar 2024 19:40:17 +0300 Subject: [PATCH 7/8] formatting fix --- example/custom/custom_test.go | 2 +- src/linter/quickfix.go | 2 +- src/linter/report.go | 6 +- src/tests/checkers/anon_class_test.go | 14 +- src/tests/checkers/arrow_functions_test.go | 4 +- src/tests/checkers/basic_test.go | 198 +++++++++--------- src/tests/checkers/catch_test.go | 20 +- src/tests/checkers/closure_test.go | 6 +- src/tests/checkers/codedup_test.go | 14 +- src/tests/checkers/deprecated_test.go | 4 +- src/tests/checkers/disable_inspection_test.go | 2 +- src/tests/checkers/discard_expr_test.go | 8 +- src/tests/checkers/emptystmt_test.go | 14 +- src/tests/checkers/function_exists_test.go | 6 +- src/tests/checkers/get_type_miss_use_test.go | 2 +- src/tests/checkers/indexing_order_test.go | 12 +- src/tests/checkers/kphp_test.go | 4 +- src/tests/checkers/linter_suppress_test.go | 14 +- src/tests/checkers/literal_type_test.go | 2 +- src/tests/checkers/misspell_test.go | 8 +- src/tests/checkers/oop_test.go | 78 +++---- src/tests/checkers/paramClobber_test.go | 12 +- src/tests/checkers/phpdoc_test.go | 26 +-- src/tests/checkers/printf_test.go | 4 +- src/tests/checkers/regexpsimplify_test.go | 10 +- src/tests/checkers/regexpvet_test.go | 6 +- src/tests/checkers/relative_name_test.go | 6 +- src/tests/checkers/shape_test.go | 12 +- src/tests/checkers/strict_mixed_test.go | 4 +- src/tests/checkers/stripTags_test.go | 8 +- src/tests/checkers/trait_test.go | 2 +- src/tests/checkers/trigger_error_test.go | 10 +- src/tests/checkers/typehint_test.go | 2 +- .../Inflector/CachedWordInflector.php | 2 +- .../lib/Doctrine/Inflector/Inflector.php | 2 +- .../Doctrine/Inflector/InflectorFactory.php | 2 +- .../lib/Doctrine/Inflector/Language.php | 2 +- .../Doctrine/Inflector/NoopWordInflector.php | 2 +- .../Inflector/Rules/English/Inflectible.php | 2 +- .../Rules/English/InflectorFactory.php | 2 +- .../Inflector/Rules/English/Rules.php | 2 +- .../Inflector/Rules/English/Uninflected.php | 2 +- .../Inflector/Rules/French/Inflectible.php | 2 +- .../Rules/French/InflectorFactory.php | 2 +- .../Doctrine/Inflector/Rules/French/Rules.php | 2 +- .../Inflector/Rules/French/Uninflected.php | 2 +- .../Rules/NorwegianBokmal/Inflectible.php | 2 +- .../NorwegianBokmal/InflectorFactory.php | 2 +- .../Inflector/Rules/NorwegianBokmal/Rules.php | 2 +- .../Rules/NorwegianBokmal/Uninflected.php | 2 +- .../lib/Doctrine/Inflector/Rules/Pattern.php | 2 +- .../lib/Doctrine/Inflector/Rules/Patterns.php | 2 +- .../Rules/Portuguese/Inflectible.php | 2 +- .../Rules/Portuguese/InflectorFactory.php | 2 +- .../Inflector/Rules/Portuguese/Rules.php | 2 +- .../Rules/Portuguese/Uninflected.php | 2 +- .../lib/Doctrine/Inflector/Rules/Ruleset.php | 2 +- .../Inflector/Rules/Spanish/Inflectible.php | 2 +- .../Rules/Spanish/InflectorFactory.php | 2 +- .../Inflector/Rules/Spanish/Rules.php | 2 +- .../Inflector/Rules/Spanish/Uninflected.php | 2 +- .../Doctrine/Inflector/Rules/Substitution.php | 2 +- .../Inflector/Rules/Substitutions.php | 2 +- .../Inflector/Rules/Transformation.php | 2 +- .../Inflector/Rules/Transformations.php | 2 +- .../Inflector/Rules/Turkish/Inflectible.php | 2 +- .../Rules/Turkish/InflectorFactory.php | 2 +- .../Inflector/Rules/Turkish/Rules.php | 2 +- .../Inflector/Rules/Turkish/Uninflected.php | 2 +- .../lib/Doctrine/Inflector/Rules/Word.php | 2 +- .../Doctrine/Inflector/RulesetInflector.php | 2 +- .../lib/Doctrine/Inflector/WordInflector.php | 2 +- .../golden/testdata/math/src/BigDecimal.php | 2 +- .../golden/testdata/math/src/BigInteger.php | 2 +- .../golden/testdata/math/src/BigNumber.php | 2 +- .../golden/testdata/math/src/BigRational.php | 2 +- .../src/Exception/DivisionByZeroException.php | 2 +- .../Exception/IntegerOverflowException.php | 2 +- .../math/src/Exception/MathException.php | 2 +- .../src/Exception/NegativeNumberException.php | 2 +- .../src/Exception/NumberFormatException.php | 2 +- .../Exception/RoundingNecessaryException.php | 2 +- .../testdata/math/src/Internal/Calculator.php | 2 +- .../Internal/Calculator/BcMathCalculator.php | 2 +- .../src/Internal/Calculator/GmpCalculator.php | 2 +- .../Internal/Calculator/NativeCalculator.php | 2 +- .../golden/testdata/math/src/RoundingMode.php | 2 +- .../quickfix/arraySyntax.php.fix.expected | 2 +- .../quickfix/binaryOp.php.fix.expected | 2 +- .../quickfix/callSimplify.php.fix.expected | 2 +- .../quickfix/complexExamples.php.fix.expected | 2 +- .../quickfix/constCase.php.fix.expected | 2 +- .../testdata/quickfix/declareStrictTypes.php | 2 +- .../declareStrictTypes.php.fix.expected | 2 +- .../quickfix/getTypeMisUse.php.fix.expected | 2 +- .../quickfix/indexingSyntax.php.fix.expected | 2 +- ...clareStrictTypesSection_1.php.fix.expected | 2 +- .../noDeclareStrictTypesSection_2.php | 2 +- ...clareStrictTypesSection_2.php.fix.expected | 4 +- .../quickfix/propNullDefault.php.fix.expected | 2 +- .../quickfix/ternarySimplify.php.fix.expected | 2 +- .../quickfix/trailingComma.php.fix.expected | 2 +- .../quickfix/unaryRepeat.php.fix.expected | 2 +- .../php8/deprecated_annotation_any.php | 2 +- .../testdata/php8/param_available_any.php | 2 +- .../testdata/php8/propertyPromotion_any.php | 2 +- src/tests/regression/issue1071_test.go | 2 +- src/tests/regression/issue11_test.go | 2 +- src/tests/regression/issue128_test.go | 2 +- src/tests/regression/issue16_test.go | 2 +- src/tests/regression/issue170_test.go | 2 +- src/tests/regression/issue182_test.go | 2 +- src/tests/regression/issue183_test.go | 2 +- src/tests/regression/issue1_test.go | 2 +- src/tests/regression/issue209_test.go | 4 +- src/tests/regression/issue252_test.go | 4 +- src/tests/regression/issue26_test.go | 8 +- src/tests/regression/issue283_test.go | 2 +- src/tests/regression/issue288_test.go | 2 +- src/tests/regression/issue289_test.go | 2 +- src/tests/regression/issue2_test.go | 2 +- src/tests/regression/issue327_test.go | 2 +- src/tests/regression/issue362_test.go | 4 +- src/tests/regression/issue375_test.go | 2 +- src/tests/regression/issue37_test.go | 2 +- src/tests/regression/issue387_test.go | 2 +- src/tests/regression/issue390_test.go | 2 +- src/tests/regression/issue3_test.go | 2 +- src/tests/regression/issue497_test.go | 2 +- src/tests/regression/issue547_test.go | 2 +- src/tests/regression/issue548_test.go | 10 +- src/tests/regression/issue556_test.go | 2 +- src/tests/regression/issue673_test.go | 2 +- src/tests/regression/issue6_test.go | 4 +- src/tests/regression/issue778_test.go | 2 +- src/tests/regression/issue78_test.go | 6 +- src/tests/regression/issue8_test.go | 2 +- src/tests/regression/issue989_test.go | 8 +- src/tests/regression/pull236_test.go | 2 +- 139 files changed, 384 insertions(+), 384 deletions(-) diff --git a/example/custom/custom_test.go b/example/custom/custom_test.go index 08c601c93..3b2e5e41b 100644 --- a/example/custom/custom_test.go +++ b/example/custom/custom_test.go @@ -11,7 +11,7 @@ func TestAssignmentAsExpression(t *testing.T) { addCheckers(test.Config()) test.AddFile(`func2()->func3(); func TestAnonClassWithConstructor(t *testing.T) { linttest.SimpleNegativeTest(t, ` $v) { $_ = [$k, $v]; @@ -188,7 +188,7 @@ $_ = [$x]; // Bad func TestForeachSimplify(t *testing.T) { test := linttest.NewSuite(t) test.AddFile(` $y]; } @@ -613,7 +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"`} @@ -1386,7 +1386,7 @@ $_ = ["\n" => 1, "\xa" => 2]; func TestDuplicateArrayKeyGood(t *testing.T) { linttest.SimpleNegativeTest(t, ` 1, "'" => 1, @@ -1397,7 +1397,7 @@ $valid_quotes = [ func TestDuplicateArrayKey(t *testing.T) { test := linttest.NewSuite(t) test.AddFile(` 'something', @@ -1413,7 +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; } @@ -46,7 +46,7 @@ echo $v->field; func TestIndexingOrderTraits(t *testing.T) { test := linttest.NewSuite(t) test.AddNamedFile("/foo/A.php", `field = $x; } @@ -80,13 +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(); @@ -1030,7 +1030,7 @@ function fn4($f4) { func TestInstanceOfElseif1(t *testing.T) { linttest.SimpleNegativeTest(t, `[0-9])~', $s); preg_match('~(?[0-9])~', $s); @@ -28,7 +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); @@ -149,7 +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']); } @@ -42,7 +42,7 @@ func TestStripTagsString1(t *testing.T) { test := linttest.NewSuite(t) test.LoadStubs = []string{"stubs/phpstorm-stubs/standard/standard_1.php"} test.AddFile(`'); } @@ -61,7 +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 0b2664391..167d820bf 100644 --- a/src/tests/checkers/trait_test.go +++ b/src/tests/checkers/trait_test.go @@ -9,7 +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 15e87f4c4..3ed4c9e56 100644 --- a/src/tests/golden/testdata/quickfix/complexExamples.php.fix.expected +++ b/src/tests/golden/testdata/quickfix/complexExamples.php.fix.expected @@ -1,6 +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 e077b8f88..128505fae 100644 --- a/src/tests/regression/issue6_test.go +++ b/src/tests/regression/issue6_test.go @@ -8,8 +8,8 @@ import ( func TestIssue6(t *testing.T) { linttest.SimpleNegativeTest(t, ` Date: Sun, 10 Mar 2024 17:28:57 +0300 Subject: [PATCH 8/8] simplify error report text --- src/linter/worker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linter/worker.go b/src/linter/worker.go index 382f3c01b..8e7beb7cd 100644 --- a/src/linter/worker.go +++ b/src/linter/worker.go @@ -316,7 +316,7 @@ func (w *Worker) analyzeFile(file *workspace.File, rootNode *ir.Root) (*rootWalk walker.afterLeaveFile() if !walker.declareSection { - walker.Report(rootNode, LevelWarning, "noDeclareSection", "You have no declare section with strict_types=1 argument") + walker.Report(rootNode, LevelWarning, "noDeclareSection", "Missed declare(strict_types=1) directive") walker.addQuickFix("notStrictTypes", walker.quickfix.CreateDeclareStrictTypes(rootNode)) }