Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/fix/resolving-const-root-namespace'
Browse files Browse the repository at this point in the history
* origin/fix/resolving-const-root-namespace:
  Fix code-style issues from Nitpick
  Add root namespace normalization, resolves #39

Conflicts:
	src/ReflectionEngine.php
  • Loading branch information
lisachenko committed Sep 25, 2016
2 parents fdee566 + 7c230c4 commit 483c4c9
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 49 deletions.
43 changes: 43 additions & 0 deletions src/NodeVisitor/RootNamespaceNormalizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
/**
* Parser Reflection API
*
* @copyright Copyright 2016, Lisachenko Alexander <[email protected]>
*
* This source file is subject to the license that is bundled
* with this source code in the file LICENSE.
*/

namespace Go\ParserReflection\NodeVisitor;

use PhpParser\Node;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\NodeVisitorAbstract;

/**
* Visitor to normalize the root namespace for the files without the namespace (root namespace)
*
* File->Namespace->Statements
*/
class RootNamespaceNormalizer extends NodeVisitorAbstract
{
/**
* {@inheritdoc}
*/
public function beforeTraverse(array $nodes)
{
// namespaces can be only top-level nodes, so we can scan them directly
foreach ($nodes as $topLevelNode) {
if ($topLevelNode instanceof Namespace_) {
// file has namespace in it, nothing to change, returning null
return null;
}
}

// if we don't have a namespaces at all, this is global namespace, wrap everything in it
$globalNamespaceNode = new Namespace_(new FullyQualified(''), $nodes);

return [$globalNamespaceNode];
}
}
19 changes: 10 additions & 9 deletions src/ReflectionEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace Go\ParserReflection;

use Go\ParserReflection\Instrument\PathResolver;
use Go\ParserReflection\NodeVisitor\RootNamespaceNormalizer;
use PhpParser\Lexer;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassLike;
Expand Down Expand Up @@ -68,6 +69,7 @@ public static function init(LocatorInterface $locator)

self::$traverser = $traverser = new NodeTraverser();
$traverser->addVisitor(new NameResolver());
$traverser->addVisitor(new RootNamespaceNormalizer());

self::$locator = $locator;
}
Expand Down Expand Up @@ -127,14 +129,9 @@ public static function parseClass($fullClassName)
$className = array_pop($namespaceParts);
$namespaceName = join('\\', $namespaceParts);

if ($namespaceName) {
// we have a namespace nodes somewhere
$namespace = self::parseFileNamespace($classFileName, $namespaceName);
$namespaceNodes = $namespace->stmts;
} else {
// global namespace
$namespaceNodes = self::parseFile($classFileName);
}
// we have a namespace node somewhere
$namespace = self::parseFileNamespace($classFileName, $namespaceName);
$namespaceNodes = $namespace->stmts;

foreach ($namespaceNodes as $namespaceLevelNode) {
if ($namespaceLevelNode instanceof ClassLike && $namespaceLevelNode->name == $className) {
Expand Down Expand Up @@ -238,7 +235,11 @@ public static function parseFileNamespace($fileName, $namespaceName)
$topLevelNodes = self::parseFile($fileName);
// namespaces can be only top-level nodes, so we can scan them directly
foreach ($topLevelNodes as $topLevelNode) {
if ($topLevelNode instanceof Namespace_ && ($topLevelNode->name->toString() == $namespaceName)) {
if (!$topLevelNode instanceof Namespace_) {
continue;
}
$topLevelNodeName = $topLevelNode->name ? $topLevelNode->name->toString() : '';
if ($topLevelNodeName === $namespaceName) {
return $topLevelNode;
}
}
Expand Down
9 changes: 1 addition & 8 deletions src/ReflectionFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

use Go\ParserReflection\Instrument\PathResolver;
use PhpParser\Node;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Namespace_;

/**
Expand Down Expand Up @@ -122,7 +121,7 @@ private function findFileNamespaces()
// namespaces can be only top-level nodes, so we can scan them directly
foreach ($this->topLevelNodes as $topLevelNode) {
if ($topLevelNode instanceof Namespace_) {
$namespaceName = $topLevelNode->name ? $topLevelNode->name->toString() : '\\';
$namespaceName = $topLevelNode->name ? $topLevelNode->name->toString() : '';

$namespaces[$namespaceName] = new ReflectionFileNamespace(
$this->fileName,
Expand All @@ -132,12 +131,6 @@ private function findFileNamespaces()
}
}

if (!$namespaces) {
// if we don't have a namespaces at all, this is global namespace
$globalNamespaceNode = new Namespace_(new FullyQualified(''), $this->topLevelNodes);
$namespaces['\\'] = new ReflectionFileNamespace($this->fileName, '\\', $globalNamespaceNode);
}

return $namespaces;
}
}
2 changes: 1 addition & 1 deletion tests/ReflectionFileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public function testGetGlobalFileNamespace()
$fileName = stream_resolve_include_path(__DIR__ . self::STUB_GLOBAL_FILE);
$reflectionFile = new ReflectionFile($fileName);

$reflectionFileNamespace = $reflectionFile->getFileNamespace('\\');
$reflectionFileNamespace = $reflectionFile->getFileNamespace('');
$this->assertInstanceOf(ReflectionFileNamespace::class, $reflectionFileNamespace);
}
}
13 changes: 13 additions & 0 deletions tests/ReflectionParameterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use Go\ParserReflection\Stub\Foo;
use Go\ParserReflection\Stub\SubFoo;
use TestParametersForRootNsClass;

class ReflectionParameterTest extends \PHPUnit_Framework_TestCase
{
Expand Down Expand Up @@ -105,6 +106,18 @@ public function testGetClassMethodReturnsSelfAndParent()
$this->assertSame(Foo::class, $parentParam->getName());
}

public function testNonConstantsResolvedForGlobalNamespace()
{
$parsedNamespace = $this->parsedRefFile->getFileNamespace('');
$parsedClass = $parsedNamespace->getClass(TestParametersForRootNsClass::class);
$parsedFunction = $parsedClass->getMethod('foo');

$parameters = $parsedFunction->getParameters();
$this->assertSame(null, $parameters[0]->getDefaultValue());
$this->assertSame(false, $parameters[1]->getDefaultValue());
$this->assertSame(true, $parameters[2]->getDefaultValue());
}

public function testGetDeclaringClassMethodReturnsObject()
{
$parsedNamespace = $this->parsedRefFile->getFileNamespace('Go\ParserReflection\Stub');
Expand Down
92 changes: 61 additions & 31 deletions tests/Stub/FileWithParameters.php
Original file line number Diff line number Diff line change
@@ -1,36 +1,66 @@
<?php

namespace Go\ParserReflection\Stub;

use Go\ParserReflection\ReflectionParameter;

const TEST_PARAMETER = 42;

function noParameters() {}
function singleParameter($test) {}
function miscParameters(
array $arrayParam,
array $arrayParamWithDefault = array(1,2,3),
array $arrayNullable = null,
callable $callableParam,
callable $callableNullable = null,
\stdClass $objectParam,
\stdClass $objectNullable = null,
ReflectionParameter $typehintedParamWithNs,
&$byReferenceParam,
&$byReferenceNullable = __CLASS__,
$constParam = TEST_PARAMETER,
$constValueParam = __NAMESPACE__, // This line is long and should be truncated
\Traversable $traversable
) {}

class Foo {
const CLASS_CONST = __CLASS__;

public function methodParam($firstParam, $optionalParam = null) {}
public function methodParamConst($firstParam = self::CLASS_CONST, $another = __CLASS__, $ns = TEST_PARAMETER) {}
namespace {
function testResolveDefaults($a = null, $b = false, $c = true)
{
}

class TestParametersForRootNsClass
{
public function foo($a = null, $b = false, $c = true)
{
}
}
}

class SubFoo extends Foo {
public function anotherMethodParam(self $selfParam, parent $parentParam) {}
namespace Go\ParserReflection\Stub {

use Go\ParserReflection\ReflectionParameter;

const TEST_PARAMETER = 42;

function noParameters()
{
}

function singleParameter($test)
{
}

function miscParameters(
array $arrayParam,
array $arrayParamWithDefault = array(1, 2, 3),
array $arrayNullable = null,
callable $callableParam,
callable $callableNullable = null,
\stdClass $objectParam,
\stdClass $objectNullable = null,
ReflectionParameter $typehintedParamWithNs,
&$byReferenceParam,
&$byReferenceNullable = __CLASS__,
$constParam = TEST_PARAMETER,
$constValueParam = __NAMESPACE__, // This line is long and should be truncated
\Traversable $traversable
) {
}

class Foo
{
const CLASS_CONST = __CLASS__;

public function methodParam($firstParam, $optionalParam = null)
{
}

public function methodParamConst($firstParam = self::CLASS_CONST, $another = __CLASS__, $ns = TEST_PARAMETER)
{
}
}

class SubFoo extends Foo
{
public function anotherMethodParam(self $selfParam, parent $parentParam)
{
}
}
}

0 comments on commit 483c4c9

Please sign in to comment.