Unverified Commit 1617b8e2 authored by Adam Zimmermann's avatar Adam Zimmermann Committed by GitHub
Browse files

feat(Todo): Add fixer for todo comments (#3177471 by adamzimmermann)

parent 8066395d
Loading
Loading
Loading
Loading
+47 −13
Original line number Diff line number Diff line
@@ -83,7 +83,7 @@ class TodoCommentSniff implements Sniff
                echo "Getting \$comment from \$tokens[$stackPtr]['content']\n";
            }

            $this->checkTodoFormat($phpcsFile, $stackPtr, $comment);
            $this->checkTodoFormat($phpcsFile, $stackPtr, $comment, $tokens);
        } else if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT_TAG) {
            // Document comment tag (i.e. comments that begin with "@").
            // Determine if this is related at all and build the full comment line
@@ -105,7 +105,7 @@ class TodoCommentSniff implements Sniff
                    echo "Result comment = $comment\n";
                }

                $this->checkTodoFormat($phpcsFile, $stackPtr, $comment);
                $this->checkTodoFormat($phpcsFile, $stackPtr, $comment, $tokens);
            }//end if
        }//end if

@@ -119,38 +119,72 @@ class TodoCommentSniff implements Sniff
     * @param int                         $stackPtr  The position of the current token
     *                                               in the stack passed in $tokens.
     * @param string                      $comment   The comment text.
     * @param array<array>                $tokens    The token data.
     *
     * @return void
     */
    private function checkTodoFormat(File $phpcsFile, $stackPtr, string $comment)
    private function checkTodoFormat(File $phpcsFile, int $stackPtr, string $comment, array $tokens)
    {
        if ($this->debug === true) {
            echo "Checking \$comment = '$comment'\n";
        }

        $expression = '/(?x)   # Set free-space mode to allow this commenting
        $expression = '/(?x)   # Set free-space mode to allow this commenting.
            ^(\/|\s)*          # At the start optionally match any forward slashes and spaces
            (?i)               # set case-insensitive mode
            (?=(               # start a positive non-consuming look-ahead to find all possible todos
              @+to(-|\s|)+do   # if one or more @ allow spaces and - between the to and do
            (?i)               # set case-insensitive mode.
            (?=(               # Start a positive non-consuming look-ahead to find all possible todos
              @+to(-|\s|)+do   # if one or more @ allow spaces and - between the to and do.
              \h*(-|:)*        # Also match the trailing "-" or ":" so they can be replaced.
              |                # or
              to(-)*do         # if no @ then only accept todo or to-do or to--do, etc, no spaces
              to(-)*do         # If no @ then only accept todo or to-do or to--do, etc, no spaces.
              (\s-|:)*         # Also match the trailing "-" or ":" so they can be replaced.
            ))
            (?-i)              # Reset to case-sensitive
            (?!                # Start another non-consuming look-ahead, this time negative
              @todo\s          # It has to match lower-case @todo followed by one space
              (?!-|:)\S        # and then any non-space except - or :
              (?!-|:)\S        # and then any non-space except "-" or ":".
            )/m';

        if ((bool) preg_match($expression, $comment) === true) {
        if ((bool) preg_match($expression, $comment, $matches) === true) {
            if ($this->debug === true) {
                echo "Failed regex - give message\n";
            }

            $comment = trim($comment, " /\r\n");
            $phpcsFile->addWarning("'%s' should match the format '@todo Fix problem X here.'", $stackPtr, 'TodoFormat', [$comment]);
            $commentTrimmed = trim($comment, " /\r\n");
            if ($commentTrimmed === '@todo') {
                // We can't fix a comment that doesn't have any text.
                $phpcsFile->addWarning("'%s' should match the format '@todo Fix problem X here.'", $stackPtr, 'TodoFormat', [$commentTrimmed]);
                $fix = false;
            } else {
                // Comments with description text are fixable.
                $fix = $phpcsFile->addFixableWarning("'%s' should match the format '@todo Fix problem X here.'", $stackPtr, 'TodoFormat', [$commentTrimmed]);
            }

            if ($fix === true) {
                if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT_TAG) {
                    // Rewrite the comment past the token content to an empty
                    // string as part of it may be part of the match, but not in
                    // the token content. Then replace the token content with
                    // the fixed comment from the matched content.
                    $phpcsFile->fixer->beginChangeset();
                    $index = ($stackPtr + 1);
                    while ($tokens[$index]['line'] === $tokens[$stackPtr]['line']) {
                        $phpcsFile->fixer->replaceToken($index, '');
                        $index++;
                    }

                    $fixedTodo = str_replace($matches[2], '@todo ', $comment);
                    $phpcsFile->fixer->replaceToken($stackPtr, $fixedTodo);
                    $phpcsFile->fixer->endChangeset();
                } else {
                    // The full comment line text is available here, so the
                    // replacement is fairly straightforward.
                    $fixedTodo = str_replace($matches[2], '@todo ', $tokens[$stackPtr]['content']);
                    $phpcsFile->fixer->replaceToken($stackPtr, $fixedTodo);
                }//end if
            }//end if
        }//end if

    }//end checkTodoFormat()


+18 −4
Original line number Diff line number Diff line
<?php

/**
 * @file
 * Test file for the todo standard.
 *
 * These are valid examples.
 *
 * @todo Valid.
 * @todo valid with lower-case first letter
 * @todo $can start with a $
 * @todo \also with backslash
 *
 * These are all incorrect.
 * These are all incorrect but can be fixed automatically.
 *
 * @TODO Error
 * @ToDo Error
 * @TODo Error
@@ -29,19 +32,26 @@
 * TODO Error
 * ToDo Error
 * to-do Error
 *
 * These are all incorrect but cannot be fully fixed automatically.
 *
 * @todo
 * @to-do
 * @TODO
 */

/**
 * Example function.
 */
function foo() {
  // These are valid examples.
  // @todo Valid.
  // @todo valid with lower-case first letter
  // @todo $can start with a $
  // @todo \also with backslash

  // This is not a todo tag. It is a general comment and we do not want
  // to do the standards checking here.

  // These are all incorrect.
  // These are all incorrect but can be fixed automatically.
  // @TODO Error
  // @ToDo Error
  // @TODo Error
@@ -61,4 +71,8 @@ function foo() {
  // TODO Error
  // ToDo Error
  // to-do Error
  // These are all incorrect but cannot be fully fixed automatically.
  // @todo
  // @to-do
  // @TODO
}
+78 −0
Original line number Diff line number Diff line
<?php

/**
 * @file
 * Test file for the todo standard.
 *
 * These are valid examples.
 *
 * @todo Valid.
 * @todo valid with lower-case first letter
 * @todo $can start with a $
 * @todo \also with backslash
 *
 * These are all incorrect but can be fixed automatically.
 *
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 * @todo Error
 *
 * These are all incorrect but cannot be fully fixed automatically.
 *
 * @todo
 * @todo
 * @todo
 */

/**
 * Example function.
 */
function foo() {
  // These are valid examples.
  // @todo Valid.
  // @todo valid with lower-case first letter
  // @todo $can start with a $
  // @todo \also with backslash
  // This is not a todo tag. It is a general comment and we do not want
  // to do the standards checking here.
  // These are all incorrect but can be fixed automatically.
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // @todo Error
  // These are all incorrect but cannot be fully fixed automatically.
  // @todo
  // @todo
  // @todo
}
+1 −1
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ class TodoCommentUnitTest extends CoderSniffUnitTest
     */
    protected function getWarningList(string $testFile): array
    {
        $warningList = (array_fill_keys(range(13, 31), 1) + array_fill_keys(range(45, 63), 1));
        $warningList = (array_fill_keys(range(16, 34), 1) + array_fill_keys(range(38, 40), 1) + array_fill_keys(range(55, 73), 1) + array_fill_keys(range(75, 77), 1));
        return $warningList;

    }//end getWarningList()