matcherDefinitions = $matcherDefinitions; $this->validateMatcherDefinitions(); $this->initializeFlatMatcherDefinitions(); // initializeFlatMatcherDefinitions() unfortunately does not deliver the actual // method, so we need to do something 99% similar here for a custom // property, to not require larger changes to the underlying abstract method. foreach ($this->matcherDefinitions as $classAndMethod => $details) { $parts = GeneralUtility::trimExplode('::', $classAndMethod); $definition = self::DEFINITION_STATIC; if (count($parts) !== 2) { $parts = GeneralUtility::trimExplode('->', $classAndMethod); $definition = self::DEFINITION_LOCAL; } // Exception-Handling removed, covered by initializeFlatMatcherDefinitions(); $method = $parts[1]; $class = $parts[0]; if (!array_key_exists($class, $this->matcherDefinitionLookup)) { $this->matcherDefinitionLookup[$class][$definition][$method]['candidates'] = []; } $this->matcherDefinitionLookup[$class][$definition][$method]['candidates'][] = $details; // Builds something like: // [ // 'TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper' => [ // 'static' => [ // 'renderStatic' => [ // 'candidates' => [ // [ // 'restFiles' => [ // 'Deprecation-104789-RenderStaticForFluidViewHelpers.rst', // ], // ], // ], // ] // ], // ], // 'TYPO3\CMS\AbstractSomething' => [ // 'local' => [ // 'someMethodName' => [ // 'candidates' => [ // [ // 'restFiles' => [ // 'Breaking-12345-something.rst', // ], // ], // [ // 'restFiles' => [ // 'Breaking-67890-something.rst', // ], // ], // ], // ] // ], // ], // ]; } } /** * Called by PhpParser. * Test for a defined method that shall longer be utilized (strong match) */ public function enterNode(Node $node): null { if (!$this->isFileIgnored($node) && !$this->isLineIgnored($node) && $node instanceof Node\Stmt\Class_ && $node->extends) { // We found a class definition. // Check what classes this definition is extending (Abstract). // Without a class extending something, this is not API usage and thus not scanned. // Now check if the extended class is part of our matcherDefinition to inspect if (array_key_exists($node->extends->name, $this->matcherDefinitionLookup)) { // Iterate all declared methods (of the inspected custom class, NOT the abstract!) $lookupMethods = $this->matcherDefinitionLookup[$node->extends->name]; foreach ($node->getMethods() as $method) { // The matcherDefinition can utilize 'Abstract::staticMethod' or 'Abstract->localMethod', // which is handled distinctly, so that the matches are stronger. $lookupKey = $method->isStatic() ? self::DEFINITION_STATIC : self::DEFINITION_LOCAL; if (isset($lookupMethods[$lookupKey][$method->name->toString()]['candidates'])) { // The checked method of an object extending a deprecated/BC class was a match. // Gather final match info (multiple ReST files can apply to a single class+method) foreach ($lookupMethods[$lookupKey][$method->name->toString()]['candidates'] as $candidate) { $this->matches[] = [ 'restFiles' => $candidate['restFiles'], 'line' => $method->getAttribute('startLine'), 'message' => sprintf( 'Definition of %s method "%s" extends from "%s"', $lookupKey, $method->name->toString(), $node->extends->name ), 'indicator' => 'strong', ]; } } } } } return null; } }