Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a439463

Browse filesBrowse files
committed
Implement rule from #105
1 parent fde7fc5 commit a439463
Copy full SHA for a439463
Expand file treeCollapse file tree

31 files changed

+441
-102
lines changed
+121Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<?php
2+
3+
/**
4+
* Copyright © Magento. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
namespace Magento2\Sniffs\Commenting;
8+
9+
use PHP_CodeSniffer\Sniffs\Sniff;
10+
use PHP_CodeSniffer\Files\File;
11+
12+
/**
13+
* Detects PHPDoc formatting for classes and interfaces.
14+
*/
15+
class ClassAndInterfacePHPDocFormattingSniff implements Sniff
16+
{
17+
/**
18+
* @var PHPDocFormattingValidator
19+
*/
20+
private $PHPDocFormattingValidator;
21+
22+
/**
23+
* @var string[] List of tags that can not be used in comments
24+
*/
25+
public $forbiddenTags = [
26+
'@category',
27+
'@package',
28+
'@subpackage'
29+
];
30+
31+
/**
32+
* Helper initialisation
33+
*/
34+
public function __construct()
35+
{
36+
$this->PHPDocFormattingValidator = new PHPDocFormattingValidator();
37+
}
38+
39+
/**
40+
* @inheritDoc
41+
*/
42+
public function register()
43+
{
44+
return [
45+
T_CLASS,
46+
T_INTERFACE
47+
];
48+
}
49+
50+
/**
51+
* @inheritDoc
52+
*/
53+
public function process(File $phpcsFile, $stackPtr)
54+
{
55+
$tokens = $phpcsFile->getTokens();
56+
57+
$namePtr = $phpcsFile->findNext(T_STRING, $stackPtr + 1, null, false, null, true);
58+
59+
$commentStartPtr = $phpcsFile->findPrevious(
60+
[
61+
T_WHITESPACE,
62+
T_DOC_COMMENT_STAR,
63+
T_DOC_COMMENT_WHITESPACE,
64+
T_DOC_COMMENT_TAG,
65+
T_DOC_COMMENT_STRING,
66+
T_DOC_COMMENT_CLOSE_TAG
67+
],
68+
$stackPtr - 1,
69+
null,
70+
true,
71+
null,
72+
true
73+
);
74+
75+
if ($tokens[$commentStartPtr]['code'] !== T_DOC_COMMENT_OPEN_TAG) {
76+
return;
77+
}
78+
79+
if ($this->PHPDocFormattingValidator->providesMeaning($namePtr, $commentStartPtr, $tokens) !== true) {
80+
$phpcsFile->addWarning(
81+
sprintf(
82+
'%s description should contain additional information beyond the name already supplies.',
83+
ucfirst($tokens[$stackPtr]['content'])
84+
),
85+
$stackPtr,
86+
'InvalidDescription'
87+
);
88+
}
89+
90+
$this->validateTags($phpcsFile, $commentStartPtr, $tokens);
91+
}
92+
93+
/**
94+
* Validates that forbidden tags are not used in comment
95+
*
96+
* @param File $phpcsFile
97+
* @param int $commentStartPtr
98+
* @param array $tokens
99+
* @return bool
100+
*/
101+
private function validateTags(File $phpcsFile, $commentStartPtr, $tokens)
102+
{
103+
$commentCloserPtr = $tokens[$commentStartPtr]['comment_closer'];
104+
105+
for ($i = $commentStartPtr; $i <= $commentCloserPtr; $i++) {
106+
if ($tokens[$i]['code'] !== T_DOC_COMMENT_TAG) {
107+
continue;
108+
}
109+
110+
if (in_array($tokens[$i]['content'], $this->forbiddenTags) === true) {
111+
$phpcsFile->addWarning(
112+
sprintf('Tag %s MUST NOT be used.', $tokens[$i]['content']),
113+
$i,
114+
'ForbiddenTags'
115+
);
116+
}
117+
}
118+
119+
return false;
120+
}
121+
}

‎Magento2/Sniffs/Commenting/ConstantsPHPDocFormattingSniff.php

Copy file name to clipboardExpand all lines: Magento2/Sniffs/Commenting/ConstantsPHPDocFormattingSniff.php
+19-30Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@
1313
*/
1414
class ConstantsPHPDocFormattingSniff implements Sniff
1515
{
16+
/**
17+
* @var PHPDocFormattingValidator
18+
*/
19+
private $PHPDocFormattingValidator;
20+
21+
/**
22+
* Helper initialisation
23+
*/
24+
public function __construct()
25+
{
26+
$this->PHPDocFormattingValidator = new PHPDocFormattingValidator();
27+
}
28+
1629
/**
1730
* @inheritDoc
1831
*/
@@ -45,42 +58,18 @@ public function process(File $phpcsFile, $stackPtr)
4558
null,
4659
true
4760
);
48-
$constName = strtolower(trim($tokens[$constNamePtr]['content'], " '\""));
4961

5062
$commentStartPtr = $phpcsFile->findPrevious(T_DOC_COMMENT_OPEN_TAG, $stackPtr - 1, null, false, null, true);
5163
if ($commentStartPtr === false) {
5264
return;
5365
}
5466

55-
$commentCloserPtr = $tokens[$commentStartPtr]['comment_closer'];
56-
for ($i = $commentStartPtr; $i <= $commentCloserPtr; $i++) {
57-
$token = $tokens[$i];
58-
59-
// Not an interesting string
60-
if ($token['code'] !== T_DOC_COMMENT_STRING) {
61-
continue;
62-
}
63-
64-
// Comment is the same as constant name
65-
$docComment = trim(strtolower($token['content']), ',.');
66-
if ($docComment === $constName) {
67-
continue;
68-
}
69-
70-
// Comment is exactly the same as constant name
71-
$docComment = str_replace(' ', '_', $docComment);
72-
if ($docComment === $constName) {
73-
continue;
74-
}
75-
76-
// We have found at lease one meaningful line in comment description
77-
return;
67+
if ($this->PHPDocFormattingValidator->providesMeaning($constNamePtr, $commentStartPtr, $tokens) !== true) {
68+
$phpcsFile->addWarning(
69+
'Constants must have short description if they add information beyond what the constant name supplies.',
70+
$stackPtr,
71+
'MissingConstantPHPDoc'
72+
);
7873
}
79-
80-
$phpcsFile->addWarning(
81-
'Constants must have short description if they add information beyond what the constant name supplies.',
82-
$stackPtr,
83-
'MissingConstantPHPDoc'
84-
);
8574
}
8675
}
+74Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
/**
4+
* Copyright © Magento. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
namespace Magento2\Sniffs\Commenting;
8+
9+
/**
10+
* Helper class for common DocBlock validations
11+
*/
12+
class PHPDocFormattingValidator
13+
{
14+
/**
15+
* Determines if the comment identified by $commentStartPtr provides additional meaning to origin at $namePtr
16+
*
17+
* @param int $namePtr
18+
* @param int $commentStartPtr
19+
* @param array $tokens
20+
* @return bool
21+
*/
22+
public function providesMeaning($namePtr, $commentStartPtr, $tokens)
23+
{
24+
$commentCloserPtr = $tokens[$commentStartPtr]['comment_closer'];
25+
$name = strtolower(str_replace([' ', '"', '_'], '', $tokens[$namePtr]['content']));
26+
27+
$hasTags = false;
28+
$hasDescription = false;
29+
30+
for ($i = $commentStartPtr; $i <= $commentCloserPtr; $i++) {
31+
$token = $tokens[$i];
32+
33+
// Important, but not the string we are looking for
34+
if ($token['code'] === T_DOC_COMMENT_TAG) {
35+
$hasTags = true;
36+
continue;
37+
}
38+
39+
// Not an interesting string
40+
if ($token['code'] !== T_DOC_COMMENT_STRING) {
41+
continue;
42+
}
43+
44+
// Wrong kind of string
45+
if ($tokens[$i - 2]['code'] === T_DOC_COMMENT_TAG) {
46+
continue;
47+
}
48+
49+
$hasDescription = true;
50+
51+
// Comment is the same as the origin name
52+
$docComment = str_replace(['_', ' ', '.', ','], '', strtolower($token['content']));
53+
if ($docComment === $name) {
54+
continue;
55+
}
56+
57+
// Only difference is word Class or Interface
58+
$docComment = str_replace(['class', 'interface'], '', $docComment);
59+
if ($docComment === $name) {
60+
continue;
61+
}
62+
63+
// We have found at lease one meaningful line in comment description
64+
return true;
65+
}
66+
67+
// Contains nothing but the tags
68+
if ($hasTags === true && $hasDescription === false) {
69+
return true;
70+
}
71+
72+
return false;
73+
}
74+
}

‎Magento2/Tests/CodeAnalysis/EmptyBlockUnitTest.php

Copy file name to clipboardExpand all lines: Magento2/Tests/CodeAnalysis/EmptyBlockUnitTest.php
-3Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77

88
use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest;
99

10-
/**
11-
* Class EmptyBlockUnitTest
12-
*/
1310
class EmptyBlockUnitTest extends AbstractSniffUnitTest
1411
{
1512
/**
+93Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
/**
4+
* Handler for PHP errors/warnings/notices that converts them to exceptions.
5+
*/
6+
class ErrorHandler
7+
{
8+
9+
}
10+
11+
class NotAnErrorHandler
12+
{
13+
14+
}
15+
16+
/**
17+
* Faulty Handler
18+
*/
19+
class FaultyHandler
20+
{
21+
22+
}
23+
24+
/**
25+
* Class SomeHandler
26+
*/
27+
class SomeHandler
28+
{
29+
30+
}
31+
32+
/**
33+
* YetAnotherHandler
34+
*/
35+
class YetAnotherHandler
36+
{
37+
38+
}
39+
40+
/**
41+
* GreenHandler
42+
* @api Do not confuse tag for faulty short description
43+
*/
44+
class GreenHandler
45+
{
46+
47+
}
48+
49+
/**
50+
*
51+
*/
52+
class EmptyHandler
53+
{
54+
55+
}
56+
57+
/**
58+
* Handler for PHP errors/warnings/notices that converts them to exceptions.
59+
*
60+
* @api is ok here
61+
* @deprecated can be used in this context
62+
* @author is actually ok
63+
* @category is irrelevant
64+
* @package is not ment to be used
65+
* @subpackage does not belong here
66+
*/
67+
class ExampleHandler
68+
{
69+
70+
}
71+
72+
/**
73+
* @api
74+
* @since 100.0.2
75+
*/
76+
class ApiHandler
77+
{
78+
79+
}
80+
81+
/**
82+
* @api
83+
*/
84+
class AsyncApiHandler
85+
{
86+
87+
}
88+
89+
/**
90+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
91+
*/
92+
class GroupRepositoryHandler
93+
{}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.