<commit_before><?php

/**
 * @link       http://patchwork2.org/
 * @author     <NAME> <<EMAIL>>
 * @copyright  2010-2018 <NAME>
 * @license    http://www.opensource.org/licenses/mit-license.html
 */
namespace Patchwork\CodeManipulation\Actions\Namespaces;

use Patchwork\CodeManipulation\Source;
use Patchwork\CodeManipulation\Actions\Generic;

/**
 * @since 2.1.0
 */
function resolveName(Source $s, $pos, $type = 'class')
{
    $name = scanQualifiedName($s, $pos);
    $pieces = explode('\\', $name);
    if ($pieces[0] === '') {
        return $name;
    }
    $uses = collectUseDeclarations($s, $pos);
    if (isset($uses[$type][$name])) {
        return '\\' . ltrim($uses[$type][$name], ' \\');
    }
    if (isset($uses['class'][$pieces[0]])) {
        $name = '\\' . ltrim($uses['class'][$pieces[0]] . '\\' . join('\\', array_slice($pieces, 1)), '\\');
    } else {
        $name = '\\' . ltrim(getNamespaceAt($s, $pos) . '\\' . $name, '\\');
    }
    return $name;
}

/**
 * @since 2.1.0
 */
function getNamespaceAt(Source $s, $pos)
{
    foreach (collectNamespaceBoundaries($s) as $namespace => $boundaryPairs) {
        foreach ($boundaryPairs as $boundaries) {
            list($begin, $end) = $boundaries;
            if ($begin <= $pos && $pos <= $end) {
                return $namespace;
            }
        }
    }
    return '';
}

function collectNamespaceBoundaries(Source $s)
{
    return $s->cache([], function() {
        if (!$this->has(T_NAMESPACE)) {
            return ['' => [[0, INF]]];
        }
        $result = [];
        foreach ($this->all(T_NAMESPACE) as $keyword) {
            if ($this->next(';', $keyword) < $this->next(Generic\LEFT_CURLY, $keyword)) {
                return [scanQualifiedName($this, $keyword + 1) => [[0, INF]]];
            }
            $begin = $this->next(Generic\LEFT_CURLY, $keyword) + 1;
            $end = $this->match($begin - 1) - 1;
            $name = scanQualifiedName($this, $keyword + 1);
            if (!isset($result[$name])) {
                $result[$name] = [];
            }
            $result[$name][] = [$begin, $end];
        }
        return $result;
    });
}

function collectUseDeclarations(Source $s, $begin)
{
    foreach (collectNamespaceBoundaries($s) as $boundaryPairs) {
        foreach ($boundaryPairs as $boundaries) {
            list($leftBoundary, $rightBoundary) = $boundaries;
            if ($leftBoundary <= $begin && $begin <= $rightBoundary) {
                $begin = $leftBoundary;
                break;
            }
        }
    }
    return $s->cache([$begin], function($begin) {
        $result = ['class' => [], 'function' => [], 'const' => []];
        # only tokens that are siblings bracket-wise are considered,
        # so trait-use instances are not an issue
        foreach ($this->siblings(T_USE, $begin) as $keyword) {
            # skip if closure-use
            $next = $this->skip(Source::junk(), $keyword);
            if ($this->is(Generic\LEFT_ROUND, $next)) {
                continue;
            }
            parseUseDeclaration($this, $next, $result);
        }
        return $result;
    });
}

function parseUseDeclaration(Source $s, $pos, array &$aliases, $prefix = '', $type = 'class')
{
    $lastPart = null;
    $whole = $prefix;
    while (true) {
        switch ($s->tokens[$pos][Source::TYPE_OFFSET]) {
            case T_FUNCTION:
                $type = 'function';
                break;
            case T_CONST:
                $type = 'const';
                break;
            case T_NS_SEPARATOR:
                if (!empty($whole)) {
                    $whole .= '\\';
                }
                break;
            case T_STRING:
            case Generic\NAME_FULLY_QUALIFIED:
            case Generic\NAME_QUALIFIED:
            case Generic\NAME_RELATIVE:
                $lastPart = $s->tokens[$pos][Source::STRING_OFFSET];
                $whole .= $lastPart;
                break;
            case T_AS:
                $pos = $s->skip(Source::junk(), $pos);
                $aliases[$type][$s->tokens[$pos][Source::STRING_OFFSET]] = $whole;<commit_msg>Update parseUseDeclaration() for single-token qualified names<commit_after><?php

/**
 * @link       http://patchwork2.org/
 * @author     <NAME> <<EMAIL>>
 * @copyright  2010-2018 <NAME>
 * @license    http://www.opensource.org/licenses/mit-license.html
 */
namespace Patchwork\CodeManipulation\Actions\Namespaces;

use Patchwork\CodeManipulation\Source;
use Patchwork\CodeManipulation\Actions\Generic;

/**
 * @since 2.1.0
 */
function resolveName(Source $s, $pos, $type = 'class')
{
    $name = scanQualifiedName($s, $pos);
    $pieces = explode('\\', $name);
    if ($pieces[0] === '') {
        return $name;
    }
    $uses = collectUseDeclarations($s, $pos);
    if (isset($uses[$type][$name])) {
        return '\\' . ltrim($uses[$type][$name], ' \\');
    }
    if (isset($uses['class'][$pieces[0]])) {
        $name = '\\' . ltrim($uses['class'][$pieces[0]] . '\\' . join('\\', array_slice($pieces, 1)), '\\');
    } else {
        $name = '\\' . ltrim(getNamespaceAt($s, $pos) . '\\' . $name, '\\');
    }
    return $name;
}

/**
 * @since 2.1.0
 */
function getNamespaceAt(Source $s, $pos)
{
    foreach (collectNamespaceBoundaries($s) as $namespace => $boundaryPairs) {
        foreach ($boundaryPairs as $boundaries) {
            list($begin, $end) = $boundaries;
            if ($begin <= $pos && $pos <= $end) {
                return $namespace;
            }
        }
    }
    return '';
}

function collectNamespaceBoundaries(Source $s)
{
    return $s->cache([], function() {
        if (!$this->has(T_NAMESPACE)) {
            return ['' => [[0, INF]]];
        }
        $result = [];
        foreach ($this->all(T_NAMESPACE) as $keyword) {
            if ($this->next(';', $keyword) < $this->next(Generic\LEFT_CURLY, $keyword)) {
                return [scanQualifiedName($this, $keyword + 1) => [[0, INF]]];
            }
            $begin = $this->next(Generic\LEFT_CURLY, $keyword) + 1;
            $end = $this->match($begin - 1) - 1;
            $name = scanQualifiedName($this, $keyword + 1);
            if (!isset($result[$name])) {
                $result[$name] = [];
            }
            $result[$name][] = [$begin, $end];
        }
        return $result;
    });
}

function collectUseDeclarations(Source $s, $begin)
{
    foreach (collectNamespaceBoundaries($s) as $boundaryPairs) {
        foreach ($boundaryPairs as $boundaries) {
            list($leftBoundary, $rightBoundary) = $boundaries;
            if ($leftBoundary <= $begin && $begin <= $rightBoundary) {
                $begin = $leftBoundary;
                break;
            }
        }
    }
    return $s->cache([$begin], function($begin) {
        $result = ['class' => [], 'function' => [], 'const' => []];
        # only tokens that are siblings bracket-wise are considered,
        # so trait-use instances are not an issue
        foreach ($this->siblings(T_USE, $begin) as $keyword) {
            # skip if closure-use
            $next = $this->skip(Source::junk(), $keyword);
            if ($this->is(Generic\LEFT_ROUND, $next)) {
                continue;
            }
            parseUseDeclaration($this, $next, $result);
        }
        return $result;
    });
}

function parseUseDeclaration(Source $s, $pos, array &$aliases, $prefix = '', $type = 'class')
{
    $lastPart = null;
    $whole = $prefix;
    while (true) {
        switch ($s->tokens[$pos][Source::TYPE_OFFSET]) {
            case T_FUNCTION:
                $type = 'function';
                break;
            case T_CONST:
                $type = 'const';
                break;
            case T_NS_SEPARATOR:
                if (!empty($whole)) {
                    $whole .= '\\';
                }
                break;
            case T_STRING:
            case Generic\NAME_FULLY_QUALIFIED:
            case Generic\NAME_QUALIFIED:
            case Generic\NAME_RELATIVE:
                $update = $s->tokens[$pos][Source::STRING_OFFSET];
                $parts = explode('\\', $update);
                $whole .= $update;
                $lastPart = end($parts);
                break;
            case T_AS:
                $pos = $s->skip(Source::junk(), $pos);
                $aliases[$type][$s->tokens[$pos][Source::STRING_OFFSET]] = $whole;
{'fraction_non_alphanumeric': 0.17739628040057226, 'fraction_numerical': 0.00619933237958989, 'mean_word_length': 1.9352694191742477, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '6805148', 'n_tokens_mistral': 2661, 'n_tokens_neox': 2555, 'n_words': 503}