Skip to content

Commit 3893034

Browse files
committed
Merge remote-tracking branch 'upstream/master' into feature/improve-sniff-code-error-message
2 parents 1665e40 + 1114d35 commit 3893034

File tree

129 files changed

+5261
-270
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

129 files changed

+5261
-270
lines changed

CHANGELOG.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,87 @@ The file documents changes to the PHP_CodeSniffer project.
66

77
_Nothing yet._
88

9+
## [3.10.1] - 2024-05-22
10+
11+
### Added
12+
- Documentation for the following sniffs:
13+
- Generic.Commenting.DocComment
14+
- Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
15+
16+
### Changed
17+
- The following have received efficiency improvements:
18+
- Type handling in the PHP Tokenizer
19+
- Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
20+
- Various housekeeping, including improvements to the tests and documentation.
21+
- Thanks to [Juliette Reinders Folmer][@jrfnl] for their contributions.
22+
23+
### Fixed
24+
- Fixed bug [#110], [#437], [#475]: `File::findStartOfStatement()`: the start of statement/expression determination for tokens in parentheses/short array brackets/others scopes, nested within match expressions, was incorrect in most cases.
25+
The trickle down effect of the bug fixes made to the `File::findStartOfStatement()` method, is that the Generic.WhiteSpace.ScopeIndent and the PEAR.WhiteSpace.ScopeIndent sniffs should now be able to correctly determine and fix the indent for match expressions containing nested expressions.
26+
These fixes also fix an issue with the `Squiz.Arrays.ArrayDeclaration` sniff and possibly other, unreported bugs.
27+
- Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
28+
- Fixed bug [#504]: The tokenizer could inadvertently mistake the last parameter in a function call using named arguments for a DNF type.
29+
- Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
30+
- Fixed bug [#508]: Tokenizer/PHP: extra hardening against handling parse errors in the type handling layer.
31+
- Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
32+
33+
[#110]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/110
34+
[#437]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437
35+
[#475]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/475
36+
[#504]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/504
37+
[#508]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/508
38+
39+
## [3.10.0] - 2024-05-20
40+
41+
### Added
42+
- Tokenizer support for PHP 8.2 Disjunctive Normal Form (DNF) types. [#3731][sq-3731], [#387], [#461]
43+
- Includes new `T_TYPE_OPEN_PARENTHESIS` and `T_TYPE_CLOSE_PARENTHESIS` tokens to represent the parentheses in DNF types.
44+
- These new tokens, like other parentheses, will have the `parenthesis_opener` and `parenthesis_closer` token array indexes set and the tokens between them will have the `nested_parenthesis` index.
45+
- The `File::getMethodProperties()`, `File::getMethodParameters()` and `File::getMemberProperties()` methods now all support DNF types. [#471], [#472], [#473]
46+
- Additionally, the following sniff has been updated to support DNF types:
47+
- Generic.PHP.LowerCaseType [#478]
48+
- Thanks to [Juliette Reinders Folmer][@jrfnl] for the patches.
49+
- Documentation for the following sniffs:
50+
- Squiz.WhiteSpace.FunctionClosingBraceSpace
51+
- Thanks to [Przemek Hernik][@przemekhernik] for the patch.
52+
53+
### Changed
54+
- The help screens have received a face-lift for improved usability and readability. [#447]
55+
- Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch and thanks to [Colin Stewart][@costdev], [Gary Jones][@GaryJones] and [@mbomb007] for reviewing.
56+
- The Squiz.Commenting.ClosingDeclarationComment sniff will now also examine and flag closing comments for traits. [#442]
57+
- Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
58+
- The following sniff(s) have efficiency improvements:
59+
- Generic.Arrays.ArrayIndent
60+
- Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
61+
- The autoloader will now always return a boolean value indicating whether it has loaded a class or not. [#479]
62+
- Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
63+
- Various housekeeping, including improvements to the tests and documentation.
64+
- Thanks to [Dan Wallis][@fredden], [Danny van der Sluijs][@DannyvdSluijs], [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions.
65+
66+
### Fixed
67+
- Fixed bug [#466] : Generic.Functions.CallTimePassByReference was not flagging call-time pass-by-reference in class instantiations using the self/parent/static keywords.
68+
- Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
69+
- Fixed bug [#494] : edge case bug in tokenization of an empty block comment.
70+
- Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
71+
- Fixed bug [#494] : edge case bug in tokenization of an empty single-line DocBlock.
72+
- Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
73+
- Fixed bug [#499] : Generic.ControlStructures.InlineControlStructure now handles statements with a comment between `else` and `if` correctly.
74+
- Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
75+
76+
[sq-3731]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3731
77+
[#387]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/387
78+
[#442]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/442
79+
[#447]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/447
80+
[#461]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/461
81+
[#466]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/466
82+
[#471]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/471
83+
[#472]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/472
84+
[#473]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/473
85+
[#478]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/478
86+
[#479]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/479
87+
[#494]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/494
88+
[#499]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/499
89+
990
## [3.9.2] - 2024-04-24
1091

1192
### Changed
@@ -6883,6 +6964,8 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
68836964
-->
68846965

68856966
[Unreleased]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/master...HEAD
6967+
[3.10.1]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.10.0...3.10.1
6968+
[3.10.0]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.9.2...3.10.0
68866969
[3.9.2]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.9.1...3.9.2
68876970
[3.9.1]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.9.0...3.9.1
68886971
[3.9.0]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.8.1...3.9.0
@@ -7020,6 +7103,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
70207103
[@cixtor]: https://github.com/cixtor
70217104
[@claylo]: https://github.com/claylo
70227105
[@codebymikey]: https://github.com/codebymikey
7106+
[@costdev]: https://github.com/costdev
70237107
[@covex-nn]: https://github.com/covex-nn
70247108
[@cweiske]: https://github.com/cweiske
70257109
[@Daimona]: https://github.com/Daimona
@@ -7118,6 +7202,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
71187202
[@michaelbutler]: https://github.com/michaelbutler
71197203
[@michalbundyra]: https://github.com/michalbundyra
71207204
[@Morerice]: https://github.com/Morerice
7205+
[@mbomb007]: https://github.com/mbomb007
71217206
[@morozov]: https://github.com/morozov
71227207
[@mrkrstphr]: https://github.com/mrkrstphr
71237208
[@mythril]: https://github.com/mythril
@@ -7136,6 +7221,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
71367221
[@pfrenssen]: https://github.com/pfrenssen
71377222
[@phil-davis]: https://github.com/phil-davis
71387223
[@photodude]: https://github.com/photodude
7224+
[@przemekhernik]: https://github.com/przemekhernik
71397225
[@r3nat]: https://github.com/r3nat
71407226
[@raul338]: https://github.com/raul338
71417227
[@realmfoo]: https://github.com/realmfoo

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ php phpcbf.phar -h
4848
```
4949

5050
These Phars are signed with the official Release key for PHPCS with the
51-
fingerprint `95DE 904A B800 754A 11D8 0B60 5E6D DE99 8AB7 3B8E`.
51+
fingerprint `689D AD77 8FF0 8760 E046 228B A978 2203 05CD 5C32`.
5252

5353
### Composer
5454
If you use Composer, you can install PHP_CodeSniffer system-wide with the following command:
@@ -76,8 +76,8 @@ You will then be able to run PHP_CodeSniffer from the vendor bin directory:
7676
### Phive
7777
If you use Phive, you can install PHP_CodeSniffer as a project tool using the following commands:
7878
```bash
79-
phive install --trust-gpg-keys 95DE904AB800754A11D80B605E6DDE998AB73B8E phpcs
80-
phive install --trust-gpg-keys 95DE904AB800754A11D80B605E6DDE998AB73B8E phpcbf
79+
phive install --trust-gpg-keys 689DAD778FF08760E046228BA978220305CD5C32 phpcs
80+
phive install --trust-gpg-keys 689DAD778FF08760E046228BA978220305CD5C32 phpcbf
8181
```
8282
You will then be able to run PHP_CodeSniffer from the `tools` directory:
8383
```bash

phpcs.xml.dist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@
139139

140140
<!-- This test file specifically *needs* Windows line endings for testing purposes. -->
141141
<rule ref="Generic.Files.LineEndings.InvalidEOLChar">
142-
<exclude-pattern>tests/Core/Tokenizer/StableCommentWhitespaceWinTest\.php</exclude-pattern>
142+
<exclude-pattern>tests/Core/Tokenizer/PHP/StableCommentWhitespaceWinTest\.php</exclude-pattern>
143143
</rule>
144144

145145
<!-- Avoid false positive with this sniff detecting itself -->

src/Config.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class Config
8585
*
8686
* @var string
8787
*/
88-
const VERSION = '3.10.0';
88+
const VERSION = '3.10.2';
8989

9090
/**
9191
* Package stability; either stable, beta or alpha.

src/Files/File.php

Lines changed: 77 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2435,51 +2435,88 @@ public function findStartOfStatement($start, $ignore=null)
24352435
// If the start token is inside the case part of a match expression,
24362436
// find the start of the condition. If it's in the statement part, find
24372437
// the token that comes after the match arrow.
2438-
$matchExpression = $this->getCondition($start, T_MATCH);
2439-
if ($matchExpression !== false) {
2440-
for ($prevMatch = $start; $prevMatch > $this->tokens[$matchExpression]['scope_opener']; $prevMatch--) {
2441-
if ($prevMatch !== $start
2442-
&& ($this->tokens[$prevMatch]['code'] === T_MATCH_ARROW
2443-
|| $this->tokens[$prevMatch]['code'] === T_COMMA)
2444-
) {
2445-
break;
2446-
}
2438+
if (empty($this->tokens[$start]['conditions']) === false) {
2439+
$conditions = $this->tokens[$start]['conditions'];
2440+
$lastConditionOwner = end($conditions);
2441+
$matchExpression = key($conditions);
2442+
2443+
if ($lastConditionOwner === T_MATCH
2444+
// Check if the $start token is at the same parentheses nesting level as the match token.
2445+
&& ((empty($this->tokens[$matchExpression]['nested_parenthesis']) === true
2446+
&& empty($this->tokens[$start]['nested_parenthesis']) === true)
2447+
|| ((empty($this->tokens[$matchExpression]['nested_parenthesis']) === false
2448+
&& empty($this->tokens[$start]['nested_parenthesis']) === false)
2449+
&& $this->tokens[$matchExpression]['nested_parenthesis'] === $this->tokens[$start]['nested_parenthesis']))
2450+
) {
2451+
// Walk back to the previous match arrow (if it exists).
2452+
$lastComma = null;
2453+
$inNestedExpression = false;
2454+
for ($prevMatch = $start; $prevMatch > $this->tokens[$matchExpression]['scope_opener']; $prevMatch--) {
2455+
if ($prevMatch !== $start && $this->tokens[$prevMatch]['code'] === T_MATCH_ARROW) {
2456+
break;
2457+
}
24472458

2448-
// Skip nested statements.
2449-
if (isset($this->tokens[$prevMatch]['bracket_opener']) === true
2450-
&& $prevMatch === $this->tokens[$prevMatch]['bracket_closer']
2451-
) {
2452-
$prevMatch = $this->tokens[$prevMatch]['bracket_opener'];
2453-
} else if (isset($this->tokens[$prevMatch]['parenthesis_opener']) === true
2454-
&& $prevMatch === $this->tokens[$prevMatch]['parenthesis_closer']
2455-
) {
2456-
$prevMatch = $this->tokens[$prevMatch]['parenthesis_opener'];
2457-
}
2458-
}
2459+
if ($prevMatch !== $start && $this->tokens[$prevMatch]['code'] === T_COMMA) {
2460+
$lastComma = $prevMatch;
2461+
continue;
2462+
}
24592463

2460-
if ($prevMatch <= $this->tokens[$matchExpression]['scope_opener']) {
2461-
// We're before the arrow in the first case.
2462-
$next = $this->findNext(Tokens::$emptyTokens, ($this->tokens[$matchExpression]['scope_opener'] + 1), null, true);
2463-
if ($next === false) {
2464-
return $start;
2465-
}
2464+
// Skip nested statements.
2465+
if (isset($this->tokens[$prevMatch]['bracket_opener']) === true
2466+
&& $prevMatch === $this->tokens[$prevMatch]['bracket_closer']
2467+
) {
2468+
$prevMatch = $this->tokens[$prevMatch]['bracket_opener'];
2469+
continue;
2470+
}
24662471

2467-
return $next;
2468-
}
2472+
if (isset($this->tokens[$prevMatch]['parenthesis_opener']) === true
2473+
&& $prevMatch === $this->tokens[$prevMatch]['parenthesis_closer']
2474+
) {
2475+
$prevMatch = $this->tokens[$prevMatch]['parenthesis_opener'];
2476+
continue;
2477+
}
24692478

2470-
if ($this->tokens[$prevMatch]['code'] === T_COMMA) {
2471-
// We're before the arrow, but not in the first case.
2472-
$prevMatchArrow = $this->findPrevious(T_MATCH_ARROW, ($prevMatch - 1), $this->tokens[$matchExpression]['scope_opener']);
2473-
if ($prevMatchArrow === false) {
2474-
// We're before the arrow in the first case.
2475-
$next = $this->findNext(Tokens::$emptyTokens, ($this->tokens[$matchExpression]['scope_opener'] + 1), null, true);
2476-
return $next;
2477-
}
2479+
// Stop if we're _within_ a nested short array statement, which may contain comma's too.
2480+
// No need to deal with parentheses, those are handled above via the `nested_parenthesis` checks.
2481+
if (isset($this->tokens[$prevMatch]['bracket_opener']) === true
2482+
&& $this->tokens[$prevMatch]['bracket_closer'] > $start
2483+
) {
2484+
$inNestedExpression = true;
2485+
break;
2486+
}
2487+
}//end for
2488+
2489+
if ($inNestedExpression === false) {
2490+
// $prevMatch will now either be the scope opener or a match arrow.
2491+
// If it is the scope opener, go the first non-empty token after. $start will have been part of the first condition.
2492+
if ($prevMatch <= $this->tokens[$matchExpression]['scope_opener']) {
2493+
// We're before the arrow in the first case.
2494+
$next = $this->findNext(Tokens::$emptyTokens, ($this->tokens[$matchExpression]['scope_opener'] + 1), null, true);
2495+
if ($next === false) {
2496+
// Shouldn't be possible.
2497+
return $start;
2498+
}
24782499

2479-
$end = $this->findEndOfStatement($prevMatchArrow);
2480-
$next = $this->findNext(Tokens::$emptyTokens, ($end + 1), null, true);
2481-
return $next;
2482-
}
2500+
return $next;
2501+
}
2502+
2503+
// Okay, so we found a match arrow.
2504+
// If $start was part of the "next" condition, the last comma will be set.
2505+
// Otherwise, $start must have been part of a return expression.
2506+
if (isset($lastComma) === true && $lastComma > $prevMatch) {
2507+
$prevMatch = $lastComma;
2508+
}
2509+
2510+
// In both cases, go to the first non-empty token after.
2511+
$next = $this->findNext(Tokens::$emptyTokens, ($prevMatch + 1), null, true);
2512+
if ($next === false) {
2513+
// Shouldn't be possible.
2514+
return $start;
2515+
}
2516+
2517+
return $next;
2518+
}//end if
2519+
}//end if
24832520
}//end if
24842521

24852522
$lastNotEmpty = $start;

0 commit comments

Comments
 (0)