Skip to content

Commit ccf8482

Browse files
committed
Merge branch 'master' into 3.x-dev
2 parents a00428d + bcd5ae7 commit ccf8482

24 files changed

+1134
-354
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ phpunit.xml
99
.settings
1010
.DS_Store
1111
.idea
12-
.vscode
12+
.vscode

.travis.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ matrix:
1717
- php: 7.0
1818
- php: 7.1
1919
- php: 7.2
20+
- php: 7.3
21+
- php: 7.4
2022
- php: nightly
2123
allow_failures:
22-
- php: 7.2
24+
- php: 7.4
2325
- php: nightly
2426

2527
before_script:

Joomla/ExampleRulesets/Joomla-CMS/ruleset.xml

Lines changed: 423 additions & 25 deletions
Large diffs are not rendered by default.

Joomla/Sniffs/Commenting/FunctionCommentSniff.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ protected function processReturn(File $phpcsFile, $stackPtr, $commentStart)
147147
{
148148
if ($tokens[$returnToken]['code'] === T_CLOSURE
149149
|| $tokens[$returnToken]['code'] === T_ANON_CLASS
150-
)
150+
)
151151
{
152152
$returnToken = $tokens[$returnToken]['scope_closer'];
153153
continue;
@@ -156,7 +156,7 @@ protected function processReturn(File $phpcsFile, $stackPtr, $commentStart)
156156
if ($tokens[$returnToken]['code'] === T_RETURN
157157
|| $tokens[$returnToken]['code'] === T_YIELD
158158
|| $tokens[$returnToken]['code'] === T_YIELD_FROM
159-
)
159+
)
160160
{
161161
break;
162162
}
@@ -186,7 +186,7 @@ protected function processReturn(File $phpcsFile, $stackPtr, $commentStart)
186186
{
187187
if ($tokens[$returnToken]['code'] === T_CLOSURE
188188
|| $tokens[$returnToken]['code'] === T_ANON_CLASS
189-
)
189+
)
190190
{
191191
$returnToken = $tokens[$returnToken]['scope_closer'];
192192
continue;
@@ -195,7 +195,7 @@ protected function processReturn(File $phpcsFile, $stackPtr, $commentStart)
195195
if ($tokens[$returnToken]['code'] === T_RETURN
196196
|| $tokens[$returnToken]['code'] === T_YIELD
197197
|| $tokens[$returnToken]['code'] === T_YIELD_FROM
198-
)
198+
)
199199
{
200200
break;
201201
}

Joomla/Sniffs/ControlStructures/ControlStructuresBracketsSniff.php

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,17 +177,51 @@ public function process(File $phpcsFile, $stackPtr)
177177
}
178178
}
179179

180-
// Anonymous classes and functions set the indent at one plus their own indent level.
181-
if ($phpcsFile->hasCondition($stackPtr, T_CLOSURE) === true
182-
|| $phpcsFile->hasCondition($stackPtr, T_ANON_CLASS) === true)
183-
{
184-
$expected = ($tokens[$stackPtr]['level'] + 1) * $this->indent;
185-
}
186-
else
180+
$baseLevel = $tokens[$stackPtr]['level'];
181+
182+
/**
183+
* Take into account any nested parenthesis that don't contribute to the level (often required for
184+
* closures and anonymous classes
185+
*/
186+
if (array_key_exists('nested_parenthesis', $tokens[$stackPtr]) === true)
187187
{
188-
$expected = $tokens[$stackPtr]['level'] * $this->indent;
188+
$nestedStructures = $tokens[$stackPtr]['nested_parenthesis'];
189+
$nestedCount = 0;
190+
191+
foreach ($nestedStructures as $start => $end)
192+
{
193+
/**
194+
* Crude way of checking for a chained method which requires an extra indent. We navigate to the open
195+
* parenthesis of the nested structure. The element before that is the function name. Before that we
196+
* check for an operator (->) and a whitespace before it (which makes it a chained method on a new line)
197+
* TODO: Is there a better way to check for a chained method? This feels very dirty!
198+
*/
199+
if ($tokens[$start - 2]['type'] === 'T_OBJECT_OPERATOR' && $tokens[$start - 3]['type'] === 'T_WHITESPACE')
200+
{
201+
/**
202+
* If we have an anonymous function/class on the same line as our chained method then we
203+
* balance out so only increase the count by 1. Else by 2.
204+
*/
205+
if ($tokens[$start + 1]['type'] === 'T_CLOSURE' || $tokens[$start + 1]['type'] === 'T_ANON_CLASS')
206+
{
207+
$nestedCount++;
208+
}
209+
else
210+
{
211+
$nestedCount += 2;
212+
}
213+
}
214+
else
215+
{
216+
$nestedCount++;
217+
}
218+
}
219+
220+
$baseLevel += $nestedCount;
189221
}
190222

223+
$expected = $baseLevel * $this->indent;
224+
191225
// We need to divide by 4 here since there is a space vs tab intent in the check vs token
192226
$expected /= $this->indent;
193227
$spaces /= $this->indent;

Joomla/Tests/ControlStructures/ControlStructuresBracketsUnitTest.inc

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,141 @@ $this->attachRule(
168168
}
169169
}
170170
);
171+
172+
// Round 2 Closure indentation tests
173+
$i = 1;
174+
$func = function ($match) use ($query, $args, &$i)
175+
{
176+
if (isset($match[6]) && $match[6] === '%')
177+
{
178+
return '%';
179+
}
180+
// No argument required, do not increment the argument index.
181+
switch ($match[5])
182+
{
183+
case 't':
184+
return $query->currentTimestamp();
185+
break;
186+
case 'z':
187+
if (true)
188+
{
189+
return $query->nullDate(true);
190+
}
191+
return $query->nullDate(false);
192+
break;
193+
case 'Z':
194+
return $query->nullDate(true);
195+
break;
196+
}
197+
};
198+
199+
class Foo
200+
{
201+
public function format($format)
202+
{
203+
$query = $this;
204+
$args = \array_slice(\func_get_args(), 1);
205+
array_unshift($args, null);
206+
207+
$i = 1;
208+
$func = function ($match) use ($query, $args, &$i) {
209+
if (isset($match[6]) && $match[6] === '%')
210+
{
211+
return '%';
212+
}
213+
214+
};
215+
}
216+
}
217+
218+
// Anonymous classes test
219+
$this->attachRule(
220+
new class($this) implements RulesInterface
221+
{
222+
public function parse(&$segments, &$vars)
223+
{
224+
// Move forward based on view
225+
switch ($segments)
226+
{
227+
case 'tracker':
228+
usort(
229+
$view,
230+
function($a, $b) use ($vars)
231+
{
232+
$ordering = $vars->getState('list.ordering');
233+
234+
if (strtolower($vars->getState('list.direction')) === 'asc')
235+
{
236+
return StringHelper::strcmp($a->$ordering, $b->$ordering);
237+
}
238+
else
239+
{
240+
return StringHelper::strcmp($b->$ordering, $a->$ordering);
241+
}
242+
}
243+
);
244+
break;
245+
}
246+
247+
return;
248+
}
249+
}
250+
);
251+
252+
class Application
253+
{
254+
public function doThings($container)
255+
{
256+
$container->alias(MyClass::class, 'MyClass')
257+
->share(
258+
'MyClass',
259+
function (Container $container) {
260+
doThing();
261+
262+
if ($thing)
263+
{
264+
bar();
265+
}
266+
267+
return foo();
268+
},
269+
true
270+
);
271+
}
272+
}
273+
274+
class Application
275+
{
276+
public function doThings($container)
277+
{
278+
$container->share(
279+
'MyClass',
280+
function (Container $container) {
281+
doThing();
282+
283+
if ($thing)
284+
{
285+
bar();
286+
}
287+
else {
288+
something();
289+
290+
if (somethingelse())
291+
{
292+
bar();
293+
}
294+
295+
anotherFunction()
296+
->withNested(function() {
297+
if ($foo){
298+
bar();
299+
}
300+
});
301+
302+
return foo();
303+
}
304+
},
305+
true
306+
);
307+
}
308+
}

0 commit comments

Comments
 (0)