1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org) |
4
|
|
|
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) |
5
|
|
|
* |
6
|
|
|
* Licensed under The MIT License |
7
|
|
|
* For full copyright and license information, please see the LICENSE.txt |
8
|
|
|
* Redistributions of files must retain the above copyright notice. |
9
|
|
|
* |
10
|
|
|
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) |
11
|
|
|
* @link http://pear.php.net/package/PHP_CodeSniffer_CakePHP |
12
|
|
|
* @since CakePHP CodeSniffer 1.0.0 |
13
|
|
|
* @license http://www.opensource.org/licenses/mit-license.php MIT License |
14
|
|
|
*/ |
15
|
|
|
|
16
|
|
|
namespace PSR2R\Sniffs\WhiteSpace; |
17
|
|
|
|
18
|
|
|
use PHP_CodeSniffer_File; |
19
|
|
|
use PSR2R\Tools\AbstractSniff; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Ensures doc block alignment with its code. |
23
|
|
|
* |
24
|
|
|
* @author Mark Scherer |
25
|
|
|
* @license MIT |
26
|
|
|
*/ |
27
|
|
|
class DocBlockAlignmentSniff extends AbstractSniff { |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @inheritDoc |
31
|
|
|
*/ |
32
|
|
|
public function register() { |
33
|
|
|
return [T_DOC_COMMENT_OPEN_TAG]; |
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @inheritDoc |
38
|
|
|
*/ |
39
|
|
|
public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { |
40
|
|
|
$tokens = $phpcsFile->getTokens(); |
41
|
|
|
$leftWall = [ |
42
|
|
|
T_CLASS, |
43
|
|
|
T_NAMESPACE, |
44
|
|
|
T_INTERFACE, |
45
|
|
|
T_TRAIT, |
46
|
|
|
T_USE |
47
|
|
|
]; |
48
|
|
|
$oneIndentation = [ |
49
|
|
|
T_FUNCTION, |
50
|
|
|
T_VARIABLE, |
51
|
|
|
T_CONST |
52
|
|
|
]; |
53
|
|
|
$allTokens = array_merge($leftWall, $oneIndentation); |
54
|
|
|
$isNotFlatFile = $phpcsFile->findNext(T_NAMESPACE, 0); |
55
|
|
|
$nextIndex = $phpcsFile->findNext($allTokens, $stackPtr + 1); |
56
|
|
|
|
57
|
|
|
$expectedColumn = $tokens[$nextIndex]['column']; |
58
|
|
|
$firstNonWhitespaceIndex = $this->findFirstNonWhitespaceInLine($phpcsFile, $nextIndex); |
|
|
|
|
59
|
|
|
if ($firstNonWhitespaceIndex) { |
|
|
|
|
60
|
|
|
$expectedColumn = $tokens[$firstNonWhitespaceIndex]['column']; |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
// We should allow for tabs and spaces |
64
|
|
|
$expectedColumnAdjusted = $expectedColumn; |
65
|
|
|
if ($expectedColumn === 2) { |
66
|
|
|
$expectedColumnAdjusted = 5; |
67
|
|
|
} elseif ($expectedColumn === 5) { |
68
|
|
|
$expectedColumnAdjusted = 2; |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
if ($nextIndex) { |
|
|
|
|
72
|
|
|
$isNotWalled = (in_array($tokens[$nextIndex]['code'], $leftWall) && $tokens[$stackPtr]['column'] !== 1); |
73
|
|
|
$isNotIndented = false; |
74
|
|
|
if ($isNotFlatFile) { |
|
|
|
|
75
|
|
|
$isNotIndented = (in_array($tokens[$nextIndex]['code'], $oneIndentation) && $tokens[$stackPtr]['column'] !== $expectedColumn && $tokens[$stackPtr]['column'] !== $expectedColumnAdjusted); |
76
|
|
|
} |
77
|
|
|
if ($isNotWalled || $isNotIndented) { |
78
|
|
|
$fix = $phpcsFile->addFixableError('Expected docblock to be aligned with code.', $stackPtr, 'NotAllowed'); |
79
|
|
|
if ($fix) { |
80
|
|
|
$docBlockEndIndex = $tokens[$stackPtr]['comment_closer']; |
81
|
|
|
|
82
|
|
|
if ($isNotWalled) { |
83
|
|
|
$prevIndex = $stackPtr - 1; |
84
|
|
|
if ($tokens[$prevIndex]['code'] !== T_WHITESPACE) { |
85
|
|
|
return; |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
$phpcsFile->fixer->beginChangeset(); |
89
|
|
|
|
90
|
|
|
$this->outdent($phpcsFile, $prevIndex); |
91
|
|
|
|
92
|
|
|
for ($i = $stackPtr; $i <= $docBlockEndIndex; $i++) { |
93
|
|
View Code Duplication |
if (!$this->isGivenKind(T_DOC_COMMENT_WHITESPACE, $tokens[$i]) || $tokens[$i]['column'] !== 1) { |
|
|
|
|
94
|
|
|
continue; |
95
|
|
|
} |
96
|
|
|
$this->outdent($phpcsFile, $i); |
97
|
|
|
} |
98
|
|
|
$phpcsFile->fixer->endChangeset(); |
99
|
|
|
return; |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
if ($isNotIndented) { |
103
|
|
|
// + means too much indentation (we need to outdend), - means not enough indentation (needs indenting) |
104
|
|
|
if ($tokens[$stackPtr]['column'] < $expectedColumnAdjusted) { |
105
|
|
|
$diff = $tokens[$stackPtr]['column'] - $expectedColumn; |
106
|
|
|
} else { |
107
|
|
|
$diff = ($tokens[$stackPtr]['column'] - $expectedColumnAdjusted) / 4; |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
$phpcsFile->fixer->beginChangeset(); |
111
|
|
|
|
112
|
|
|
$prevIndex = $stackPtr - 1; |
113
|
|
|
if ($diff < 0 && $tokens[$prevIndex]['line'] !== $tokens[$stackPtr]['line']) { |
114
|
|
|
$phpcsFile->fixer->addContentBefore($stackPtr, str_repeat("\t", -$diff)); |
115
|
|
|
} else { |
116
|
|
|
$this->outdent($phpcsFile, $prevIndex); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
for ($i = $stackPtr; $i <= $docBlockEndIndex; $i++) { |
120
|
|
View Code Duplication |
if (!$this->isGivenKind(T_DOC_COMMENT_WHITESPACE, $tokens[$i]) || $tokens[$i]['column'] !== 1) { |
|
|
|
|
121
|
|
|
continue; |
122
|
|
|
} |
123
|
|
|
if ($diff < 0) { |
124
|
|
|
$this->indent($phpcsFile, $i, -$diff); |
125
|
|
|
} else { |
126
|
|
|
$this->outdent($phpcsFile, $i, $diff); |
127
|
|
|
} |
128
|
|
|
} |
129
|
|
|
$phpcsFile->fixer->endChangeset(); |
130
|
|
|
} |
131
|
|
|
} |
132
|
|
|
} |
133
|
|
|
} |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* @param \PHP_CodeSniffer_File $phpcsFile |
138
|
|
|
* @param int $index |
139
|
|
|
* @return int|null |
140
|
|
|
*/ |
141
|
|
|
protected function findFirstNonWhitespaceInLine(PHP_CodeSniffer_File $phpcsFile, $index) { |
142
|
|
|
$tokens = $phpcsFile->getTokens(); |
143
|
|
|
|
144
|
|
|
$firstIndex = $index; |
145
|
|
|
while (!empty($tokens[$firstIndex - 1]) && $tokens[$firstIndex - 1]['line'] === $tokens[$index]['line']) { |
146
|
|
|
$firstIndex--; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
return $phpcsFile->findNext(T_WHITESPACE, $firstIndex, $index, true); |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
} |
153
|
|
|
|
This check looks for type mismatches where the missing type is
false
. This is usually indicative of an error condtion.Consider the follow example
This function either returns a new
DateTime
object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returnedfalse
before passing on the value to another function or method that may not be able to handle afalse
.