Skip to content
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
171 changes: 171 additions & 0 deletions Sniffs/Commenting/MultiLineBlockCommentSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName -- Sniffs follow PHPCS and WordPress Coding.
/**
* BSU WordPress Coding Standard.
*
* @package BSU\BSUWordPressCS
* @license https://opensource.org/licenses/MIT MIT
*/

namespace BSUWordPressCS\Sniffs\Commenting;

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

/**
* Enforces BSUWordPressCS Rule for multi-line block comments.
*
* It will ignore:
* - Comments that already use the PHPDoc format (/** ... *\/).
* - Single-line /* ... *\/ comments (handled by SingleLineCommentSniff).
* - Block comments that appear after code on the same line (handled by InlineCommentSniff).
*
* It will convert:
* - Multi-line /* ... *\/ block comments to the PHPDoc (/** ... *\/) format.
*/
class MultiLineBlockCommentSniff implements Sniff {

/**
* Register an array of tokens used in this sniff.
*
* @return array
*/
public function register() {

return array( T_COMMENT );

}







/**
* Processes this sniff, when one of the registered tokens is encountered.
*
* @param File $phpcs_file The file being scanned.
* @param int $stack_position The position of the current token in the stack passed in $tokens.
*
* @return void
*/
public function process( File $phpcs_file, $stack_position ) {

/**
* Get the token from the file.
*/
$tokens = $phpcs_file->getTokens();

/**
* Define comment content
*
* Get the raw content of the token.
*/
$comment_content = $tokens[ $stack_position ]['content'];

/**
* Define trimmed comment
*
* Get the trimmed content for checks.
*/
$trimmed_comment = trim( $comment_content );

/**
* Define $check_content
*
* Create a whitespace-less version for robust linter directive checks.
*/
$check_content = preg_replace( '/[\s\xA0\xC2\xA0]+/', '', $comment_content );

/**
* Check if comment is a phpcs or coverage directive — ignore it.
*/
if (
strpos( $check_content, 'phpcs:' ) !== false ||
strpos( $check_content, '@codeCoverageIgnore' ) !== false
) {

return;

}

/**
* Check if comment is already a PHPDoc — ignore it.
*/
if ( substr( $trimmed_comment, 0, 3 ) === '/**' ) {

return;

}

/**
* Check if comment is a block comment — if not, ignore it.
*/
if ( substr( $trimmed_comment, 0, 2 ) !== '/*' ) {

return;

}

/**
* Check if comment contains a newline.
* Single-line /* ... *\/ comments are handled by SingleLineCommentSniff, not this one.
*/
if ( preg_match( '/\R/', $comment_content ) !== 1 ) {

return;

}

/**
* Define $last_code_token_pos
*
* Find the position of the last non-whitespace/non-HTML token before the comment.
* Non-breaking spaces are often tokenized as T_INLINE_HTML.
*/
$last_code_token_pos = $phpcs_file->findPrevious( array( T_WHITESPACE, T_INLINE_HTML ), $stack_position - 1, null, true );

/**
* Check if a non-whitespace token was found
* AND if it's on the same line as the comment.
* If so, this is an inline comment handled by InlineCommentSniff — ignore it.
*/
if ( false !== $last_code_token_pos && $tokens[ $last_code_token_pos ]['line'] === $tokens[ $stack_position ]['line'] ) {

return;

}

/**
* Define the error
*
* Set the error message for the sniff.
*/
$error = 'Multi-line block comments must use the PHPDoc format (/** ... */).';

/**
* Define $fix
*
* Add the fixable error.
*/
$fix = $phpcs_file->addFixableError( $error, $stack_position, 'MultiLineBlockComment' );

/**
* Check if $fix is true.
*/
if ( true === $fix ) {

/**
* Define $fixed_content
*
* Replace the opening /* with /** to convert to PHPDoc format.
*/
$fixed_content = preg_replace( '/^(\s*)\/\*(\s)/', '$1/**$2', $comment_content );

$phpcs_file->fixer->beginChangeset();
$phpcs_file->fixer->replaceToken( $stack_position, $fixed_content );
$phpcs_file->fixer->endChangeset();

}
}
}
8 changes: 4 additions & 4 deletions Sniffs/Functions/GetSiteUrlSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,24 @@ public function register() {
*/
public function process( File $phpcs_file, $stack_position ) {

/*
/**
* Get the token from the file.
*/
$tokens = $phpcs_file->getTokens();

/*
/**
* Check if the current token content is the function name 'get_site_url'.
*/
if ( 'get_site_url' === $tokens[ $stack_position ]['content'] ) {

/*
/**
* Optional: Check if it's being called as a function.
*/
$next_token = $phpcs_file->findNext( T_WHITESPACE, $stack_position + 1, null, true );

if ( T_OPEN_PARENTHESIS === $tokens[ $next_token ]['code'] ) {

/*
/**
* Add the Error message
*/
$phpcs_file->addError(
Expand Down
8 changes: 4 additions & 4 deletions Sniffs/Functions/GetTemplateDirectorySniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,24 @@ public function register() {
*/
public function process( File $phpcs_file, $stack_position ) {

/*
/**
* Get the token from the file.
*/
$tokens = $phpcs_file->getTokens();

/*
/**
* Check if the current token content is the function name 'get_template_directory'.
*/
if ( 'get_template_directory' === $tokens[ $stack_position ]['content'] ) {

/*
/**
* Optional: Check if it's being called as a function.
*/
$next_token = $phpcs_file->findNext( T_WHITESPACE, $stack_position + 1, null, true );

if ( T_OPEN_PARENTHESIS === $tokens[ $next_token ]['code'] ) {

/*
/**
* Add the Error message
*/
$phpcs_file->addError(
Expand Down
16 changes: 8 additions & 8 deletions Sniffs/Spacing/NoBlankLineAfterOpenBraceSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ public function register() {
*/
public function process( File $phpcs_file, $stack_position ) {

/*
/**
* Get the token from the file.
*/
$tokens = $phpcs_file->getTokens();

/*
/**
* Use scope_opener when PHPCS has already resolved it. This correctly
* handles functions with return type declarations (e.g. ): bool {) where
* a findNext() for T_COLON would match the return-type colon rather than
Expand All @@ -75,17 +75,17 @@ public function process( File $phpcs_file, $stack_position ) {

}

/*
/**
* Find the first non-whitespace line after the opening brace or colon.
*/
$next_line_position = $phpcs_file->findNext( T_WHITESPACE, $open_brace_position + 1, null, true );

/*
/**
* Check if the next non-whitespace token is a closing brace.
*/
$closing_brace_position = $phpcs_file->findNext( array( T_CLOSE_CURLY_BRACKET, T_ENDIF, T_ENDFOREACH ), $open_brace_position + 1 );

/*
/**
* Skip the block if it opens and closes immediately.
*/
if ( false !== $closing_brace_position && $tokens[ $closing_brace_position ]['line'] === $tokens[ $open_brace_position ]['line'] + 1 ) {
Expand All @@ -94,7 +94,7 @@ public function process( File $phpcs_file, $stack_position ) {

}

/*
/**
* Ensure there is a blank line after the opening brace, even if a comment follows.
*/
if ( $tokens[ $next_line_position ]['line'] - $tokens[ $open_brace_position ]['line'] <= 1 ) {
Expand All @@ -109,7 +109,7 @@ public function process( File $phpcs_file, $stack_position ) {

$phpcs_file->fixer->beginChangeset();

/*
/**
* Retrieve the indentation of the line after the opening brace.
*/
$indentation = '';
Expand All @@ -126,7 +126,7 @@ public function process( File $phpcs_file, $stack_position ) {
}
}

/*
/**
* Add the new blank line with the correct indentation.
*/
$phpcs_file->fixer->addContent( $open_brace_position, PHP_EOL . $indentation );
Expand Down
14 changes: 7 additions & 7 deletions Sniffs/Spacing/NoBlankLineBeforeCloseBraceSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,20 @@ public function register() {
*/
public function process( File $phpcs_file, $stack_position ) {

/*
/**
* Get the token from the file.
*/
$tokens = $phpcs_file->getTokens();

/*
/**
* Find the opening brace or colon (for alternative syntax).
*/
$open_brace_position = $phpcs_file->findNext(
array( T_OPEN_CURLY_BRACKET, T_COLON ),
$stack_position + 1
);

/*
/**
* If not found, exit the sniff.
*/
if ( false === $open_brace_position ) {
Expand All @@ -74,7 +74,7 @@ public function process( File $phpcs_file, $stack_position ) {

}

/*
/**
* Define $close_brace_position using bracket_closer.
*/
$close_brace_position = $tokens[ $open_brace_position ]['bracket_closer'] ?? null;
Expand All @@ -84,7 +84,7 @@ public function process( File $phpcs_file, $stack_position ) {

}

/*
/**
* Define $prev_code_position for last meaningful line before the close brace.
*/
$prev_code_position = $phpcs_file->findPrevious(
Expand Down Expand Up @@ -120,7 +120,7 @@ public function process( File $phpcs_file, $stack_position ) {

}

/*
/**
* Find next and previous non-whitespace tokens around the closing brace.
*/
$next_code_position = $phpcs_file->findNext(
Expand Down Expand Up @@ -176,7 +176,7 @@ public function process( File $phpcs_file, $stack_position ) {

}

/*
/**
* Calculate line difference to detect missing blank line.
*/
$line_difference = $tokens[ $close_brace_position ]['line'] - $tokens[ $prev_code_position ]['line'];
Expand Down
28 changes: 28 additions & 0 deletions Tests/Commenting/MultiLineBlockCommentUnitTest.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php
/**
* Test fixture for MultiLineBlockCommentSniff.
*
* Lines marked FAIL expect exactly 1 error.
* Lines marked PASS expect no error.
*/

// FAIL: multi-line /* */ block on its own line.
/*
* This should be a PHPDoc block.
*/

// PASS: already a PHPDoc docblock.
/**
* This is correct.
*/

// PASS: single-line /* */ — handled by SingleLineCommentSniff, not this one.
/* This is a single-line block comment. */

// PASS: block comment after code on same line — handled by InlineCommentSniff.
$a = 1; /* trailing comment */

// FAIL: another multi-line /* */ block on its own line.
/*
* This should also be flagged.
*/
Loading