FindBugsプラグイン(カスタムチェック)を作るとき、OpcodeStackDetectorを継承したりします。
これの持つメソッドやら使うのに必要なクラスを知ってる範囲で書こうと思います。
(本当はFindBugsプラグインの作り方も書きたいんですけどなかなかまとまらないので別に機会に。)
FindBugsプラグイン作るとき参考にしたサイト:
https://code.google.com/p/findbugs/wiki/DetectorPluginTutorial
http://ttimez.blogspot.jp/
#OpcodeStackDetectorの持つ各関数の意味(本当に合ってるかわかりません。)
##getClassConstantOperand()
INVOKE系で呼ばれるプロシージャのクラス名が取れる。
Stringの場合、
"java.lang.String"ではなく"java/lang/String"で返る。
##getNameConstantOperand()
INVOKE系で呼ばれるプロシージャ名が取れる。
"()"は無し。
コンストラクタは""っぽい。
##getSigConstantOperand()
INVOKE系で呼ばれるプロシージャの引数と返り値をよくわからない文字列(シグニチャ)にした値が取れる。
String.valueOf(Object):String だと"(Ljava/lang/Object;)Ljava/lang/String;"な感じ。
クラス系は"L"で始まってクラス名書いて";"で終わる様子。
intは"I"、booleanは"Z"、longが"J"、返り値voidは"V"っぽい。
";"が必要なのはクラスの時だけ。
http://docs.oracle.com/javase/jp/1.5.0/guide/jni/spec/types.html#wp276
http://www.hakkaku.net/articles/20090302-399
##getNumberArguments(getSigConstantOperand())
INVOKE系で呼ばれるプロシージャに引数いくつ渡しているか取れる。
getNumberArguments()だとなぜか-1されていたので上記を使うほうがいいと思う。
##getStringConstantOperand()
LDC系でStringの定数値を返す。
LDC系はint・longの定数も入ってくるのでそこで使うとIllegalStateExceptionが投げられるっぽい。
ちゃんと確認してないけど、getIntConstant()、getLongConstant() がお仲間かな?
##getPC()
現在のPC(行的概念)が取れる。
##getMethodName()
現在visitしているメソッド名が取れる。
##getClassName()
現在visitしているクラス名が取れる。
##getRegisterOperand()
LOAD・STORE系でRegisterアクセスしてる場合の番号が取得できる。
##isRegisterLoad()
現在行がLOAD系かどうか?IINCを含む
##isRegisterStore()
現在行がSTORE系かどうか?IINCを含む
##isRegisterStore(int opcode)
opcodeがSTORE系かどうか?IINCは含まれない(嫌がらせか?)
##isMethodCall()
INVOKE系かどうか?
##getStack()
順番に処理した場合のStackに保持された情報(OpcodeStack)が取れる。
##OpcodeStack.getStackItem(int)
stack情報(OpcodeStack.Item)が取れる。
##OpcodeStack.getStackDepth()
いまstackにいくつ情報があるか?
##OpcodeStack.Item.getPC()
stackがどこで積まれたか?だと思いきや正しく取れない。なんで?
@Override
public void afterOpcode(int seen) {
super.afterOpcode(seen);
for (int i = 0; i < getStack().getStackDepth(); i++) {
Item item = getStack().getStackItem(i);
if (item.getPC() == -1) {
item.setPC(getPC());//PCのセット
} else {
break;
}
}
}
ってかいたらうまく取れるようになりそう。
##OpcodeStack.getLVValue(int)
getRegisterNumber()が引数と一致するOpcodeStack.Itemの取得。
##OpcodeStack.Item.getRegisterNumber()
stackがRegister経由で渡された場合のRegisterナンバー。
##OpcodeStack.Item.getSignature()
stackのシグニチャがとれる。
##OpcodeStack.Item.getConstant()
stackが定数の場合その値が取れる。
##atCatchBlock()
今catchの中が始まるよって意味。
ASTORE系でチェックするとよさそう。
##BugReporter.reportBug(BugInstance)
基本。バグを通知する。
##BugInstance(Detector detector, String type, int priority)
基本。バグの中身。
detectorは自分(this)
typeはバグコード
priorityは優先度(HIGH_PRIORITYとか)
##BugInstance.addClassAndMethod(...)
見てるクラスとそのメソッド名が通知できる。
add系の順番で
messages.xmlの{1}とかにメッセージ出せるっぽい。
##BugInstance.addString(...)
任意のStringが通知できる。
add系の順番で
messages.xmlの{1}とかにメッセージ出せるっぽい。
##BugInstance.addSourceLine(BytecodeScanningDetector visitor)
どこの行か通知できるっぽい。
visitorは自分(this)
今sawOpcodeしてる行が通知できる。
##BugInstance.addSourceLine(BytecodeScanningDetector visitor, int pc)
どこの行か通知できるっぽい。
visitorは自分(this)
PCに対応する行が通知できる。
add系の順番で
messages.xmlの{1}とかにメッセージ出せるっぽい。
#参考になるかもしれない外部リンク
##日本語で書かれている(情報は少ないです)
http://ttimez.blogspot.jp/
##プロジェクトの作り方など
https://code.google.com/p/findbugs/wiki/DetectorPluginTutorial
##seenの意味を調べる
https://ja.wikipedia.org/wiki/Java%E4%BB%AE%E6%83%B3%E3%83%9E%E3%82%B7%E3%83%B3#.E3.83.8B.E3.83.BC.E3.83.A2.E3.83.8B.E3.83.83.E3.82.AF.E8.A1.A8
https://www.vmth.ucdavis.edu/incoming/Jasmin/jvmref.html