EN JP CN

Java チューニングチュートリアル 4 - 追加指摘を検出するための NPE.RET のチューニング (高度)

Java チューニングチュートリアル 4 - 追加指摘を検出するための NPE.RET のチューニング (高度)

Java チューニングチュートリアル 4 - 追加指摘を検出するための NPE.RET のチューニング (高度)

Java チューニングチュートリアル 4 - 追加指摘を検出するための NPE.RET のチューニング (高度)
注: 追加指摘を検出する (「未検知」の処理) ための既存チェッカーのチューニングは高度なチューニング機能とみなされます。

アサートが正しくない場合、junit ライブラリのアサートメソッドから実行時例外がスローされます。Java コードの実行時例外は望ましくないため、フィールドはこのケースを使用して、Java knowledge base (ナレッジベース) に @Sink 注釈を使用する方法について示します。

フィールドは、次の抜粋を使用します。

import static junit.framework.Assert.assertNotNull;


public class SinkSample {

   public static void main(final String[] args) {      
      final SinkSample s = new SinkSample();     
      final Object o = s.get();     
      assertNotNull(o);  
   }
   
   private Object get() {      
      if (hashCode() < 0) {       
         return new Object();     
      }     
      return null;   
   }
}

メソッド get() は null を返すことができ、null の場合は assertNotNull(o) 呼び出しで実行時例外がスローされます。このような状況は、NPE.RET チェッカーで検出して防止することが望まれます。

.jkb ファイルの作成およびシンクとしての assertNotNull の追加

.jkb ファイルで assertNotNull をシンクとして記述します。

package junit.framework;


class Assert {  
   public static void assertNotNull(@Sink Object object);
}

Sink レコードのチェッカーへのバインド

@Sink を追加した後、@Bind("NPE.RET") を使用してデータを指摘にバインドします。

package junit.framework;

@Bind("NPE.RET") class Assert {

public static void assertNotNull(@Sink Object object);

}

knowledge base (ナレッジベース) のテスト

knowledge base (ナレッジベース) をテストするには:

  1. kwcheck を使用して knowledge base (ナレッジベース) をプロジェクトにインポートします。
    kwcheck import sink.jkb
    
  2. 解析を実行します。
    kwcheck run
    

この knowledge base (ナレッジベース) を使用してコードを解析すると、Klocwork で NPE.RET 指摘が検出されるようになります。

ソースとしての assertNull の追加

assertNotNull は NPE.RET の null チェックとして使用できますが、呼び出しのパラメーターが null の場合にのみメソッドが実行を継続するため、assertNull を null ソースとして処理することができます。以下を参照してください。

package com.klocwork.jdefects.checkers.dfa.binding_walkthrough;

import static junit.framework.Assert.assertNull;

public class SourceSample {
  

   private Object field;
   
   public void setField(Object field) {      
      this.field = field;
   }
   
   public String toString() {     
      StringBuilder sb = new StringBuilder();     
      assertNull(field);      
      sb.append('[');      
      sb.append(field.hashCode());      
      sb.append(']');     
      return sb.toString();   
   }
}

上の例で、assertNull によりフィールドが null であることが保証されますが、次の行でこの null 値の逆参照が試行されます。

sb.append(field.hashCode());

この状況を検出するためには、knowledge base (ナレッジベース) に @Source を追加してチェッカーにバインドする必要があります。

package junit.framework;


@Bind("NPE.RET")
class Assert {   
   public static void assertNull(@Source Object object);
}

knowledge base (ナレッジベース) をテストするには:

  1. kwcheck を使用して knowledge base (ナレッジベース) をプロジェクトにインポートします。
    kwcheck import sink.jkb
    
  2. 解析を実行します。
    kwcheck run
    

kwcheck を実行すると、NPE.RET が検出されることがわかります。

Prop レコードの knowledge base (ナレッジベース) への追加

junit フレームワークには、与えられた 2 つのオブジェクトの等価を検証するためのいくつかのメソッドがあります。これは、1 つのオブジェクトが null の場合、メソッドの実行後に他のオブジェクトも null になるはずであることを意味します。つまり、次の抜粋に対して NPE.RET が報告される必要があります。

import static junit.framework.Assert.assertEquals;


public class PropSample {


   private Object field;

   public void setField(Object field) {      
      this.field = field;  
   }
  
   public String toString() {      
      final Object o = get();      
      assertEquals(field, o);      
      return field.toString();   
   }
   
   private Object get() {      
      if (hashCode() > 0) {        
         return new Object();      
      }     
      return null;  
   }
}

get() は null を返すことができるため、NPE.RET が報告され、戻り値がフィールドと等価であることを示すアサートが出されます。 このフィールドは return field.toString();) 行で逆参照されます。

注: assertEquals は反射式で、何らかのパラメーターが null の場合は他のパラメーターも null であることを意味します。したがって、.jkb ファイルにそれぞれ @In 注釈と @Out 注釈を使用した 2 つの @Prop メソッドを使用する必要があります。

Java knowledge base (ナレッジベース) ファイルに以下を追加します。

package junit.framework;
class Assert {  
   @Prop public static void assertEquals(@In Object objA, @Out Object objB);   
   @Prop public static void assertEquals(@Out Object objA, @In Object objB);
}

knowledge base (ナレッジベース) のテスト

knowledge base (ナレッジベース) をテストするには:

  1. kwcheck を使用して knowledge base (ナレッジベース) をプロジェクトにインポートします。
    kwcheck import <file>.jkb
    
  2. 解析を実行します。
    kwcheck run