Skip to content

Commit

Permalink
WIP: Missing docblocks for #[\Override]
Browse files Browse the repository at this point in the history
Fixes #155

POC
  • Loading branch information
andrewnicols committed Apr 23, 2024
1 parent 02a279e commit 9d2c0dc
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
The format of this change log follows the advice given at [Keep a CHANGELOG](https://keepachangelog.com).

## [Unreleased]
### Chagned
- The `moodle.Commenting.MissingDocblock` sniff will now detect use of the Override attribute (Fixes #155).

## [v3.4.6] - 2024-04-03
### Fixed
Expand Down
18 changes: 16 additions & 2 deletions moodle/Sniffs/Commenting/MissingDocblockSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

namespace MoodleHQ\MoodleCS\moodle\Sniffs\Commenting;

use MoodleHQ\MoodleCS\moodle\Util\Attributes;
use MoodleHQ\MoodleCS\moodle\Util\Docblocks;
use MoodleHQ\MoodleCS\moodle\Util\MoodleUtil;
use MoodleHQ\MoodleCS\moodle\Util\TokenUtil;
Expand Down Expand Up @@ -183,6 +184,19 @@ protected function processFunctions(File $phpcsFile, int $stackPtr): void {

foreach ($missingDocblocks as $typePtr => $extendsOrImplements) {
$token = $tokens[$typePtr];
$useWarning = $extendsOrImplements;
if ($extendsOrImplements) {
$attributes = Attributes::getAttributePointers($phpcsFile, $typePtr);
foreach ($attributes as $attributePtr) {
$attribute = Attributes::getAttributeProperties($phpcsFile, $attributePtr);
if ($attribute['attribute_name'] === '\Override') {
// Skip methods that are marked as overrides.
continue 2;
}
}
$useWarning = false;
}

$objectName = TokenUtil::getObjectName($phpcsFile, $typePtr);
$objectType = TokenUtil::getObjectType($phpcsFile, $typePtr);

Expand All @@ -195,7 +209,7 @@ protected function processFunctions(File $phpcsFile, int $stackPtr): void {
[$objectType, $objectName]
);
}
} elseif ($extendsOrImplements) {
} elseif ($useWarning) {
$phpcsFile->addWarning('Missing docblock for %s %s', $typePtr, 'Missing', [$objectType, $objectName]);
} else {
$phpcsFile->addError('Missing docblock for %s %s', $typePtr, 'Missing', [$objectType, $objectName]);
Expand Down Expand Up @@ -257,5 +271,5 @@ protected function processConstants(File $phpcsFile, int $stackPtr): void {
);
}
}
}
}
}
23 changes: 18 additions & 5 deletions moodle/Tests/Sniffs/Commenting/MissingDocblockSniffTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
namespace MoodleHQ\MoodleCS\moodle\Tests\Sniffs\Commenting;

use MoodleHQ\MoodleCS\moodle\Tests\MoodleCSBaseTestCase;
use PHP_CodeSniffer\Config;
use PHP_CodeSniffer\Files\DummyFile;
use PHP_CodeSniffer\Ruleset;

/**
* Test the MissingDocblockSniff sniff.
Expand Down Expand Up @@ -68,11 +65,11 @@ public static function docblockCorrectnessProvider(): array {
159 => 'Missing docblock for function test_method',
166 => 'Missing docblock for function test_method',
170 => 'Missing docblock for class example_extends',
171 => 'Missing docblock for function test_method',
175 => 'Missing docblock for class example_implements',
176 => 'Missing docblock for function test_method',
],
'warnings' => [
171 => 'Missing docblock for function test_method',
176 => 'Missing docblock for function test_method',
],
],
'File level tag, no class' => [
Expand Down Expand Up @@ -166,6 +163,22 @@ public static function docblockCorrectnessProvider(): array {
18 => 'Missing docblock for function this_is_a_dataprovider in testcase',
],
],
'With and without Overrides attributes' => [
'fixture' => 'with_and_without_overrides',
'fixtureFilename' => null,
'errors' => [
1 => 'Missing docblock for file with_and_without_overrides.php',
11 => 'Missing docblock for function has_override',
13 => 'Missing docblock for function no_override',
21 => 'Missing docblock for function has_override',
23 => 'Missing docblock for function no_override',
33 => 'Missing docblock for function no_override',
43 => 'Missing docblock for function no_override',
53 => 'Missing docblock for function no_override',
],
'warnings' => [
],
],
];

if (version_compare(PHP_VERSION, '8.0.0') >= 0) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace MoodleHQ\MoodleCS\moodle\Tests\Sniffs\PHPUnit;


/**
* Class level docblock.
*/
class base_class {
#[\Override]
public function has_override(): void {}

public function no_override(): void {}
}

/**
* Base interface.
*/
interface base_interface {
#[\Override]
public function has_override(): void {}

public function no_override(): void {}
}

/**
* Class which extends another class.
*/
class child_class extends base_class {
#[\Override]
public function has_override(): void {}

public function no_override(): void {}
}

/**
* Interface which extends another interface.
*/
interface child_interface extends base_interface {
#[\Override]
public function has_override(): void {}

public function no_override(): void {}
}

/**
* Class which implements an interface.
*/
class child_class_implements_interface implements base_interface {
#[\Override]
public function has_override(): void {}

public function no_override(): void {}
}
71 changes: 71 additions & 0 deletions moodle/Tests/Util/AttributesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.

namespace MoodleHQ\MoodleCS\moodle\Tests\Util;

use MoodleHQ\MoodleCS\moodle\Tests\MoodleCSBaseTestCase;
use MoodleHQ\MoodleCS\moodle\Util\Attributes;
use PHP_CodeSniffer\Config;
use PHP_CodeSniffer\Files\DummyFile;
use PHP_CodeSniffer\Ruleset;

/**
* Test the Attributes specific moodle utilities class
*
* @copyright 2024 onwards Andrew Lyons <[email protected]>
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* @covers \MoodleHQ\MoodleCS\moodle\Util\Attributes
*/
class AttributesTest extends MoodleCSBaseTestCase
{
/**
* @dataProvider validTagsProvider
*/
public function testGetAttributePointers(
string $content,
string|int $stackPtrSearch,
?array $expected
): void {
$config = new Config([]);
$ruleset = new Ruleset($config);

$phpcsFile = new DummyFile($content, $ruleset, $config);
$phpcsFile->process();

$tokens = $phpcsFile->getTokens();
$docPtr = $phpcsFile->findNext($stackPtrSearch, 0);
$docblock = $tokens[$docPtr];
$testPtr = reset($docblock['comment_tags']);

$this->assertEquals($expected, Docblocks::isValidTag($phpcsFile, $testPtr));
}

public static function validTagsProvider(): array {
return [
'No attrinbutes' => [
'<?php
/**
* @param string $param
*/
function exampleFunction(string $param): void {}',
T_FUNCTION,
true,
],
];
}
}
106 changes: 106 additions & 0 deletions moodle/Util/Attributes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.

namespace MoodleHQ\MoodleCS\moodle\Util;

use PHP_CodeSniffer\Files\File;
use PHPCSUtils\Utils\Context;
use PHPCSUtils\Utils\Namespaces;

/**
* Utilities related to PHP Attributes.
*
* @copyright 2024 Andrew Lyons <[email protected]>
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class Attributes
{
/**
* Get the pointer for an Attribute on an Attributable object.
*
* @param File $phpcsFile
* @param int $stackPtr
* @return array
*/
public static function getAttributePointers(

Check warning on line 39 in moodle/Util/Attributes.php

View check run for this annotation

Codecov / codecov/patch

moodle/Util/Attributes.php#L39

Added line #L39 was not covered by tests
File $phpcsFile,
int $stackPtr
): array {
$tokens = $phpcsFile->getTokens();
$attributes = [];

Check warning on line 44 in moodle/Util/Attributes.php

View check run for this annotation

Codecov / codecov/patch

moodle/Util/Attributes.php#L43-L44

Added lines #L43 - L44 were not covered by tests

$stopAt = [
T_DOC_COMMENT_CLOSE_TAG,
T_CLOSE_CURLY_BRACKET,
T_OPEN_CURLY_BRACKET,
T_SEMICOLON,
];

Check warning on line 51 in moodle/Util/Attributes.php

View check run for this annotation

Codecov / codecov/patch

moodle/Util/Attributes.php#L46-L51

Added lines #L46 - L51 were not covered by tests

for ($attributePtr = $stackPtr; $attributePtr > 0; $attributePtr--) {
$token = $tokens[$attributePtr];
if (isset($token['attribute_opener'])) {
$attributePtr = $token['attribute_opener'];
$attributes[] = $attributePtr;
} elseif (isset($token['attribute_closer'])) {
$attributes[] = $attributePtr;
} elseif (Context::inAttribute($phpcsFile, $attributePtr)) {
$attributePtr = $token['attribute_opener'];
$attributes[] = $attributePtr;

Check warning on line 62 in moodle/Util/Attributes.php

View check run for this annotation

Codecov / codecov/patch

moodle/Util/Attributes.php#L53-L62

Added lines #L53 - L62 were not covered by tests
}

if (in_array($token['code'], $stopAt)) {
break;

Check warning on line 66 in moodle/Util/Attributes.php

View check run for this annotation

Codecov / codecov/patch

moodle/Util/Attributes.php#L65-L66

Added lines #L65 - L66 were not covered by tests
}
}

return $attributes;

Check warning on line 70 in moodle/Util/Attributes.php

View check run for this annotation

Codecov / codecov/patch

moodle/Util/Attributes.php#L70

Added line #L70 was not covered by tests
}

public static function getAttributeProperties(

Check warning on line 73 in moodle/Util/Attributes.php

View check run for this annotation

Codecov / codecov/patch

moodle/Util/Attributes.php#L73

Added line #L73 was not covered by tests
File $phpcsFile,
int $stackPtr
): ?array {
$tokens = $phpcsFile->getTokens();
if (!isset($tokens[$stackPtr]['attribute_opener'])) {
return null;

Check warning on line 79 in moodle/Util/Attributes.php

View check run for this annotation

Codecov / codecov/patch

moodle/Util/Attributes.php#L77-L79

Added lines #L77 - L79 were not covered by tests
}

$opener = $tokens[$stackPtr]['attribute_opener'];
$closer = $tokens[$stackPtr]['attribute_closer'];

Check warning on line 83 in moodle/Util/Attributes.php

View check run for this annotation

Codecov / codecov/patch

moodle/Util/Attributes.php#L82-L83

Added lines #L82 - L83 were not covered by tests

$properties = [
'attribute_opener' => $opener,
'attribute_closer' => $closer,
'attribute_name' => null,
];

Check warning on line 89 in moodle/Util/Attributes.php

View check run for this annotation

Codecov / codecov/patch

moodle/Util/Attributes.php#L85-L89

Added lines #L85 - L89 were not covered by tests

$stopAt = [
T_OPEN_PARENTHESIS,
];

Check warning on line 93 in moodle/Util/Attributes.php

View check run for this annotation

Codecov / codecov/patch

moodle/Util/Attributes.php#L91-L93

Added lines #L91 - L93 were not covered by tests

for ($i = $opener + 1; $i < $closer; $i++) {
if (in_array($tokens[$i]['code'], $stopAt)) {
break;

Check warning on line 97 in moodle/Util/Attributes.php

View check run for this annotation

Codecov / codecov/patch

moodle/Util/Attributes.php#L95-L97

Added lines #L95 - L97 were not covered by tests
}
$properties['attribute_name'] .= $tokens[$i]['content'];

Check warning on line 99 in moodle/Util/Attributes.php

View check run for this annotation

Codecov / codecov/patch

moodle/Util/Attributes.php#L99

Added line #L99 was not covered by tests
}

// TODO Get the qualified name.

return $properties;

Check warning on line 104 in moodle/Util/Attributes.php

View check run for this annotation

Codecov / codecov/patch

moodle/Util/Attributes.php#L104

Added line #L104 was not covered by tests
}
}

0 comments on commit 9d2c0dc

Please sign in to comment.