public function getMethodAttributes($index)
    {
        $tokens = $this->tokens;
        $token = $tokens[$index];

        if (!$token->isGivenKind(T_FUNCTION)) {
            throw new \LogicException(sprintf('No T_FUNCTION at given index %d, got %s.', $index, $token->getName()));
        }

        $attributes = [
            'visibility' => null,
            'static' => false,
            'abstract' => false,
            'final' => false,
        ];

        for ($i = $index; $i >= 0; --$i) {
            $tokenIndex = $tokens->getPrevMeaningfulToken($i);

            $i = $tokenIndex;
            $token = $tokens[$tokenIndex];

            if ($token->isGivenKind(T_STATIC)) {
                $attributes['static'] = true;

                continue;
            }

            if ($token->isGivenKind(T_FINAL)) {
                $attributes['final'] = true;

                continue;
            }

            if ($token->isGivenKind(T_ABSTRACT)) {
                $attributes['abstract'] = true;

                continue;
            }

            // visibility

            if ($token->isGivenKind(T_PRIVATE)) {
                $attributes['visibility'] = T_PRIVATE;

                continue;
            }

            if ($token->isGivenKind(T_PROTECTED)) {
                $attributes['visibility'] = T_PROTECTED;

                continue;
            }

            if ($token->isGivenKind(T_PUBLIC)) {
                $attributes['visibility'] = T_PUBLIC;

                continue;
            }

            // found a meaningful token that is not part of
            // the function signature; stop looking
            break;
        }

        return $attributes;
    }