Unverified Commit f7a44429 authored by Mitch Portier's avatar Mitch Portier Committed by GitHub
Browse files

feat(FullyQualifiedNamespace): Add alias support and avoid classname conflicts...

feat(FullyQualifiedNamespace): Add alias support and avoid classname conflicts (#3112316 by Arkener)
parent ab1034a8
Loading
Loading
Loading
Loading
+62 −26
Original line number Diff line number Diff line
@@ -78,42 +78,72 @@ class FullyQualifiedNamespaceSniff implements Sniff
            return ($after + 1);
        }

        $error = 'Namespaced classes/interfaces/traits should be referenced with use statements';
        $fix   = $phpcsFile->addFixableError($error, $stackPtr, 'UseStatementMissing');

        if ($fix === true) {
        $fullName  = $phpcsFile->getTokensAsString(($before + 1), ($after - 1 - $before));
        $fullName  = trim($fullName, "\ \n");

            $phpcsFile->fixer->beginChangeset();

            // Replace the fully qualified name with the local name.
            for ($i = ($before + 1); $i < $after; $i++) {
                if ($tokens[$i]['code'] !== T_WHITESPACE) {
                    $phpcsFile->fixer->replaceToken($i, '');
                }
            }

        $parts     = explode('\\', $fullName);
        $className = end($parts);
            $phpcsFile->fixer->addContentBefore(($after - 1), $className);

        // Check if there is a use statement already for this class and
        // namespace.
        $conflict     = false;
        $alreadyUsed  = false;
        $aliasName    = false;
        $useStatement = $phpcsFile->findNext(T_USE, 0);
        while ($useStatement !== false && empty($tokens[$useStatement]['conditions']) === true) {
                $useEnd   = $phpcsFile->findEndOfStatement($useStatement);
                $classRef = trim($phpcsFile->getTokensAsString(($useStatement + 1), ($useEnd - 1 - $useStatement)));
                if (strcasecmp($classRef, $fullName) === 0) {
            $endPtr      = $phpcsFile->findEndOfStatement($useStatement);
            $useEnd      = ($phpcsFile->findNext([T_STRING, T_NS_SEPARATOR, T_WHITESPACE], ($useStatement + 1), null, true) - 1);
            $useFullName = trim($phpcsFile->getTokensAsString(($useStatement + 1), ($useEnd - $useStatement)));

            // Check if use statement contains an alias.
            $asPtr = $phpcsFile->findNext(T_AS, ($useEnd + 1), $endPtr);
            if ($asPtr !== false) {
                $aliasName = trim($phpcsFile->getTokensAsString(($asPtr + 1), ($endPtr - 1 - $asPtr)));
            }

            if (strcasecmp($useFullName, $fullName) === 0) {
                $alreadyUsed = true;
                break;
            }

                $useStatement = $phpcsFile->findNext(T_USE, ($useEnd + 1));
            $parts        = explode('\\', $useFullName);
            $useClassName = end($parts);

            // Check if the resulting classname would conflict with another
            // use statement.
            if ($aliasName === $className || $useClassName === $className) {
                $conflict = true;
                break;
            }

            $aliasName    = false;
            $useStatement = $phpcsFile->findNext(T_USE, ($endPtr + 1));
        }//end while

        $error = 'Namespaced classes/interfaces/traits should be referenced with use statements';
        if ($conflict === true) {
            $fix = false;
            $phpcsFile->addError($error, $stackPtr, 'UseStatementMissing');
        } else {
            $fix = $phpcsFile->addFixableError($error, $stackPtr, 'UseStatementMissing');
        }

        if ($fix === true) {
            $phpcsFile->fixer->beginChangeset();

            // Replace the fully qualified name with the local name.
            for ($i = ($before + 1); $i < $after; $i++) {
                if ($tokens[$i]['code'] !== T_WHITESPACE) {
                    $phpcsFile->fixer->replaceToken($i, '');
                }
            }

            // Use alias name if available.
            if ($aliasName !== false) {
                $phpcsFile->fixer->addContentBefore(($after - 1), $aliasName);
            } else {
                $phpcsFile->fixer->addContentBefore(($after - 1), $className);
            }

            // @todo Check if the name is already in use - then we need to alias it.
            // Insert use statement at the beginning of the file if it is not there
            // already. Also check if another sniff (for example
            // UnusedUseStatementSniff) has already deleted the use statement, then
@@ -121,22 +151,28 @@ class FullyQualifiedNamespaceSniff implements Sniff
            if ($alreadyUsed === false
                || $phpcsFile->fixer->getTokenContent($useStatement) !== $tokens[$useStatement]['content']
            ) {
                if ($aliasName !== false) {
                    $use = "use $fullName as $aliasName;";
                } else {
                    $use = "use $fullName;";
                }

                // Check if there is a group of use statements and add it there.
                $useStatement = $phpcsFile->findNext(T_USE, 0);
                if ($useStatement !== false && empty($tokens[$useStatement]['conditions']) === true) {
                    $phpcsFile->fixer->addContentBefore($useStatement, "use $fullName;\n");
                    $phpcsFile->fixer->addContentBefore($useStatement, "$use\n");
                } else {
                    // Check if there is an @file comment.
                    $beginning   = 0;
                    $fileComment = $phpcsFile->findNext(T_WHITESPACE, ($beginning + 1), null, true);
                    if ($tokens[$fileComment]['code'] === T_DOC_COMMENT_OPEN_TAG) {
                        $beginning = $tokens[$fileComment]['comment_closer'];
                        $phpcsFile->fixer->addContent($beginning, "\n\nuse $fullName;\n");
                        $phpcsFile->fixer->addContent($beginning, "\n\n$use\n");
                    } else {
                        $phpcsFile->fixer->addContent($beginning, "use $fullName;\n");
                    }
                        $phpcsFile->fixer->addContent($beginning, "$use\n");
                    }
                }
            }//end if

            $phpcsFile->fixer->endChangeset();
        }//end if
+64 −1
Original line number Diff line number Diff line
<?php

$x = new \Drupal\my_module\Example\MyUrlHelper();
/**
 * @file
 * Example.
 */

use Test\Bar;
use Test\NotUsed;
use Test\Alias as TestAlias;

/**
 * Example.
 */
class Example {

  /**
   * Description.
   */
  public function test1(TestAlias $alias) {

  }

  /**
   * Description.
   */
  public function test2(Test\NotUsed $notUsed) {

  }

  /**
   * Description.
   */
  public function test3(Test\Alias $alias) {

  }

  /**
   * Description.
   */
  public function test4(Test\Foo $foo) {

  }

  /**
   * Description.
   */
  public function test5(Bar $bar) {

  }

  /**
   * Description.
   */
  public function test6(TestDiff\Bar $bar) {

  }

  /**
   * Description.
   */
  public function test7(TestDiff\TestAlias $anotherAlias) {

  }

}
+60 −2
Original line number Diff line number Diff line
@@ -2,8 +2,66 @@

/**
 * @file
 * Example.
 */

use Drupal\my_module\Example\MyUrlHelper;
use Test\Foo;
use Test\NotUsed;
use Test\Bar;
use Test\Alias as TestAlias;

$x = new MyUrlHelper();
/**
 * Example.
 */
class Example {

  /**
   * Description.
   */
  public function test1(TestAlias $alias) {

  }

  /**
   * Description.
   */
  public function test2(NotUsed $notUsed) {

  }

  /**
   * Description.
   */
  public function test3(TestAlias $alias) {

  }

  /**
   * Description.
   */
  public function test4(Foo $foo) {

  }

  /**
   * Description.
   */
  public function test5(Bar $bar) {

  }

  /**
   * Description.
   */
  public function test6(TestDiff\Bar $bar) {

  }

  /**
   * Description.
   */
  public function test7(TestDiff\TestAlias $anotherAlias) {

  }

}
+7 −1
Original line number Diff line number Diff line
@@ -22,7 +22,13 @@ class FullyQualifiedNamespaceUnitTest extends CoderSniffUnitTest
    {
        switch ($testFile) {
        case 'FullyQualifiedNamespaceUnitTest.inc':
            return [3 => 1];
            return [
                27 => 1,
                34 => 1,
                41 => 1,
                55 => 1,
                62 => 1,
            ];
        case 'FullyQualifiedNamespaceUnitTest.1.inc':
            return [16 => 1];
        }