Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check namespaces and class imports for leading backslash #61

Merged
merged 1 commit into from
Sep 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .phplint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ path: ./
exclude:
- vendor
- moodle/Tests/fixtures
- moodle/Tests/Sniffs/Namespaces/fixtures
71 changes: 71 additions & 0 deletions moodle/Sniffs/Namespaces/NamespaceStatementSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php
// This file is part of Moodle - http://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 <http://www.gnu.org/licenses/>.

/**
* Checks that each file contains the standard GPL comment.
*
* @package moodle-cs
* @copyright 2023 Andrew Lyons <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

namespace MoodleHQ\MoodleCS\moodle\Sniffs\Namespaces;

use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Util\Tokens;

// phpcs:disable moodle.NamingConventions

class NamespaceStatementSniff implements Sniff {
public function register()
{
return [
T_NAMESPACE,
];
}

public function process(File $file, $stackPtr)
{
$tokens = $file->getTokens();
// Format should be:
// - T_NAMESPACE
// - T_WHITESPACE
// - T_STRING

$checkPtr = $stackPtr + 2;
$token = $tokens[$checkPtr];
if ($token['code'] === T_NS_SEPARATOR) {
$fqdn = '';
$stop = $file->findNext(Tokens::$emptyTokens, ($stackPtr + 2));
for ($i = $stackPtr + 2; $i < $stop; $i++) {
$fqdn .= $tokens[$i]['content'];
}
$fix = $file->addFixableError(
'Namespace should not start with a slash: %s',
$checkPtr,
'LeadingSlash',
[$fqdn]
);

if ($fix) {
$file->fixer->beginChangeset();
$file->fixer->replaceToken($checkPtr, '');
$file->fixer->endChangeset();
}
}
}
}
55 changes: 10 additions & 45 deletions moodle/Tests/MoodleCSBaseTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,53 +80,18 @@ public function set_component_mapping(array $mapping): void {
*
* @param string $standard name of the standard to be tested.
*/
protected function set_standard($standard) {
$installedStandards = \PHP_CodeSniffer\Util\Standards::getInstalledStandardDetails();

foreach (array_keys($installedStandards) as $standard) {
if (\PHP_CodeSniffer\Util\Standards::isInstalledStandard($standard) === false) {
// They didn't select a valid coding standard, so help them
// out by letting them know which standards are installed.
$error = 'ERROR: the "'.$standard.'" coding standard is not installed. ';
ob_start();
\PHP_CodeSniffer\Util\Standards::printInstalledStandards();
$error .= ob_get_contents();
ob_end_clean();
throw new \PHP_CodeSniffer\Exceptions\DeepExitException($error, 3);
}
protected function set_standard(string$standard) {
if (\PHP_CodeSniffer\Util\Standards::isInstalledStandard($standard) === false) {
// They didn't select a valid coding standard, so help them
// out by letting them know which standards are installed.
$error = "ERROR: the '{$standard}' coding standard is not installed.\n";
ob_start();
\PHP_CodeSniffer\Util\Standards::printInstalledStandards();
$error .= ob_get_contents();
ob_end_clean();
throw new \PHP_CodeSniffer\Exceptions\DeepExitException($error, 3);
}
$this->standard = $standard;
return;
// Since 2.9 arbitrary standard directories are not allowed by default,
// only those under the CodeSniffer/Standards dir are detected. Other base
// dirs containing standards can be added using CodeSniffer.conf or the
// PHP_CODESNIFFER_CONFIG_DATA global (installed_paths setting).
// We are using the global way here to avoid changes in the phpcs import.
// phpcs:disable
if (!isset($GLOBALS['PHP_CODESNIFFER_CONFIG_DATA']['installed_paths'])) {
$localcodecheckerpath = realpath(__DIR__ . '/../');
$GLOBALS['PHP_CODESNIFFER_CONFIG_DATA'] = ['installed_paths' => $localcodecheckerpath];
}
// phpcs:enable

// Basic search of standards in the allowed directories.
$stdsearch = array(
__DIR__ . '/../phpcs/src/Standards', // PHPCS standards dir.
__DIR__ . '/..', // Plugin local_codechecker dir, allowed above via global.
);

foreach ($stdsearch as $stdpath) {
$stdpath = realpath($stdpath . '/' . $standard);
$stdfile = $stdpath . '/ruleset.xml';
if (file_exists($stdfile)) {
$this->standard = $stdpath; // Need to pass the path here.
break;
}
}
// Standard not found, fail.
if ($this->standard === null) {
$this->fail('Standard "' . $standard . '" not found.');
}
}

/**
Expand Down
76 changes: 76 additions & 0 deletions moodle/Tests/Sniffs/Namespaces/NamespaceStatementSniffTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php
// This file is part of Moodle - http://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 <http://www.gnu.org/licenses/>.

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

use MoodleHQ\MoodleCS\moodle\Tests\MoodleCSBaseTestCase;

// phpcs:disable moodle.NamingConventions

/**
* Test the NoLeadingSlash sniff.
*
* @package moodle-cs
* @category test
* @copyright 2023 Andrew Lyons <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* @covers \MoodleHQ\MoodleCS\moodle\Sniffs\Namespaces\NoLeadingSlashSniff
*/
class NamespaceStatementSniffTest extends MoodleCSBaseTestCase
{
public static function leading_slash_provider(): array
{
return [
[
'fixture' => 'correct_namespace',
'warnings' => [],
'errors' => [],
],
[
'fixture' => 'leading_backslash',
'warnings' => [],
'errors' => [
3 => 'Namespace should not start with a slash: \MoodleHQ\MoodleCS\moodle\Tests\Sniffs\Namespaces',
],
],
[
'fixture' => 'curly_namespace',
'warnings' => [],
'errors' => [
3 => 'Namespace should not start with a slash: \MoodleHQ\MoodleCS\moodle\Tests\Sniffs\Namespaces',
],
],
];
}
/**
* @dataProvider leading_slash_provider
*/
public function test_leading_slash(
string $fixture,
array $warnings,
array $errors
): void
{
$this->set_standard('moodle');
$this->set_sniff('moodle.Namespaces.NamespaceStatement');
$this->set_fixture(sprintf("%s/fixtures/%s.php", __DIR__, $fixture));
$this->set_warnings($warnings);
$this->set_errors($errors);

$this->verify_cs_results();
}
}
8 changes: 8 additions & 0 deletions moodle/Tests/Sniffs/Namespaces/fixtures/correct_namespace.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

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

defined('MOODLE_INTERNAL') || die(); // Make this always the 1st line in all CS fixtures.

class correct_test extends base_test {
}
5 changes: 5 additions & 0 deletions moodle/Tests/Sniffs/Namespaces/fixtures/curly_namespace.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

namespace \MoodleHQ\MoodleCS\moodle\Tests\Sniffs\Namespaces {
class leading_backslash {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

namespace MoodleHQ\MoodleCS\moodle\Tests\Sniffs\Namespaces {
class leading_backslash {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

namespace MoodleHQ\MoodleCS\moodle\Tests\Sniffs\Namespaces {
class leading_backslash {}
}
8 changes: 8 additions & 0 deletions moodle/Tests/Sniffs/Namespaces/fixtures/leading_backslash.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

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

defined('MOODLE_INTERNAL') || die(); // Make this always the 1st line in all CS fixtures.

class leading_backslash extends base_test {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

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

defined('MOODLE_INTERNAL') || die(); // Make this always the 1st line in all CS fixtures.

class leading_backslash extends base_test {
}
6 changes: 6 additions & 0 deletions moodle/ruleset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@
<severity>0</severity>
</rule>

<!--
Namespace statements, and class imports (use statements) should not use a leading backslash.
-->
<rule ref="PSR12.Files.ImportStatement.LeadingSlash"/>
<rule ref="moodle.Namespaces.NamespaceStatement"/>

<!-- Let's add the complete PHPCompatibility standard -->
<rule ref="PHPCompatibility" />

Expand Down