Skip to content

Commit 483c4c9

Browse files
committed
Merge remote-tracking branch 'origin/fix/resolving-const-root-namespace'
* origin/fix/resolving-const-root-namespace: Fix code-style issues from Nitpick Add root namespace normalization, resolves #39 Conflicts: src/ReflectionEngine.php
2 parents fdee566 + 7c230c4 commit 483c4c9

6 files changed

+129
-49
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
/**
3+
* Parser Reflection API
4+
*
5+
* @copyright Copyright 2016, Lisachenko Alexander <[email protected]>
6+
*
7+
* This source file is subject to the license that is bundled
8+
* with this source code in the file LICENSE.
9+
*/
10+
11+
namespace Go\ParserReflection\NodeVisitor;
12+
13+
use PhpParser\Node;
14+
use PhpParser\Node\Name\FullyQualified;
15+
use PhpParser\Node\Stmt\Namespace_;
16+
use PhpParser\NodeVisitorAbstract;
17+
18+
/**
19+
* Visitor to normalize the root namespace for the files without the namespace (root namespace)
20+
*
21+
* File->Namespace->Statements
22+
*/
23+
class RootNamespaceNormalizer extends NodeVisitorAbstract
24+
{
25+
/**
26+
* {@inheritdoc}
27+
*/
28+
public function beforeTraverse(array $nodes)
29+
{
30+
// namespaces can be only top-level nodes, so we can scan them directly
31+
foreach ($nodes as $topLevelNode) {
32+
if ($topLevelNode instanceof Namespace_) {
33+
// file has namespace in it, nothing to change, returning null
34+
return null;
35+
}
36+
}
37+
38+
// if we don't have a namespaces at all, this is global namespace, wrap everything in it
39+
$globalNamespaceNode = new Namespace_(new FullyQualified(''), $nodes);
40+
41+
return [$globalNamespaceNode];
42+
}
43+
}

src/ReflectionEngine.php

+10-9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
namespace Go\ParserReflection;
1212

1313
use Go\ParserReflection\Instrument\PathResolver;
14+
use Go\ParserReflection\NodeVisitor\RootNamespaceNormalizer;
1415
use PhpParser\Lexer;
1516
use PhpParser\Node;
1617
use PhpParser\Node\Stmt\ClassLike;
@@ -68,6 +69,7 @@ public static function init(LocatorInterface $locator)
6869

6970
self::$traverser = $traverser = new NodeTraverser();
7071
$traverser->addVisitor(new NameResolver());
72+
$traverser->addVisitor(new RootNamespaceNormalizer());
7173

7274
self::$locator = $locator;
7375
}
@@ -127,14 +129,9 @@ public static function parseClass($fullClassName)
127129
$className = array_pop($namespaceParts);
128130
$namespaceName = join('\\', $namespaceParts);
129131

130-
if ($namespaceName) {
131-
// we have a namespace nodes somewhere
132-
$namespace = self::parseFileNamespace($classFileName, $namespaceName);
133-
$namespaceNodes = $namespace->stmts;
134-
} else {
135-
// global namespace
136-
$namespaceNodes = self::parseFile($classFileName);
137-
}
132+
// we have a namespace node somewhere
133+
$namespace = self::parseFileNamespace($classFileName, $namespaceName);
134+
$namespaceNodes = $namespace->stmts;
138135

139136
foreach ($namespaceNodes as $namespaceLevelNode) {
140137
if ($namespaceLevelNode instanceof ClassLike && $namespaceLevelNode->name == $className) {
@@ -238,7 +235,11 @@ public static function parseFileNamespace($fileName, $namespaceName)
238235
$topLevelNodes = self::parseFile($fileName);
239236
// namespaces can be only top-level nodes, so we can scan them directly
240237
foreach ($topLevelNodes as $topLevelNode) {
241-
if ($topLevelNode instanceof Namespace_ && ($topLevelNode->name->toString() == $namespaceName)) {
238+
if (!$topLevelNode instanceof Namespace_) {
239+
continue;
240+
}
241+
$topLevelNodeName = $topLevelNode->name ? $topLevelNode->name->toString() : '';
242+
if ($topLevelNodeName === $namespaceName) {
242243
return $topLevelNode;
243244
}
244245
}

src/ReflectionFile.php

+1-8
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
use Go\ParserReflection\Instrument\PathResolver;
1515
use PhpParser\Node;
16-
use PhpParser\Node\Name\FullyQualified;
1716
use PhpParser\Node\Stmt\Namespace_;
1817

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

127126
$namespaces[$namespaceName] = new ReflectionFileNamespace(
128127
$this->fileName,
@@ -132,12 +131,6 @@ private function findFileNamespaces()
132131
}
133132
}
134133

135-
if (!$namespaces) {
136-
// if we don't have a namespaces at all, this is global namespace
137-
$globalNamespaceNode = new Namespace_(new FullyQualified(''), $this->topLevelNodes);
138-
$namespaces['\\'] = new ReflectionFileNamespace($this->fileName, '\\', $globalNamespaceNode);
139-
}
140-
141134
return $namespaces;
142135
}
143136
}

tests/ReflectionFileTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public function testGetGlobalFileNamespace()
5555
$fileName = stream_resolve_include_path(__DIR__ . self::STUB_GLOBAL_FILE);
5656
$reflectionFile = new ReflectionFile($fileName);
5757

58-
$reflectionFileNamespace = $reflectionFile->getFileNamespace('\\');
58+
$reflectionFileNamespace = $reflectionFile->getFileNamespace('');
5959
$this->assertInstanceOf(ReflectionFileNamespace::class, $reflectionFileNamespace);
6060
}
6161
}

tests/ReflectionParameterTest.php

+13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use Go\ParserReflection\Stub\Foo;
55
use Go\ParserReflection\Stub\SubFoo;
6+
use TestParametersForRootNsClass;
67

78
class ReflectionParameterTest extends \PHPUnit_Framework_TestCase
89
{
@@ -105,6 +106,18 @@ public function testGetClassMethodReturnsSelfAndParent()
105106
$this->assertSame(Foo::class, $parentParam->getName());
106107
}
107108

109+
public function testNonConstantsResolvedForGlobalNamespace()
110+
{
111+
$parsedNamespace = $this->parsedRefFile->getFileNamespace('');
112+
$parsedClass = $parsedNamespace->getClass(TestParametersForRootNsClass::class);
113+
$parsedFunction = $parsedClass->getMethod('foo');
114+
115+
$parameters = $parsedFunction->getParameters();
116+
$this->assertSame(null, $parameters[0]->getDefaultValue());
117+
$this->assertSame(false, $parameters[1]->getDefaultValue());
118+
$this->assertSame(true, $parameters[2]->getDefaultValue());
119+
}
120+
108121
public function testGetDeclaringClassMethodReturnsObject()
109122
{
110123
$parsedNamespace = $this->parsedRefFile->getFileNamespace('Go\ParserReflection\Stub');

tests/Stub/FileWithParameters.php

+61-31
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,66 @@
11
<?php
22

3-
namespace Go\ParserReflection\Stub;
4-
5-
use Go\ParserReflection\ReflectionParameter;
6-
7-
const TEST_PARAMETER = 42;
8-
9-
function noParameters() {}
10-
function singleParameter($test) {}
11-
function miscParameters(
12-
array $arrayParam,
13-
array $arrayParamWithDefault = array(1,2,3),
14-
array $arrayNullable = null,
15-
callable $callableParam,
16-
callable $callableNullable = null,
17-
\stdClass $objectParam,
18-
\stdClass $objectNullable = null,
19-
ReflectionParameter $typehintedParamWithNs,
20-
&$byReferenceParam,
21-
&$byReferenceNullable = __CLASS__,
22-
$constParam = TEST_PARAMETER,
23-
$constValueParam = __NAMESPACE__, // This line is long and should be truncated
24-
\Traversable $traversable
25-
) {}
26-
27-
class Foo {
28-
const CLASS_CONST = __CLASS__;
29-
30-
public function methodParam($firstParam, $optionalParam = null) {}
31-
public function methodParamConst($firstParam = self::CLASS_CONST, $another = __CLASS__, $ns = TEST_PARAMETER) {}
3+
namespace {
4+
function testResolveDefaults($a = null, $b = false, $c = true)
5+
{
6+
}
7+
8+
class TestParametersForRootNsClass
9+
{
10+
public function foo($a = null, $b = false, $c = true)
11+
{
12+
}
13+
}
3214
}
3315

34-
class SubFoo extends Foo {
35-
public function anotherMethodParam(self $selfParam, parent $parentParam) {}
16+
namespace Go\ParserReflection\Stub {
17+
18+
use Go\ParserReflection\ReflectionParameter;
19+
20+
const TEST_PARAMETER = 42;
21+
22+
function noParameters()
23+
{
24+
}
25+
26+
function singleParameter($test)
27+
{
28+
}
29+
30+
function miscParameters(
31+
array $arrayParam,
32+
array $arrayParamWithDefault = array(1, 2, 3),
33+
array $arrayNullable = null,
34+
callable $callableParam,
35+
callable $callableNullable = null,
36+
\stdClass $objectParam,
37+
\stdClass $objectNullable = null,
38+
ReflectionParameter $typehintedParamWithNs,
39+
&$byReferenceParam,
40+
&$byReferenceNullable = __CLASS__,
41+
$constParam = TEST_PARAMETER,
42+
$constValueParam = __NAMESPACE__, // This line is long and should be truncated
43+
\Traversable $traversable
44+
) {
45+
}
46+
47+
class Foo
48+
{
49+
const CLASS_CONST = __CLASS__;
50+
51+
public function methodParam($firstParam, $optionalParam = null)
52+
{
53+
}
54+
55+
public function methodParamConst($firstParam = self::CLASS_CONST, $another = __CLASS__, $ns = TEST_PARAMETER)
56+
{
57+
}
58+
}
59+
60+
class SubFoo extends Foo
61+
{
62+
public function anotherMethodParam(self $selfParam, parent $parentParam)
63+
{
64+
}
65+
}
3666
}

0 commit comments

Comments
 (0)