EN JP CN

kwdefectimport を使用した外部欠陥のインポート

kwdefectimport を使用した外部欠陥のインポート

Kwdefectimport を使用して外部欠陥のリストを Klocwork にインポートすることができます。外部欠陥は、Klocwork に依存しない、外部ツールまたはプロセスによって検出された欠陥です。

Kwbuildproject の後および kwadmin -loadの前で、ビルド時にコマンドラインで Kwdefectimport を実行します。kwadmin -load .実行時は kwbuildproject によって作成されたアーティファクト (テーブルおよびファイル) のデータを使用し、その後、kwadmin 用に新しい問題データを作成してロードします。

 
 

外部欠陥を Klocwork にインポートするには、次の手順を実行します。

  1. 欠陥のリストを作成または入手します。ご利用の実装に応じて、このリストはファイル、ストリーム、またはポートのいずれかの形式になります。
  2. 欠陥がチェッカーにマッピングされる位置で .pconf チェッカー設定ファイルを作成します。
  3. インターフェイス com.klocwork.defectimport.IDefectParser を実装して欠陥リストファイルをパースする欠陥パーサーを作成します。
  4. 解析の一部として kwdefectimport を実行します。位置は、kwbuildproject の後かつ kwadmin -load の実行前に実行します。

ソース欠陥ファイルでの作業

欠陥ソースの正確な形式は異なる場合がありますが、データは有効で欠陥ごとに少なくとも以下の 4 つの要素が含まれている必要があります。

要素説明
欠陥コード欠陥の高レベルのカテゴリを表す文字列。次の例では、欠陥コードは要素 <ErrorId> で表されています。
ファイル名

現在の欠陥を含んでいるソースファイルの絶対パスとファイル名または相対パスとファイル名。次のように --working-directory 引数を kwdefectimport に指定した場合、ファイル名は (引数で指定した値に応じた) 関連リンクと見なされます。作業ディレクトリを指定しない場合、ファイル名は絶対パスである必要があります。

次の例では、ファイル名は F 属性で表されています。

行番号

欠陥を含んでいる (ソースファイルの) 行番号。

次の例では、ファイル名は L 属性で表されています。

メッセージオプション。欠陥を説明するメッセージ。メッセージは Klocwork 内に表示され、ユーザーにコンテキストを提供します。

以下に、一般的な欠陥ソースファイルを示します。

<ErrorId Id="ERR_TYP_TIMER_NOT_ACTIVE" NumberOfEntries="4">
  <Msg F="czagenmx.sdl" L="2786" S="C">timer t_wf_czg not activated in any path</Msg>
  <Msg F="czahanmx.sdl" L="5051" S="C">timer t_wf_czg_sup_ack not activated in any path</Msg>
  <Msg F="czahanmx.sdl" L="5074" S="C">timer t_wf_czg_sup_ack not activated in any path</Msg>
  <Msg F="czahanmx.sdl" L="5092" S="C">timer t_wf_czg_sup_ack not activated in any path</Msg>
</ErrorId>  
Note: サンプルには、各欠陥の重要度レベルを表す S 属性も含まれています。各欠陥の重要度レベルは分類基準で定義されているので、この属性はパーサーによって無視できます。

分類基準の作成

 

欠陥をインポートする前に、外部欠陥を関連付ける欠陥分類基準、カテゴリ、および欠陥タイプを定義する必要があります。定義は .pconf ファイルを作成することによって行います。 この XML ファイルに欠陥のカテゴリおよび重要度タイプを定義し、ユーザーに表示するエラーメッセージを格納します。

次の例は、.pconf ファイルの抜粋を示しています。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<checkers version="1.4">
    <severitytable max="10" warningStart="3" locale="en">
        <severity name="Critical" number="1"/>
         ...
    </severitytable>
    <categories name="TN SDL SDT" locale="en">
        <category name="Err.Lex.Tn">
            <error id="ERR_LEX_COM_IN_COM"/>
            <error id="ERR_LEX_LONG_ID"/>
			<error id="ERR_LEX_RESERVED"/>
        </category>  
        ...
    </categories>
    <checkergroup api="none" id="TN.DEFAULT.CHECKERGROUP" language="SDL/SDT">
        <checker id="ERR.LEX.TN">
            <error autogroupby="0" enabled="true" id="ERR_LEX_LONG_ID" severity="3">
                <title locale="en" text="ID longer than 31 characters"/>
                <title locale="ja" text="ID longer than 31 characters"/>
                <message locale="en" text="{0}"/>
                <message locale="ja" text="{0}"/>
            </error>
            <error autogroupby="0" enabled="true" id="ERR_LEX_RESERVED" severity="3">
                <title locale="en" text="ID is reserved in ANSI C"/>
                <title locale="ja" text="ID is reserved in ANSI C"/>
                <message locale="en" text="{0}"/>
                <message locale="ja" text="{0}"/>
            </error>
            <error autogroupby="0" enabled="true" id="ERR_LEX_COM_IN_COM" severity="3">
                <title locale="en" text="Missing close comment"/>
                <title locale="ja" text="Missing close comment"/>
                <message locale="en" text="{0}"/>
                <message locale="ja" text="{0}"/>
            </error>			
        </checker> 
        ...           
    </checkergroup>
</checkers>  
.pconf ファイルには、3 つの子要素を定義して構成する必要があります。
要素説明
<severitytable>重要度階層を定義します。
<categories>チェッカーカテゴリのセットを定義します。各カテゴリには関連チェッカーのセットが含まれます。通常、カテゴリはチェッカーを機能別にまとめるために使用します。たとえば、"精度の損失" や "危険な型キャスト" などです。これらは通常、ユーザーによって定義されます。
<checkergroup>関連チェッカーのグループを定義します。たとえば、"組み込み C# Path チェッカー" などです。これらは通常、ユーザーによって定義されます。

.pconf ファイルの作成

.pconf ファイルを作成してインポートするには、次のウォークスルーに従います。

  1. チェッカー設定情報を格納する XML ファイルを作成します。.pconf ファイルを作成するには、既存の構成ファイルとテキストエディターを使用するか、または Klocwork Configuration Editor を使用できます。

    分類基準の作成および変更の詳細については、統合ビルド解析用チェッカーの設定を参照してください。

  2. .pconf ファイルに<severitytable> 要素を追加します。これがルート要素の最初の子になります。ワークフローによっては重要度レベルは任意である場合があるため、このセクションはそのままにしておくことができます。
    <severitytable max="10" warningStart="3" locale="en">
      <severity name="Critical" number="1"/>
      <severity name="Error" number="2"/>
      <severity name="Warning" number="3"/>
      <severity name="Review" number="4"/>
      <severity name="Severity 5" number="5"/>
      <severity name="Severity 6" number="6"/>
      <severity name="Severity 7" number="7"/>
      <severity name="Severity 8" number="8"/>
      <severity name="Severity 9" number="9"/>
      <severity name="Severity 10" number="10"/>
    </severitytable>  
  3. .pconf ファイルに <categories> 要素を追加します。
    <categories name="TN SDL SDT" locale="en">  
      <category name="Err.Sym.Tn">
        <error id="ERR_SYM_NO_TERMINATOR"/>
        <error id="ERR_SYM_EXP_UNCHANGED"/>
        <error id="ERR_SYM_ENUM_LACK_ANSWER"/>
        <error id="ERR_SYM_UNREACHABLE_STATEMENT"/>
      </category>
    </categories>   
    • <categories> 要素には、実際のチェッカーカテゴリを定義する <category> 要素が含まれます。<categories> 要素と <category> 要素の name 属性は、ユーザーによって定義されます。カテゴリに含まれる欠陥タイプを表す <category> の名前を指定する必要があります。
    • <error> 要素の id 属性は、外部欠陥リストで指定された <ErrorID> への直接マッピングです。
  4. .pconf ファイルに <checkergroup> 要素を追加します。
    <checkergroup api="none" id="TN.DEFAULT.CHECKERGROUP" language="SDL/SDT">
      <checker id="ERR.LEX.TN">
       <error autogroupby="0" enabled="true" id="ERR_LEX_LONG_ID" severity="3">
         <title locale="en" text="ID longer than 31 characters"/>
         <title locale="ja" text="ID longer than 31 characters"/>
         <message locale="en" text="{0}"/>
         <message locale="ja" text="{0}"/>
       </error>
       <error autogroupby="0" enabled="true" id="ERR_LEX_RESERVED" severity="3">
         <title locale="en" text="ID is reserved in ANSI C"/>
         <title locale="ja" text="ID is reserved in ANSI C"/>
         <message locale="en" text="{0}"/>
         <message locale="ja" text="{0}"/>
        </error>
      </checker>  
    次のテーブルでは、<checkergroup> 内の要素について説明します。
    要素属性
    <checkergroup>
    api
    どのチェッカーも実行しないことを示すには、"none" を指定します。
    id
    ユーザー定義
    言語
    ユーザー定義。通常は、ソースコードのプログラミング言語を表します。
    <checker>
    id
    ユーザー定義。ただし、通常はカプセル化する欠陥タイプのグループ名を表します。
    <error>
    autogroupby
    0 に設定されます。
    有効
    true に設定されます。
    id
    <error> 要素の id 属性は、外部欠陥リストで指定された <ErrorID> への直接マッピングです。
    重要度
    欠陥リストファイルで定義された重要度レベルの解釈に基づく値。
    <title>
    ロケール
    タイトル文字列のロケールコード。たとえば、"en" や "ja" です。
    text
    欠陥の簡単な概要を説明する文字列。
    <message>
    ロケール
    タイトル文字列のロケールコード。たとえば、"en" や "ja" です。
    text
    欠陥の簡単な概要を説明する文字列、または欠陥リストで指定されたメッセージを渡すための {0}。欠陥メッセージは既に生成されており、メッセージのテキストをソースファイル内の行に関連付けることだけが目的であるため、メッセージはそのまま変数として渡されます。
  5. XML ファイルを保存し、Klocwork インストールパスにある /plugins ディレクトリにコピーします。

欠陥パーサーの作成

Klocwork に欠陥をインポートするには、インターフェイス、com.klocwork.defectimport.IDefectParser を実装する Java クラスを書き込む必要があります。また、この実装には、String を受け入れるパブリックな単一引数のコンストラクタが必要です。この String は、Klocwork にインポートされる外部欠陥のリストを格納するリソースを表します。このリソースにはファイル、ストリーム、ポート、またはその他のユーザー定義のソースを指定できます。次の例で、リソースは欠陥を格納するファイルのフルパスを表しています。また、次のインターフェイスメソッドを満たす反復子を作成し、Kwdefectimport 内から明示的に呼び出すことができるパブリックメソッドがないことにも注意してください:
Iterator<SourceDefect> getDefects();  
したがって、パーサーではコンストラクタ内からこの反復子を準備する必要があります。次の例では、コンストラクタ内からこの実装固有のメソッド parse() を呼び出す方法を確認します。

サンプルパーサー

このパーサーの詳細な例では、欠陥が XML としてエクスポートされます。IDefectParser の実装は、SAX の DefaultHandler を拡張します。

package com.thirdparty.defectexport.parser;

import com.klocwork.defectimport.IDefectParser;
import com.klocwork.defectimport.SourceDefect;
import org.jetbrains.annotations.NonNls;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;
import java.io.IOException;
import java.util.*;

public class ThirdPartyKlocworkDefectParser extends DefaultHandler implements IDefectParser {
    //where the listing of the source defects resides (file, stream?, port?, etc)
    private final String defectsSource;
    //list of items discovered at the defectsSource, each of which having been converted to a SourceDefect
    private final List<SourceDefect> sourceDefects = new ArrayList<SourceDefect>();

    private SourceDefect sourceDefect;
    private boolean inByErrorId;
    private boolean inMsg;
    private String currentErrorId = "";
    StringBuilder buffer = new StringBuilder(1024);

    public ThirdPartyKlocworkDefectParser (final String defectsSource) throws ParserConfigurationException, SAXException, IOException {
        this.defectsSource = defectsSource;
        parse();
    }

    @Override
    public void startElement(final String uri, final String localName, final String qName, final Attributes atts) throws SAXException
    {
        buffer.setLength(0);

        if(localName.equals(ELEM_BY_ERROR_ID)){
            inByErrorId = true;
        }

        if(inByErrorId && localName.equals(ELEM_ERROR_ID)){
            final String attributeId = atts.getValue(ATTR_ID);
            if(!attributeId.equals(currentErrorId)){
                currentErrorId = attributeId;
            }
        }

        if(inByErrorId && localName.equals(ELEM_MSG)){
            inMsg = true;
            sourceDefect = new SourceDefect();
            sourceDefect.setErrorId(currentErrorId);
            final String fileName = atts.getValue(ATTR_FILE);
            sourceDefect.setFileName(fileName);
            sourceDefect.setLineNumber(Integer.valueOf(atts.getValue(ATTR_LINE)));
            sourceDefect.setMessage(qName);
        }
    }

    @Override
    public void endElement (final String uri, final String localName, final String qName)
            throws SAXException
    {
        if(inByErrorId && localName.equals(ELEM_MSG)){
            sourceDefect.setMessage(buffer.toString());
            sourceDefects.add(sourceDefect);
            inMsg = false;
        }
    }

    @Override
    public void characters(final char[] ch, final int start, final int length) throws SAXException {
        if(inByErrorId && inMsg){
            buffer.append(ch, start, length);
        }
    }

    @Override
    public Iterator<SourceDefect> getDefects() {

        return Collections.unmodifiableCollection(sourceDefects).iterator();
    }

    private void parse() throws ParserConfigurationException, SAXException, IOException {
        final SAXParserFactory spf = SAXParserFactory.newInstance();
        spf.setNamespaceAware(true);

        final SAXParser parser = spf.newSAXParser();
        final XMLReader reader = parser.getXMLReader();
        reader.setContentHandler(this);
        reader.parse(new File(defectsSource).toURI().toURL().toString());
    }

    @Override
    public void close() {
        //not required for this implementation
    }

    @SuppressWarnings("HardCodedStringLiteral")
    @NonNls
    private static final String ELEM_BY_ERROR_ID = "ByErrorId";

    @SuppressWarnings("HardCodedStringLiteral")
    @NonNls
    private static final String ELEM_ERROR_ID = "ErrorId";

    @SuppressWarnings("HardCodedStringLiteral")
    @NonNls
    private static final String ATTR_ID  = "Id";

    @SuppressWarnings("HardCodedStringLiteral")
    @NonNls
    private static final String ELEM_MSG = "Msg";

    @SuppressWarnings("HardCodedStringLiteral")
    @NonNls
    private static final String ATTR_FILE  = "F";

    @SuppressWarnings("HardCodedStringLiteral")
    @NonNls
    private static final String ATTR_LINE  = "L";

}  

欠陥のインポート

 

外部欠陥ファイルを定義し、それらの欠陥をチェッカー設定にマッピングし、パーサーを記述すると、kwdefectimport を実行して外部欠陥を Klocwork にインポートできるようになります。Kwbuildproject の実行後かつ kwadmin -loadの実行前に Kwdefectimport をコマンドラインから実行します。

実行時、kwdefectimport はソース欠陥リストファイルを開いて欠陥の種類を読み取り、該当するソースファイルとコード行にマッピングします。テーブルディレクトリで file.dat ファイルと entity.dat ファイルが変更されます。欠陥が problem_ext.pbf と呼ばれる新しいファイルに書き込まれます。このファイルは後で kwadmin -load によってロードされます。

コマンドラインでの kwdefectimport の実行

コマンドラインからの kwdefectimport の実行例を次に示します。

kwdefectimport --tables-directory "C:/Klocwork/Server XY.Z/projects_root/projects/abc_main" 
--working-directory "C:/_workspaces/ABC_Main/src" --parser-class com.klocwork.defectimport.parser.TNSDLDefectParser 
--rejected-defects C:/tables/rejecteddefects.json --ext-libs "C:/Klocwork/lib/kwdefectimport.jar" 
--ext-libs "C:/Klocwork/lib/another_required_library.jar" "C:\already_analyzed_defects_in_proprietary_format\defects_01.xml" "C:\already_analyzed_defects_in_proprietary_format\defects_02.xml

kwdefectimport の実行とそのオプションの詳細については、Kwdefectimportを参照してください。

自動ビルドの一部としての kwdefectimport の実行

通常の自動 Klocwork ツールチェーン (kwbuildprojectkwadmin -load の間) の一部として kwdefectimportを含める場合、続行するかどうかを決定するために kwdefectimport の終了コードが必要になります。すべてのエラーコードが記載されたリストについては、Kwdefectimportを参照してください。

次の例では DOS バッチスクリプトを使用して、終了コードで、終了コードに基づいて発生するアクションを決定する方法を示します。この例では、caller.batrun_kwdefectimport.bat の 2 つのバッチファイルがあります。caller.bat ファイルは kwdefectimport を実行し、終了コードを呼び出し側に返します。run_kwdefectimport.bat ファイルは caller.bat を呼び出して、それから caller.bat の終了コードに基づいて実行を決定します。

run_kwdefectimport.bat

@echo off
set errorlevel=
"C:\Klocwork\Server 12.0\bin\kwdefectimport.exe" --tables-directory C:\tables\20131024 --working-directory "C:/_workspaces/Main/REP/sources/kwdefectimport/test_resources/source_dir" --parser-class com.klocwork.defectimport.parser.TNSDLDefectParser --rejected-defects C:/tables/rejecteddefects.json "C:/_workspaces/Main/REP/sources/kwdefectimport/test_resources/sdl_defects/tncheck.xml"
exit /b %errorlevel%

caller.bat

caller.bat
@echo off
call run_kwdefectimport.bat
echo Exit Code is %errorlevel%
set atemp=%errorlevel%
echo atemp is %atemp%

set BUILD_FAILED_EXIT_CODE=1
set DEFECT_TYPES_NOT_REGISTERED_EXIT_CODE=16
set DUPLICATE_DEFECTS_FOUND_EXIT_CODE=32
set SOURCE_FILES_NOT_FOUND_EXIT_CODE=64
set SOURCE_FILES_NOT_REFERENCED_EXIT_CODE=128

set /A critical="%atemp%&%BUILD_FAILED_EXIT_CODE%"
set /A dnr="%atemp%&%DEFECT_TYPES_NOT_REGISTERED_EXIT_CODE%"
set /A dup="%atemp%&%DUPLICATE_DEFECTS_FOUND_EXIT_CODE%"
set /A snf="%atemp%&%SOURCE_FILES_NOT_FOUND_EXIT_CODE%"
set /A snr="%atemp%&%SOURCE_FILES_NOT_REFERENCED_EXIT_CODE%"

echo dnr %dnr%
echo dup %dup%
echo snf %snf%
echo snr %snr%

if "%dnr%" == "%DEFECT_TYPES_NOT_REGISTERED_EXIT_CODE%" echo Defect type(s) not registered
rem if "%dnr%" == 16 goto whatever_you_want_to_do_with_this_case
if "%dup%" == "%DUPLICATE_DEFECTS_FOUND_EXIT_CODE%" echo Duplicate defect(s) found
rem as above
if "%snf%" == "%SOURCE_FILES_NOT_FOUND_EXIT_CODE%" echo Source file(s) not found
rem as above
if "%snr%" == "%SOURCE_FILES_NOT_REFERENCED_EXIT_CODE%" echo Source file(s) not referenced
rem as above
if "%critical%" == "1" echo BUILD FAILED
rem You probably don't want to continue
REM place actions to take here

pause
rem Pause would _not_ be used in a production environment