Commit 0d8ca01a authored by Daniel Siepmann's avatar Daniel Siepmann

Merge branch 'feature/44-add-checks-for-deprecated-removed-extensions' into 'develop'

FEATURE: Add checks for deprecated/removed extensions

Closes #44

See merge request !70
parents e8e0b11d f5c609e5
Pipeline #266 passed with stages
in 2 minutes and 1 second
......@@ -233,6 +233,28 @@ Using ``runtime-set``:
--runtime-set removedClassConfigFiles "/Some/Absolute/Path/*.yaml"
.. _configuration-removedExtensionConfigFiles:
removedExtensionConfigFiles
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Configure where to look for configuration files defining the removed extensions. Default is
``Configuration/Removed/Extension/*.yaml`` inside the standard itself. We already try to deliver as
much as possible. Globing is used, so placeholders like ``*`` are possible, see
https://secure.php.net/manual/en/function.glob.php
Using :file:`ruleset.xml`:
.. code:: xml
<config name="removedExtensionConfigFiles" value="/Some/Absolute/Path/*.yaml"/>
Using ``runtime-set``:
.. code:: bash
--runtime-set removedExtensionConfigFiles "/Some/Absolute/Path/*.yaml"
.. _configuration-removedGlobalConfigFiles:
removedGlobalConfigFiles
......
......@@ -109,6 +109,9 @@ functions. For configuration options see :ref:`configuration-removedClassConfigF
Check for usage of *removed PHP globals*. The globals are configured in same way as removed
functions. For configuration options see :ref:`configuration-removedGlobalConfigFiles`.
Check for usage of *removed TYPO3 extension*. For configuration options see
:ref:`configuration-removedExtensionConfigFiles`.
Check for usage of *removed signals*. The signals are configured in same way as removed
functions. For configuration options see :ref:`configuration-removedSignalConfigFiles`.
......
Typo3Update\Feature\RemovedExtensionFeature:
- Typo3Update_Sniffs_Classname_InheritanceSniff
- Typo3Update_Sniffs_Classname_InlineCommentSniff
- Typo3Update_Sniffs_Classname_InstanceofSniff
- Typo3Update_Sniffs_Classname_InstantiationWithMakeInstanceSniff
- Typo3Update_Sniffs_Classname_InstantiationWithNewSniff
- Typo3Update_Sniffs_Classname_InstantiationWithObjectManagerSniff
- Typo3Update_Sniffs_Classname_IsACallSniff
- Typo3Update_Sniffs_Classname_MissingVendorForPluginsAndModulesSniff
- Typo3Update_Sniffs_Classname_PhpDocCommentSniff
- Typo3Update_Sniffs_Classname_StaticCallSniff
- Typo3Update_Sniffs_Classname_TypeHintCatchExceptionSniff
- Typo3Update_Sniffs_Classname_TypeHintSniff
- Typo3Update_Sniffs_Classname_UseSniff
# Breaking changes in 7.0: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Index.html#breaking-changes
'7.0':
perm:
replacement: 'The logic is moved into EXT:beuser'
docsUrl: 'https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-62339-MoveExtPermIntoExtBeuser.html'
......@@ -21,12 +21,15 @@ namespace Typo3Update\Feature;
*/
use PHP_CodeSniffer_File as PhpCsFile;
use Typo3Update\Sniffs\ExtendedPhpCsSupportTrait;
/**
* Provides "feature" support for sniffs.
*/
trait FeaturesSupport
{
use ExtendedPhpCsSupportTrait;
/**
* @return Features
*/
......@@ -44,6 +47,8 @@ trait FeaturesSupport
*/
public function processFeatures(PhpCsFile $phpcsFile, $stackPtr, $content)
{
$content = $this->getStringContent($content);
foreach ($this->getFeatures() as $featureClassName) {
$feature = $this->createFeature($featureClassName);
$feature->process($phpcsFile, $stackPtr, $content);
......
<?php
namespace Typo3Update\Feature;
/*
* Copyright (C) 2017 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program 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 2
* of the License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHP_CodeSniffer_File as PhpCsFile;
use Typo3Update\Options;
class RemovedExtensionFeature extends AbstractYamlRemovedUsage
{
public function process(PhpCsFile $phpcsFile, $classnamePosition, $classname)
{
$extname = $this->getExtnameFromClassname($classname);
if ($extname === '' || $this->configured->isRemoved($extname) === false) {
return;
}
$this->addWarning(
$phpcsFile,
$classnamePosition,
$this->configured->getRemoved($extname)
);
}
protected function getExtnameFromClassname($classname)
{
$classname = ltrim($classname, '\\');
$classnameParts = array_filter(preg_split('/\\\\|_/', $classname));
$classnameParts = array_values($classnameParts); // To reset key numbers of array.
$extname = '';
if (count($classnameParts) <= 2) {
return '';
}
$extname = $classnameParts[1];
if (stripos($classname, 'TYPO3\CMS') === 0) {
$extname = $classnameParts[2];
}
return strtolower($extname);
}
protected function prepareStructure(array $typo3Versions)
{
$newStructure = [];
foreach ($typo3Versions as $typo3Version => $removals) {
foreach ($removals as $removed => $config) {
$config['name'] = $removed;
$config['identifier'] = 'RemovedExtension.' . str_replace('\\', '_', ltrim($removed, '\\'));
$config['versionRemoved'] = $typo3Version;
$config['oldUsage'] = $removed;
$newStructure[$removed] = $config;
}
}
return $newStructure;
}
protected function getRemovedConfigFiles()
{
return Options::getRemovedExtensionConfigFiles();
}
}
......@@ -56,6 +56,17 @@ class Options
);
}
/**
* @return array<string>
*/
public static function getRemovedExtensionConfigFiles()
{
return static::getOptionFileNames(
'removedExtensionConfigFiles',
__DIR__ . '/Configuration/Removed/Extension/*.yaml'
);
}
/**
* Returns an array of absolute file names containing removed function configurations.
*
......
......@@ -62,19 +62,75 @@ abstract class AbstractClassnameChecker implements PhpCsSniff
*/
public function process(PhpCsFile $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
try {
if ($this->shouldLookBefore()) {
list($classnamePosition, $classname) = $this->getBefore($phpcsFile, $stackPtr);
} else {
list($classnamePosition, $classname) = $this->getAfter($phpcsFile, $stackPtr);
}
} catch (\UnexpectedValueException $e) {
return;
}
if ($this->shouldLookBefore()) {
$classnamePosition = $phpcsFile->findPrevious(T_STRING, $stackPtr);
} else {
$classnamePosition = $phpcsFile->findNext(T_STRING, $stackPtr);
$this->processFeatures($phpcsFile, $classnamePosition, $classname);
}
/**
* Get position and classname before current stack pointer.
*
* @param PhpCsFile $phpcsFile
* @param int $stackPtr The position in the stack where
*
* @return array
*/
protected function getBefore(PhpCsFile $phpcsFile, $stackPtr)
{
$possibleStart = $phpcsFile->findPrevious([
T_STRING, T_NS_SEPARATOR,
], $stackPtr - 1, null, true, null, true);
if ($possibleStart === false) {
throw new \UnexpectedValueException('Could not find start of classname.', 1494319966);
}
$classnamePosition = $phpcsFile->findNext(T_STRING, $possibleStart);
if ($classnamePosition === false) {
return;
throw new \UnexpectedValueException('Could not find start of classname.', 1494319966);
}
$classname = $tokens[$classnamePosition]['content'];
$this->processFeatures($phpcsFile, $classnamePosition, $classname);
$end = $phpcsFile->findNext([
T_STRING, T_NS_SEPARATOR
], $classnamePosition + 1, $stackPtr + 1, true, null, true);
if ($end === false) {
throw new \UnexpectedValueException('Could not find end of classname.', 1494319651);
}
$classname = $phpcsFile->getTokensAsString($classnamePosition, $end - $classnamePosition);
return [$classnamePosition, $classname];
}
/**
* Get position and classname after current stack pointer.
*
* @param PhpCsFile $phpcsFile
* @param int $stackPtr The position in the stack where
*
* @return array
*/
protected function getAfter(PhpCsFile $phpcsFile, $stackPtr)
{
$classnamePosition = $phpcsFile->findNext(T_STRING, $stackPtr);
if ($classnamePosition === false) {
throw new \UnexpectedValueException('Could not find start of classname.', 1494319665);
}
$end = $phpcsFile->findNext([T_STRING, T_NS_SEPARATOR], $classnamePosition, null, true, null, true);
if ($end === false) {
throw new \UnexpectedValueException('Could not find end of classname.', 1494319651);
}
$classname = $phpcsFile->getTokensAsString($classnamePosition, $end - $classnamePosition);
return [$classnamePosition, $classname];
}
}
......@@ -72,11 +72,19 @@ class Typo3Update_Sniffs_Classname_InheritanceSniff extends AbstractClassnameChe
return;
}
$lastPosition = $phpcsFile->findNext(T_OPEN_CURLY_BRACKET, $stackPtr);
foreach ($interfaces as $interface) {
$position = $phpcsFile->findNext(T_STRING, $stackPtr, null, false, $interface);
if ($position === false) {
continue;
}
$interface = trim($interface, '\\');
$position = $stackPtr;
do {
try {
list($position, $classname) = $this->getAfter($phpcsFile, $position + 1);
} catch (\UnexpectedValueException $e) {
continue 2;
}
} while ($classname !== $interface && $position <= $lastPosition);
$this->processFeatures($phpcsFile, $position, $interface);
}
......
......@@ -34,7 +34,7 @@ class Typo3Update_Sniffs_Classname_InstantiationWithMakeInstanceSniff extends Ab
*/
public function register()
{
return Tokens::$functionNameTokens;
return [T_STRING];
}
/**
......@@ -57,13 +57,12 @@ class Typo3Update_Sniffs_Classname_InstantiationWithMakeInstanceSniff extends Ab
return;
}
$classnamePosition = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, $stackPtr);
$classnamePosition = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, $stackPtr, null, false, null, true);
if ($classnamePosition === false) {
return;
}
$classname = $tokens[$classnamePosition]['content'];
$this->originalTokenContent = $tokens[$classnamePosition]['content'];
$this->processFeatures($phpcsFile, $classnamePosition, $classname);
}
}
......@@ -51,10 +51,18 @@ class Typo3Update_Sniffs_Classname_TypeHintSniff extends AbstractClassnameChecke
continue;
}
$position = $phpcsFile->findPrevious(T_STRING, $parameter['token'], $stackPtr, false, null, true);
$position = $phpcsFile->findPrevious([
T_OPEN_PARENTHESIS, T_COMMA
], $parameter['token'] - 2, $stackPtr, false, null, true);
if ($position === false) {
continue;
}
$position = $phpcsFile->findNext(T_STRING, $position);
if ($position === false) {
continue;
}
$this->processFeatures($phpcsFile, $position, $parameter['type_hint']);
}
}
......
......@@ -19,7 +19,6 @@
* 02110-1301, USA.
*/
use PHP_CodeSniffer_File as PhpCsFile;
use Typo3Update\Sniffs\Classname\AbstractClassnameChecker;
class Typo3Update_Sniffs_Classname_UseSniff extends AbstractClassnameChecker
......
<?php
/*
* Copyright (C) 2017 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program 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 2
* of the License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHP_CodeSniffer_File as PhpCsFile;
use Typo3Update\Options;
use Typo3Update\Sniffs\ExtendedPhpCsSupportTrait;
use Typo3Update\Sniffs\Removed\AbstractGenericUsage;
class Typo3Update_Sniffs_Removed_ExtensionSniff extends AbstractGenericUsage
{
use ExtendedPhpCsSupportTrait;
/**
* @var array
*/
public $methodsToCheck = ['isLoaded', 'extPath', 'extRelPath', 'getCN', 'getExtensionVersion'];
public function register()
{
return [T_STRING];
}
protected function getRemovedConfigFiles()
{
return Options::getRemovedExtensionConfigFiles();
}
protected function findRemoved(PhpCsFile $phpcsFile, $stackPtr)
{
$token = $phpcsFile->getTokens()[$stackPtr];
if (!$this->isFunctionCall($phpcsFile, $stackPtr)
|| !in_array($token['content'], $this->methodsToCheck)
) {
return [];
}
$arguments = $this->getFunctionCallParameters($phpcsFile, $stackPtr);
if ($this->configured->isRemoved($arguments[0])) {
return [$this->configured->getRemoved($arguments[0])];
}
return [];
}
}
......@@ -42,23 +42,6 @@ class Typo3Update_Sniffs_Removed_TypoScriptConstantSniff extends AbstractGeneric
];
}
protected function prepareStructure(array $typo3Versions)
{
$newStructure = [];
foreach ($typo3Versions as $typo3Version => $removals) {
foreach ($removals as $removed => $config) {
$config['name'] = $removed;
$config['identifier'] = $removed;
$config['oldUsage'] = $removed;
$config['versionRemoved'] = $typo3Version;
$newStructure[$removed] = $config;
}
}
return $newStructure;
}
protected function findRemoved(PhpCsFile $phpcsFile, $stackPtr)
{
$removed = [];
......
......@@ -56,14 +56,41 @@
"severity": 5,
"source": "Typo3Update.Classname.Inheritance.legacyClassname",
"type": "ERROR"
},
{
"column": 35,
"fixable": false,
"line": 34,
"message": "Calls to removed code are not allowed; found perm. Removed in 7.0. The logic is moved into EXT:beuser. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-62339-MoveExtPermIntoExtBeuser.html",
"severity": 5,
"source": "Typo3Update.Classname.Inheritance.RemovedExtension.perm",
"type": "WARNING"
},
{
"column": 6,
"fixable": false,
"line": 35,
"message": "Calls to removed code are not allowed; found perm. Removed in 7.0. The logic is moved into EXT:beuser. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-62339-MoveExtPermIntoExtBeuser.html",
"severity": 5,
"source": "Typo3Update.Classname.Inheritance.RemovedExtension.perm",
"type": "WARNING"
},
{
"column": 5,
"fixable": false,
"line": 36,
"message": "Calls to removed code are not allowed; found perm. Removed in 7.0. The logic is moved into EXT:beuser. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-62339-MoveExtPermIntoExtBeuser.html",
"severity": 5,
"source": "Typo3Update.Classname.Inheritance.RemovedExtension.perm",
"type": "WARNING"
}
],
"warnings": 0
"warnings": 3
}
},
"totals": {
"errors": 6,
"fixable": 6,
"warnings": 0
"warnings": 3
}
}
......@@ -30,3 +30,10 @@ class InputFileForIssues extends Tx_Extbase_Configuration_Configurationmanager i
{
}
class InputFileForIssues extends \TYPO3\CMS\Perm\Controller\PermissionAjaxController implements
\TYPO3\CMS\Perm\Controller\PermissionAjaxController,
TYPO3\CMS\Perm\Controller\PermissionModuleController
{
}
......@@ -19,5 +19,5 @@
- // @var Tx_Extbase_Command_HelpCommandController $variable
+ // @var \TYPO3\CMS\Extbase\Command\HelpCommandController $variable
$variable;
}
}
/* @var $variable TYPO3\CMS\Perm\Controller\PermissionAjaxController */
......@@ -38,14 +38,50 @@
"severity": 5,
"source": "Typo3Update.Classname.InlineComment.legacyClassname",
"type": "ERROR"
},
{
"column": 9,
"fixable": false,
"line": 38,
"message": "Calls to removed code are not allowed; found perm. Removed in 7.0. The logic is moved into EXT:beuser. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-62339-MoveExtPermIntoExtBeuser.html",
"severity": 5,
"source": "Typo3Update.Classname.InlineComment.RemovedExtension.perm",
"type": "WARNING"
},
{
"column": 9,
"fixable": false,
"line": 41,
"message": "Calls to removed code are not allowed; found perm. Removed in 7.0. The logic is moved into EXT:beuser. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-62339-MoveExtPermIntoExtBeuser.html",
"severity": 5,
"source": "Typo3Update.Classname.InlineComment.RemovedExtension.perm",
"type": "WARNING"
},
{
"column": 9,
"fixable": false,
"line": 44,
"message": "Calls to removed code are not allowed; found perm. Removed in 7.0. The logic is moved into EXT:beuser. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-62339-MoveExtPermIntoExtBeuser.html",
"severity": 5,
"source": "Typo3Update.Classname.InlineComment.RemovedExtension.perm",
"type": "WARNING"
},
{
"column": 9,
"fixable": false,
"line": 47,
"message": "Calls to removed code are not allowed; found perm. Removed in 7.0. The logic is moved into EXT:beuser. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-62339-MoveExtPermIntoExtBeuser.html",
"severity": 5,
"source": "Typo3Update.Classname.InlineComment.RemovedExtension.perm",
"type": "WARNING"
}
],
"warnings": 0
"warnings": 4
}
},
"totals": {
"errors": 4,
"fixable": 4,
"warnings": 0
"warnings": 4
}
}
......@@ -34,5 +34,17 @@ class InputFileForIssues
// @var Tx_Extbase_Command_HelpCommandController $variable
$variable;
/* @var $variable TYPO3\CMS\Perm\Controller\PermissionAjaxController */
$variable;
// @var $variable \TYPO3\CMS\Perm\Controller\PermissionAjaxController
$variable;
/* @var \TYPO3\CMS\Perm\Controller\PermissionAjaxController $variable */
$variable;
// @var TYPO3\CMS\Perm\Controller\PermissionAjaxController $variable
$variable;
}
}
--- tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/InstanceofSniff/InputFileForIssues.php
+++ PHP_CodeSniffer
@@ -19,6 +19,6 @@
@@ -19,7 +19,7 @@
* 02110-1301, USA.
*/
......@@ -8,3 +8,4 @@
+if ($a instanceof \TYPO3\CMS\Core\SingletonInterface) {
// do something
}
if ($a instanceof \TYPO3\CMS\Perm\Controller\PermissionAjaxController) {
......@@ -11,14 +11,32 @@
"severity": 5,
"source": "Typo3Update.Classname.Instanceof.legacyClassname",
"type": "ERROR"
},
{
"column": 20,
"fixable": false,
"line": 25,
"message": "Calls to removed code are not allowed; found perm. Removed in 7.0. The logic is moved into EXT:beuser. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-62339-MoveExtPermIntoExtBeuser.html",
"severity": 5,
"source": "Typo3Update.Classname.Instanceof.RemovedExtension.perm",
"type": "WARNING"
},
{
"column": 19,
"fixable": false,
"line": 28,
"message": "Calls to removed code are not allowed; found perm. Removed in 7.0. The logic is moved into EXT:beuser. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-62339-MoveExtPermIntoExtBeuser.html",
"severity": 5,
"source": "Typo3Update.Classname.Instanceof.RemovedExtension.perm",
"type": "WARNING"
}
],
"warnings": 0
"warnings": 2
}
},
"totals": {
"errors": 1,
"fixable": 1,
"warnings": 0
"warnings": 2
}
}
......@@ -22,3 +22,9 @@
if ($a instanceof t3lib_Singleton) {
// do something
}
if ($a instanceof \TYPO3\CMS\Perm\Controller\PermissionAjaxController) {
// do something
}
if ($a instanceof TYPO3\CMS\Perm\Controller\PermissionAjaxController) {
// do something
}
......@@ -11,14 +11,23 @@
"severity": 5,
"source": "Typo3Update.Classname.InstantiationWithMakeInstance.legacyClassname",
"type": "ERROR"
},
{
"column": 25,
"fixable": false,
"line": 27,
"message": "Calls to removed code are not allowed; found perm. Removed in 7.0. The logic is moved into EXT:beuser. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-62339-MoveExtPermIntoExtBeuser.html",
"severity": 5,
"source": "Typo3Update.Classname.InstantiationWithMakeInstance.RemovedExtension.perm",
"type": "WARNING"
}
],
"warnings": 0
"warnings": 1