Page MenuHomePhabricator

Add namespace support in Diviner's PHP atomizer
Needs ReviewPublic

Authored by Firehed on Jul 2 2014, 1:25 AM.
Tags
None
Referenced Files
F13085216: D9792.diff
Wed, Apr 24, 11:44 PM
Unknown Object (File)
Sat, Apr 20, 7:12 PM
Unknown Object (File)
Fri, Apr 19, 6:35 PM
Unknown Object (File)
Fri, Apr 19, 6:35 PM
Unknown Object (File)
Fri, Apr 19, 6:35 PM
Unknown Object (File)
Fri, Apr 19, 6:35 PM
Unknown Object (File)
Fri, Apr 19, 6:07 PM
Unknown Object (File)
Fri, Apr 19, 5:42 PM

Details

Reviewers
epriestley
Group Reviewers
Blessed Reviewers
Maniphest Tasks
T2284: Make Diviner namespace aware
Summary

This feeds namespace information into Diviner's context fields, when it's available.

Test Plan

Ran the bin/diviner generate on PHP source files that had:

  • No namespace declared
  • A single, full-file namespace with namespace NS; syntax
  • A file using multiple namespaces with namespace NS { } syntax
  • A non-namespaced file using namespace { /*body*/ } syntax

Goes along with D9791 for T2284

Diff Detail

Repository
rP Phabricator
Branch
php_ns_diviner
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 1625
Build 1626: [Placeholder Plan] Wait for 30 Seconds

Event Timeline

Firehed retitled this revision from to Add namespace support in Diviner's PHP atomizer.
Firehed updated this object.
Firehed edited the test plan for this revision. (Show Details)
Firehed added a reviewer: epriestley.
src/applications/diviner/atomizer/DivinerPHPAtomizer.php
169

I'm not sure this is ideal: it sets a method's context to the namespace without the class. It should probably either remain null or include both. The latter may make linking a bit more consistent (e.g. we have a ton of create static methods which could be disambiguated)

epriestley edited edge metadata.

I think I caught one material issue. I think it would be reasonable to detect + throw on that if you don't want to deal with getting it right, since it's pretty sketchy to write namespace X; multiple times in a singe source file.

I think we want to drop the trailing \\, but let me poke at D9791 and see if we run into anything awful.

src/applications/diviner/atomizer/DivinerPHPAtomizer.php
34–38

Does this get the right result on:

namespace Foo;
namespace Bar;

class A {}

It looks like it will atomize it all as belonging to Foo. (This might be a bit tricky to get right.)

169

Yeah, I would expect this to include the namespace and the class.

This revision now requires changes to proceed.Jul 2 2014, 1:38 AM
src/applications/diviner/atomizer/DivinerPHPAtomizer.php
34–38

Woah - I'd always assumed that was invalid syntax, but sure enough it isn't. Shouldn't be too terrible to handle once I figure out what that actually does.

Yeah, I had to test locally too. But it's PHP, so of course it works!

Firehed edited edge metadata.

Perform some crazy slizing and dicing to handle a format that PHP never should have supported:

<?php
namespace Foo;
class Foo { }
class Bar { }
namespace Bar;
class Foo { }
class Bar { }

Just discovered that this screws up the line numbers from the source file since it rebuilds the tree during parsing. This feels like an incredibly wrong way to select, effectively, a few branches out of the AASTTree, but I couldn't find anything better in the source to handle it.

Firehed edited edge metadata.

Significant cleanup to NS range detection for weird files that do evil things. Fixes line numbering issue, and now includes class name in the context for method declarations

  • further clean up namespace/context work
  • add php atomizer test cases and fix an issue they exposed

Remove hanging vim swapfile

This looks great to me, but I think I came up with a "clever" construction it gets wrong.

src/applications/diviner/atomizer/DivinerPHPAtomizer.php
32

(Double semicolon.)

36–37

Does this get:

namespace X {
  class A;
}

class B;

...wrong? (never analyzes the global namespace at the end)? Or, for that matter, does it get this right? (misses the hole in the middle?)

namespace X {
  class A;
}

class B;

namespace Y {
  class C;
}

At a minimum, they don't seem to be represented in the test cases.

(I'm also 100% fine with "detect this file is more crazy than anything you'll ever do and throw" at any level of complexity here.)

This looks great to me, but I think I came up with a "clever" construction it gets wrong.

My word, why would they allow syntax like that? I'll write a test case for it and see what happens, but that's probably just "give up you damn fool" territory :)

Yeah, presumably there's not much intersection between the set of users who use namespaces like that and the set of users who want to generate codebase documentation.

Turns out this is actually illegal (as I thought):

10:50:12 eric@Eric-MBP ~/dev/phabricator/phabricator/src/applications/diviner/atomizer/__tests__/data [0]$ php -l NamespaceMixed.phps

Fatal error: Cannot mix bracketed namespace declarations with unbracketed namespace declarations in NamespaceMixed.phps on line 7

Errors parsing NamespaceMixed.phps
10:50:16 eric@Eric-MBP ~/dev/phabricator/phabricator/src/applications/diviner/atomizer/__tests__/data [255]$ cat NamespaceMixed.phps

<?php

namespace X {
  class A { }
}

namespace Y;

class A { }