PHP
静的解析
Phan

phanの `Phan\Exception\IssueException` に悩まされた

Travis上で、掲題のエラーが発生して静的解析を実行できない状態に陥った。
※ ver.はPhan 0.9.4

Phan\Exception\IssueException in phar:///home/travis/phan/phan/src/Phan/AST/ContextNode.php:1325

実行状態をよく観察してみると、Analysysに入る前にParseのフェーズでコケてるかな?という印象を持った。

解析に入ったあとであれば、以前に会社のブログにも書いた内容となり「stubとか置いてないかな」で行けそうなのに・・・と感じていた。

http://tech.connehito.com/entry/docker-phan

原因の調査

localで git bisect などを用いて原因の切り分けを行うにはphanの実行が重すぎるので、 メンバーが活動していない時間帯を狙って "っぽい"コミットとその前後をpushしまくり、Travisに食わせた。

結果として、 composer require google/cloud を実行したコミットからこの問題が発生している

問題箇所の特定

backtraceをみて、var_dumpデバッグだ・・・!をローカルでやりました。

backtraceが取れているので。

Phan\Exception\IssueException in /opt/phan/src/Phan/AST/ContextNode.php:1311 464MB/465MB
Stack trace:
#0 /opt/phan/src/Phan/AST/UnionTypeVisitor.php(1196): Phan\AST\ContextNode->getClassConst()
#1 /opt/phan/src/Phan/AST/Visitor/Element.php(142): Phan\AST\UnionTypeVisitor->visitClassConst(Object(ast\Node))
#2 /opt/phan/src/Phan/AST/Visitor/KindVisitorImplementation.php(22): Phan\AST\Visitor\Element::acceptNodeAndKindVisitor(Object(ast\Node), Object(Phan\AST\UnionTypeVisitor))
#3 /opt/phan/src/Phan/AST/UnionTypeVisitor.php(138): Phan\AST\Visitor\KindVisitorImplementation->__invoke(Object(ast\Node))
#4 /opt/phan/src/Phan/Language/UnionType.php(174): Phan\AST\UnionTypeVisitor::unionTypeFromNode(Object(Phan\CodeBase), Object(Phan\Language\Context), Object(ast\Node), false)
#5 /opt/phan/src/Phan/Language/FutureUnionType.php(57): Phan\Language\UnionType::fromNode(Object(Phan\Language\Context), Object(Phan\CodeBase), Object(ast\Node), false)
#6 /opt/phan/src/Phan/Language/Element/ElementFutureUnionType.php(56): Phan\Language\FutureUnionType->get()
#7 /opt/phan/src/Phan/Language/Element/Property.php(82): Phan\Language\Element\Property->getFutureUnionType()
#8 /opt/phan/src/Phan/Analysis/CompositionAnalyzer.php(76): Phan\Language\Element\Property->getUnionType()
#9 /opt/phan/src/Phan/Language/Element/Clazz.php(2229): Phan\Analysis\CompositionAnalyzer::analyzeComposition(Object(Phan\CodeBase), Object(Phan\Language\Element\Clazz))
#10 /opt/phan/src/Phan/Analysis.php(305): Phan\Language\Element\Clazz->analyze(Object(Phan\CodeBase))
#11 /opt/phan/src/Phan/Phan.php(212): Phan\Analysis::analyzeClasses(Object(Phan\CodeBase), NULL)
#12 /opt/phan/src/phan.php(54): Phan\Phan::analyzeFileList(Object(Phan\CodeBase), Object(Closure))
#13 /opt/phan/phan(2): require_once('/opt/phan/src/p...')
#14 {main}

ので、 /opt/phan/src/Phan/AST/ContextNode.php:1311 付近で情報をdumpさせるように改変。

image.png

これで、最後に残された例外の情報から直接の起因がわかる。
\Google\Cloud\Spannerというクラスがない という事で。よろしくないですね
image.png

対処

今回は使っていないクラスだったので、解析対象から外すという手段を選択可能だった。

image.png
これで、一旦通るようになる。

もしくは、目的としているサービスが限定されているなら(ex: big-query)、セパレートされたパッケージを利用するというのも手。

ex: composer remove google/cloud && composer require google/cloud-bigquery