@@ -28,34 +28,84 @@ class Symfony3Custom_Sniffs_Commenting_FunctionCommentSniff extends PEAR_Sniffs_
28
28
*/
29
29
public function process (PHP_CodeSniffer_File $ phpcsFile , $ stackPtr )
30
30
{
31
- if (false === $ commentEnd = $ phpcsFile ->findPrevious (
32
- array (
33
- T_COMMENT ,
34
- T_DOC_COMMENT ,
35
- T_CLASS ,
36
- T_FUNCTION ,
37
- T_OPEN_TAG ,
38
- ),
39
- ($ stackPtr - 1 )
40
- )
31
+ $ tokens = $ phpcsFile ->getTokens ();
32
+ $ find = PHP_CodeSniffer_Tokens::$ methodPrefixes ;
33
+ $ find [] = T_WHITESPACE ;
34
+
35
+ $ commentEnd = $ phpcsFile ->findPrevious ($ find , ($ stackPtr - 1 ), null , true );
36
+ if ($ tokens [$ commentEnd ]['code ' ] === T_COMMENT ) {
37
+ // Inline comments might just be closing comments for
38
+ // control structures or functions instead of function comments
39
+ // using the wrong comment type. If there is other code on the line,
40
+ // assume they relate to that code.
41
+ $ prev = $ phpcsFile ->findPrevious ($ find , ($ commentEnd - 1 ), null , true );
42
+ if ($ prev !== false && $ tokens [$ prev ]['line ' ] === $ tokens [$ commentEnd ]['line ' ]) {
43
+ $ commentEnd = $ prev ;
44
+ }
45
+ }
46
+
47
+ $ name = $ phpcsFile ->getDeclarationName ($ stackPtr );
48
+ $ commentRequired = strpos ($ name , 'test ' ) !== 0
49
+ && $ name !== 'setUp '
50
+ && $ name !== 'tearDown ' ;
51
+
52
+ if ($ tokens [$ commentEnd ]['code ' ] !== T_DOC_COMMENT_CLOSE_TAG
53
+ && $ tokens [$ commentEnd ]['code ' ] !== T_COMMENT
41
54
) {
42
- return ;
55
+ $ hasComment = false ;
56
+ $ phpcsFile ->recordMetric ($ stackPtr , 'Function has doc comment ' , 'no ' );
57
+
58
+ if ($ commentRequired ) {
59
+ $ phpcsFile ->addError ('Missing function doc comment ' , $ stackPtr , 'Missing ' );
60
+ return ;
61
+ } else {
62
+ // The comment may not be required, we'll see in next checks
63
+ }
64
+ } else {
65
+ $ hasComment = true ;
66
+ $ phpcsFile ->recordMetric ($ stackPtr , 'Function has doc comment ' , 'yes ' );
43
67
}
44
68
45
- $ tokens = $ phpcsFile ->getTokens ();
46
- $ code = $ tokens [$ commentEnd ]['code ' ];
69
+ $ commentStart = null ;
70
+ if ($ hasComment ) {
71
+ if ($ tokens [$ commentEnd ]['code ' ] === T_COMMENT ) {
72
+ $ phpcsFile ->addError ('You must use "/**" style comments for a function comment ' , $ stackPtr , 'WrongStyle ' );
47
73
48
- $ name = $ phpcsFile ->getDeclarationName ($ stackPtr );
74
+ return ;
75
+ }
49
76
50
- $ commentRequired = strpos ($ name , 'test ' ) !== 0 && $ name !== 'setUp ' && $ name !== 'tearDown ' ;
77
+ if ($ tokens [$ commentEnd ]['line ' ] !== ($ tokens [$ stackPtr ]['line ' ] - 1 )) {
78
+ $ error = 'There must be no blank lines after the function comment ' ;
79
+ $ phpcsFile ->addError ($ error , $ commentEnd , 'SpacingAfter ' );
80
+ }
51
81
52
- if (($ code === T_COMMENT && !$ commentRequired )
53
- || ($ code !== T_DOC_COMMENT && !$ commentRequired )
54
- ) {
55
- return ;
82
+ $ commentStart = $ tokens [$ commentEnd ]['comment_opener ' ];
83
+ foreach ($ tokens [$ commentStart ]['comment_tags ' ] as $ tag ) {
84
+ if ($ tokens [$ tag ]['content ' ] === '@see ' ) {
85
+ // Make sure the tag isn't empty.
86
+ $ string = $ phpcsFile ->findNext (T_DOC_COMMENT_STRING , $ tag , $ commentEnd );
87
+ if ($ string === false || $ tokens [$ string ]['line ' ] !== $ tokens [$ tag ]['line ' ]) {
88
+ $ error = 'Content missing for @see tag in function comment ' ;
89
+ $ phpcsFile ->addError ($ error , $ tag , 'EmptySees ' );
90
+ }
91
+ }
92
+ }
56
93
}
57
94
58
- parent ::process ($ phpcsFile , $ stackPtr );
95
+ $ this ->processReturn ($ phpcsFile , $ stackPtr , $ commentStart );
96
+
97
+ $ realParams = $ phpcsFile ->getMethodParameters ($ stackPtr );
98
+ if ($ hasComment ) {
99
+ // These checks need function comment
100
+ $ this ->processParams ($ phpcsFile , $ stackPtr , $ commentStart );
101
+ $ this ->processThrows ($ phpcsFile , $ stackPtr , $ commentStart );
102
+ } elseif (count ($ realParams ) > 0 ) {
103
+ foreach ($ realParams as $ neededParam ) {
104
+ $ error = 'Doc comment for parameter "%s" missing ' ;
105
+ $ data = array ($ neededParam ['name ' ]);
106
+ $ phpcsFile ->addError ($ error , $ stackPtr , 'MissingParamTag ' , $ data );
107
+ }
108
+ }
59
109
}
60
110
61
111
/**
@@ -64,7 +114,7 @@ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
64
114
* @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
65
115
* @param int $stackPtr The position of the current token
66
116
* in the stack passed in $tokens.
67
- * @param int $commentStart The position in the stack
117
+ * @param int|null $commentStart The position in the stack
68
118
* where the comment started.
69
119
*
70
120
* @return void
@@ -74,8 +124,10 @@ protected function processReturn(
74
124
$ stackPtr ,
75
125
$ commentStart
76
126
) {
77
-
78
- if ($ this ->isInheritDoc ($ phpcsFile , $ stackPtr )) {
127
+ // Check for inheritDoc if there is comment
128
+ if ((null !== $ commentStart )
129
+ && $ this ->isInheritDoc ($ phpcsFile , $ stackPtr )
130
+ ) {
79
131
return ;
80
132
}
81
133
@@ -102,7 +154,15 @@ protected function processReturn(
102
154
if ($ tokens [$ i ]['code ' ] === T_RETURN
103
155
&& $ this ->isMatchingReturn ($ tokens , $ i )
104
156
) {
105
- parent ::processReturn ($ phpcsFile , $ stackPtr , $ commentStart );
157
+ if (null !== $ commentStart ) {
158
+ parent ::processReturn ($ phpcsFile , $ stackPtr , $ commentStart );
159
+ } else {
160
+ // There is no doc and we need one with @return
161
+ $ error = 'Missing @return tag in function comment ' ;
162
+ $ phpcsFile ->addError ($ error , $ stackPtr , 'MissingReturn ' );
163
+
164
+ }
165
+
106
166
break ;
107
167
}
108
168
}
0 commit comments