<commit_before><?php
namespace Mw\Metamorph\Step\TransformationVisitor;

use Mw\Metamorph\Transformation\TransformationVisitor\AbstractVisitor;
use PhpParser\Node;

class ClassNamespaceRewriterVisitor extends AbstractVisitor {

	/** @var \PhpParser\Node\Stmt\Namespace_ */
	protected $currentNamespaceNode = NULL;

	/** @var \PhpParser\Node\Stmt\Class_ */
	protected $currentClassNode = NULL;

	protected $newNamespace = NULL;

	protected $imports = [];

	protected $definedClasses = [];

	public function beforeTraverse(array $nodes) {
		$this->imports              = [];
		$this->currentNamespaceNode = NULL;
		$this->newNamespace         = NULL;
	}

	public function enterNode(Node $node) {
		if ($node->getDocComment()) {
			$this->replaceOldClassnamesInDocComment($node);
		}

		if ($node instanceof Node\Stmt\Namespace_) {
			$this->currentNamespaceNode = $node;
		} elseif ($node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Interface_) {
			return $this->convertClassNameForOldClass($node);
		} elseif ($node instanceof Node\Name) {
			return $this->convertClassNameForOldClassUsage($node);
		} elseif ($node instanceof Node\Scalar\String) {
			return $this->convertClassNameInString($node);
		}
		return NULL;
	}

	public function leaveNode(Node $node) {
		if ($node instanceof Node\Stmt\Namespace_) {
			$this->currentNamespaceNode = NULL;
			if ($this->newNamespace !== NULL) {
				$uses = $this->getUseStatements();

				$node->name  = $this->newNamespace;
				$node->stmts = array_merge($uses, $node->stmts);

				$this->newNamespace = NULL;
				return $node;
			}
		}
		return NULL;
	}

	public function afterTraverse(array $nodes) {
		if (NULL !== $this->newNamespace) {
			$useNodes      = $this->getUseStatements();
			$namespaceNode = new Node\Stmt\Namespace_($this->newNamespace, array_merge($useNodes, $nodes));

			return [$namespaceNode];
		}
		return NULL;
	}

	private function getNamespaceAndRelativeNameForOldClass($oldClass) {
		$newName           = $this->classMap->getClassMapping($oldClass)->getNewClassName();
		$newNameComponents = explode('\\', $newName);

		$relativeClassName = array_pop($newNameComponents);
		$namespace         = implode('\\', $newNameComponents);

		return [$namespace, $relativeClassName];
	}

	private function getUseStatements() {
		$uses = [];

		foreach ($this->imports as $fqcn => $name) {
			$useuse = new Node\Stmt\UseUse($name);
			$uses[] = new Node\Stmt\Use_([$useuse]);
		}

		return $uses;
	}

	/**
	 * @param Node $node
	 * @return array
	 */
	public function replaceOldClassnamesInDocComment(Node $node) {
		$text = $node->getDocComment()->getText();

		foreach ($this->classMap->getClassMappings() as $classMapping) {
			$new = '\\' . $classMapping->getNewClassName();
			$old = $classMapping->getOldClassName();

			if (strpos($text, $old) !== FALSE) {
				$text = str_replace('\\' . $old, $new, $text);
				$text = str_replace($old, $new, $text);
			}
		}

		$node->getDocComment()->setText($text);
	}

	/**
	 * @param Node $node
	 * @return null|Node
	 */
	private function convertClassNameForOldClass(Node $node) {
		if ($node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Interface_) {
			$this->currentClassNode = $node;<commit_msg>Use FQDNs when rewriting class usages (import aliases may conflict)<commit_after><?php
namespace Mw\Metamorph\Step\TransformationVisitor;

use Mw\Metamorph\Transformation\TransformationVisitor\AbstractVisitor;
use PhpParser\Node;

class ClassNamespaceRewriterVisitor extends AbstractVisitor {

	/** @var \PhpParser\Node\Stmt\Namespace_ */
	protected $currentNamespaceNode = NULL;

	/** @var \PhpParser\Node\Stmt\Class_ */
	protected $currentClassNode = NULL;

	protected $newNamespace = NULL;

	protected $imports = [];

	protected $definedClasses = [];

	public function beforeTraverse(array $nodes) {
		$this->imports              = [];
		$this->currentNamespaceNode = NULL;
		$this->newNamespace         = NULL;
	}

	public function enterNode(Node $node) {
		if ($node->getDocComment()) {
			$this->replaceOldClassnamesInDocComment($node);
		}

		if ($node instanceof Node\Stmt\Namespace_) {
			$this->currentNamespaceNode = $node;
		} elseif ($node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Interface_) {
			return $this->convertClassNameForOldClass($node);
		} elseif ($node instanceof Node\Name) {
			return $this->convertClassNameForOldClassUsage($node);
		} elseif ($node instanceof Node\Scalar\String) {
			return $this->convertClassNameInString($node);
		}
		return NULL;
	}

	public function leaveNode(Node $node) {
		if ($node instanceof Node\Stmt\Namespace_) {
			$this->currentNamespaceNode = NULL;
			if ($this->newNamespace !== NULL) {
				$node->name         = $this->newNamespace;
				$this->newNamespace = NULL;

				return $node;
			}
		}
		return NULL;
	}

	public function afterTraverse(array $nodes) {
		if (NULL !== $this->newNamespace) {
			$namespaceNode = new Node\Stmt\Namespace_($this->newNamespace, $nodes);
			return [$namespaceNode];
		}
		return NULL;
	}

	private function getNamespaceAndRelativeNameForOldClass($oldClass) {
		$newName           = $this->classMap->getClassMapping($oldClass)->getNewClassName();
		$newNameComponents = explode('\\', $newName);

		$relativeClassName = array_pop($newNameComponents);
		$namespace         = implode('\\', $newNameComponents);

		return [$namespace, $relativeClassName];
	}

	/**
	 * @param Node $node
	 * @return array
	 */
	public function replaceOldClassnamesInDocComment(Node $node) {
		$text = $node->getDocComment()->getText();

		foreach ($this->classMap->getClassMappings() as $classMapping) {
			$new = '\\' . $classMapping->getNewClassName();
			$old = $classMapping->getOldClassName();

			if (strpos($text, $old) !== FALSE) {
				$text = str_replace('\\' . $old, $new, $text);
				$text = str_replace($old, $new, $text);
			}
		}

		$node->getDocComment()->setText($text);
	}

	/**
	 * @param Node $node
	 * @return null|Node
	 */
	private function convertClassNameForOldClass(Node $node) {
		if ($node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Interface_) {
			$this->currentClassNode = $node;
{'fraction_non_alphanumeric': 0.15149544863459039, 'fraction_numerical': 0.0, 'mean_word_length': 4.136060100166945, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1697944', 'n_tokens_mistral': 2092, 'n_tokens_neox': 1900, 'n_words': 385}