You are here

private function ThemeFunctionDeprecationAnalyzer::analyzeFunction in Upgrade Status 8.3

Same name and namespace in other branches
  1. 8.2 src/ThemeFunctionDeprecationAnalyzer.php \Drupal\upgrade_status\ThemeFunctionDeprecationAnalyzer::analyzeFunction()

Analyzes function for definition of theme functions.

This doesn't recognize functions in all edge cases. For example, theme functions could be generated dynamically in a number of different ways. However, this will be useful in most use cases.

Parameters

$function: The function to be analyzed.

\Drupal\Core\Extension\Extension $extension: The extension that is being tested.

Return value

\Drupal\upgrade_status\DeprecationMessage[]

1 call to ThemeFunctionDeprecationAnalyzer::analyzeFunction()
ThemeFunctionDeprecationAnalyzer::analyze in src/ThemeFunctionDeprecationAnalyzer.php
Analyzes theme functions in an extension.

File

src/ThemeFunctionDeprecationAnalyzer.php, line 102

Class

ThemeFunctionDeprecationAnalyzer
A theme function deprecation analyzer.

Namespace

Drupal\upgrade_status

Code

private function analyzeFunction(string $function, Extension $extension) : array {
  $deprecation_messages = [];
  try {
    $function_reflection = new \ReflectionFunction($function);
  } catch (\ReflectionException $e) {

    // Not all extensions implement theme hooks.
    return [];
  }
  $parser = (new ParserFactory())
    ->create(ParserFactory::PREFER_PHP7);
  try {
    $ast = $parser
      ->parse(file_get_contents($function_reflection
      ->getFileName()));
  } catch (Error $error) {

    // The function cannot be evaluated because of a syntax error.
    $deprecation_messages[] = new DeprecationMessage(sprintf('Parse error while processing the %s hook implementation.', $theme_function), $function_reflection
      ->getFileName(), $node
      ->getStartLine());
  }
  if (!is_iterable($ast)) {
    return [];
  }
  $finder = new NodeFinder();

  // Find the node for the function that is being analyzed.
  $function_node = $finder
    ->findFirst($ast, function (Node $node) use ($function) {
    return $node instanceof Function_ && isset($node->name) && $node->name->name === $function;
  });
  if (!$function_node) {

    // This should never happen because the file has been loaded based on the
    // existence of the function.
    return [];
  }

  // Find theme functions that have been defined using the array syntax.
  // @code
  // function hook_theme() {
  //   return [
  //     'theme_hook' => ['function' => theme_function'],
  //   ];
  // }
  // @endcode
  $theme_function_nodes = $finder
    ->find([
    $function_node,
  ], function (Node $node) {
    return $node instanceof ArrayItem && $node->key instanceof String_ && $node->key->value === 'function';
  });
  foreach ($theme_function_nodes as $node) {
    $theme_function = $node->value instanceof String_ ? sprintf('"%s"', $node->value->value) : 'an unknown';
    $deprecation_messages[] = new DeprecationMessage(sprintf('The %s is defining %s theme function. Theme functions are deprecated. For more info, see https://www.drupal.org/node/2575445.', $extension
      ->getType(), $theme_function), $function_reflection
      ->getFileName(), $node
      ->getStartLine());
  }

  // Find theme functions that are being added to an existing array using
  // the array square bracket syntax.
  // @code
  // function hook_theme_registry_alter(&$theme_registry) {
  //   $theme_registry['theme_hook']['function'] = 'another_theme_function';
  // }
  // @endcode
  $theme_function_dim_nodes = $finder
    ->find([
    $function_node,
  ], function (Node $node) {
    return $node instanceof Assign && $node->var instanceof ArrayDimFetch && $node->var->dim instanceof String_ && $node->var->dim->value === 'function';
  });
  foreach ($theme_function_dim_nodes as $node) {
    $theme_function = $node->expr instanceof String_ ? sprintf('"%s"', $node->expr->value) : 'an unknown';
    $deprecation_messages[] = new DeprecationMessage(sprintf('The %s is defining %s theme function. Theme functions are deprecated. For more info, see https://www.drupal.org/node/2575445.', $extension
      ->getType(), $theme_function), $function_reflection
      ->getFileName(), $node
      ->getStartLine());
  }
  return $deprecation_messages;
}