warnings::methodのメカニズム
なぜかスレッドが無効になっている環境ではテストが通らないようだが,とりあえず公開した。
さてメカニズムだが,まずどんなOPコードが生成されるのかを目視したうえで,どのようにOPコードツリーを走査するのか考える。
$ perl -MO=Concise -e 'foo()' 6 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v ->3 5 <1> entersub[t2] vKS/TARG,1 ->6 - <1> ex-list K ->5 3 <0> pushmark s ->4 - <1> ex-rv2cv sK/1 ->- 4 <#> gv[*foo] s/EARLYCV ->5 $ perl -MO=Concise -e 'Foo->foo()' 7 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v ->3 6 <1> entersub[t1] vKS/TARG ->7 3 <0> pushmark s ->4 4 <$> const[PV "Foo"] sM/BARE ->5 5 <$> method_named[PVIV "foo"] ->6
warnings::methodの場合は関数呼び出しとメソッド呼び出しを区別した上で,関数呼び出しの際に使われるCVをみつけてCvMETHODフラグを確認すればいい。この場合はentersub(OP_ENTERSUB)に目をつけた。あとは適当にツリー構造を走査する要領で,op_sibling(同じ階層にある次のノード)やらop_first(最初の子ノード)やらをたどってgv(OP_GV)を見つける。あとはそのGVからCVを取り出してフラグチェックをするだけだ。なお,OPコードについてはドキュメントが少ないので,このあたりの作業はop.cやpp*.cの類を見ながら進めればよい。
ところで,warnings::method内部でためしにUNIVERSAL::can/isaを:method付きで再宣言してみたのだが,-wの元でUNIVERSAL::can/isaを関数として呼び出しているモジュールをロードすると警告を出す…が,これがちょっとうるさい。
$ perl -we 'use warnings::method; use B::Deparse' Method UNIVERSAL::isa() called as a function at Deparse.pm line 673.
その使い方のほとんどは,UNIVERSAL::isa($sv, 'ARRAY')といった,リファレンスの型を確認するためのものなのでそれほど危険ではないのだが,モジュールによっては大量の警告が出てしまう。