
昨年11月、SonarQube用のPVS-Studioプラグインの開発と使用に関する記事がブログに公開されました。 実際のプロジェクトでプラグインをテストするリクエストをいただいたお客様や関心のあるユーザーから多くのフィードバックを受け取りました。 この問題への関心は衰えていないため、C#プロジェクトPascalABC.NETでテストすることにしました。 また、SonarQubeには独自の静的C#コードアナライザーSonarC#が含まれていることを忘れないでください。 写真を完成させるために、調査とSonarC#を実施します。 この作業の目的は、アナライザーを比較することではなく、アナライザーとSonarQubeサービスとの相互作用の主な機能を示すことです。 PVS-Studioはエラーや潜在的な脆弱性を検索するための特別なツールであり、SonarQubeは多数のパラメーター(コードの複製、コーディング標準への準拠、コードカバレッジ)によってコードの品質を評価するサービスであるため、アナライザーの直接比較は完全には正しくありません単体テスト、コードのエラーの可能性、コードのコメントの密度、技術的な負債など
はじめに
SonarQubeプラットフォームとPVS-Studioアナライザーとの統合について
説明している
記事の資料をよく理解しておくことをお勧めします。
次に、研究プロジェクトについて少し説明します。 PascalABC.NETは、PascalABC.NET、C#、Visual Basic.NET、F#、IronPythonでプログラムを作成するためのWeb環境だけでなく、独自の開発環境を含む新世代のPascalプログラミング言語です。 このプロジェクトはC#で開発され、フリーライセンスLGPLv3の下で配布されました。
プロジェクトサイト 。 ソースコードは、GitHubの
リポジトリからダウンロードできます。
PascalABC.NETソリューションには、拡張子が「.cs」の2628個のファイルが含まれており、約752千行のコード(
SourceMonitorユーティリティを使用して取得したメトリック)が
含まれています。 したがって、プロジェクトは私たちの研究目的に非常に適しています。
SonarC#
前述したように、
SonarQubeサービスには、とりわけ静的C#コードアナライザーが含まれています。 私たちの場合のように、開いているプロジェクトをサイトに追加して分析するには、いくつかの簡単な手順で十分です。
SonarQube Webサイトに登録するためにGitHubアカウントを使用しました。 次に、クイックスタート
手順を使用しまし
た 。 PascalABC.NETプロジェクトのアカウントへのリンク、一意の組織キーの取得、ローカルコンピューターでのセットアップなど、セットアッププロセス全体で約15分かかりました。 プロジェクトの分析にはさらに10分かかりました。 その後、
結果はSonarQube Webサイトにアップロードされ、誰でも見ることができます。
SonarQubeは、PascalABC.NETコードで発生する可能性のあるエラーについて3636の警告を発行しました。

これらのうち、8個のブロッカー(即時削除が必要)、64個のクリティカル、1742個の重要、および1822個の非重要。 情報メッセージは発行されませんでした。 受け取った警告に精通し、興味深いエラーを見つけ、誤検知の割合を理解してみましょう。 これを行うには、SonarQubeサービスで提供されるさまざまなディメンションで便利なフィルタリングツールを使用します。 ブロックアラートから始めましょう。
ブロッカー

ご覧のとおり、2つのルールに対してブロッキング警告が発行されます:無限再帰とIDisposableリソースのクリア。 ブロッカー警告の1つの例を次に示します。

Instanceプロパティのgetセクションで、
instanceの代わりに
Instanceが誤って返され、無限再帰が生成されます。
他のすべてのブロッカーレベルの警告もエラーです。
クリティカル

クリティカルレベルでは、無効な型キャストルールに対して64個の警告が発行されました。 次の警告のいずれかを検討してください。

コードと実装のリストを検討した結果、アナライザーに同意します。現時点では、
IBaseScopeインターフェイスと
IComparableインターフェイスの両方
を 一度に実装する単一の型は実際には存在せず、その結果、
boxItem.ItemがIComparableチェックは常に
falseになり
ます 。 ただし、この場合のエラーについては説明しません。最初に、このようなチェックが存在することで、型
(IComparable)のboxItem.Itemをキャストしようとしたときに例外が発生しなくなるため
です。 次に、たとえば、特定の
dllをいつでもソリューションに接続
できます 。この
場合 、
IBaseScope インターフェイスと
IComparableインターフェイスの両方を実装する型が宣言され
ます 。 おそらく開発者はこれを頼りにして、チェック後にのみ型変換を実現していました。 私の意見では、考慮される警告はマイナーセクションのメッセージとして分類されるべきであり、実行にとって重要ではありません。また、重大レベルでの存在は誤検知と見なされるべきです。
残りの63個の警告は、考慮された警告に類似しています。
メジャー
このレベルでは、15種類の診断に対して1742年に多くの警告が発行されました。

実際のエラーを見つけてアナライザーの機能を評価するために、警告のリストを見ていきましょう。
一般的な例外は決してスローされるべきではありませんルールは、
throwを使用して汎用例外の
スローを報告します。 PascalABC.NETプロジェクトコードには、634個の同様の構成体が見つかりました。 大部分の形式は次のとおりです。

また、開発者によって意図的に残された、コード内の「スタブ」に類似した構造(600以上)が多数あります。

もちろん、一般的な例外をスローするのは「悪い形式」です。 それにもかかわらず、これは決して間違いではないようです。 さらに、コード作成者がそのような数で意図的に作成した可能性は低いです。 はい、PascalABC.NETプロジェクトでの例外処理は明らかに一律ではありません。 それにもかかわらず、マイナーセクションまたはアナライザの誤検知でさえ、同じタイプのこれらすべての634の警告の場所。
ところで、これはSonarC#とPVS-Studioアナライザーの違いの良い例です。 SonarC#はコード内の「臭い」を指し、これらの警告を発行するのに絶対に正しい。 プロジェクトの品質を判断できます。 PVS-Studioアナライザの開発者である私たちの観点からは、これらは誤検知です。エラーとセキュリティの欠陥の検索に焦点を合わせているからです。
デッドストアは削除する必要がありますまた、変数が割り当て間で使用されない場合、変数の再割り当てに関する618個の警告の非常に大きなグループがあります。 ここでは次のパターンが優先されます。

変数は宣言中に初期化され、保存された値を使用したことがないため、新しい値が割り当てられます。 もちろん、これを行うべきではありません。 リソースの節約についての質問と、別の間違いやタイプミスの疑いがあります。 しかし実際には、これらの構造はいずれも間違いではありません。 繰り返しますが、このような警告がすべて重要度の高いエラーセクションに配置された理由は不明です。 私の意見では、これはすべて誤検知です。
フォームのいくつかの絶対に明確な誤検知警告があります。

この場合、アナライザの推奨事項に従うと、プログラムのロジックに違反します。
したがって、検討中のグループからの618個の警告の中から、単一の実際のエラーを見つけることはできませんでした。
浮動小数点数の等価性をテストしないでください151比較されたオペランドの一方または両方が実数型である比較構造に対して警告が発行されました。 実際、このような比較はしばしば誤った結果をもたらしますが、これは実際の変数をメモリに保存する特性に関連しており、たとえばコンパイラの設定によって異なる場合があります。 このような設計は、問題なく非常に長い間機能します。 この場合、それぞれのケースで、そのようなコードの誤りを判断する必要があります。 たとえば、比較された値が数学的計算の結果である場合、これらの値の直接的な比較は通常誤りです。 2つの実定数を比較する場合、おそらくこれは意味のある方法で行われ、エラーは発生しません。
PascalABC.NETコードでは、主に次の実際の変数との比較パターンに遭遇しました。

比較は2つの実変数と整数型変数を持つ実変数の両方で行われることに注意してください。 もちろん、そのようなコードは完全に安全ではありません。比較された値がどのように取得されたかは不明です。 ここで明らかな間違いについて話す価値はありますか? 明確な答えを出すことは困難です。 ただし、コードにはおそらくいくつかの改良が必要です。
ちなみに、PVS-Studioアナライザーは、このような疑わしい比較についても警告しますが、これらの診断は信頼性レベルが低く、研究のために推奨されていません。
また、アナライザーによって発行される警告には、次のような明らかな誤報があります。

この場合、
byte型の2つの変数
が比較されます。
左右の変数は
byte_const_node型
です 。
public class byte_const_node : concrete_constant<byte>, SemanticTree.IByteConstantNode { public byte_const_node(byte value, location loc) : base(value, loc) { } .... } public abstract class concrete_constant<ConstantType> : constant_node { private ConstantType _constant_value; public concrete_constant(ConstantType value, location loc) : base(compiled_type_node.get_type_node(typeof(ConstantType)), loc) { _constant_value = value; } .... public ConstantType constant_value { get { return _constant_value; } .... } .... } .... }
この警告グループは、メジャーセクションに合理的に配置されていると思います。 ただし、すべての警告がエラーを検出したとは考えません。 いずれの場合も、コードの作成者が決定を下す必要があります。
複数行のブロックは中括弧で囲む必要がありますプログラム実行ロジックに影響する潜在的なフォーマットエラーを含む、108個の警告のグループ。 ここで私は非常に疑わしい構造を見つけました。 例:

このフラグメントでは、おそらく括弧が欠落しています。 いずれの場合でも、開発者はコードをフォーマットして、プログラムのロジックをよりよく理解する必要があります。
別の同様の警告:

エラーはありませんが、コードは乱雑に見えます。 リファクタリングが必要です。
原則として、このグループからの警告はすべてケースで発行されましたが、実際のエラーは明らかになりませんでした。
NULLポインターを逆参照しないでくださいnullリンクによるアクセスの可能性に関する75の警告。 このブロックでは、興味深いエラーが見つかりました。

実際、コードの初期段階では、
returned_scope変数は使用前に常に
nullがチェックされ
ますが、この場合は忘れていました。
public override void visit(....) { .... if (returned_scope != null && ....) { .... } else if (returned_scope != null) { .... } returned_scope.declaringUnit = entry_scope;
別の同様のエラー:

最初のケースでは、変数
piは使用前に
null がチェックされ
ますが、次に
pi.CompilationUnitを呼び出す
ときに、これを行うのを忘れます。
警告ブロックには、それほど明白ではないエラーのほか、誤検知が含まれています。 ここで実際のエラーを見つける割合を85%と評価します。 非常に良い結果。
条件は無条件に「true」または「false」に評価されるべきではありませんプログラムのロジックに関係なく実行可能な条件に関する警告のブロック。 見つかった典型的なエラー:

著者が改善する必要のある奇妙なコード。 重大な間違いが行われた可能性があります。
一般に、グループにはこのようなエラーの約70%が含まれます。
プロパティゲッターから例外をスローしないでくださいプロパティのgetセクションで例外をスローしないでください。必要に応じて、プロパティの代わりにメソッドを使用してください。 このグループには、このような警告が46個含まれています。 それらの大部分は、開発者が意図的にまたは忘却から残した「スタブ」です。

リファクタリングを必要とする非常に正しい構造もありません:

ただし、これらの警告はエラーとは見なしません。 それらをマイナーセクションに帰属させる方が合理的だと思います。
コンストラクターで静的フィールドを更新しないでくださいコンストラクターで静的フィールドを更新する危険性についての診断:クラスのすべてのインスタンスでフィールドが再初期化されるため、プログラムの動作に一貫性がなくなる可能性があります。 合計で、PascalABC.NETアナライザーはこのような警告を26個生成しました。 私はそれらの間で本当の間違いを見つけませんでした。 以下に、発見されたコードスニペットの例をいくつか示します。

毎回、クラスの新しいインスタンスへのリンクが
_instance静的変数に書き込まれます。 変数の名前から判断すると、それが意図されたものです。

parsers_loadedフラグは、クラスの少なくとも1つのインスタンスが既に作成されていることを
通知します。 犯罪者はいません。
「=」の代わりに「= +」を使用しないでください興味深い診断は、演算子 "-="の代わりに、たとえば "=-"が誤って使用されたことです。 アナライザーは、9つの警告を発行しました。 残念ながら、それらはすべて誤検知です。 変数宣言である構文に対して6つの警告が発行されました。原則として、演算子「-= "または" + = "を使用することはできません」:

残りの3つの警告は、コードの作成者がスペースを使用してコードをフォーマットすることを明らかに好まないという事実によるものです。

関連する「if / else if」ステートメントは同じ条件にしないでくださいifブロックと
else ifブロックの条件が同じコードフラグメントに対して5つの警告が発行されました。 多くの場合、このようなコードはすでにエラーが発生しているか、エラーの可能性が含まれています。 今回のケースでは、5つの警告のうち4つに条件の単純な複製と実行ブロックが含まれていました。これはもちろん疑わしいですが、重大なエラーではありません。 1つの警告はより興味深いものです。

最初の
ifブロックの条件の一部がコメント化される前は、次の
ifブロックの条件とは異なりました。 また、次の
場合 、この2番目の実行ユニットに注意してください。空の場合。 演算子は「;」のみです。 非常に奇妙で疑わしいコード。
ブールコンテキストでは短絡ロジックを使用する必要がありますたとえば、診断は、
boolなどの式に
&&の代わりに
&演算子を誤って使用する可能性があることを警告します。 合計5つの疑わしい構造が見つかりました。 エラーが含まれていない場合もありますが、それらはすべて何らかの形で注意が必要です。 それらの1つの例を次に示します。

この場合、「|」演算子を使用していると断言することはできません 誤ったのは、内部で複雑なロジックを持つプロパティが右側でチェックされるためです。 おそらく、開発者は両方の条件が常にチェックされるように努めました。
例外を明示的に再スローしないでください例外スタックの損失に関する診断。 アナライザーは、同じタイプの4つの警告を次の形式で発行しました。

もちろん、これを行うべきではありません。 アプリケーションのさらなるデバッグは困難です。 しかし、これらすべての警告はそれほど重要ではありません。 私の意見では、マイナーセクションでの彼らの位置。
変数を自己割り当てしないでください変数自体への値の割り当てに関する3つの警告。 見つかったコードフラグメントの1つの例を次に示します。

奇妙で明らかに誤りのあるコード。
visitNode宣言は次の
とおりです。
protected bool visitNode = true;
この警告グループには2つのエラーがあります。
二項演算子の両側で同じ式を使用しないでください診断は、同一の部分式がある条件を検索します。 2つの疑わしい構造が見つかりました。 それらのいずれにも明らかなエラーはありませんが、おそらくコードの見た目と動作が異なるはずです。 警告の1つの例:

奇妙なコード。 2番目のチェックを置き換えるのを忘れている可能性があります。
「ToString()」メソッドはnullを返さないメジャーセクションの最後の警告グループ。
ToString()メソッドのオーバーロードは正しく実装されていません。 2つの警告が発行されましたが、どちらもエラーです。 それらの1つの例:

オーバーロードされた
ToString()メソッドから
nullを返すのは正しくありません
。 string.Emptyを使用する必要があります。
マイナー
ここでは、1822件の警告が発行されました。 このレベルは重要ではないため、ここで本当に興味深いエラーを見つけることはまずありません。 また、通常、このレベルでは多くの誤検知が記録されます。 したがって、この研究ではマイナーレベルの警告は考慮しません。
SonarC#アナライザーのテスト結果
まとめると、一般的に、アナライザーはブロッカー、クリティカル、およびメジャーレベルで実際のエラーを発見したと言えます(1814の警告に対して268のエラーまたは非常に疑わしい構造をカウントしました)。 それにもかかわらず、誤検知の割合は非常に大きく、85%以上に達します。 これにより、結果の分析が大幅に複雑になります。
SonarQube用のPVS-Studioプラグイン
SonarQubeのPVS-Studioアナライザーの統合
セクションは、弊社Webサイトの
ドキュメントセクションで説明されています。 統合をゼロからセットアップするのに約15分かかりました。 プロジェクトをチェックして、結果をローカルのSonarQubeサーバーにアップロードすると、同じ量がかかりました。
PVS-Studioは、PascalABC.NETコードの検証中に1039個の警告を発行しました。 これらのうち、クリティカルレベルの156個の警告、541-メジャーレベルの警告、342-マイナーレベルの警告。

軽度の警告は考慮されません。これは、通常、誤検知の割合が高いためです。
クリティカルレベルの診断アラートの配布:

メジャーレベルでの診断警告の分布:

クリティカルおよびメジャーのレベルで697個の警告を分析した結果、そのうち204個が誤検知に起因していることがわかりました。 これは、重要度の第1および第2レベルでの警告の総数の約29%に相当します。 したがって、PascalABC.NETプロジェクトの実際のエラーと疑わしい構造を検出する割合は71%です。 コードの行数(KLOC)に関して、これはKLOCあたり0.66エラーです。 見つかった最も興味深いエラーを見てみましょう。 便宜上、診断ルール番号の昇順のエラーを引用します。
コピーペーストV3001 「||」の左と右に同一の副次式「token.Kind == openBracketToken」があります。 演算子。 ICSharpCode.SharpDevelop NRefactoryInsightWindowHandler.cs 66
readonly int eofToken, commaToken, openParensToken, closeParensToken, openBracketToken, closeBracketToken, openBracesToken, closeBracesToken, statementEndToken; public void InitializeOpenedInsightWindow(....) { .... if (token.Kind == openParensToken || token.Kind == openBracketToken || token.Kind == openBracketToken) {
ifブロック条件では、
token.Kind == openBracketTokenの等価性
が二重チェックされます。 クラスで宣言されたフィールドの中で、
openBracesTokenと非常によく似た名前のフィールドを見つけることができます。 おそらく、このフィールドは条件にありませんでした。 この場合、修正されたコードのバージョンは次のようになります。
public void InitializeOpenedInsightWindow(....) { .... if (token.Kind == openParensToken || token.Kind == openBracketToken || token.Kind == openBracesToken) { bracketCount++; } .... }
コード内の同様のエラー:
- V3001 「&&」演算子の左側と右側には、同一のサブ式「File.Exists(pdbFileName)」があります。 VisualPascalABCNET RunnerManagerHandlers.cs 165
- V3001 「&&」演算子の左右に同じサブ式「_pascal_set_constant.values!= Null」があります。 TreeConverter syntax_tree_visitor.cs 4553
不注意V3003 「if(A){...} else if(A){...}」パターンの使用が検出されました。 論理エラーが存在する可能性があります。 行を確認してください:597、631。ParserTools SyntaxTreeComparer.cs 597
public void CompareInternal(....) { .... if (left is ident) CompareInternal(left as ident, right as ident); .... else if (left is int64_const) CompareInternal(left as int64_const, right as int64_const); .... else if (left is int64_const) CompareInternal(left as int64_const, right as int64_const); .... }
指定されたコードフラグメントには、実際には約30の類似したチェックが含まれており、そのうち2つは完全に同一です。 おそらくここにはエラーはなく、不注意のためにコードが単純に複製されています。 しかし、開発者によると、チェックの1つは異なって見える可能性があります。 この場合、深刻な論理エラーに対処しています。
同様のエラー:
- V3003 「if(A){...} else if(A){...}」パターンの使用が検出されました。 論理エラーが存在する可能性があります。 行を確認してください:1599、1611。ParserTools SyntaxTreeComparer.cs 1599
- V3003 「if(A){...} else if(A){...}」パターンの使用が検出されました。 論理エラーが存在する可能性があります。 行を確認してください:1611、1615。ParserTools SyntaxTreeComparer.cs 1611
- V3003 「if(A){...} else if(A){...}」パターンの使用が検出されました。 論理エラーが存在する可能性があります。 103、209行を確認してください。SyntaxVisitors SimplePrettyPrinterVisitor.cs 103
Copy-Paste v2.0V3004 「then」ステートメントは「else」ステートメントと同等です。 VisualPascalABCNET CodeCompletionWindow.cs 204
public void HandleMouseWheel(....) { .... if (System.Windows.Forms.SystemInformation.MouseWheelScrollLines > 0) { newValue = this.vScrollBar.Value - (control.TextEditorProperties.MouseWheelScrollDown ? 1 : -1) * multiplier; } else { newValue = this.vScrollBar.Value - (control.TextEditorProperties.MouseWheelScrollDown ? 1 : -1) * multiplier; } .... }
ifブロックの両方のブランチには、同一の部分式が含まれています。 この場合、このフラグメントの正しいバージョンについて結論付けることは困難ですが、指定された形式では、コードは期待どおりに機能しません。
コード内の同様のエラー:
- V3004 「then」ステートメントは「else」ステートメントと同等です。 NETGenerator NETGenerator.cs 439
- V3004 「then」ステートメントは「else」ステートメントと同等です。 NETGenerator NETGenerator.cs 2338
- V3004 「then」ステートメントは「else」ステートメントと同等です。 NETGenerator NETGenerator.cs 4062
- V3004 「then」ステートメントは「else」ステートメントと同等です。 NETGenerator NETGenerator.cs 5971
- V3004 「then」ステートメントは「else」ステートメントと同等です。 NETGenerator NETGenerator.cs 6069
- V3004 「then」ステートメントは「else」ステートメントと同等です。 CodeCompletion CodeFormatter.cs 1254
- V3004 「then」ステートメントは「else」ステートメントと同等です。 CodeCompletion DomConverter.cs 428
- V3004 「then」ステートメントは「else」ステートメントと同等です。 TreeConverter type_table.cs 380
- V3004 「then」ステートメントは「else」ステートメントと同等です。 TreeConverter type_table.cs 401
- V3004 「then」ステートメントは「else」ステートメントと同等です。 TreeConverter type_table.cs 424
これら20個のエラーのうち最初の10個だけを引用しました。
変数はそれ自体に割り当てられます。V3005 「miGenerateRealization.Visible」変数はそれ自体に割り当てられます。 VisualPascalABCNET OptionsManager.cs 342
public void UpdateUserOptions() { .... tsViewIntellisensePanel.Visible = tssmIntellisence.Visible = tsGotoDefinition.Visible = tsGotoRealization.Visible = tsFindAllReferences.Visible = miGenerateRealization.Visible = miGenerateRealization.Visible = cmGenerateRealization.Visible = cmsCodeCompletion.Visible = cmFindAllReferences.Visible = cmGotoDefinition.Visible = cmGotoRealization.Visible = UserOptions.AllowCodeCompletion; }
変数
miGenerateRealization.Visibleは、割り当て中に同じ値を2回取得します。 おそらく、余分な割り当てが誤って追加された可能性があります。 ただし、
miGenerateRealization.Visible変数のいずれかではなく、初期化されていない他の変数
が存在する場合
があります。
別の同様のエラーが見つかりました:
V3005 「visitNode」変数はそれ自体に割り当てられます。 SyntaxVisitors SimplePrettyPrinterVisitor.cs 106
再割り当てV3008 「codeCompileUnit」変数には、値が連続して2回割り当てられます。 おそらくこれは間違いです。 チェック行:126、124。VisualPascalABCNET CodeDomHostLoader.cs 126
CodeCompileUnit codeCompileUnit = null; private DesignSurface Designer; .... protected override CodeCompileUnit Parse() { .... CodeCompileUnit ccu = null; DesignSurface ds = new DesignSurface(); .... ccu = cg.GetCodeCompileUnit(idh); .... codeCompileUnit = ccu; Designer = ds; codeCompileUnit = ccu;
コードから、
codeCompileUnit変数
を同じ値に再割り当てするための論理的な説明はまったくないことが
わかります。
コード内の同様のエラー:
- V3008 「mSTEPToolStripMenuItem_Enabled」変数には、連続して2回値が割り当てられます。 おそらくこれは間違いです。 チェック行:541、532。VisualPascalABCNET VisibilityService.cs 541
- V3008変数には連続して2回値が割り当てられます。 おそらくこれは間違いです。 行を確認:62、60。NETGenerator Helpers.cs 62
- V3008 「loc」変数には、連続して2回値が割り当てられます。 おそらくこれは間違いです。 行を確認してください:2123、2122。TreeConverter compilation_context.cs 2123
- V3008 「cnfn.function_code」変数には、連続して2回値が割り当てられます。 おそらくこれは間違いです。 行を確認してください:260、259。TreeConverter functions_calls.cs 260
- V3008 「namespace_func.function_code」変数には、連続して2回値が割り当てられます。 おそらくこれは間違いです。 行を確認してください:267、266。TreeConverter functions_calls.cs 267
- V3008 「ti.init_meth」変数には、連続して2回値が割り当てられます。 おそらくこれは間違いです。 チェック行:1739、1735。NETGenerator NETGenerator.cs 1739
メソッドの結果は常に同じですV3009このメソッドが常に「false」という同じ値を返すのは奇妙です。 NETGenerator NETGenerator.cs 5434
private bool BeginOnForNode(IStatementNode value) {
おそらくここでは、リファクタリング時の不注意に対処しています。 以前のコードでは、
trueを返すコードブロックがありました。 ただし、これらはコメント化され、メソッドは、作業の結果に関係なく
falseを返し
ます 。
コード内の同様のエラー:
- V3009このメソッドが常に1つの同じ値「0」を返すのは奇妙です。 PABCNETC CommandConsoleCompiler.cs 297
- V3009このメソッドが常に1つの同じ値「0」を返すのは奇妙です。 PABCNETCclear CommandConsoleCompiler.cs 266
不注意V3010関数 'OrderBy'の戻り値を使用する必要があります。 ICSharpCode.SharpDevelop RefactoringService.cs 86
static IEnumerable<ITreeNode<IClass>> FindDerivedClassesTree(....) { .... var result = new List<TreeNode<IClass>>(); .... result.OrderBy(node => node.Content.FullyQualifiedName);
結果リストのソート
結果はどこにも保存されません。 指定されたフラグメントの修正バージョン:
static IEnumerable<ITreeNode<IClass>> FindDerivedClassesTree(....) { .... var result = new List<TreeNode<IClass>>(); .... return result.OrderBy(node => node.Content.FullyQualifiedName); }
そして別のそのようなエラー:
V3010関数「ToString」の戻り値を使用する必要があります。 CodeCompletion SymTable.cs 2145
ロジックの問題V3018アプリケーションのロジックの検査を検討してください。 「else」キーワードが欠落している可能性があります。 VisualPascalABCNET InsightWindow.cs 145
public void HandleMouseWheel(MouseEventArgs e) { .... if (e.Delta > 0) { if (control.TextEditorProperties.MouseWheelScrollDown) { CurrentData = (CurrentData + 1) % DataProvider.InsightDataCount; } else { CurrentData = (CurrentData + DataProvider.InsightDataCount - 1) % DataProvider.InsightDataCount; } } if (e.Delta < 0) {
if条件
(e.Delta <0)に注意してください。 コードのフォーマット方法とプログラムロジックに基づいて、結論は次のとおりです。おそらく
elseキーワードが欠落している可能性があります。 それでも、この設計の特徴について正確な答えを出すことができるのは著者だけです。
as演算子を使用する場合の古典的なエラーV3019 「as」キーワードを使用した型変換後に、誤った変数がnullと比較される可能性があります。 変数「baseScope」、「this.baseScope」を確認します。 CodeCompletion SymTable.cs 3497
public TypeScope(...., SymScope baseScope) { .... this.baseScope = baseScope as TypeScope; .... if (baseScope == null) { .... } .... }
baseScope引数を
TypeScope型にキャストした後
、 誤って
null がチェックされる
this.baseScopeフィールド
は nullではなく、
baseScope引数です。 コードの修正バージョン:
public TypeScope(...., SymScope baseScope) { .... this.baseScope = baseScope as TypeScope; .... if (this.baseScope == null) { .... } .... }
コード内の同様のエラー:
- V3019 「as」キーワードを使用した型変換後に、誤った変数がnullと比較される可能性があります。 変数「returned_scope」、「ts」を確認してください。 CodeCompletion ExpressionVisitor.cs 1595
- V3019 「as」キーワードを使用した型変換後に、誤った変数がnullと比較される可能性があります。 変数「returned_scope」、「tmp_scope」を確認してください。 CodeCompletion DomSyntaxTreeVisitor.cs 1553
- V3019 「as」キーワードを使用した型変換後に、誤った変数がnullと比較される可能性があります。 変数「returned_scope」、「ts.elementType」を確認してください。 CodeCompletion DomSyntaxTreeVisitor.cs 2815
- V3019 「as」キーワードを使用した型変換後に、誤った変数がnullと比較される可能性があります。 変数「returned_scope」、「es.elementType」を確認してください。 CodeCompletion DomSyntaxTreeVisitor.cs 2828
- V3019 「as」キーワードを使用した型変換後に、誤った変数がnullと比較される可能性があります。 変数「node」、「solutionFolderNode」を確認します。 ICSharpCode.SharpDevelop SolutionNodeCommands.cs 21
- V3019 「as」キーワードを使用した型変換後に、誤った変数がnullと比較される可能性があります。 変数「node」、「solutionFolderNode」を確認します。 ICSharpCode.SharpDevelop SolutionNodeCommands.cs 91
- V3019 「as」キーワードを使用した型変換後に、誤った変数がnullと比較される可能性があります。 変数「node」、「solutionFolderNode」を確認します。 ICSharpCode.SharpDevelop SolutionNodeCommands.cs 115
- V3019 「as」キーワードを使用した型変換後に、誤った変数がnullと比較される可能性があります。 変数「node」、「solutionFolderNode」を確認します。 ICSharpCode.SharpDevelop SolutionNodeCommands.cs 138
- V3019 「as」キーワードを使用した型変換後に、誤った変数がnullと比較される可能性があります。 変数「rr」、「mrr」を確認してください。 ICSharpCode.SharpDevelop RefactoringService.cs 330
不正確なコードV3022式 't == null'は常にtrueです。 VisualPascalABCNET Debugger.cs 141
public static Type GetTypeForStatic(string name) { Type t = stand_types[name] as Type; if (t != null) return t; if (t == null)
エラーはありませんが、プログラムは乱雑に見えます。
コード内の同様の構造:
- V3022式「CodeCompletion.CodeCompletionController.CurrentParser == null」は常にfalseです。 VisualPascalABCNET CodeCompletionKeyHandler.cs 91
- V3022式「CodeCompletion.CodeCompletionController.CurrentParser == null」は常にfalseです。 VisualPascalABCNET CodeCompletionKeyHandler.cs 114
- V3022式「CodeCompletion.CodeCompletionController.CurrentParser == null」は常にfalseです。 VisualPascalABCNET CodeCompletionKeyHandler.cs 136
- V3022式「CodeCompletion.CodeCompletionController.CurrentParser == null」は常にfalseです。 VisualPascalABCNET CodeCompletionKeyHandler.cs 183
- V3022式 ' defaultCompletionElement == null && data!= Null'は常にfalseです。 VisualPascalABCNET CodeCompletionProvider.cs 507
- V3022式「inRecalculateNeedsRedraw」は常にfalseです。 VisualPascalABCNET DynamicTreeView.cs 1103
- V3022 Expression 'expressionResult!= Null && expressionResult!= ""'常にfalseです。 VisualPascalABCNET CodeCompletionActions.cs 225
- V3022式「SaveCanceled」は常にfalseです。 VisualPascalABCNET FileOperations.cs 442
- V3022式 '!SaveCanceled'は常にtrueです。 VisualPascalABCNET FileOperations.cs 450
- V3022式 '_format_expr.format2!= Null'は常にtrueです。 VisualPascalABCNET ExpressionEvaluation.cs 7028
45以上の警告のうち最初の10個だけを警告しました。
冗長なチェックまたはエラー?V3030定期的なチェック。 「upperScopeWhereVarsAreCaptured!= Scope」条件は、383行目で既に確認されています。TreeConverter CapturedVariablesSubstitutionClassGenerator.cs 391
private void VisitCapturedVar(....) { .... if (upperScopeWhereVarsAreCaptured != scope) { .... if (upperScopeWhereVarsAreCaptured != scope) { .... } .... } .... }
通常、このような構成はエラーではありませんが、チェックの1つに別の条件が含まれている可能性があります。
コード内の同様のエラー:
- V3030定期的なチェック。 「kav.Count == 0」条件は2525行目ですでに検証されています。ParserTools DefaultLanguageInformation.cs 2518
- V3030定期的なチェック。 「ret_tn!= Null」条件は、289行目ですでに検証されています。CodeCompletion FindReferences.cs 291
- V3030定期的なチェック。 'kav.Count == 0'条件は、885行目で既に検証されています。VBNETParser LanguageInformation.cs 888
奇妙なフォーマットV3033この「else」ブランチは、前の「if」ステートメントに適用する必要がある可能性があります。 TreeConverter syntax_tree_visitor.cs 14894
public override void visit(....) { .... if (_var_def_statement.inital_value != null) if (is_event) AddError(....); else { .... } .... }
プログラムのロジックによれば、
elseキーワードは
if(is_event)条件ブロックを参照します。 ただし、コードは、まったく異なる印象が作成されるようにフォーマットされています。 括弧
{}を使用すると、おそらく問題が解決するでしょう。
タイプミスV3038 'enum_consts [i]'引数が 'Compare'メソッドに数回渡されました。 代わりに他の引数を渡す必要があります。 CodeCompletion SymTable.cs 2206
private List<string> enum_consts = new List<string>(); public override bool IsEqual(SymScope ts) { EnumScope es = ts as EnumScope; if (es == null) return false; if (enum_consts.Count != es.enum_consts.Count) return false; for (int i = 0; i < es.enum_consts.Count; i++) if (string.Compare(enum_consts[i], this.enum_consts[i], true) != 0)
残念ながら、
IsEqualメソッドに
はローカル変数
enum_constsの宣言が含まれて
いません。
for enum_consts .
IsEqual :
public override bool IsEqual(SymScope ts) { .... for (int i = 0; i < es.enum_consts.Count; i++) if (string.Compare(enum_consts[i], es.enum_consts[i], true) != 0) .... }
v2.0V3043 The code's operational logic does not correspond with its formatting. ステートメントは右側にインデントされますが、常に実行されます。 中括弧が欠落している可能性があります。 VBNETParser LanguageInformation.cs 1002
public override string FindExpression(....) { .... switch (ch) { .... case '(': if (kav.Count == 0) { .... } else sb.Insert(0, ch); punkt_sym = true; break; } .... }
punkt_sym = true kav.Count == 0 . , , ,
kav.Count != 0 .
:
V3043 The code's operational logic does not correspond with its formatting. ステートメントは右側にインデントされますが、常に実行されます。 中括弧が欠落している可能性があります。 ICSharpCode.SharpDevelop AbstractConsolePad.cs 159
V3052 The original exception object 'e' was swallowed. 元の例外のスタックが失われる可能性があります。 NETGenerator NETGenerator.cs 925
public void ConvertFromTree(....) { .... try { .... } catch (System.Runtime.InteropServices.COMException e) { throw new TreeConverter.SaveAssemblyError(e.Message); } .... }
COMException . , ,
SaveAssemblyError , :
public class SaveAssemblyError : CompilationError { .... public SaveAssemblyError(string text) { _text = text; } .... }
, — . , , .
:
- V3052 The original exception object 'e' was swallowed. 元の例外のスタックが失われる可能性があります。 NETGenerator NETGenerator.cs 929
- V3052 The original exception object 'ex' was swallowed. 元の例外のスタックが失われる可能性があります。 ICSharpCode.SharpDevelop ReferenceFolderNodeCommands.cs 92
- V3052 The original exception object 'ex' was swallowed. 元の例外のスタックが失われる可能性があります。 TreeConverter syntax_tree_visitor.cs 16324
V3053 An excessive expression. Examine the substrings 'reduction' and 'reduction('. TreeConverter OpenMP.cs 267
private void ProcessClauses(string Text, ....) { .... if (....) { .... } else if (AllowReduction && (Text.StartsWith("reduction") || Text.StartsWith("reduction("))) { .... } .... }
«reduction(» ,
«reduction» .
V3070 Uninitialized variable 'event_add_method_prefix' is used when initializing the 'event_add_method_nameformat' variable. TreeConverter compiler_string_consts.cs 313
public static class compiler_string_consts { .... public static string event_add_method_nameformat = event_add_method_prefix + "{0}"; .... public static string event_add_method_prefix = "add_"; .... }
,
event_add_method_nameformat "{0}" ,
«add_{0}» . :
public static class compiler_string_consts { .... public static string event_add_method_prefix = "add_"; .... public static string event_add_method_nameformat = event_add_method_prefix + "{0}"; .... }
:
V3070 Uninitialized variable 'event_remove_method_prefix' is used when initializing the 'event_remove_method_nameformat' variable. TreeConverter compiler_string_consts.cs 314
:V3080 nullの逆参照の可能性。 Consider inspecting 'tc'. CodeCompletion CodeCompletionPCUReader.cs 736
private TypeScope GetTemplateInstance() { TypeScope tc = null;
,
tc GetTemplateClassReference() . , —
null . ,
for . , ,
GetTemplateInstance() . , .
:
- V3080 nullの逆参照の可能性。 Consider inspecting 'bfc'. TreeConverter syntax_tree_visitor.cs 7334
- V3080 nullの逆参照の可能性。 Consider inspecting 'bfc'. TreeConverter syntax_tree_visitor.cs 7336
- V3080 nullの逆参照の可能性。 Consider inspecting 'bfc'. TreeConverter syntax_tree_visitor.cs 7338
- V3080 nullの逆参照の可能性。 Consider inspecting 'bfc'. TreeConverter syntax_tree_visitor.cs 7340
- V3080 nullの逆参照の可能性。 Consider inspecting 'bfc'. TreeConverter syntax_tree_visitor.cs 7409
- V3080 nullの逆参照の可能性。 Consider inspecting 'bfc'. TreeConverter syntax_tree_visitor.cs 7411
- V3080 nullの逆参照の可能性。 Consider inspecting 'bfc'. TreeConverter syntax_tree_visitor.cs 7413
- V3080 nullの逆参照の可能性。 Consider inspecting 'bfc'. TreeConverter syntax_tree_visitor.cs 7415
:V3095 The 'VisualEnvironmentCompiler.RemoteCompiler' object was used before it was verified against null. Check lines: 52, 54. CompilerController CompilerControllerPlugin.cs 52
public CompilerController_VisualPascalABCPlugin(....) { .... VisualEnvironmentCompiler.RemoteCompiler.InternalDebug.RunOnMono = CompilerInformation.cbRunMono.Checked; .... if (VisualEnvironmentCompiler.RemoteCompiler != null) .... }
null . :
public CompilerController_VisualPascalABCPlugin(....) { .... if (VisualEnvironmentCompiler.RemoteCompiler != null) { VisualEnvironmentCompiler.RemoteCompiler. InternalDebug.RunOnMono = CompilerInformation.cbRunMono.Checked; .... } }
:
- V3095 The 'cun' object was used before it was verified against null. Check lines: 400, 401. Compiler PCUReader.cs 400
- V3095 The 'cnfn.ConnectedToType.element_type' object was used before it was verified against null. Check lines: 2918, 2930. Compiler PCUReader.cs 2918
- V3095 The '_currentTreeNode' object was used before it was verified against null. Check lines: 590, 593. TreeConverter CapturedVariablesTreeBuilder.cs 590
- V3095 The 'Units' object was used before it was verified against null. Check lines: 3031, 3073. Compiler Compiler.cs 3031
- V3095 The 'frm' object was used before it was verified against null. Check lines: 2358, 2364. NETGenerator NETGenerator.cs 2358
- V3095 The 'InitalValue' object was used before it was verified against null. Check lines: 2915, 2918. NETGenerator NETGenerator.cs 2915
- V3095 The 'InitalValue' object was used before it was verified against null. Check lines: 2952, 2956. NETGenerator NETGenerator.cs 2952
- V3095 The 'InitalValue' object was used before it was verified against null. Check lines: 3005, 3009. NETGenerator NETGenerator.cs 3005
- V3095 The 'InitalValue' object was used before it was verified against null. Check lines: 3041, 3045. NETGenerator NETGenerator.cs 3041
- V3095 The 'InitalValue' object was used before it was verified against null. Check lines: 3103, 3107. NETGenerator NETGenerator.cs 3103
10 40.
: x2V3110 Possible infinite recursion inside 'SetRange' method. TreeConverter SymbolInfoArrayList.cs 439
V3110 Possible infinite recursion inside 'SetRange' method. TreeConverter SymbolInfoArrayList.cs 444
public void SetRange(int index,SymbolInfo[] tnarr) { SetRange(index,tnarr); } public void SetRange(int index,SymbolInfoArrayList tnarl) { SetRange(index,tnarl); }
, . . . .
:
- V3110 Possible infinite recursion inside 'node_kind' property. TreeConverter functions.cs 2528
- V3110 Possible infinite recursion inside 'node_location_kind' property. TreeConverter functions.cs 2590
- V3110 Possible infinite recursion inside 'node_kind' property. TreeConverter functions.cs 2693
- V3110 Possible infinite recursion inside 'node_location_kind' property. TreeConverter functions.cs 2704
- V3110 Possible infinite recursion inside 'Instance' property. ParserTools LanguageInformation.cs 549
EqualsV3115 Passing 'null' to 'Equals' method should not result in 'NullReferenceException'. ICSharpCode.SharpDevelop ServiceReferenceMapFile.cs 31
public override bool Equals(object obj) { var rhs = obj as ServiceReferenceMapFile; return FileName == rhs.FileName;
.
null rhs . ,
null obj :
public override bool Equals(object obj) { if (obj == null || !(obj is ServiceReferenceMapFile)) return false; var rhs = obj as ServiceReferenceMapFile; return FileName == rhs.FileName; }
V3125 The 'resources' object was used after it was verified against null. Check lines: 215, 211. VisualPascalABCNET DesignerResourceService.cs 215
public System.Resources.IResourceReader GetResourceReader(System.Globalization.CultureInfo info) { .... if (resources != null && resources.ContainsKey(info.Name)) { resourceStorage = resources[info.Name]; } else { resourceStorage = new ResourceStorage(); resources[info.Name] = resourceStorage;
null resources , ,
else . . :
public System.Resources.IResourceReader GetResourceReader(System.Globalization.CultureInfo info) { .... if (resources != null) { if (resources.ContainsKey(info.Name)) { resourceStorage = resources[info.Name]; } else { resourceStorage = new ResourceStorage(); resources[info.Name] = resourceStorage; } } .... }
:
- V3125 The 'this._grid' object was used after it was verified against null. Check lines: 751, 746. VisualPascalABCNET TreeGridNode.cs 751
- V3125 The 'this._grid' object was used after it was verified against null. Check lines: 774, 770. VisualPascalABCNET TreeGridNode.cs 774
- V3125 The 'node.Parent' object was used after it was verified against null. Check lines: 369, 350. VisualPascalABCNET TreeGridView.cs 369
- V3125 The 'CurrentCodeFileDocument' object was used after it was verified against null. Check lines: 395, 384. VisualPascalABCNET WindowOperations.cs 395
- V3125 The 'value.main_function' object was used after it was verified against null. Check lines: 948, 942. LanguageConverter Visitor.cs 948
- V3125 The 'left.prim_val' object was used after it was verified against null. Check lines: 4711, 4699. VisualPascalABCNET ExpressionEvaluation.cs 4711
- V3125 The 'left.obj_val' object was used after it was verified against null. Check lines: 4849, 4822. VisualPascalABCNET ExpressionEvaluation.cs 4849
- V3125 The 'to' object was used after it was verified against null. Check lines: 335, 327. TreeConverter CapturedVariablesTreeBuilder.cs 335
- V3125 The 'dii_left' object was used after it was verified against null. Check lines: 256, 254. TreeConverter LambdaHelper.cs 256
- V3125 The 't' object was used after it was verified against null. Check lines: 23, 20. TreeConverter semantic_checks_for_sugar.cs 23
10 80 (!).
V3128 The 'dockPanel' field is used before it is initialized in constructor. ICSharpCode.SharpDevelop SearchResultsPad.cs 49
.... DockPanel dockPanel; .... public SearchResultsPad() { .... defaultToolbarItems = ToolBarService. CreateToolBarItems(dockPanel, ....);
dockPanel SearchResultsPad , . ,
CreateToolBarItems null , , ,
null. , ,
defaultToolbarItems .
統計
. SonarC# PVS-Studio . SonarC# . , «» . PVS-Studio , . , , :
- SonarC# — , ;
- PVS-Studio — .
PascalABC.NET ( Blocker, Critical Major):

, . SonarC# , , . . , PVS-Studio . , .
おわりに
, , PVS-Studio SonarC# SonarQube . . SonarQube . , .
SonarQube .
PVS-Studio SonarQube . —
Enterprise . SonarQube, PVS-Studio .
PVS-Studioをダウンロードして試してください:
http :
//www.viva64.com/en/pvs-studio/PVS-Studio
. デモバージョンの
制限を削除する場合は、PVS-Studioの包括的な研究の一時的なライセンスを取得するために私たちに書き込むこともできます。
この記事を英語圏の聴衆と共有したい場合は、翻訳へのリンクを使用してください:Sergey Khrenov。
Analysis of PascalABC.NET using SonarQube plugins: SonarC# and PVS-Studio