<commit_before><?php

namespace PhpSpec\Util;

class MethodAnalyser
{
    /**
     * @param string $class
     * @param string $method
     *
     * @return boolean
     */
    public function methodIsEmpty($class, $method)
    {
        return $this->reflectionMethodIsEmpty(new \ReflectionMethod($class, $method));
    }

    /**
     * @param \ReflectionMethod $method
     *
     * @return bool
     */
    public function reflectionMethodIsEmpty(\ReflectionMethod $method)
    {
        if ($this->isNotImplementedInPhp($method)) {
            return false;
        }

        $code = $this->getCodeBody($method);
        $codeWithoutComments = $this->stripComments($code);

        return $this->codeIsOnlyBlocksAndWhitespace($codeWithoutComments);
    }

    /**
     * @param ReflectionMethod $reflectionMethod
     *
     * @return string
     */
    private function getCodeBody(\ReflectionMethod $reflectionMethod)
    {
        $reflectionClass = $reflectionMethod->getDeclaringClass();

        $length = $reflectionMethod->getEndLine() - $reflectionMethod->getStartLine();
        $lines = file($reflectionClass->getFileName());

        if ($length == 0 ) {
            return preg_replace('/.*function.*{/', '', $lines[$reflectionMethod->getStartLine()-1]);
        }

        return join("\n", array_slice($lines, $reflectionMethod->getStartLine(), $length));
    }

    /**
     * @param string $code
     * @return string
     */
    private function stripComments($code)
    {
        $tokens = token_get_all('<?php ' . $code);

        $comments = array_map(
            function ($token) {
                return $token[1];
            },
            array_filter($tokens,
                function ($token) {
                    return is_array($token)
                    && in_array($token[0], array(T_COMMENT, T_DOC_COMMENT));
                })
        );

        $commentless = str_replace($comments, '', $code);

        return $commentless;
    }

    /**
     * @param string $codeWithoutComments
     * @return bool
     */
    private function codeIsOnlyBlocksAndWhitespace($codeWithoutComments)
    {
        return (bool)preg_match('/^[\s{}]*$/s', $codeWithoutComments);
    }

    /**
     * @param \ReflectionMethod $method
     * @return bool
     */
    private function isNotImplementedInPhp(\ReflectionMethod $method)
    {
        return false === $method->getDeclaringClass()->getFileName();<commit_msg>HHVM support<commit_after><?php

namespace PhpSpec\Util;

class MethodAnalyser
{
    /**
     * @param string $class
     * @param string $method
     *
     * @return boolean
     */
    public function methodIsEmpty($class, $method)
    {
        return $this->reflectionMethodIsEmpty(new \ReflectionMethod($class, $method));
    }

    /**
     * @param \ReflectionMethod $method
     *
     * @return bool
     */
    public function reflectionMethodIsEmpty(\ReflectionMethod $method)
    {
        if ($this->isNotImplementedInPhp($method)) {
            return false;
        }

        $code = $this->getCodeBody($method);
        $codeWithoutComments = $this->stripComments($code);

        return $this->codeIsOnlyBlocksAndWhitespace($codeWithoutComments);
    }

    /**
     * @param ReflectionMethod $reflectionMethod
     *
     * @return string
     */
    private function getCodeBody(\ReflectionMethod $reflectionMethod)
    {
        $reflectionClass = $reflectionMethod->getDeclaringClass();

        $length = $reflectionMethod->getEndLine() - $reflectionMethod->getStartLine();
        $lines = file($reflectionClass->getFileName());

        if ($length == 0 ) {
            return preg_replace('/.*function.*{/', '', $lines[$reflectionMethod->getStartLine()-1]);
        }

        return join("\n", array_slice($lines, $reflectionMethod->getStartLine(), $length));
    }

    /**
     * @param string $code
     * @return string
     */
    private function stripComments($code)
    {
        $tokens = token_get_all('<?php ' . $code);

        $comments = array_map(
            function ($token) {
                return $token[1];
            },
            array_filter($tokens,
                function ($token) {
                    return is_array($token)
                    && in_array($token[0], array(T_COMMENT, T_DOC_COMMENT));
                })
        );

        $commentless = str_replace($comments, '', $code);

        return $commentless;
    }

    /**
     * @param string $codeWithoutComments
     * @return bool
     */
    private function codeIsOnlyBlocksAndWhitespace($codeWithoutComments)
    {
        return (bool)preg_match('/^[\s{}]*$/s', $codeWithoutComments);
    }

    /**
     * @param \ReflectionMethod $method
     * @return bool
     */
    private function isNotImplementedInPhp(\ReflectionMethod $method)
    {
        $filename = $method->getDeclaringClass()->getFileName();

        if (false === $filename) {
            return true;
        }

        // HHVM <=3.2.0 does not return FALSE correctly
        if (preg_match('#^/([:/]systemlib.|/$)#', $filename)) {
            return true;
        }

        return false;
{'fraction_non_alphanumeric': 0.1382398753894081, 'fraction_numerical': 0.002141744548286604, 'mean_word_length': 2.2126328955597248, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 29, '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': '5611099', 'n_tokens_mistral': 1475, 'n_tokens_neox': 1418, 'n_words': 258}