From f972533e04e3e5c65cb8ad5c054351bd358768c1 Mon Sep 17 00:00:00 2001
From: Daniel Siepmann <coding@daniel-siepmann.de>
Date: Tue, 25 Apr 2017 09:22:50 +0200
Subject: [PATCH 01/11] WIP|FEATURE: Check for removed php classes.

* Add feature to existing code base and logic, see #72 .
* Add first removed classes for TYPO3 7.0 as example.
* Adjust first test to make sure basic implementation works.

Relates: #41
---
 .../Configuration/Features/RemovedClass.yaml  |  14 +
 .../Configuration/Removed/Classes/7.0.yaml    |  11 +
 .../Feature/RemovedByYamlConfiguration.php    | 294 ++++++++++++++++++
 .../Feature/RemovedClassFeature.php           |  56 ++++
 src/Standards/Typo3Update/Options.php         |  13 +
 .../PhpDocCommentSniff/Expected.diff          |   3 +-
 .../PhpDocCommentSniff/Expected.json          |  17 +-
 .../PhpDocCommentSniff/InputFileForIssues.php |   1 +
 8 files changed, 404 insertions(+), 5 deletions(-)
 create mode 100644 src/Standards/Typo3Update/Configuration/Features/RemovedClass.yaml
 create mode 100644 src/Standards/Typo3Update/Configuration/Removed/Classes/7.0.yaml
 create mode 100644 src/Standards/Typo3Update/Feature/RemovedByYamlConfiguration.php
 create mode 100644 src/Standards/Typo3Update/Feature/RemovedClassFeature.php

diff --git a/src/Standards/Typo3Update/Configuration/Features/RemovedClass.yaml b/src/Standards/Typo3Update/Configuration/Features/RemovedClass.yaml
new file mode 100644
index 0000000..1b7974f
--- /dev/null
+++ b/src/Standards/Typo3Update/Configuration/Features/RemovedClass.yaml
@@ -0,0 +1,14 @@
+Typo3Update\Feature\RemovedClassFeature:
+  - 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
diff --git a/src/Standards/Typo3Update/Configuration/Removed/Classes/7.0.yaml b/src/Standards/Typo3Update/Configuration/Removed/Classes/7.0.yaml
new file mode 100644
index 0000000..2341204
--- /dev/null
+++ b/src/Standards/Typo3Update/Configuration/Removed/Classes/7.0.yaml
@@ -0,0 +1,11 @@
+# Breaking changes in 7.0: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Index.html#breaking-changes
+'7.0':
+  \TYPO3\CMS\Backend\Template\MediumDocumentTemplate:
+    replacement: 'Use \TYPO3\CMS\Backend\Template\DocumentTemplate instead'
+    docsUrl: 'https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61782-DeprecatedDocumentTemplateClassesRemoved.html'
+  \TYPO3\CMS\Backend\Template\SmallDocumentTemplate:
+    replacement: 'Use \TYPO3\CMS\Backend\Template\DocumentTemplate instead'
+    docsUrl: 'https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61782-DeprecatedDocumentTemplateClassesRemoved.html'
+  \TYPO3\CMS\Backend\Template\StandardDocumentTemplate:
+    replacement: 'Use \TYPO3\CMS\Backend\Template\DocumentTemplate instead'
+    docsUrl: 'https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61782-DeprecatedDocumentTemplateClassesRemoved.html'
diff --git a/src/Standards/Typo3Update/Feature/RemovedByYamlConfiguration.php b/src/Standards/Typo3Update/Feature/RemovedByYamlConfiguration.php
new file mode 100644
index 0000000..53f28a5
--- /dev/null
+++ b/src/Standards/Typo3Update/Feature/RemovedByYamlConfiguration.php
@@ -0,0 +1,294 @@
+<?php
+namespace Typo3Update\Sniffs\Removed;
+
+/*
+ * 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 PHP_CodeSniffer_Sniff as PhpCsSniff;
+use PHP_CodeSniffer_Tokens as Tokens;
+use Symfony\Component\Yaml\Yaml;
+use Typo3Update\Options;
+
+/**
+ * Contains common functionality for removed code like constants or functions.
+ *
+ * Removed parts are configured using YAML-Files, for examples see
+ * src/Standards/Typo3Update/Configuration/Removed/Constants/7.0.yaml Also
+ * check out the configuration options in Readme.rst.
+ */
+abstract class AbstractGenericUsage implements PhpCsSniff
+{
+    use \Typo3Update\Sniffs\ExtendedPhpCsSupportTrait;
+
+    /**
+     * Configuration to define removed code.
+     *
+     * @var array
+     */
+    protected $configured = [];
+
+    /**
+     * Constant for the current sniff instance.
+     * @var array
+     */
+    protected $removed = [];
+
+    public function __construct()
+    {
+        if ($this->configured === []) {
+            foreach ($this->getRemovedConfigFiles() as $file) {
+                $this->configured = array_merge(
+                    $this->configured,
+                    $this->prepareStructure(Yaml::parse(file_get_contents((string) $file)))
+                );
+            }
+        }
+    }
+
+    /**
+     * Return file names containing removed configurations.
+     *
+     * @return array<string>
+     */
+    abstract protected function getRemovedConfigFiles();
+
+    /**
+     * Prepares structure from config for later usage.
+     *
+     * @param array $typo3Versions
+     * @return array
+     */
+    protected function prepareStructure(array $typo3Versions)
+    {
+        $newStructure = [];
+
+        foreach ($typo3Versions as $typo3Version => $removals) {
+            foreach ($removals as $removed => $config) {
+                // Split static methods and methods.
+                $split = preg_split('/::|->/', $removed);
+
+                $newStructure[$removed] = $config;
+
+                $newStructure[$removed]['static'] = strpos($removed, '::') !== false;
+                $newStructure[$removed]['fqcn'] = null;
+                $newStructure[$removed]['class'] = null;
+                $newStructure[$removed]['name'] = $split[0];
+                $newStructure[$removed]['version_removed'] = $typo3Version;
+
+                // If split contains two parts, it's a class
+                if (isset($split[1])) {
+                    $newStructure[$removed]['fqcn'] = $split[0];
+                    $newStructure[$removed]['class'] = array_slice(
+                        explode('\\', $newStructure[$removed]['fqcn']),
+                        -1
+                    )[0];
+                    $newStructure[$removed]['name'] = $split[1];
+                }
+            };
+        }
+
+        return $newStructure;
+    }
+
+    /**
+     * Processes the tokens that this sniff is interested in.
+     *
+     * This is the default implementation, as most of the time next T_STRING is
+     * the class name. This way only the register method has to be registered
+     * in default cases.
+     *
+     * @param PhpCsFile $phpcsFile The file where the token was found.
+     * @param int                  $stackPtr  The position in the stack where
+     *                                        the token was found.
+     *
+     * @return void
+     */
+    public function process(PhpCsFile $phpcsFile, $stackPtr)
+    {
+        if (!$this->isRemoved($phpcsFile, $stackPtr)) {
+            return;
+        }
+
+        $this->addMessage($phpcsFile, $stackPtr);
+    }
+
+    /**
+     * Check whether the current token is removed.
+     *
+     * @param PhpCsFile $phpcsFile
+     * @param int $stackPtr
+     * @return bool
+     */
+    protected function isRemoved(PhpCsFile $phpcsFile, $stackPtr)
+    {
+        $tokens = $phpcsFile->getTokens();
+        $staticPosition = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true, null, true);
+
+        $name = $tokens[$stackPtr]['content'];
+        $isStatic = false;
+        $class = false;
+
+        if ($staticPosition !== false) {
+            $isStatic = $tokens[$staticPosition]['code'] === T_DOUBLE_COLON;
+        }
+
+        if ($isStatic) {
+            $class = $phpcsFile->findPrevious(T_STRING, $staticPosition, null, false, null, true);
+            if ($class !== false) {
+                $class = $tokens[$class]['content'];
+            }
+        }
+
+        $this->removed = $this->getMatchingRemoved($name, $class, $isStatic);
+        return $this->removed !== [];
+    }
+
+    /**
+     * Returns all matching removed functions for given arguments.
+     *
+     * @param string $name
+     * @param string $className The last part of the class name, splitted by namespaces.
+     * @param bool $isStatic
+     *
+     * @return array
+     */
+    protected function getMatchingRemoved($name, $className, $isStatic)
+    {
+        // We will not match any static calls, without the class name, at least for now.
+        if ($isStatic === true && $className === false) {
+            return [];
+        }
+
+        return array_filter(
+            $this->configured,
+            function ($config) use ($name, $isStatic, $className) {
+                return $name === $config['name']
+                    && $isStatic === $config['static']
+                    && (
+                        $className === $config['class']
+                        || $className === false
+                    )
+                ;
+            }
+        );
+    }
+
+    /**
+     * Add message for the given token position.
+     *
+     * Default is a warning, non fixable. Just overwrite in concrete sniff, if
+     * something different suites better.
+     *
+     * @param PhpCsFile $phpcsFile
+     * @param int $tokenPosition
+     *
+     * @return void
+     */
+    protected function addMessage(PhpCsFile $phpcsFile, $tokenPosition)
+    {
+        foreach ($this->removed as $constant) {
+            $phpcsFile->addWarning(
+                'Legacy calls are not allowed; found %s. Removed in %s. %s. See: %s',
+                $tokenPosition,
+                $this->getIdentifier($constant),
+                [
+                    $this->getOldUsage($constant),
+                    $this->getRemovedVersion($constant),
+                    $this->getReplacement($constant),
+                    $this->getDocsUrl($constant),
+                ]
+            );
+        }
+    }
+
+    /**
+     * Identifier for configuring this specific error / warning through PHPCS.
+     *
+     * @param array $config
+     *
+     * @return string
+     */
+    protected function getIdentifier(array $config)
+    {
+        $name = $config['name'];
+        if ($config['class']) {
+            $name = $config['class'] . '.' . $name;
+        }
+
+        return $name;
+    }
+
+    /**
+     * The original call, to allow user to check matches.
+     *
+     * As we match the name, that can be provided by multiple classes, you
+     * should provide an example, so users can check that this is the legacy
+     * one.
+     *
+     * @param array $config
+     *
+     * @return string
+     */
+    abstract protected function getOldUsage(array $config);
+
+    /**
+     * Returns TYPO3 version when the breaking change happened.
+     *
+     * To let user decide whether this is important for him.
+     *
+     * @param array $config
+     *
+     * @return string
+     */
+    protected function getRemovedVersion(array $config)
+    {
+        return $config['version_removed'];
+    }
+
+    /**
+     * The new call, or information how to migrate.
+     *
+     * To provide feedback for user to ease migration.
+     *
+     * @param array $config
+     *
+     * @return string
+     */
+    protected function getReplacement(array $config)
+    {
+        $newCall = $config['replacement'];
+        if ($newCall !== null) {
+            return $newCall;
+        }
+        return 'There is no replacement, just remove call';
+    }
+
+    /**
+     * Allow user to lookup the official docs related to this deprecation / breaking change.
+     *
+     * @param array $config The converted structure for a single constant.
+     *
+     * @return string
+     */
+    protected function getDocsUrl(array $config)
+    {
+        return $config['docsUrl'];
+    }
+}
diff --git a/src/Standards/Typo3Update/Feature/RemovedClassFeature.php b/src/Standards/Typo3Update/Feature/RemovedClassFeature.php
new file mode 100644
index 0000000..d81c34d
--- /dev/null
+++ b/src/Standards/Typo3Update/Feature/RemovedClassFeature.php
@@ -0,0 +1,56 @@
+<?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 as PhpCs;
+use PHP_CodeSniffer_File as PhpCsFile;
+use PHP_CodeSniffer_Sniff as PhpCsSniff;
+
+/**
+ * This feature will add fixable errors for old legacy classnames.
+ *
+ * Can be attached to sniffs returning classnames.
+ */
+class RemovedClassFeature implements FeatureInterface
+{
+    /**
+     * Process like a PHPCS Sniff.
+     *
+     * @param PhpCsFile $phpcsFile
+     * @param int $classnamePosition
+     * @param string $classname
+     *
+     * @return void
+     */
+    public function process(PhpCsFile $phpcsFile, $classnamePosition, $classname)
+    {
+        if ($this->isClassnameRemoved($classname) === false) {
+            return;
+        }
+
+        $phpcsFile->addError(
+            'Removed classes are not allowed; found "%s", use "%s" instead',
+            $classnamePosition,
+            'removedClassname',
+            [$classname]
+        );
+    }
+}
diff --git a/src/Standards/Typo3Update/Options.php b/src/Standards/Typo3Update/Options.php
index 1ce768c..935da03 100644
--- a/src/Standards/Typo3Update/Options.php
+++ b/src/Standards/Typo3Update/Options.php
@@ -95,6 +95,19 @@ class Options
         );
     }
 
+    /**
+     * Returns an array of absolute file names containing removed class configurations.
+     *
+     * @return array<string>
+     */
+    public static function getRemovedClassConfigFiles()
+    {
+        return static::getOptionFileNames(
+            'removedClassConfigFiles',
+            __DIR__ . '/../Configuration/Removed/Classes/*.yaml'
+        );
+    }
+
     /**
      * Get the option by optionName, if not defined, use default.
      *
diff --git a/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/Expected.diff b/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/Expected.diff
index 807e03e..36a8cf7 100644
--- a/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/Expected.diff
+++ b/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/Expected.diff
@@ -1,6 +1,6 @@
 --- tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/InputFileForIssues.php
 +++ PHP_CodeSniffer
-@@ -22,19 +22,19 @@
+@@ -22,20 +22,20 @@
  class InputFileForIssues
  {
      /**
@@ -13,6 +13,7 @@
      /**
 -     * @param t3lib_div
 +     * @param \TYPO3\CMS\Core\Utility\GeneralUtility
+      * @param \TYPO3\CMS\Backend\Template\MediumDocumentTemplate
       *
 -     * @return Tx_Extbase_Configuration_Configurationmanager
 +     * @return \TYPO3\CMS\Extbase\Configuration\ConfigurationManager
diff --git a/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/Expected.json b/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/Expected.json
index dc72038..c528d04 100644
--- a/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/Expected.json
+++ b/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/Expected.json
@@ -21,10 +21,19 @@
                     "source": "Typo3Update.Classname.PhpDocComment.legacyClassname",
                     "type": "ERROR"
                 },
+                {
+                    "column": 15,
+                    "fixable": false,
+                    "line": 32,
+                    "message": "Legacy calls are not allowed; found \\TYPO3\\CMS\\Backend\\Template\\MediumDocumentTemplate. Removed in 7.0. Use \\TYPO3\\CMS\\Backend\\Template\\DocumentTemplate instead. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61782-DeprecatedDocumentTemplateClassesRemoved.html",
+                    "severity": 5,
+                    "source": "Typo3Update.LegacyClassnames.DocComment.TYPO3_CMS_Backend_Template_MediumDocumentTemplate",
+                    "type": "WARNING"
+                },
                 {
                     "column": 16,
                     "fixable": true,
-                    "line": 33,
+                    "line": 34,
                     "message": "Legacy classes are not allowed; found \"Tx_Extbase_Configuration_Configurationmanager\", use \"TYPO3\\CMS\\Extbase\\Configuration\\ConfigurationManager\" instead",
                     "severity": 5,
                     "source": "Typo3Update.Classname.PhpDocComment.legacyClassname",
@@ -33,19 +42,19 @@
                 {
                     "column": 18,
                     "fixable": true,
-                    "line": 37,
+                    "line": 38,
                     "message": "Legacy classes are not allowed; found \"t3lib_div\", use \"TYPO3\\CMS\\Core\\Utility\\GeneralUtility\" instead",
                     "severity": 5,
                     "source": "Typo3Update.Classname.PhpDocComment.legacyClassname",
                     "type": "ERROR"
                 }
             ],
-            "warnings": 0
+            "warnings": 1
         }
     },
     "totals": {
         "errors": 4,
         "fixable": 4,
-        "warnings": 0
+        "warnings": 1
     }
 }
diff --git a/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/InputFileForIssues.php b/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/InputFileForIssues.php
index 92acefb..7a2de67 100644
--- a/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/InputFileForIssues.php
+++ b/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/InputFileForIssues.php
@@ -29,6 +29,7 @@ class InputFileForIssues
 
     /**
      * @param t3lib_div
+     * @param \TYPO3\CMS\Backend\Template\MediumDocumentTemplate
      *
      * @return Tx_Extbase_Configuration_Configurationmanager
      */
-- 
GitLab


From fad2a4e498e11026c99a78e17729e17e6a2f5ce2 Mon Sep 17 00:00:00 2001
From: Daniel Siepmann <coding@daniel-siepmann.de>
Date: Thu, 27 Apr 2017 11:48:59 +0200
Subject: [PATCH 02/11] FEATURE: Allow empty feature yaml files

* Handle empty yaml files for features in options class.
---
 src/Standards/Typo3Update/Options.php | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/Standards/Typo3Update/Options.php b/src/Standards/Typo3Update/Options.php
index 935da03..6db1bd2 100644
--- a/src/Standards/Typo3Update/Options.php
+++ b/src/Standards/Typo3Update/Options.php
@@ -140,10 +140,11 @@ class Options
         );
 
         foreach ($fileNames as $file) {
-            $option = array_merge(
-                $option,
-                Yaml::parse(file_get_contents((string) $file))
-            );
+            $content = Yaml::parse(file_get_contents((string) $file));
+            if ($content === null) {
+                $content = [];
+            }
+            $option = array_merge($option, $content);
         }
 
         return $option;
-- 
GitLab


From 2659066e2125c83ed0abe09d5d43716215b6c3eb Mon Sep 17 00:00:00 2001
From: Daniel Siepmann <coding@daniel-siepmann.de>
Date: Thu, 27 Apr 2017 12:50:10 +0200
Subject: [PATCH 03/11] WIP|TASK: Migrate
 Typo3Update_Sniffs_Removed_TypoScriptSniff

* Refactor yaml based removed check architecture.
* Migrate TypoScriptSniff to new architecture.

Relates: #71
---
 composer.json                                 |   1 +
 .../Feature/RemovedByYamlConfiguration.php    | 294 ------------------
 .../RemovedByYamlConfiguration.php            |  60 ++++
 .../Sniffs/Removed/AbstractGenericUsage.php   | 233 ++------------
 .../Sniffs/Removed/TypoScriptSniff.php        |  47 +--
 5 files changed, 94 insertions(+), 541 deletions(-)
 delete mode 100644 src/Standards/Typo3Update/Feature/RemovedByYamlConfiguration.php
 create mode 100644 src/Standards/Typo3Update/RemovedByYamlConfiguration.php

diff --git a/composer.json b/composer.json
index 6f9a5df..87aab93 100644
--- a/composer.json
+++ b/composer.json
@@ -23,6 +23,7 @@
         ]
     },
     "require": {
+        "php": "~7.1",
         "helmich/typo3-typoscript-parser": "1.1.*",
         "squizlabs/php_codesniffer": "2.8.*",
         "symfony/yaml": "3.2.*",
diff --git a/src/Standards/Typo3Update/Feature/RemovedByYamlConfiguration.php b/src/Standards/Typo3Update/Feature/RemovedByYamlConfiguration.php
deleted file mode 100644
index 53f28a5..0000000
--- a/src/Standards/Typo3Update/Feature/RemovedByYamlConfiguration.php
+++ /dev/null
@@ -1,294 +0,0 @@
-<?php
-namespace Typo3Update\Sniffs\Removed;
-
-/*
- * 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 PHP_CodeSniffer_Sniff as PhpCsSniff;
-use PHP_CodeSniffer_Tokens as Tokens;
-use Symfony\Component\Yaml\Yaml;
-use Typo3Update\Options;
-
-/**
- * Contains common functionality for removed code like constants or functions.
- *
- * Removed parts are configured using YAML-Files, for examples see
- * src/Standards/Typo3Update/Configuration/Removed/Constants/7.0.yaml Also
- * check out the configuration options in Readme.rst.
- */
-abstract class AbstractGenericUsage implements PhpCsSniff
-{
-    use \Typo3Update\Sniffs\ExtendedPhpCsSupportTrait;
-
-    /**
-     * Configuration to define removed code.
-     *
-     * @var array
-     */
-    protected $configured = [];
-
-    /**
-     * Constant for the current sniff instance.
-     * @var array
-     */
-    protected $removed = [];
-
-    public function __construct()
-    {
-        if ($this->configured === []) {
-            foreach ($this->getRemovedConfigFiles() as $file) {
-                $this->configured = array_merge(
-                    $this->configured,
-                    $this->prepareStructure(Yaml::parse(file_get_contents((string) $file)))
-                );
-            }
-        }
-    }
-
-    /**
-     * Return file names containing removed configurations.
-     *
-     * @return array<string>
-     */
-    abstract protected function getRemovedConfigFiles();
-
-    /**
-     * Prepares structure from config for later usage.
-     *
-     * @param array $typo3Versions
-     * @return array
-     */
-    protected function prepareStructure(array $typo3Versions)
-    {
-        $newStructure = [];
-
-        foreach ($typo3Versions as $typo3Version => $removals) {
-            foreach ($removals as $removed => $config) {
-                // Split static methods and methods.
-                $split = preg_split('/::|->/', $removed);
-
-                $newStructure[$removed] = $config;
-
-                $newStructure[$removed]['static'] = strpos($removed, '::') !== false;
-                $newStructure[$removed]['fqcn'] = null;
-                $newStructure[$removed]['class'] = null;
-                $newStructure[$removed]['name'] = $split[0];
-                $newStructure[$removed]['version_removed'] = $typo3Version;
-
-                // If split contains two parts, it's a class
-                if (isset($split[1])) {
-                    $newStructure[$removed]['fqcn'] = $split[0];
-                    $newStructure[$removed]['class'] = array_slice(
-                        explode('\\', $newStructure[$removed]['fqcn']),
-                        -1
-                    )[0];
-                    $newStructure[$removed]['name'] = $split[1];
-                }
-            };
-        }
-
-        return $newStructure;
-    }
-
-    /**
-     * Processes the tokens that this sniff is interested in.
-     *
-     * This is the default implementation, as most of the time next T_STRING is
-     * the class name. This way only the register method has to be registered
-     * in default cases.
-     *
-     * @param PhpCsFile $phpcsFile The file where the token was found.
-     * @param int                  $stackPtr  The position in the stack where
-     *                                        the token was found.
-     *
-     * @return void
-     */
-    public function process(PhpCsFile $phpcsFile, $stackPtr)
-    {
-        if (!$this->isRemoved($phpcsFile, $stackPtr)) {
-            return;
-        }
-
-        $this->addMessage($phpcsFile, $stackPtr);
-    }
-
-    /**
-     * Check whether the current token is removed.
-     *
-     * @param PhpCsFile $phpcsFile
-     * @param int $stackPtr
-     * @return bool
-     */
-    protected function isRemoved(PhpCsFile $phpcsFile, $stackPtr)
-    {
-        $tokens = $phpcsFile->getTokens();
-        $staticPosition = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true, null, true);
-
-        $name = $tokens[$stackPtr]['content'];
-        $isStatic = false;
-        $class = false;
-
-        if ($staticPosition !== false) {
-            $isStatic = $tokens[$staticPosition]['code'] === T_DOUBLE_COLON;
-        }
-
-        if ($isStatic) {
-            $class = $phpcsFile->findPrevious(T_STRING, $staticPosition, null, false, null, true);
-            if ($class !== false) {
-                $class = $tokens[$class]['content'];
-            }
-        }
-
-        $this->removed = $this->getMatchingRemoved($name, $class, $isStatic);
-        return $this->removed !== [];
-    }
-
-    /**
-     * Returns all matching removed functions for given arguments.
-     *
-     * @param string $name
-     * @param string $className The last part of the class name, splitted by namespaces.
-     * @param bool $isStatic
-     *
-     * @return array
-     */
-    protected function getMatchingRemoved($name, $className, $isStatic)
-    {
-        // We will not match any static calls, without the class name, at least for now.
-        if ($isStatic === true && $className === false) {
-            return [];
-        }
-
-        return array_filter(
-            $this->configured,
-            function ($config) use ($name, $isStatic, $className) {
-                return $name === $config['name']
-                    && $isStatic === $config['static']
-                    && (
-                        $className === $config['class']
-                        || $className === false
-                    )
-                ;
-            }
-        );
-    }
-
-    /**
-     * Add message for the given token position.
-     *
-     * Default is a warning, non fixable. Just overwrite in concrete sniff, if
-     * something different suites better.
-     *
-     * @param PhpCsFile $phpcsFile
-     * @param int $tokenPosition
-     *
-     * @return void
-     */
-    protected function addMessage(PhpCsFile $phpcsFile, $tokenPosition)
-    {
-        foreach ($this->removed as $constant) {
-            $phpcsFile->addWarning(
-                'Legacy calls are not allowed; found %s. Removed in %s. %s. See: %s',
-                $tokenPosition,
-                $this->getIdentifier($constant),
-                [
-                    $this->getOldUsage($constant),
-                    $this->getRemovedVersion($constant),
-                    $this->getReplacement($constant),
-                    $this->getDocsUrl($constant),
-                ]
-            );
-        }
-    }
-
-    /**
-     * Identifier for configuring this specific error / warning through PHPCS.
-     *
-     * @param array $config
-     *
-     * @return string
-     */
-    protected function getIdentifier(array $config)
-    {
-        $name = $config['name'];
-        if ($config['class']) {
-            $name = $config['class'] . '.' . $name;
-        }
-
-        return $name;
-    }
-
-    /**
-     * The original call, to allow user to check matches.
-     *
-     * As we match the name, that can be provided by multiple classes, you
-     * should provide an example, so users can check that this is the legacy
-     * one.
-     *
-     * @param array $config
-     *
-     * @return string
-     */
-    abstract protected function getOldUsage(array $config);
-
-    /**
-     * Returns TYPO3 version when the breaking change happened.
-     *
-     * To let user decide whether this is important for him.
-     *
-     * @param array $config
-     *
-     * @return string
-     */
-    protected function getRemovedVersion(array $config)
-    {
-        return $config['version_removed'];
-    }
-
-    /**
-     * The new call, or information how to migrate.
-     *
-     * To provide feedback for user to ease migration.
-     *
-     * @param array $config
-     *
-     * @return string
-     */
-    protected function getReplacement(array $config)
-    {
-        $newCall = $config['replacement'];
-        if ($newCall !== null) {
-            return $newCall;
-        }
-        return 'There is no replacement, just remove call';
-    }
-
-    /**
-     * Allow user to lookup the official docs related to this deprecation / breaking change.
-     *
-     * @param array $config The converted structure for a single constant.
-     *
-     * @return string
-     */
-    protected function getDocsUrl(array $config)
-    {
-        return $config['docsUrl'];
-    }
-}
diff --git a/src/Standards/Typo3Update/RemovedByYamlConfiguration.php b/src/Standards/Typo3Update/RemovedByYamlConfiguration.php
new file mode 100644
index 0000000..f1ab402
--- /dev/null
+++ b/src/Standards/Typo3Update/RemovedByYamlConfiguration.php
@@ -0,0 +1,60 @@
+<?php
+namespace Typo3Update;
+
+/*
+ * 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 Symfony\Component\Yaml\Yaml;
+
+class RemovedByYamlConfiguration
+{
+    /**
+     * Configuration to define removed code.
+     *
+     * @var array
+     */
+    protected $configured = [];
+
+    public function __construct(array $configFiles, $prepareStructure)
+    {
+        foreach ($configFiles as $file) {
+            $this->configured = array_merge(
+                $this->configured,
+                $prepareStructure(Yaml::parse(file_get_contents((string) $file)))
+            );
+        }
+    }
+
+    public function isRemoved($identifier)
+    {
+        return isset($this->configured[$identifier]);
+    }
+
+    public function getRemoved($identifier)
+    {
+        if (!$this->isRemoved($identifier)) {
+            throw new \Exception(
+                sprintf('Identifier "%s" is not configured to be removed.', $identifier),
+                1493289133
+            );
+        }
+
+        return $this->configured[$identifier];
+    }
+}
diff --git a/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php
index 3cda85a..f8e8e0a 100644
--- a/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php
+++ b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php
@@ -22,9 +22,7 @@ namespace Typo3Update\Sniffs\Removed;
 
 use PHP_CodeSniffer_File as PhpCsFile;
 use PHP_CodeSniffer_Sniff as PhpCsSniff;
-use PHP_CodeSniffer_Tokens as Tokens;
-use Symfony\Component\Yaml\Yaml;
-use Typo3Update\Options;
+use Typo3Update\RemovedByYamlConfiguration;
 
 /**
  * Contains common functionality for removed code like constants or functions.
@@ -35,233 +33,60 @@ use Typo3Update\Options;
  */
 abstract class AbstractGenericUsage implements PhpCsSniff
 {
-    use \Typo3Update\Sniffs\ExtendedPhpCsSupportTrait;
-
-    /**
-     * Configuration to define removed code.
-     *
-     * @var array
-     */
-    protected $configured = [];
-
-    /**
-     * Entries removed in current sniff.
-     * @var array
-     */
-    protected $removed = [];
+    protected $configured;
 
     public function __construct()
     {
-        if ($this->configured === []) {
-            foreach ($this->getRemovedConfigFiles() as $file) {
-                $this->configured = array_merge(
-                    $this->configured,
-                    $this->prepareStructure(Yaml::parse(file_get_contents((string) $file)))
-                );
-            }
-        }
+        $this->configured = new RemovedByYamlConfiguration(
+            $this->getRemovedConfigFiles(),
+            \Closure::fromCallable([$this, 'prepareStructure'])
+        );
     }
 
-    /**
-     * Return file names containing removed configurations.
-     *
-     * @return array<string>
-     */
-    abstract protected function getRemovedConfigFiles();
-
     /**
      * Prepares structure from config for later usage.
      *
      * @param array $typo3Versions
      * @return array
      */
-    protected function prepareStructure(array $typo3Versions)
-    {
-        $newStructure = [];
-
-        foreach ($typo3Versions as $typo3Version => $removals) {
-            foreach ($removals as $removed => $config) {
-                // Split static methods and methods.
-                $split = preg_split('/::|->/', $removed);
-
-                $newStructure[$removed] = $config;
-
-                $newStructure[$removed]['static'] = strpos($removed, '::') !== false;
-                $newStructure[$removed]['fqcn'] = null;
-                $newStructure[$removed]['class'] = null;
-                $newStructure[$removed]['name'] = $split[0];
-                $newStructure[$removed]['version_removed'] = $typo3Version;
-
-                // If split contains two parts, it's a class
-                if (isset($split[1])) {
-                    $newStructure[$removed]['fqcn'] = $split[0];
-                    $newStructure[$removed]['class'] = array_slice(
-                        explode('\\', $newStructure[$removed]['fqcn']),
-                        -1
-                    )[0];
-                    $newStructure[$removed]['name'] = $split[1];
-                }
-            }
-        }
-
-        return $newStructure;
-    }
+    abstract protected function prepareStructure(array $typo3Versions);
 
     /**
-     * Processes the tokens that this sniff is interested in.
-     *
-     * This is the default implementation, as most of the time next T_STRING is
-     * the class name. This way only the register method has to be registered
-     * in default cases.
-     *
-     * @param PhpCsFile $phpcsFile The file where the token was found.
-     * @param int                  $stackPtr  The position in the stack where
-     *                                        the token was found.
-     *
-     * @return void
-     */
-    public function process(PhpCsFile $phpcsFile, $stackPtr)
-    {
-        if (!$this->isRemoved($phpcsFile, $stackPtr)) {
-            return;
-        }
-
-        $this->addMessage($phpcsFile, $stackPtr);
-    }
-
-    /**
-     * Check whether the current token is removed.
+     * Return file names containing removed configurations.
      *
-     * @param PhpCsFile $phpcsFile
-     * @param int $stackPtr
-     * @return bool
+     * @return array<string>
      */
-    protected function isRemoved(PhpCsFile $phpcsFile, $stackPtr)
-    {
-        $tokens = $phpcsFile->getTokens();
-        $staticPosition = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true, null, true);
-
-        $name = $tokens[$stackPtr]['content'];
-        $isStatic = false;
-        $class = false;
-
-        if ($staticPosition !== false) {
-            $isStatic = $tokens[$staticPosition]['code'] === T_DOUBLE_COLON;
-        }
-
-        if ($isStatic) {
-            $class = $phpcsFile->findPrevious(T_STRING, $staticPosition, null, false, null, true);
-            if ($class !== false) {
-                $class = $tokens[$class]['content'];
-            }
-        }
+    abstract protected function getRemovedConfigFiles();
 
-        $this->removed = $this->getMatchingRemoved($name, $class, $isStatic);
-        return $this->removed !== [];
-    }
+    abstract protected function findRemoved(PhpCsFile $phpcsFile, $stackPtr);
 
-    /**
-     * Returns all matching removed functions for given arguments.
-     *
-     * @param string $name
-     * @param string $className The last part of the class name, splitted by namespaces.
-     * @param bool $isStatic
-     *
-     * @return array
-     */
-    protected function getMatchingRemoved($name, $className, $isStatic)
+    public function process(PhpCsFile $phpcsFile, $stackPtr)
     {
-        // We will not match any static calls, without the class name, at least for now.
-        if ($isStatic === true && $className === false) {
-            return [];
+        $removed = $this->findRemoved($phpcsFile, $stackPtr);
+        if ($removed === []) {
+            return;
         }
 
-        return array_filter(
-            $this->configured,
-            function ($config) use ($name, $isStatic, $className) {
-                return $name === $config['name']
-                    && $isStatic === $config['static']
-                    && (
-                        $className === $config['class']
-                        || $className === false
-                    )
-                ;
-            }
-        );
+        $this->addMessage($removed);
     }
 
-    /**
-     * Add message for the given token position.
-     *
-     * Default is a warning, non fixable. Just overwrite in concrete sniff, if
-     * something different suites better.
-     *
-     * @param PhpCsFile $phpcsFile
-     * @param int $tokenPosition
-     *
-     * @return void
-     */
-    protected function addMessage(PhpCsFile $phpcsFile, $tokenPosition)
+    protected function addMessage(array $removed)
     {
-        foreach ($this->removed as $removed) {
+        foreach ($removed as $removed) {
             $phpcsFile->addWarning(
-                'Legacy calls are not allowed; found %s. Removed in %s. %s. See: %s',
+                'Calls to removed code are not allowed; found %s. Removed in %s. %s. See: %s',
                 $tokenPosition,
-                $this->getIdentifier($removed),
+                $removed['identifier'],
                 [
-                    $this->getOldUsage($removed),
-                    $this->getRemovedVersion($removed),
+                    $removed['oldUsage'],
+                    $removed['versionRemoved'],
                     $this->getReplacement($removed),
-                    $this->getDocsUrl($removed),
+                    $removed['docsUrl'],
                 ]
             );
         }
     }
 
-    /**
-     * Identifier for configuring this specific error / warning through PHPCS.
-     *
-     * @param array $config
-     *
-     * @return string
-     */
-    protected function getIdentifier(array $config)
-    {
-        $name = $config['name'];
-        if ($config['class']) {
-            $name = $config['class'] . '.' . $name;
-        }
-
-        return $name;
-    }
-
-    /**
-     * The original call, to allow user to check matches.
-     *
-     * As we match the name, that can be provided by multiple classes, you
-     * should provide an example, so users can check that this is the legacy
-     * one.
-     *
-     * @param array $config
-     *
-     * @return string
-     */
-    abstract protected function getOldUsage(array $config);
-
-    /**
-     * Returns TYPO3 version when the breaking change happened.
-     *
-     * To let user decide whether this is important for him.
-     *
-     * @param array $config
-     *
-     * @return string
-     */
-    protected function getRemovedVersion(array $config)
-    {
-        return $config['version_removed'];
-    }
-
     /**
      * The new call, or information how to migrate.
      *
@@ -279,16 +104,4 @@ abstract class AbstractGenericUsage implements PhpCsSniff
         }
         return 'There is no replacement, just remove call';
     }
-
-    /**
-     * Allow user to lookup the official docs related to this deprecation / breaking change.
-     *
-     * @param array $config
-     *
-     * @return string
-     */
-    protected function getDocsUrl(array $config)
-    {
-        return $config['docsUrl'];
-    }
 }
diff --git a/src/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff.php b/src/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff.php
index 98c0cca..739f21a 100644
--- a/src/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff.php
+++ b/src/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff.php
@@ -59,7 +59,6 @@ class Typo3Update_Sniffs_Removed_TypoScriptSniff extends AbstractGenericUsage
     protected function prepareStructure(array $typo3Versions)
     {
         $newStructure = [];
-
         foreach ($typo3Versions as $typo3Version => $removals) {
             foreach ($removals as $removed => $config) {
                 $config['type'] = TokenInterface::TYPE_OBJECT_IDENTIFIER;
@@ -70,7 +69,9 @@ class Typo3Update_Sniffs_Removed_TypoScriptSniff extends AbstractGenericUsage
                 }
 
                 $config['name'] = $removed;
-                $config['version_removed'] = $typo3Version;
+                $config['identifier'] = str_replace('.', '-', $removed);
+                $config['versionRemoved'] = $typo3Version;
+                $config['oldUsage'] = $removed;
 
                 $newStructure[$removed] = $config;
             }
@@ -86,48 +87,20 @@ class Typo3Update_Sniffs_Removed_TypoScriptSniff extends AbstractGenericUsage
      * @param int $stackPtr
      * @return bool
      */
-    protected function isRemoved(PhpCsFile $phpcsFile, $stackPtr)
+    protected function findRemoved(PhpCsFile $phpcsFile, $stackPtr)
     {
         $tokens = $phpcsFile->getTokens();
         $token = $tokens[$stackPtr];
         $objectIdentifier = $token['content'];
 
-        if (isset($this->configured[$objectIdentifier]) && $token['type'] === $this->configured[$objectIdentifier]['type']) {
-            $this->removed = [
-                $this->configured[$objectIdentifier]
-            ];
-            return true;
+        if (!$this->configured->isRemoved($objectIdentifier)) {
+            return [];
         }
 
-        return false;
-    }
-
-    /**
-     * Identifier for configuring this specific error / warning through PHPCS.
-     *
-     * @param array $config
-     *
-     * @return string
-     */
-    protected function getIdentifier(array $config)
-    {
-        return str_replace('.', '-', $config['name']);
-    }
-
-    /**
-     * The original call, to allow user to check matches.
-     *
-     * As we match the name, that can be provided by multiple classes, you
-     * should provide an example, so users can check that this is the legacy
-     * one.
-     *
-     * @param array $config
-     *
-     * @return string
-     */
-    protected function getOldUsage(array $config)
-    {
-        return $config['name'];
+        $removed = $this->configured->getRemoved($objectIdentifier);
+        if ($token['type'] === $removed['type']) {
+            return [$removed];
+        }
     }
 
     /**
-- 
GitLab


From 5704351d22dd91aac9a57402bb1f9191f18ec9b6 Mon Sep 17 00:00:00 2001
From: Daniel Siepmann <coding@daniel-siepmann.de>
Date: Thu, 27 Apr 2017 12:53:07 +0200
Subject: [PATCH 04/11] TASK: Adjust to PHP 7.1

* As PHP 7.1 is required, document and adjust tests in CI.

Relates: #71
---
 .gitlab-ci.yml                 | 10 +++-------
 Documentation/source/index.rst |  2 ++
 2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 88d1918..202f4e0 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -27,7 +27,7 @@ sync:github:
     - git push --mirror ${MIRROR_GIT_URL}
 
 lint:coding-guideline: &PHP-LINTING
-  image: php:7.0-alpine
+  image: php:7.1-alpine
   stage: test
   script:
     - ./vendor/bin/phpcs -s -n --report-full=result/phpcs-full.txt --report-diff=result/phpcs-diff.txt --report-summary=result/phpcs-summary.txt
@@ -41,16 +41,12 @@ lint:php-mass-detection:
   script:
     - ./vendor/bin/phpmd src text phpmd.xml > result/phpmd.txt
 
-test:5.6: &PHP-UNITTESTING
-  image: php:5.6-alpine
+test:7.1: &PHP-UNITTESTING
+  image: php:7.1-alpine
   stage: test
   script:
     - ./vendor/bin/phpunit
 
-test:7.0:
-  <<: *PHP-UNITTESTING
-  image: php:7.0-alpine
-
 test:latest:
   <<: *PHP-UNITTESTING
   image: php:7-alpine
diff --git a/Documentation/source/index.rst b/Documentation/source/index.rst
index 93ec3be..709f4ec 100644
--- a/Documentation/source/index.rst
+++ b/Documentation/source/index.rst
@@ -19,6 +19,8 @@ Requirements
 To install the project you need ``composer`` to be installed and inside your ``$PATH``.
 Otherwise run ``make install-composer`` to install composer.
 
+At least PHP 7.1 is required.
+
 Installation
 ============
 
-- 
GitLab


From 84dd380a3ce64547f80a71277229ea3a5294db41 Mon Sep 17 00:00:00 2001
From: Daniel Siepmann <coding@daniel-siepmann.de>
Date: Thu, 27 Apr 2017 13:23:51 +0200
Subject: [PATCH 05/11] TASK: Migrate GenericFunctionCallSniff

* Migrate GenericFunctionCallSniff to new architecture.
* Provide new abstract class for php removed functions and constants.
* Fix TypoScriptSniff not always returning array.
* Adjust warnings in Expected.json

Relates: #71
---
 .../RemovedByYamlConfiguration.php            |   5 +
 .../Removed/AbstractGenericPhpUsage.php       | 141 ++++++++++++++++++
 .../Sniffs/Removed/AbstractGenericUsage.php   |  14 +-
 .../Removed/GenericFunctionCallSniff.php      |  49 +-----
 .../Sniffs/Removed/TypoScriptSniff.php        |   2 +
 .../GenericConstantUsageSniff/Expected.json   |  10 +-
 .../GenericFunctionCallSniff/Expected.json    |  10 +-
 .../Removed/TypoScriptSniff/Expected.json     |  18 +--
 8 files changed, 176 insertions(+), 73 deletions(-)
 create mode 100644 src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericPhpUsage.php

diff --git a/src/Standards/Typo3Update/RemovedByYamlConfiguration.php b/src/Standards/Typo3Update/RemovedByYamlConfiguration.php
index f1ab402..a527e43 100644
--- a/src/Standards/Typo3Update/RemovedByYamlConfiguration.php
+++ b/src/Standards/Typo3Update/RemovedByYamlConfiguration.php
@@ -46,6 +46,11 @@ class RemovedByYamlConfiguration
         return isset($this->configured[$identifier]);
     }
 
+    public function getAllRemoved()
+    {
+        return $this->configured;
+    }
+
     public function getRemoved($identifier)
     {
         if (!$this->isRemoved($identifier)) {
diff --git a/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericPhpUsage.php b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericPhpUsage.php
new file mode 100644
index 0000000..d93645f
--- /dev/null
+++ b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericPhpUsage.php
@@ -0,0 +1,141 @@
+<?php
+namespace Typo3Update\Sniffs\Removed;
+
+/*
+ * 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\Sniffs\ExtendedPhpCsSupportTrait;
+
+abstract class AbstractGenericPhpUsage extends AbstractGenericUsage
+{
+    use ExtendedPhpCsSupportTrait;
+
+    protected function prepareStructure(array $typo3Versions)
+    {
+        $newStructure = [];
+
+        foreach ($typo3Versions as $typo3Version => $removals) {
+            foreach ($removals as $removed => $config) {
+                $newStructure[$removed] = $config;
+
+                $newStructure[$removed]['fqcn'] = null;
+                $newStructure[$removed]['class'] = null;
+                $newStructure[$removed]['versionRemoved'] = $typo3Version;
+
+                $this->handleStatic($removed, $newStructure[$removed]);
+
+                $newStructure[$removed]['oldUsage'] = $this->getOldUsage($newStructure[$removed]);
+                $newStructure[$removed]['identifier'] = $this->getIdentifier($newStructure[$removed]);
+            };
+        }
+
+        return $newStructure;
+    }
+
+    protected function findRemoved(PhpCsFile $phpcsFile, $stackPtr)
+    {
+        if (!$this->isFunctionCall($phpcsFile, $stackPtr)) {
+            return [];
+        }
+
+        $tokens = $phpcsFile->getTokens();
+        $staticPosition = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true, null, true);
+
+        $name = $tokens[$stackPtr]['content'];
+        $isStatic = false;
+        $class = false;
+
+        if ($staticPosition !== false) {
+            $isStatic = $tokens[$staticPosition]['code'] === T_DOUBLE_COLON;
+        }
+
+        if ($isStatic) {
+            $class = $phpcsFile->findPrevious(T_STRING, $staticPosition, null, false, null, true);
+            if ($class !== false) {
+                $class = $tokens[$class]['content'];
+            }
+        }
+
+        return $this->getMatchingRemoved($name, $class, $isStatic);
+    }
+
+    /**
+     * Returns all matching removed functions for given arguments.
+     *
+     * @param string $name
+     * @param string $className The last part of the class name, splitted by namespaces.
+     * @param bool $isStatic
+     *
+     * @return array
+     */
+    protected function getMatchingRemoved($name, $className, $isStatic)
+    {
+        // We will not match any static calls, without the class name, at least for now.
+        if ($isStatic === true && $className === false) {
+            return [];
+        }
+
+        return array_filter(
+            $this->configured->getAllRemoved(),
+            function ($config) use ($name, $isStatic, $className) {
+                return $name === $config['name']
+                    && $isStatic === $config['static']
+                    && (
+                        $className === $config['class']
+                        || $className === false
+                    )
+                ;
+            }
+        );
+    }
+
+    protected function handleStatic($identifier, array &$config)
+    {
+        $split = preg_split('/::|->/', $identifier);
+
+        $config['name'] = $split[0];
+        $config['static'] = strpos($identifier, '::') !== false;
+
+        if (isset($split[1])) {
+            $config['fqcn'] = $split[0];
+            $config['class'] = array_slice(explode('\\', $config['fqcn']), -1)[0];
+            $config['name'] = $split[1];
+        }
+    }
+
+    protected function getOldUsage(array $config)
+    {
+        $concat = '->';
+        if ($config['static']) {
+            $concat = '::';
+        }
+        return $config['fqcn'] . $concat . $config['name'];
+    }
+
+    protected function getIdentifier(array $config)
+    {
+        $name = $config['name'];
+        if ($config['class']) {
+            $name = $config['class'] . '.' . $name;
+        }
+
+        return $name;
+    }
+}
diff --git a/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php
index f8e8e0a..ff67d4f 100644
--- a/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php
+++ b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php
@@ -62,20 +62,10 @@ abstract class AbstractGenericUsage implements PhpCsSniff
 
     public function process(PhpCsFile $phpcsFile, $stackPtr)
     {
-        $removed = $this->findRemoved($phpcsFile, $stackPtr);
-        if ($removed === []) {
-            return;
-        }
-
-        $this->addMessage($removed);
-    }
-
-    protected function addMessage(array $removed)
-    {
-        foreach ($removed as $removed) {
+        foreach ($this->findRemoved($phpcsFile, $stackPtr) as $removed) {
             $phpcsFile->addWarning(
                 'Calls to removed code are not allowed; found %s. Removed in %s. %s. See: %s',
-                $tokenPosition,
+                $stackPtr,
                 $removed['identifier'],
                 [
                     $removed['oldUsage'],
diff --git a/src/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff.php b/src/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff.php
index 4124eb2..7fa8a12 100644
--- a/src/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff.php
+++ b/src/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff.php
@@ -19,26 +19,15 @@
  * 02110-1301, USA.
  */
 
-use PHP_CodeSniffer_File as PhpCsFile;
 use PHP_CodeSniffer_Tokens as Tokens;
-use Typo3Update\Sniffs\Removed\AbstractGenericUsage;
+use Typo3Update\Sniffs\Removed\AbstractGenericPhpUsage;
 use Typo3Update\Options;
 
 /**
  * Sniff that handles all calls to removed functions.
  */
-class Typo3Update_Sniffs_Removed_GenericFunctionCallSniff extends AbstractGenericUsage
+class Typo3Update_Sniffs_Removed_GenericFunctionCallSniff extends AbstractGenericPhpUsage
 {
-    /**
-     * Return file names containing removed configurations.
-     *
-     * @return array<string>
-     */
-    protected function getRemovedConfigFiles()
-    {
-        return Options::getRemovedFunctionConfigFiles();
-    }
-
     /**
      * Returns the token types that this sniff is interested in.
      *
@@ -46,40 +35,16 @@ class Typo3Update_Sniffs_Removed_GenericFunctionCallSniff extends AbstractGeneri
      */
     public function register()
     {
-        return Tokens::$functionNameTokens;
+        return [T_STRING];
     }
 
     /**
-     * Check whether function at given point is removed.
-     *
-     * @return bool
-     */
-    protected function isRemoved(PhpCsFile $phpcsFile, $stackPtr)
-    {
-        if (!$this->isFunctionCall($phpcsFile, $stackPtr)) {
-            return false;
-        }
-
-        return parent::isRemoved($phpcsFile, $stackPtr);
-    }
-
-    /**
-     * The original function call, to allow user to check matches.
-     *
-     * As we match the function name, that can be provided by multiple classes,
-     * you should provide an example, so users can check that this is the
-     * legacy one.
-     *
-     * @param array $config The converted structure for a single function.
+     * Return file names containing removed configurations.
      *
-     * @return string
+     * @return array<string>
      */
-    protected function getOldUsage(array $config)
+    protected function getRemovedConfigFiles()
     {
-        $concat = '->';
-        if ($config['static']) {
-            $concat = '::';
-        }
-        return $config['fqcn'] . $concat . $config['name'];
+        return Options::getRemovedFunctionConfigFiles();
     }
 }
diff --git a/src/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff.php b/src/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff.php
index 739f21a..419b55a 100644
--- a/src/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff.php
+++ b/src/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff.php
@@ -101,6 +101,8 @@ class Typo3Update_Sniffs_Removed_TypoScriptSniff extends AbstractGenericUsage
         if ($token['type'] === $removed['type']) {
             return [$removed];
         }
+
+        return [];
     }
 
     /**
diff --git a/tests/Fixtures/Standards/Typo3Update/Sniffs/Removed/GenericConstantUsageSniff/Expected.json b/tests/Fixtures/Standards/Typo3Update/Sniffs/Removed/GenericConstantUsageSniff/Expected.json
index e3072f3..6d0f5d6 100644
--- a/tests/Fixtures/Standards/Typo3Update/Sniffs/Removed/GenericConstantUsageSniff/Expected.json
+++ b/tests/Fixtures/Standards/Typo3Update/Sniffs/Removed/GenericConstantUsageSniff/Expected.json
@@ -7,7 +7,7 @@
                     "column": 9,
                     "fixable": false,
                     "line": 22,
-                    "message": "Legacy calls are not allowed; found constant PATH_tslib. Removed in 7.0. The folder and constant no longer exist. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61459-RemovalTslib.html",
+                    "message": "Calls to removed code are not allowed; found constant PATH_tslib. Removed in 7.0. The folder and constant no longer exist. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61459-RemovalTslib.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.GenericConstantUsage.PATH_tslib",
                     "type": "WARNING"
@@ -16,7 +16,7 @@
                     "column": 11,
                     "fixable": false,
                     "line": 23,
-                    "message": "Legacy calls are not allowed; found constant TYPO3_MOD_PATH. Removed in 7.4. It is required to route modules through typo3/mod.php from now on in case the module relies on the definition of those constants. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.4/Breaking-67987-RemovedEntryScriptHandling.html",
+                    "message": "Calls to removed code are not allowed; found constant TYPO3_MOD_PATH. Removed in 7.4. It is required to route modules through typo3/mod.php from now on in case the module relies on the definition of those constants. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.4/Breaking-67987-RemovedEntryScriptHandling.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.GenericConstantUsage.TYPO3_MOD_PATH",
                     "type": "WARNING"
@@ -25,7 +25,7 @@
                     "column": 75,
                     "fixable": false,
                     "line": 24,
-                    "message": "Legacy calls are not allowed; found constant \\TYPO3\\CMS\\IndexedSearch\\Controller\\SearchFormController::WILDCARD_LEFT. Removed in 7.6. Use \\TYPO3\\CMS\\IndexedSearch\\Utility\\LikeWildcard::LEFT instead. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.6/Breaking-69227-StringsForLikeAreNotProperlyEscaped.html",
+                    "message": "Calls to removed code are not allowed; found constant \\TYPO3\\CMS\\IndexedSearch\\Controller\\SearchFormController::WILDCARD_LEFT. Removed in 7.6. Use \\TYPO3\\CMS\\IndexedSearch\\Utility\\LikeWildcard::LEFT instead. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.6/Breaking-69227-StringsForLikeAreNotProperlyEscaped.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.GenericConstantUsage.SearchFormController.WILDCARD_LEFT",
                     "type": "WARNING"
@@ -34,7 +34,7 @@
                     "column": 39,
                     "fixable": false,
                     "line": 27,
-                    "message": "Legacy calls are not allowed; found constant \\TYPO3\\CMS\\IndexedSearch\\Controller\\SearchFormController::WILDCARD_LEFT. Removed in 7.6. Use \\TYPO3\\CMS\\IndexedSearch\\Utility\\LikeWildcard::LEFT instead. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.6/Breaking-69227-StringsForLikeAreNotProperlyEscaped.html",
+                    "message": "Calls to removed code are not allowed; found constant \\TYPO3\\CMS\\IndexedSearch\\Controller\\SearchFormController::WILDCARD_LEFT. Removed in 7.6. Use \\TYPO3\\CMS\\IndexedSearch\\Utility\\LikeWildcard::LEFT instead. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.6/Breaking-69227-StringsForLikeAreNotProperlyEscaped.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.GenericConstantUsage.SearchFormController.WILDCARD_LEFT",
                     "type": "WARNING"
@@ -43,7 +43,7 @@
                     "column": 66,
                     "fixable": false,
                     "line": 29,
-                    "message": "Legacy calls are not allowed; found constant \\TYPO3\\CMS\\IndexedSearch\\Controller\\SearchFormController::WILDCARD_LEFT. Removed in 7.6. Use \\TYPO3\\CMS\\IndexedSearch\\Utility\\LikeWildcard::LEFT instead. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.6/Breaking-69227-StringsForLikeAreNotProperlyEscaped.html",
+                    "message": "Calls to removed code are not allowed; found constant \\TYPO3\\CMS\\IndexedSearch\\Controller\\SearchFormController::WILDCARD_LEFT. Removed in 7.6. Use \\TYPO3\\CMS\\IndexedSearch\\Utility\\LikeWildcard::LEFT instead. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.6/Breaking-69227-StringsForLikeAreNotProperlyEscaped.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.GenericConstantUsage.SearchFormController.WILDCARD_LEFT",
                     "type": "WARNING"
diff --git a/tests/Fixtures/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff/Expected.json b/tests/Fixtures/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff/Expected.json
index f2e61ab..a818be1 100644
--- a/tests/Fixtures/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff/Expected.json
+++ b/tests/Fixtures/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff/Expected.json
@@ -7,7 +7,7 @@
                     "column": 41,
                     "fixable": false,
                     "line": 24,
-                    "message": "Legacy calls are not allowed; found \\TYPO3\\CMS\\Core\\Utility\\GeneralUtility::loadTCA. Removed in 7.0. There is no replacement, just remove call. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61785-LoadTcaFunctionRemoved.html",
+                    "message": "Calls to removed code are not allowed; found \\TYPO3\\CMS\\Core\\Utility\\GeneralUtility::loadTCA. Removed in 7.0. There is no replacement, just remove call. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61785-LoadTcaFunctionRemoved.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.GenericFunctionCall.GeneralUtility.loadTCA",
                     "type": "WARNING"
@@ -16,7 +16,7 @@
                     "column": 17,
                     "fixable": false,
                     "line": 26,
-                    "message": "Legacy calls are not allowed; found \\TYPO3\\CMS\\Core\\Utility\\GeneralUtility::loadTCA. Removed in 7.0. There is no replacement, just remove call. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61785-LoadTcaFunctionRemoved.html",
+                    "message": "Calls to removed code are not allowed; found \\TYPO3\\CMS\\Core\\Utility\\GeneralUtility::loadTCA. Removed in 7.0. There is no replacement, just remove call. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61785-LoadTcaFunctionRemoved.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.GenericFunctionCall.GeneralUtility.loadTCA",
                     "type": "WARNING"
@@ -25,7 +25,7 @@
                     "column": 44,
                     "fixable": false,
                     "line": 28,
-                    "message": "Legacy calls are not allowed; found \\TYPO3\\CMS\\Core\\Utility\\GeneralUtility::loadTCA. Removed in 7.0. There is no replacement, just remove call. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61785-LoadTcaFunctionRemoved.html",
+                    "message": "Calls to removed code are not allowed; found \\TYPO3\\CMS\\Core\\Utility\\GeneralUtility::loadTCA. Removed in 7.0. There is no replacement, just remove call. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61785-LoadTcaFunctionRemoved.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.GenericFunctionCall.GeneralUtility.loadTCA",
                     "type": "WARNING"
@@ -34,7 +34,7 @@
                     "column": 8,
                     "fixable": false,
                     "line": 31,
-                    "message": "Legacy calls are not allowed; found \\TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController->includeTCA. Removed in 7.0. Full TCA is always loaded during bootstrap in FE, the method is obsolete. If an eid script calls this method to load TCA, use \\TYPO3\\CMS\\Frontend\\Utility\\EidUtility::initTCA() instead. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61785-FrontendTcaFunctionsRemoved.html",
+                    "message": "Calls to removed code are not allowed; found \\TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController->includeTCA. Removed in 7.0. Full TCA is always loaded during bootstrap in FE, the method is obsolete. If an eid script calls this method to load TCA, use \\TYPO3\\CMS\\Frontend\\Utility\\EidUtility::initTCA() instead. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61785-FrontendTcaFunctionsRemoved.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.GenericFunctionCall.TypoScriptFrontendController.includeTCA",
                     "type": "WARNING"
@@ -43,7 +43,7 @@
                     "column": 17,
                     "fixable": false,
                     "line": 35,
-                    "message": "Legacy calls are not allowed; found \\TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController->includeTCA. Removed in 7.0. Full TCA is always loaded during bootstrap in FE, the method is obsolete. If an eid script calls this method to load TCA, use \\TYPO3\\CMS\\Frontend\\Utility\\EidUtility::initTCA() instead. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61785-FrontendTcaFunctionsRemoved.html",
+                    "message": "Calls to removed code are not allowed; found \\TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController->includeTCA. Removed in 7.0. Full TCA is always loaded during bootstrap in FE, the method is obsolete. If an eid script calls this method to load TCA, use \\TYPO3\\CMS\\Frontend\\Utility\\EidUtility::initTCA() instead. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61785-FrontendTcaFunctionsRemoved.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.GenericFunctionCall.TypoScriptFrontendController.includeTCA",
                     "type": "WARNING"
diff --git a/tests/Fixtures/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff/Expected.json b/tests/Fixtures/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff/Expected.json
index ff6e6bd..e66a962 100644
--- a/tests/Fixtures/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff/Expected.json
+++ b/tests/Fixtures/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff/Expected.json
@@ -7,7 +7,7 @@
                     "column": 10,
                     "fixable": false,
                     "line": 2,
-                    "message": "Legacy calls are not allowed; found styles.insertContent. Removed in 7.0. Either remove usage of styles.insertContent or add a snippet at an early point in TypoScript for backwards compatibility. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-42543-DefaultTypoScriptRemoved.html",
+                    "message": "Calls to removed code are not allowed; found styles.insertContent. Removed in 7.0. Either remove usage of styles.insertContent or add a snippet at an early point in TypoScript for backwards compatibility. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-42543-DefaultTypoScriptRemoved.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.TypoScript.styles-insertContent",
                     "type": "WARNING"
@@ -16,7 +16,7 @@
                     "column": 11,
                     "fixable": false,
                     "line": 3,
-                    "message": "Legacy calls are not allowed; found styles.insertContent. Removed in 7.0. Either remove usage of styles.insertContent or add a snippet at an early point in TypoScript for backwards compatibility. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-42543-DefaultTypoScriptRemoved.html",
+                    "message": "Calls to removed code are not allowed; found styles.insertContent. Removed in 7.0. Either remove usage of styles.insertContent or add a snippet at an early point in TypoScript for backwards compatibility. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-42543-DefaultTypoScriptRemoved.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.TypoScript.styles-insertContent",
                     "type": "WARNING"
@@ -25,7 +25,7 @@
                     "column": 1,
                     "fixable": false,
                     "line": 6,
-                    "message": "Legacy calls are not allowed; found styles.insertContent. Removed in 7.0. Either remove usage of styles.insertContent or add a snippet at an early point in TypoScript for backwards compatibility. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-42543-DefaultTypoScriptRemoved.html",
+                    "message": "Calls to removed code are not allowed; found styles.insertContent. Removed in 7.0. Either remove usage of styles.insertContent or add a snippet at an early point in TypoScript for backwards compatibility. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-42543-DefaultTypoScriptRemoved.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.TypoScript.styles-insertContent",
                     "type": "WARNING"
@@ -34,7 +34,7 @@
                     "column": 1,
                     "fixable": false,
                     "line": 13,
-                    "message": "Legacy calls are not allowed; found mod.web_list.alternateBgColors. Removed in 7.0. Removed without substitution. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-53658-RemoveAlternateBgColorsOption.html",
+                    "message": "Calls to removed code are not allowed; found mod.web_list.alternateBgColors. Removed in 7.0. Removed without substitution. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-53658-RemoveAlternateBgColorsOption.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.TypoScript.mod-web_list-alternateBgColors",
                     "type": "WARNING"
@@ -43,7 +43,7 @@
                     "column": 10,
                     "fixable": false,
                     "line": 26,
-                    "message": "Legacy calls are not allowed; found CLEARGIF. Removed in 7.1. Any installation should migrate to alternatives such as FLUIDTEMPLATE to customize the output of the content. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.1/Breaking-64639-RemovedContentObjects.html",
+                    "message": "Calls to removed code are not allowed; found CLEARGIF. Removed in 7.1. Any installation should migrate to alternatives such as FLUIDTEMPLATE to customize the output of the content. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.1/Breaking-64639-RemovedContentObjects.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.TypoScript.CLEARGIF",
                     "type": "WARNING"
@@ -52,7 +52,7 @@
                     "column": 10,
                     "fixable": false,
                     "line": 27,
-                    "message": "Legacy calls are not allowed; found COLUMNS. Removed in 7.1. Any installation should migrate to alternatives such as FLUIDTEMPLATE to customize the output of the content. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.1/Breaking-64639-RemovedContentObjects.html",
+                    "message": "Calls to removed code are not allowed; found COLUMNS. Removed in 7.1. Any installation should migrate to alternatives such as FLUIDTEMPLATE to customize the output of the content. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.1/Breaking-64639-RemovedContentObjects.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.TypoScript.COLUMNS",
                     "type": "WARNING"
@@ -61,7 +61,7 @@
                     "column": 10,
                     "fixable": false,
                     "line": 28,
-                    "message": "Legacy calls are not allowed; found CTABLE. Removed in 7.1. Any installation should migrate to alternatives such as FLUIDTEMPLATE to customize the output of the content. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.1/Breaking-64639-RemovedContentObjects.html",
+                    "message": "Calls to removed code are not allowed; found CTABLE. Removed in 7.1. Any installation should migrate to alternatives such as FLUIDTEMPLATE to customize the output of the content. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.1/Breaking-64639-RemovedContentObjects.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.TypoScript.CTABLE",
                     "type": "WARNING"
@@ -70,7 +70,7 @@
                     "column": 10,
                     "fixable": false,
                     "line": 29,
-                    "message": "Legacy calls are not allowed; found OTABLE. Removed in 7.1. Any installation should migrate to alternatives such as FLUIDTEMPLATE to customize the output of the content. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.1/Breaking-64639-RemovedContentObjects.html",
+                    "message": "Calls to removed code are not allowed; found OTABLE. Removed in 7.1. Any installation should migrate to alternatives such as FLUIDTEMPLATE to customize the output of the content. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.1/Breaking-64639-RemovedContentObjects.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.TypoScript.OTABLE",
                     "type": "WARNING"
@@ -79,7 +79,7 @@
                     "column": 10,
                     "fixable": false,
                     "line": 30,
-                    "message": "Legacy calls are not allowed; found HRULER. Removed in 7.1. Any installation should migrate to alternatives such as FLUIDTEMPLATE to customize the output of the content. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.1/Breaking-64639-RemovedContentObjects.html",
+                    "message": "Calls to removed code are not allowed; found HRULER. Removed in 7.1. Any installation should migrate to alternatives such as FLUIDTEMPLATE to customize the output of the content. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.1/Breaking-64639-RemovedContentObjects.html",
                     "severity": 5,
                     "source": "Typo3Update.Removed.TypoScript.HRULER",
                     "type": "WARNING"
-- 
GitLab


From bcbd1f96bc5740bdf19150ed813d31ff03390316 Mon Sep 17 00:00:00 2001
From: Daniel Siepmann <coding@daniel-siepmann.de>
Date: Thu, 27 Apr 2017 13:33:28 +0200
Subject: [PATCH 06/11] TASK: Migrate GenericConstantUsageSniff

* Migrate GenericConstantUsageSniff to new architecture.
* Move non common functionality from AbstractGenericPhpUsage to concrete
  classes.

Relates: #71
---
 .../Removed/AbstractGenericPhpUsage.php       | 21 +++-------
 .../Removed/GenericConstantUsageSniff.php     | 40 ++++---------------
 .../Removed/GenericFunctionCallSniff.php      | 38 ++++++++++--------
 3 files changed, 35 insertions(+), 64 deletions(-)

diff --git a/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericPhpUsage.php b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericPhpUsage.php
index d93645f..c426721 100644
--- a/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericPhpUsage.php
+++ b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericPhpUsage.php
@@ -21,11 +21,13 @@ namespace Typo3Update\Sniffs\Removed;
  */
 
 use PHP_CodeSniffer_File as PhpCsFile;
-use Typo3Update\Sniffs\ExtendedPhpCsSupportTrait;
 
 abstract class AbstractGenericPhpUsage extends AbstractGenericUsage
 {
-    use ExtendedPhpCsSupportTrait;
+    public function register()
+    {
+        return [T_STRING];
+    }
 
     protected function prepareStructure(array $typo3Versions)
     {
@@ -51,10 +53,6 @@ abstract class AbstractGenericPhpUsage extends AbstractGenericUsage
 
     protected function findRemoved(PhpCsFile $phpcsFile, $stackPtr)
     {
-        if (!$this->isFunctionCall($phpcsFile, $stackPtr)) {
-            return [];
-        }
-
         $tokens = $phpcsFile->getTokens();
         $staticPosition = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true, null, true);
 
@@ -120,15 +118,6 @@ abstract class AbstractGenericPhpUsage extends AbstractGenericUsage
         }
     }
 
-    protected function getOldUsage(array $config)
-    {
-        $concat = '->';
-        if ($config['static']) {
-            $concat = '::';
-        }
-        return $config['fqcn'] . $concat . $config['name'];
-    }
-
     protected function getIdentifier(array $config)
     {
         $name = $config['name'];
@@ -138,4 +127,6 @@ abstract class AbstractGenericPhpUsage extends AbstractGenericUsage
 
         return $name;
     }
+
+    abstract protected function getOldUsage(array $config);
 }
diff --git a/src/Standards/Typo3Update/Sniffs/Removed/GenericConstantUsageSniff.php b/src/Standards/Typo3Update/Sniffs/Removed/GenericConstantUsageSniff.php
index 1ee46b1..e42a07d 100644
--- a/src/Standards/Typo3Update/Sniffs/Removed/GenericConstantUsageSniff.php
+++ b/src/Standards/Typo3Update/Sniffs/Removed/GenericConstantUsageSniff.php
@@ -19,42 +19,11 @@
  * 02110-1301, USA.
  */
 
-use PHP_CodeSniffer_File as PhpCsFile;
-use Typo3Update\Sniffs\Removed\AbstractGenericUsage;
+use Typo3Update\Sniffs\Removed\AbstractGenericPhpUsage;
 use Typo3Update\Options;
 
-/**
- * Sniff that handles all calls to removed constants.
- */
-class Typo3Update_Sniffs_Removed_GenericConstantUsageSniff extends AbstractGenericUsage
+class Typo3Update_Sniffs_Removed_GenericConstantUsageSniff extends AbstractGenericPhpUsage
 {
-    /**
-     * Return file names containing removed configurations.
-     *
-     * @return array<string>
-     */
-    protected function getRemovedConfigFiles()
-    {
-        return Options::getRemovedConstantConfigFiles();
-    }
-
-    /**
-     * Returns the token types that this sniff is interested in.
-     *
-     * @return array<int>
-     */
-    public function register()
-    {
-        return [T_STRING];
-    }
-
-    /**
-     * The original constant call, to allow user to check matches.
-     *
-     * @param array $config
-     *
-     * @return string
-     */
     protected function getOldUsage(array $config)
     {
         $old = $config['name'];
@@ -64,4 +33,9 @@ class Typo3Update_Sniffs_Removed_GenericConstantUsageSniff extends AbstractGener
 
         return 'constant ' . $old;
     }
+
+    protected function getRemovedConfigFiles()
+    {
+        return Options::getRemovedConstantConfigFiles();
+    }
 }
diff --git a/src/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff.php b/src/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff.php
index 7fa8a12..4d1784b 100644
--- a/src/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff.php
+++ b/src/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff.php
@@ -19,32 +19,38 @@
  * 02110-1301, USA.
  */
 
-use PHP_CodeSniffer_Tokens as Tokens;
-use Typo3Update\Sniffs\Removed\AbstractGenericPhpUsage;
+use PHP_CodeSniffer_File as PhpCsFile;
 use Typo3Update\Options;
+use Typo3Update\Sniffs\ExtendedPhpCsSupportTrait;
+use Typo3Update\Sniffs\Removed\AbstractGenericPhpUsage;
 
 /**
  * Sniff that handles all calls to removed functions.
  */
 class Typo3Update_Sniffs_Removed_GenericFunctionCallSniff extends AbstractGenericPhpUsage
 {
-    /**
-     * Returns the token types that this sniff is interested in.
-     *
-     * @return array<int>
-     */
-    public function register()
-    {
-        return [T_STRING];
-    }
+    use ExtendedPhpCsSupportTrait;
 
-    /**
-     * Return file names containing removed configurations.
-     *
-     * @return array<string>
-     */
     protected function getRemovedConfigFiles()
     {
         return Options::getRemovedFunctionConfigFiles();
     }
+
+    protected function findRemoved(PhpCsFile $phpcsFile, $stackPtr)
+    {
+        if (!$this->isFunctionCall($phpcsFile, $stackPtr)) {
+            return [];
+        }
+
+        return parent::findRemoved($phpcsFile, $stackPtr);
+    }
+
+    protected function getOldUsage(array $config)
+    {
+        $concat = '->';
+        if ($config['static']) {
+            $concat = '::';
+        }
+        return $config['fqcn'] . $concat . $config['name'];
+    }
 }
-- 
GitLab


From b9bdd5dd3b89b4661994f4123622db14c88e2fb0 Mon Sep 17 00:00:00 2001
From: Daniel Siepmann <coding@daniel-siepmann.de>
Date: Thu, 27 Apr 2017 14:05:05 +0200
Subject: [PATCH 07/11] TASK: Migrate RemovedClassFeature

* Also migrate RemovedClassFeature to new structure with
  AbstractYamlRemovedUsage

Relates: #71
---
 .../Feature/AbstractYamlRemovedUsage.php      | 103 ++++++++++++++++++
 .../Typo3Update/Feature/FeatureInterface.php  |   6 +
 .../Feature/RemovedClassFeature.php           |  51 +++++----
 src/Standards/Typo3Update/Options.php         |   2 +-
 .../PhpDocCommentSniff/Expected.json          |   4 +-
 5 files changed, 140 insertions(+), 26 deletions(-)
 create mode 100644 src/Standards/Typo3Update/Feature/AbstractYamlRemovedUsage.php

diff --git a/src/Standards/Typo3Update/Feature/AbstractYamlRemovedUsage.php b/src/Standards/Typo3Update/Feature/AbstractYamlRemovedUsage.php
new file mode 100644
index 0000000..9395d44
--- /dev/null
+++ b/src/Standards/Typo3Update/Feature/AbstractYamlRemovedUsage.php
@@ -0,0 +1,103 @@
+<?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 as PhpCs;
+use PHP_CodeSniffer_File as PhpCsFile;
+use PHP_CodeSniffer_Sniff as PhpCsSniff;
+use Typo3Update\RemovedByYamlConfiguration;
+
+/**
+ * Contains common functionality for removed code like constants or functions.
+ *
+ * Removed parts are configured using YAML-Files, for examples see
+ * src/Standards/Typo3Update/Configuration/Removed/Constants/7.0.yaml Also
+ * check out the configuration options in Readme.rst.
+ */
+abstract class AbstractYamlRemovedUsage implements FeatureInterface
+{
+    /**
+     * @var array
+     */
+    protected $configured;
+
+    /**
+     * @var PhpCsSniff
+     */
+    protected $sniff;
+
+    public function __construct(PhpCsSniff $sniff)
+    {
+        $this->sniff = $sniff;
+        $this->configured = new RemovedByYamlConfiguration(
+            $this->getRemovedConfigFiles(),
+            \Closure::fromCallable([$this, 'prepareStructure'])
+        );
+    }
+
+    /**
+     * Prepares structure from config for later usage.
+     *
+     * @param array $typo3Versions
+     * @return array
+     */
+    abstract protected function prepareStructure(array $typo3Versions);
+
+    /**
+     * Return file names containing removed configurations.
+     *
+     * @return array<string>
+     */
+    abstract protected function getRemovedConfigFiles();
+
+    protected function addWarning(PhpCsFile $phpcsFile, $stackPtr, array $removed)
+    {
+        $phpcsFile->addWarning(
+            'Calls to removed code are not allowed; found %s. Removed in %s. %s. See: %s',
+            $stackPtr,
+            $removed['identifier'],
+            [
+                $removed['oldUsage'],
+                $removed['versionRemoved'],
+                $this->getReplacement($removed),
+                $removed['docsUrl'],
+            ]
+        );
+    }
+
+    /**
+     * The new call, or information how to migrate.
+     *
+     * To provide feedback for user to ease migration.
+     *
+     * @param array $config
+     *
+     * @return string
+     */
+    protected function getReplacement(array $config)
+    {
+        $newCall = $config['replacement'];
+        if ($newCall !== null) {
+            return $newCall;
+        }
+        return 'There is no replacement, just remove call';
+    }
+}
diff --git a/src/Standards/Typo3Update/Feature/FeatureInterface.php b/src/Standards/Typo3Update/Feature/FeatureInterface.php
index 39de10c..ac8b7a9 100644
--- a/src/Standards/Typo3Update/Feature/FeatureInterface.php
+++ b/src/Standards/Typo3Update/Feature/FeatureInterface.php
@@ -21,12 +21,18 @@ namespace Typo3Update\Feature;
  */
 
 use PHP_CodeSniffer_File as PhpCsFile;
+use PHP_CodeSniffer_Sniff as PhpCsSniff;
 
 /**
  * See "Features" in documentation.
  */
 interface FeatureInterface
 {
+    /**
+     * @var PhpCsSniff $sniff
+     */
+    public function __construct(PhpCsSniff $sniff);
+
     /**
      * Process like a PHPCS Sniff.
      *
diff --git a/src/Standards/Typo3Update/Feature/RemovedClassFeature.php b/src/Standards/Typo3Update/Feature/RemovedClassFeature.php
index d81c34d..ffc61df 100644
--- a/src/Standards/Typo3Update/Feature/RemovedClassFeature.php
+++ b/src/Standards/Typo3Update/Feature/RemovedClassFeature.php
@@ -20,37 +20,42 @@ namespace Typo3Update\Feature;
  * 02110-1301, USA.
  */
 
-use PHP_CodeSniffer as PhpCs;
 use PHP_CodeSniffer_File as PhpCsFile;
-use PHP_CodeSniffer_Sniff as PhpCsSniff;
+use Typo3Update\Options;
 
-/**
- * This feature will add fixable errors for old legacy classnames.
- *
- * Can be attached to sniffs returning classnames.
- */
-class RemovedClassFeature implements FeatureInterface
+class RemovedClassFeature extends AbstractYamlRemovedUsage
 {
-    /**
-     * Process like a PHPCS Sniff.
-     *
-     * @param PhpCsFile $phpcsFile
-     * @param int $classnamePosition
-     * @param string $classname
-     *
-     * @return void
-     */
     public function process(PhpCsFile $phpcsFile, $classnamePosition, $classname)
     {
-        if ($this->isClassnameRemoved($classname) === false) {
+        if (! $this->configured->isRemoved($classname)) {
             return;
         }
-
-        $phpcsFile->addError(
-            'Removed classes are not allowed; found "%s", use "%s" instead',
+        $this->addWarning(
+            $phpcsFile,
             $classnamePosition,
-            'removedClassname',
-            [$classname]
+            $this->configured->getRemoved($classname)
         );
     }
+
+    protected function prepareStructure(array $typo3Versions)
+    {
+        $newStructure = [];
+        foreach ($typo3Versions as $typo3Version => $removals) {
+            foreach ($removals as $removed => $config) {
+                $config['name'] = $removed;
+                $config['identifier'] = 'RemovedClass.' . str_replace('\\', '_', ltrim($removed, '\\'));
+                $config['versionRemoved'] = $typo3Version;
+                $config['oldUsage'] = $removed;
+
+                $newStructure[$removed] = $config;
+            }
+        }
+
+        return $newStructure;
+    }
+
+    protected function getRemovedConfigFiles()
+    {
+        return Options::getRemovedClassConfigFiles();
+    }
 }
diff --git a/src/Standards/Typo3Update/Options.php b/src/Standards/Typo3Update/Options.php
index 6db1bd2..62b8a78 100644
--- a/src/Standards/Typo3Update/Options.php
+++ b/src/Standards/Typo3Update/Options.php
@@ -104,7 +104,7 @@ class Options
     {
         return static::getOptionFileNames(
             'removedClassConfigFiles',
-            __DIR__ . '/../Configuration/Removed/Classes/*.yaml'
+            __DIR__ . '/Configuration/Removed/Classes/*.yaml'
         );
     }
 
diff --git a/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/Expected.json b/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/Expected.json
index c528d04..89158c7 100644
--- a/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/Expected.json
+++ b/tests/Fixtures/Standards/Typo3Update/Sniffs/Classname/PhpDocCommentSniff/Expected.json
@@ -25,9 +25,9 @@
                     "column": 15,
                     "fixable": false,
                     "line": 32,
-                    "message": "Legacy calls are not allowed; found \\TYPO3\\CMS\\Backend\\Template\\MediumDocumentTemplate. Removed in 7.0. Use \\TYPO3\\CMS\\Backend\\Template\\DocumentTemplate instead. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61782-DeprecatedDocumentTemplateClassesRemoved.html",
+                    "message": "Calls to removed code are not allowed; found \\TYPO3\\CMS\\Backend\\Template\\MediumDocumentTemplate. Removed in 7.0. Use \\TYPO3\\CMS\\Backend\\Template\\DocumentTemplate instead. See: https://docs.typo3.org/typo3cms/extensions/core/7.6/Changelog/7.0/Breaking-61782-DeprecatedDocumentTemplateClassesRemoved.html",
                     "severity": 5,
-                    "source": "Typo3Update.LegacyClassnames.DocComment.TYPO3_CMS_Backend_Template_MediumDocumentTemplate",
+                    "source": "Typo3Update.Classname.PhpDocComment.RemovedClass.TYPO3_CMS_Backend_Template_MediumDocumentTemplate",
                     "type": "WARNING"
                 },
                 {
-- 
GitLab


From 510774a3cc47bf6dabd498815e597a18b2d752c5 Mon Sep 17 00:00:00 2001
From: Daniel Siepmann <coding@daniel-siepmann.de>
Date: Thu, 27 Apr 2017 14:16:22 +0200
Subject: [PATCH 08/11] TASK: Support at least PHP 5.6

* Adjust CI , composer and docs.
* Migrate modern code to 5.6 supported code.

Relates: #71
---
 .gitlab-ci.yml                                       | 12 ++++++++++--
 Documentation/source/index.rst                       |  3 ++-
 composer.json                                        |  2 +-
 .../Typo3Update/Feature/AbstractYamlRemovedUsage.php |  9 ++++++++-
 .../Sniffs/Removed/AbstractGenericUsage.php          |  9 ++++++++-
 5 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 202f4e0..af289ad 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -41,12 +41,20 @@ lint:php-mass-detection:
   script:
     - ./vendor/bin/phpmd src text phpmd.xml > result/phpmd.txt
 
-test:7.1: &PHP-UNITTESTING
-  image: php:7.1-alpine
+test:5.6: &PHP-UNITTESTING
+  image: php:5.6-alpine
   stage: test
   script:
     - ./vendor/bin/phpunit
 
+test:7.0:
+  <<: *PHP-UNITTESTING
+  image: php:7.0-alpine
+
+test:7.1:
+  <<: *PHP-UNITTESTING
+  image: php:7.1-alpine
+
 test:latest:
   <<: *PHP-UNITTESTING
   image: php:7-alpine
diff --git a/Documentation/source/index.rst b/Documentation/source/index.rst
index 709f4ec..1dd04c3 100644
--- a/Documentation/source/index.rst
+++ b/Documentation/source/index.rst
@@ -19,7 +19,8 @@ Requirements
 To install the project you need ``composer`` to be installed and inside your ``$PATH``.
 Otherwise run ``make install-composer`` to install composer.
 
-At least PHP 7.1 is required.
+We recommend to use at least PHP 5.6, we do not test with lower versions as 5.6 is latest maintained
+version.
 
 Installation
 ============
diff --git a/composer.json b/composer.json
index 87aab93..623bfde 100644
--- a/composer.json
+++ b/composer.json
@@ -23,7 +23,7 @@
         ]
     },
     "require": {
-        "php": "~7.1",
+        "php": ">=5.6",
         "helmich/typo3-typoscript-parser": "1.1.*",
         "squizlabs/php_codesniffer": "2.8.*",
         "symfony/yaml": "3.2.*",
diff --git a/src/Standards/Typo3Update/Feature/AbstractYamlRemovedUsage.php b/src/Standards/Typo3Update/Feature/AbstractYamlRemovedUsage.php
index 9395d44..d5463d6 100644
--- a/src/Standards/Typo3Update/Feature/AbstractYamlRemovedUsage.php
+++ b/src/Standards/Typo3Update/Feature/AbstractYamlRemovedUsage.php
@@ -49,10 +49,17 @@ abstract class AbstractYamlRemovedUsage implements FeatureInterface
         $this->sniff = $sniff;
         $this->configured = new RemovedByYamlConfiguration(
             $this->getRemovedConfigFiles(),
-            \Closure::fromCallable([$this, 'prepareStructure'])
+            $this->getPrepateStructure()
         );
     }
 
+    protected function getPrepateStructure()
+    {
+        return function (array $typo3Versions) {
+            return call_user_func_array([$this, 'prepareStructure'], [$typo3Versions]);
+        };
+    }
+
     /**
      * Prepares structure from config for later usage.
      *
diff --git a/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php
index ff67d4f..ba2ba40 100644
--- a/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php
+++ b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php
@@ -39,10 +39,17 @@ abstract class AbstractGenericUsage implements PhpCsSniff
     {
         $this->configured = new RemovedByYamlConfiguration(
             $this->getRemovedConfigFiles(),
-            \Closure::fromCallable([$this, 'prepareStructure'])
+            $this->getPrepateStructure()
         );
     }
 
+    protected function getPrepateStructure()
+    {
+        return function (array $typo3Versions) {
+            return call_user_func_array([$this, 'prepareStructure'], [$typo3Versions]);
+        };
+    }
+
     /**
      * Prepares structure from config for later usage.
      *
-- 
GitLab


From 003609342edb40beb14d176aa9e09fd724112742 Mon Sep 17 00:00:00 2001
From: Daniel Siepmann <coding@daniel-siepmann.de>
Date: Thu, 27 Apr 2017 14:37:24 +0200
Subject: [PATCH 09/11] TASK: Refactor DRY

* Don't duplicate code and logic.
* Move common code to parent class.

Relates: #71
---
 .../Typo3Update/AbstractYamlRemovedUsage.php  | 72 ++++++++++++++++
 .../Feature/AbstractYamlRemovedUsage.php      | 84 +------------------
 .../Sniffs/Removed/AbstractGenericUsage.php   | 73 +---------------
 3 files changed, 78 insertions(+), 151 deletions(-)
 create mode 100644 src/Standards/Typo3Update/AbstractYamlRemovedUsage.php

diff --git a/src/Standards/Typo3Update/AbstractYamlRemovedUsage.php b/src/Standards/Typo3Update/AbstractYamlRemovedUsage.php
new file mode 100644
index 0000000..84aee44
--- /dev/null
+++ b/src/Standards/Typo3Update/AbstractYamlRemovedUsage.php
@@ -0,0 +1,72 @@
+<?php
+namespace Typo3Update;
+
+/*
+ * 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\RemovedByYamlConfiguration;
+
+abstract class AbstractYamlRemovedUsage
+{
+    protected $configured;
+
+    public function __construct()
+    {
+        $this->configured = new RemovedByYamlConfiguration(
+            $this->getRemovedConfigFiles(),
+            $this->getPrepareStructureCallback()
+        );
+    }
+
+    protected function getPrepareStructureCallback()
+    {
+        return function (array $typo3Versions) {
+            return call_user_func_array([$this, 'prepareStructure'], [$typo3Versions]);
+        };
+    }
+
+    abstract protected function prepareStructure(array $typo3Versions);
+
+    abstract protected function getRemovedConfigFiles();
+
+    protected function addWarning(PhpCsFile $phpcsFile, $stackPtr, array $removed)
+    {
+        $phpcsFile->addWarning(
+            'Calls to removed code are not allowed; found %s. Removed in %s. %s. See: %s',
+            $stackPtr,
+            $removed['identifier'],
+            [
+                $removed['oldUsage'],
+                $removed['versionRemoved'],
+                $this->getReplacement($removed),
+                $removed['docsUrl'],
+            ]
+        );
+    }
+
+    protected function getReplacement(array $config)
+    {
+        $newCall = $config['replacement'];
+        if ($newCall !== null) {
+            return $newCall;
+        }
+        return 'There is no replacement, just remove call';
+    }
+}
diff --git a/src/Standards/Typo3Update/Feature/AbstractYamlRemovedUsage.php b/src/Standards/Typo3Update/Feature/AbstractYamlRemovedUsage.php
index d5463d6..2a1fb9f 100644
--- a/src/Standards/Typo3Update/Feature/AbstractYamlRemovedUsage.php
+++ b/src/Standards/Typo3Update/Feature/AbstractYamlRemovedUsage.php
@@ -20,91 +20,13 @@ namespace Typo3Update\Feature;
  * 02110-1301, USA.
  */
 
-use PHP_CodeSniffer as PhpCs;
-use PHP_CodeSniffer_File as PhpCsFile;
 use PHP_CodeSniffer_Sniff as PhpCsSniff;
-use Typo3Update\RemovedByYamlConfiguration;
+use Typo3Update\AbstractYamlRemovedUsage as BaseAbstractYamlRemovedUsage;
 
-/**
- * Contains common functionality for removed code like constants or functions.
- *
- * Removed parts are configured using YAML-Files, for examples see
- * src/Standards/Typo3Update/Configuration/Removed/Constants/7.0.yaml Also
- * check out the configuration options in Readme.rst.
- */
-abstract class AbstractYamlRemovedUsage implements FeatureInterface
+abstract class AbstractYamlRemovedUsage extends BaseAbstractYamlRemovedUsage implements FeatureInterface
 {
-    /**
-     * @var array
-     */
-    protected $configured;
-
-    /**
-     * @var PhpCsSniff
-     */
-    protected $sniff;
-
     public function __construct(PhpCsSniff $sniff)
     {
-        $this->sniff = $sniff;
-        $this->configured = new RemovedByYamlConfiguration(
-            $this->getRemovedConfigFiles(),
-            $this->getPrepateStructure()
-        );
-    }
-
-    protected function getPrepateStructure()
-    {
-        return function (array $typo3Versions) {
-            return call_user_func_array([$this, 'prepareStructure'], [$typo3Versions]);
-        };
-    }
-
-    /**
-     * Prepares structure from config for later usage.
-     *
-     * @param array $typo3Versions
-     * @return array
-     */
-    abstract protected function prepareStructure(array $typo3Versions);
-
-    /**
-     * Return file names containing removed configurations.
-     *
-     * @return array<string>
-     */
-    abstract protected function getRemovedConfigFiles();
-
-    protected function addWarning(PhpCsFile $phpcsFile, $stackPtr, array $removed)
-    {
-        $phpcsFile->addWarning(
-            'Calls to removed code are not allowed; found %s. Removed in %s. %s. See: %s',
-            $stackPtr,
-            $removed['identifier'],
-            [
-                $removed['oldUsage'],
-                $removed['versionRemoved'],
-                $this->getReplacement($removed),
-                $removed['docsUrl'],
-            ]
-        );
-    }
-
-    /**
-     * The new call, or information how to migrate.
-     *
-     * To provide feedback for user to ease migration.
-     *
-     * @param array $config
-     *
-     * @return string
-     */
-    protected function getReplacement(array $config)
-    {
-        $newCall = $config['replacement'];
-        if ($newCall !== null) {
-            return $newCall;
-        }
-        return 'There is no replacement, just remove call';
+        parent::__construct();
     }
 }
diff --git a/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php
index ba2ba40..b7ab259 100644
--- a/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php
+++ b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php
@@ -22,83 +22,16 @@ namespace Typo3Update\Sniffs\Removed;
 
 use PHP_CodeSniffer_File as PhpCsFile;
 use PHP_CodeSniffer_Sniff as PhpCsSniff;
-use Typo3Update\RemovedByYamlConfiguration;
+use Typo3Update\AbstractYamlRemovedUsage as BaseAbstractYamlRemovedUsage;
 
-/**
- * Contains common functionality for removed code like constants or functions.
- *
- * Removed parts are configured using YAML-Files, for examples see
- * src/Standards/Typo3Update/Configuration/Removed/Constants/7.0.yaml Also
- * check out the configuration options in Readme.rst.
- */
-abstract class AbstractGenericUsage implements PhpCsSniff
+abstract class AbstractGenericUsage extends BaseAbstractYamlRemovedUsage implements PhpCsSniff
 {
-    protected $configured;
-
-    public function __construct()
-    {
-        $this->configured = new RemovedByYamlConfiguration(
-            $this->getRemovedConfigFiles(),
-            $this->getPrepateStructure()
-        );
-    }
-
-    protected function getPrepateStructure()
-    {
-        return function (array $typo3Versions) {
-            return call_user_func_array([$this, 'prepareStructure'], [$typo3Versions]);
-        };
-    }
-
-    /**
-     * Prepares structure from config for later usage.
-     *
-     * @param array $typo3Versions
-     * @return array
-     */
-    abstract protected function prepareStructure(array $typo3Versions);
-
-    /**
-     * Return file names containing removed configurations.
-     *
-     * @return array<string>
-     */
-    abstract protected function getRemovedConfigFiles();
-
     abstract protected function findRemoved(PhpCsFile $phpcsFile, $stackPtr);
 
     public function process(PhpCsFile $phpcsFile, $stackPtr)
     {
         foreach ($this->findRemoved($phpcsFile, $stackPtr) as $removed) {
-            $phpcsFile->addWarning(
-                'Calls to removed code are not allowed; found %s. Removed in %s. %s. See: %s',
-                $stackPtr,
-                $removed['identifier'],
-                [
-                    $removed['oldUsage'],
-                    $removed['versionRemoved'],
-                    $this->getReplacement($removed),
-                    $removed['docsUrl'],
-                ]
-            );
-        }
-    }
-
-    /**
-     * The new call, or information how to migrate.
-     *
-     * To provide feedback for user to ease migration.
-     *
-     * @param array $config
-     *
-     * @return string
-     */
-    protected function getReplacement(array $config)
-    {
-        $newCall = $config['replacement'];
-        if ($newCall !== null) {
-            return $newCall;
+            $this->addWarning($phpcsFile, $stackPtr, $removed);
         }
-        return 'There is no replacement, just remove call';
     }
 }
-- 
GitLab


From 11db09a3038861154bd4bad524deb0b083208d1c Mon Sep 17 00:00:00 2001
From: Daniel Siepmann <coding@daniel-siepmann.de>
Date: Thu, 27 Apr 2017 15:40:02 +0200
Subject: [PATCH 10/11] TASK: Update phpdocs

* Remove unnecessary docs.
* Add necessary docs.
---
 .../Typo3Update/AbstractYamlRemovedUsage.php  | 25 ++++++++++++++++++
 .../RemovedByYamlConfiguration.php            | 14 ++++++++++
 .../Removed/AbstractGenericPhpUsage.php       | 24 +++++++++++++++++
 .../Sniffs/Removed/AbstractGenericUsage.php   |  9 +++++++
 .../Removed/GenericFunctionCallSniff.php      |  3 ---
 .../Sniffs/Removed/TypoScriptSniff.php        | 26 -------------------
 6 files changed, 72 insertions(+), 29 deletions(-)

diff --git a/src/Standards/Typo3Update/AbstractYamlRemovedUsage.php b/src/Standards/Typo3Update/AbstractYamlRemovedUsage.php
index 84aee44..37d1c4e 100644
--- a/src/Standards/Typo3Update/AbstractYamlRemovedUsage.php
+++ b/src/Standards/Typo3Update/AbstractYamlRemovedUsage.php
@@ -23,8 +23,14 @@ namespace Typo3Update;
 use PHP_CodeSniffer_File as PhpCsFile;
 use Typo3Update\RemovedByYamlConfiguration;
 
+/**
+ * Base class for all classes working with removed configuration through yaml files.
+ */
 abstract class AbstractYamlRemovedUsage
 {
+    /**
+     * @var array
+     */
     protected $configured;
 
     public function __construct()
@@ -35,6 +41,9 @@ abstract class AbstractYamlRemovedUsage
         );
     }
 
+    /**
+     * @return \Callable
+     */
     protected function getPrepareStructureCallback()
     {
         return function (array $typo3Versions) {
@@ -42,10 +51,22 @@ abstract class AbstractYamlRemovedUsage
         };
     }
 
+    /**
+     * @param array $typo3Versions
+     * @return array
+     */
     abstract protected function prepareStructure(array $typo3Versions);
 
+    /**
+     * @return array
+     */
     abstract protected function getRemovedConfigFiles();
 
+    /**
+     * @param PhpCsFile $phpcsFile
+     * @param int $stackPtr
+     * @param array $removed
+     */
     protected function addWarning(PhpCsFile $phpcsFile, $stackPtr, array $removed)
     {
         $phpcsFile->addWarning(
@@ -61,6 +82,10 @@ abstract class AbstractYamlRemovedUsage
         );
     }
 
+    /**
+     * @param array $config
+     * @return string
+     */
     protected function getReplacement(array $config)
     {
         $newCall = $config['replacement'];
diff --git a/src/Standards/Typo3Update/RemovedByYamlConfiguration.php b/src/Standards/Typo3Update/RemovedByYamlConfiguration.php
index a527e43..f1596a9 100644
--- a/src/Standards/Typo3Update/RemovedByYamlConfiguration.php
+++ b/src/Standards/Typo3Update/RemovedByYamlConfiguration.php
@@ -31,6 +31,10 @@ class RemovedByYamlConfiguration
      */
     protected $configured = [];
 
+    /**
+     * @param array $configFiles
+     * @param Callable $prepareStructure
+     */
     public function __construct(array $configFiles, $prepareStructure)
     {
         foreach ($configFiles as $file) {
@@ -41,16 +45,26 @@ class RemovedByYamlConfiguration
         }
     }
 
+    /**
+     * @param string $identifier
+     * @return bool
+     */
     public function isRemoved($identifier)
     {
         return isset($this->configured[$identifier]);
     }
 
+    /**
+     * @return array
+     */
     public function getAllRemoved()
     {
         return $this->configured;
     }
 
+    /**
+     * @return array
+     */
     public function getRemoved($identifier)
     {
         if (!$this->isRemoved($identifier)) {
diff --git a/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericPhpUsage.php b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericPhpUsage.php
index c426721..99c81d1 100644
--- a/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericPhpUsage.php
+++ b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericPhpUsage.php
@@ -24,11 +24,18 @@ use PHP_CodeSniffer_File as PhpCsFile;
 
 abstract class AbstractGenericPhpUsage extends AbstractGenericUsage
 {
+    /**
+     * @return int[]
+     */
     public function register()
     {
         return [T_STRING];
     }
 
+    /**
+     * @param array $typo3Versions
+     * @return array
+     */
     protected function prepareStructure(array $typo3Versions)
     {
         $newStructure = [];
@@ -51,6 +58,11 @@ abstract class AbstractGenericPhpUsage extends AbstractGenericUsage
         return $newStructure;
     }
 
+    /**
+     * @param PhpCsFile $phpcsFile
+     * @param int $stackPtr
+     * @return array
+     */
     protected function findRemoved(PhpCsFile $phpcsFile, $stackPtr)
     {
         $tokens = $phpcsFile->getTokens();
@@ -104,6 +116,10 @@ abstract class AbstractGenericPhpUsage extends AbstractGenericUsage
         );
     }
 
+    /**
+     * @param string $identifier
+     * @param array &$config
+     */
     protected function handleStatic($identifier, array &$config)
     {
         $split = preg_split('/::|->/', $identifier);
@@ -118,6 +134,10 @@ abstract class AbstractGenericPhpUsage extends AbstractGenericUsage
         }
     }
 
+    /**
+     * @param array $config
+     * @return string
+     */
     protected function getIdentifier(array $config)
     {
         $name = $config['name'];
@@ -128,5 +148,9 @@ abstract class AbstractGenericPhpUsage extends AbstractGenericUsage
         return $name;
     }
 
+    /**
+     * @param array $config
+     * @return string
+     */
     abstract protected function getOldUsage(array $config);
 }
diff --git a/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php
index b7ab259..557dcb5 100644
--- a/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php
+++ b/src/Standards/Typo3Update/Sniffs/Removed/AbstractGenericUsage.php
@@ -26,8 +26,17 @@ use Typo3Update\AbstractYamlRemovedUsage as BaseAbstractYamlRemovedUsage;
 
 abstract class AbstractGenericUsage extends BaseAbstractYamlRemovedUsage implements PhpCsSniff
 {
+    /**
+     * @param PhpCsFile $phpcsFile
+     * @param int $stackPtr
+     * @return array
+     */
     abstract protected function findRemoved(PhpCsFile $phpcsFile, $stackPtr);
 
+    /**
+     * @param PhpCsFile $phpcsFile
+     * @param int $stackPtr
+     */
     public function process(PhpCsFile $phpcsFile, $stackPtr)
     {
         foreach ($this->findRemoved($phpcsFile, $stackPtr) as $removed) {
diff --git a/src/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff.php b/src/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff.php
index 4d1784b..2915a87 100644
--- a/src/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff.php
+++ b/src/Standards/Typo3Update/Sniffs/Removed/GenericFunctionCallSniff.php
@@ -24,9 +24,6 @@ use Typo3Update\Options;
 use Typo3Update\Sniffs\ExtendedPhpCsSupportTrait;
 use Typo3Update\Sniffs\Removed\AbstractGenericPhpUsage;
 
-/**
- * Sniff that handles all calls to removed functions.
- */
 class Typo3Update_Sniffs_Removed_GenericFunctionCallSniff extends AbstractGenericPhpUsage
 {
     use ExtendedPhpCsSupportTrait;
diff --git a/src/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff.php b/src/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff.php
index 419b55a..6638b34 100644
--- a/src/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff.php
+++ b/src/Standards/Typo3Update/Sniffs/Removed/TypoScriptSniff.php
@@ -24,9 +24,6 @@ use PHP_CodeSniffer_File as PhpCsFile;
 use Typo3Update\Options;
 use Typo3Update\Sniffs\Removed\AbstractGenericUsage;
 
-/**
- * Check usage of removed or breaking changed TypoScript.
- */
 class Typo3Update_Sniffs_Removed_TypoScriptSniff extends AbstractGenericUsage
 {
     /**
@@ -37,11 +34,6 @@ class Typo3Update_Sniffs_Removed_TypoScriptSniff extends AbstractGenericUsage
         'TYPOSCRIPT',
     ];
 
-    /**
-     * Returns the token types that this sniff is interested in.
-     *
-     * @return array<int>
-     */
     public function register()
     {
         return [
@@ -50,12 +42,6 @@ class Typo3Update_Sniffs_Removed_TypoScriptSniff extends AbstractGenericUsage
         ];
     }
 
-    /**
-     * Prepares structure from config for later usage.
-     *
-     * @param array $typo3Versions
-     * @return array
-     */
     protected function prepareStructure(array $typo3Versions)
     {
         $newStructure = [];
@@ -80,13 +66,6 @@ class Typo3Update_Sniffs_Removed_TypoScriptSniff extends AbstractGenericUsage
         return $newStructure;
     }
 
-    /**
-     * Check whether the current token is removed.
-     *
-     * @param PhpCsFile $phpcsFile
-     * @param int $stackPtr
-     * @return bool
-     */
     protected function findRemoved(PhpCsFile $phpcsFile, $stackPtr)
     {
         $tokens = $phpcsFile->getTokens();
@@ -105,11 +84,6 @@ class Typo3Update_Sniffs_Removed_TypoScriptSniff extends AbstractGenericUsage
         return [];
     }
 
-    /**
-     * Return file names containing removed configurations.
-     *
-     * @return array<string>
-     */
     protected function getRemovedConfigFiles()
     {
         return Options::getRemovedTypoScriptConfigFiles();
-- 
GitLab


From 9e3f7ac1e507713d021c39967428dabb58c2dc59 Mon Sep 17 00:00:00 2001
From: Daniel Siepmann <coding@daniel-siepmann.de>
Date: Tue, 2 May 2017 08:09:10 +0200
Subject: [PATCH 11/11] TASK: Fix MR issues

* Remove construct from interface.
* Fix wrong type hints.
* Keep naming of variable in sync.
* Also keep conditions format in sync.

Relates: #71
---
 .../Typo3Update/AbstractYamlRemovedUsage.php     | 16 ++++++++--------
 .../Typo3Update/Feature/FeatureInterface.php     |  5 -----
 .../Typo3Update/Feature/RemovedClassFeature.php  |  2 +-
 .../Typo3Update/RemovedByYamlConfiguration.php   |  2 +-
 4 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/src/Standards/Typo3Update/AbstractYamlRemovedUsage.php b/src/Standards/Typo3Update/AbstractYamlRemovedUsage.php
index 37d1c4e..e753605 100644
--- a/src/Standards/Typo3Update/AbstractYamlRemovedUsage.php
+++ b/src/Standards/Typo3Update/AbstractYamlRemovedUsage.php
@@ -29,7 +29,7 @@ use Typo3Update\RemovedByYamlConfiguration;
 abstract class AbstractYamlRemovedUsage
 {
     /**
-     * @var array
+     * @var RemovedByYamlConfiguration
      */
     protected $configured;
 
@@ -65,19 +65,19 @@ abstract class AbstractYamlRemovedUsage
     /**
      * @param PhpCsFile $phpcsFile
      * @param int $stackPtr
-     * @param array $removed
+     * @param array $config
      */
-    protected function addWarning(PhpCsFile $phpcsFile, $stackPtr, array $removed)
+    protected function addWarning(PhpCsFile $phpcsFile, $stackPtr, array $config)
     {
         $phpcsFile->addWarning(
             'Calls to removed code are not allowed; found %s. Removed in %s. %s. See: %s',
             $stackPtr,
-            $removed['identifier'],
+            $config['identifier'],
             [
-                $removed['oldUsage'],
-                $removed['versionRemoved'],
-                $this->getReplacement($removed),
-                $removed['docsUrl'],
+                $config['oldUsage'],
+                $config['versionRemoved'],
+                $this->getReplacement($config),
+                $config['docsUrl'],
             ]
         );
     }
diff --git a/src/Standards/Typo3Update/Feature/FeatureInterface.php b/src/Standards/Typo3Update/Feature/FeatureInterface.php
index ac8b7a9..8ab83a7 100644
--- a/src/Standards/Typo3Update/Feature/FeatureInterface.php
+++ b/src/Standards/Typo3Update/Feature/FeatureInterface.php
@@ -28,11 +28,6 @@ use PHP_CodeSniffer_Sniff as PhpCsSniff;
  */
 interface FeatureInterface
 {
-    /**
-     * @var PhpCsSniff $sniff
-     */
-    public function __construct(PhpCsSniff $sniff);
-
     /**
      * Process like a PHPCS Sniff.
      *
diff --git a/src/Standards/Typo3Update/Feature/RemovedClassFeature.php b/src/Standards/Typo3Update/Feature/RemovedClassFeature.php
index ffc61df..5584dfc 100644
--- a/src/Standards/Typo3Update/Feature/RemovedClassFeature.php
+++ b/src/Standards/Typo3Update/Feature/RemovedClassFeature.php
@@ -27,7 +27,7 @@ class RemovedClassFeature extends AbstractYamlRemovedUsage
 {
     public function process(PhpCsFile $phpcsFile, $classnamePosition, $classname)
     {
-        if (! $this->configured->isRemoved($classname)) {
+        if ($this->configured->isRemoved($classname) === false) {
             return;
         }
         $this->addWarning(
diff --git a/src/Standards/Typo3Update/RemovedByYamlConfiguration.php b/src/Standards/Typo3Update/RemovedByYamlConfiguration.php
index f1596a9..046c180 100644
--- a/src/Standards/Typo3Update/RemovedByYamlConfiguration.php
+++ b/src/Standards/Typo3Update/RemovedByYamlConfiguration.php
@@ -33,7 +33,7 @@ class RemovedByYamlConfiguration
 
     /**
      * @param array $configFiles
-     * @param Callable $prepareStructure
+     * @param \Callable $prepareStructure
      */
     public function __construct(array $configFiles, $prepareStructure)
     {
-- 
GitLab