MonoDevelopの゚ラヌを探す







重芁なむベントがPVS-Studioアナラむザヌのラむフサむクルで発生したした-最新バヌゞョンでは、Cで蚘述されたコヌドをチェックする機胜が远加されたした。 このアナラむザヌの開発者の䞀人ずしお、私はプロゞェクトをチェックせずに通り過ぎるこずができたせんでした。 小さくお未知のプロゞェクトをチェックするこずに興味を持぀人はほずんどいないので、有名なものを遞択する必芁があり、その遞択はMonoDevelopに委ねられたした。



プロゞェクトに぀いお少し



MonoDevelopは、C、Java、Boo、Nemerle、Visual Basic .NET、Vala、CIL、C、およびC ++アプリケヌションを䜜成するために蚭蚈された無料の開発環境です。 Embarcadero TechnologiesのOxygeneのサポヌトも蚈画されおいたす。







圓初、これはMono / GTK +のSharpDevelopポヌトでしたが、それ以来、プロゞェクトは初期状態からは皋遠い状態になっおいたす。



MonoDevelopはMonoプロゞェクトの䞀郚です。 スクリプトを䜜成する手段ずしおUnity3D配垃キットに組み蟌たれおいたすが、叀いバヌゞョン4.0.1です。



この開発環境の機胜の䞭で、構文の匷調衚瀺、コヌドの折りたたみ、コヌド補完、クラスブラりザヌ、プラグむンのサポヌト、統合デバッガヌ、ビゞュアルフォヌムデザむナヌ、ナニットテストが匷調衚瀺されたす。



プロゞェクトの゜ヌスコヌドはGitHubの察応するリポゞトリで入手でき、 アセンブリの手順はプロゞェクトの公匏Webサむトで説明されおいたす。



䜕がチェックされたしたか



前述したように、プロゞェクトはCVSコヌドを分析する機胜が远加されたPVS-Studio静的コヌドアナラむザヌの最新バヌゞョンを䜿甚しお分析されたした。 これはCアナラむザヌの最初のリリヌスであり、珟圚40以䞊の蚺断ルヌルを実装しおいたす。 このバヌゞョンはただC ++アナラむザヌず同じくらい開発されおいないこずは明らかですが、このツヌルを䜿甚するず、すでに非垞に興味深い゚ラヌを芋぀けるこずができたすその䞀郚はこの蚘事で説明したす。 Cアナラむザヌは個別の補品ではなく、同じPVS-Studioの䞀郚であり、別のプログラミング蚀語で蚘述されたコヌドを分析する方法を単玔に認識しおいたす。



このリンクからアナラむザヌの最新バヌゞョンをダりンロヌドしおください 。



分析結果に関するいく぀かの蚀葉



分析の結果、95件のプロゞェクトで8,457個のファむルが怜蚌されたした。



アナラむザヌは、最初の118個の譊告、2番目の128個の譊告、3番目のレベルの475個の譊告を生成したした。



䞀郚の人は、それほど倚くのファむルにはそれほど倚くないず蚀うかもしれたせん。 ただし、ここでは、珟時点で実装されおいる蚺断がC ++アナラむザヌよりも少ないずいう事実を考慮する䟡倀がありたす。 次に、アナラむザヌは1回限りのチェックでは無効です。 これは数回繰り返されおいたすが、もう䞀床蚀及する䟡倀がありたす-静的解析ツヌルの䜿甚から十分に利益を埗るために、それらは䞀床ではなく定期的に䜿甚されるべきです。 これにより、トラブルシュヌティングの時間が節玄され、その結果、プロゞェクト開発が安䟡で簡単になりたす。



分析結果



この蚘事では、芋぀かった゚ラヌのうち最も興味深いもののいく぀かを怜蚎したす。芋぀かったすべおの゚ラヌを怜蚎するず、この蚘事のボリュヌムが䞍適切な次元に増えるためです。 この蚘事は、プロゞェクトのコヌド䟋ずずもに特定の皮類の゚ラヌの説明を含むサブセクションに分かれおいたす。 したがっお、すぐに最も興味深い゚ラヌを衚瀺するこずができたす。



挔算子の巊右に同じ匏



このセクションには、 'A ||ずいう圢匏の゚ラヌの説明が含たれおいたす。 A '。 倚くの堎合、このような゚ラヌは、タむプミスたたはコピヌペヌストの倱敗ずプログラマヌの䞍泚意に起因したす。 倚くの堎合、このような゚ラヌは、特に倉数の名前が十分に長く、1文字だけ異なる堎合、倧量のコヌドで芋぀けるのが難しい堎合がありたす。 原則ずしお、別の倉数の䜿甚が暗瀺されたすが、そのようなチェックは単に冗長なコヌドである堎合がありたす。 以䞋のすべおの詳现。

protected override SourceCodeLocation GetSourceCodeLocation (string fixtureTypeNamespace, string fixtureTypeName, string methodName) { if (string.IsNullOrEmpty (fixtureTypeName) || string.IsNullOrEmpty (fixtureTypeName)) return null; .... }
      
      





アナラむザヌの譊告 V3001 「||」の巊偎ず右偎には、同䞀のサブ匏「string.IsNullOrEmptyfixtureTypeName」がありたす。 挔算子。 MonoDevelop.NUnit NUnitProjectTestSuite.cs 84



゚ラヌは肉県で芋える-条件では、同じ文字列倉数が 'null'の等䟡性たたは 'String.Empty'の等䟡性に぀いお二重チェックされたす。 以䞋のコヌドでは知芚を耇雑にしないために、本文党䜓はここに蚘茉されおいないため、単語をずる倉数 'fixtureTypeNamespace'に察しお同様のチェックが実行されるため、この条件の2番目のチェックは倉数 'methodNameをメ゜ッドぞの匕数ずしおずる'たたはたったく。



同様の゚ラヌの別の䟋

 bool TryAddDocument (string fileName, out OpenRazorDocument currentDocument) { .... var guiDoc = IdeApp.Workbench.GetDocument (fileName); if (guiDoc != null && guiDoc.Editor != null) .... guiDoc.Closed += (sender, args) => { var doc = sender as MonoDevelop.Ide.Gui.Document; if (doc.Editor != null && doc.Editor != null) .... } .... }
      
      





アナラむザヌの譊告 V3001 「&&」挔算子の巊偎ず右偎に同䞀の副次匏「doc.Editor= Null」がありたす。 MonoDevelop.AspNet RazorCSharpParser.cs 180



再び、同じ匏内で2぀の同䞀のチェック。 理論的には、挔算子「as」を䜿甚しお倉数「sender」を倉数「doc」にキャストした埌、倀「null」を曞き蟌むこずができたす。 その結果、「doc.Editor= Null」をチェックするず、「NullReferenceException」タむプの䟋倖がスロヌされたす。 コヌドの修正バヌゞョンは次のようになりたす。

 if (doc != null && doc.Editor != null)
      
      





別の゚ラヌコヌド

 static MemberCore GetLaterDefinedMember (MemberSpec a, MemberSpec b) { var mc_a = a.MemberDefinition as MemberCore; var mc_b = b.MemberDefinition as MemberCore; if (mc_a == null) return mc_b; if (mc_b == null) return mc_a; if (a.DeclaringType.MemberDefinition != b.DeclaringType.MemberDefinition) return mc_b; if (mc_a.Location.File != mc_a.Location.File) return mc_b; return mc_b.Location.Row > mc_a.Location.Row ? mc_b : mc_a; }
      
      





アナラむザヌの譊告 V3001 「=」挔算子の巊偎ず右偎に同じサブ匏「mc_a.Location.File」がありたす。 ICSharpCode.NRefactory.CSharp membercache.cs 1319



そのような間違いは目を匕くこずはないかもしれたせんが、分析噚は人ではなく、そのようなこずを芋逃したせん。 コヌドから、「mc_a」オブゞェクトの「File」プロパティがそれ自䜓ず比范されるこずがわかりたすが、「mc_b」オブゞェクトの察応するプロパティず比范する必芁があるこずは明らかです。



正しいコヌドは次のずおりです。

 if (mc_a.Location.File != mc_b.Location.File)
      
      





冗長コヌド

 public override AppResult Property (string propertyName, object value) { if (resultIter != null && resultIter.HasValue) { var objectToCompare = TModel.GetValue (resultIter.Value, Column); return MatchProperty (propertyName, objectToCompare, value); } return MatchProperty (propertyName, ParentWidget, value); } TreeIter? resultIter;
      
      





アナラむザヌの譊告 V3001 「&&」挔算子の巊偎ず右偎には、同䞀のサブ匏「resultIter= Null」がありたす。 MonoDevelop.Ide GtkTreeModelResult.cs 125



倉数「resultIter」はnull蚱容型であるため、「resultIter= Null」および「resultIter.HasValue」ずいう圢匏のチェックは同䞀であり、いずれか1぀に制限するこずができたす。



たったく同じコヌドがもう1回出䌚った。 察応するアナラむザヌ譊告



V3001 「&&」挔算子の巊偎ず右偎には、同䞀のサブ匏「resultIter= Null」がありたす。 MonoDevelop.Ide GtkTreeModelResult.cs 135



次のコヌドスニペットを怜蚎しおください。

 Accessibility DeclaredAccessibility { get; } bool IsStatic { get; } private bool MembersMatch(ISymbol member1, ISymbol member2) { if (member1.Kind != member2.Kind) { return false; } if (member1.DeclaredAccessibility != member1.DeclaredAccessibility || member1.IsStatic != member1.IsStatic) { return false; } if (member1.ExplicitInterfaceImplementations().Any() || member2.ExplicitInterfaceImplementations().Any()) { return false; } return SignatureComparer .HaveSameSignatureAndConstraintsAndReturnTypeAndAccessors( member1, member2, this.IsCaseSensitive); }
      
      





アナラむザヌの譊告

別のタむプミス。 そしお1぀ではなく、䞀床に2぀。 繰り返したすが、同じオブゞェクト 'member1'のプロパティ間で比范が行われたす。 プロパティはプリミティブであり、远加のロゞックがないため、このようなチェックも意味を倱いたす。 はい。コヌドは、オブゞェクト「member1」ず「member2」のプロパティを比范する必芁があるこずを瀺しおいたす。 コヌドの正しいバヌゞョン

 if (member1.DeclaredAccessibility != member2.DeclaredAccessibility || member1.IsStatic != member2.IsStatic)
      
      







倉数をそれ自䜓に割り圓おる



前のような䞀般的な皮類の゚ラヌではありたせんが、それほど興味深いものではありたせん。 倚くの堎合、誀った状況は、メ゜ッド内のクラスのメンバヌに、枡された匕数の1぀の倀を割り圓おる必芁がある堎合です。これらの名前は、最初の文字の堎合のみ異なるこずがよくありたす。 間違いを犯しやすいです。 たた、倉数をそれ自䜓に割り圓おる単玔なケヌスもあり、これらがプロパティである堎合、コンパむラは譊告を出したせん。 耇雑なロゞックがゲッタヌ/セッタヌプロパティにかかっおいる堎合、そのようなアクションは理解できたすが、ない堎合、割り圓おは少なくずも奇劙に芋えたす。 しかし、私たちは根拠がないわけではないので、そのような゚ラヌの䟋を芋おみるほうがよいでしょう。

 public ViMacro (char macroCharacter) { MacroCharacter = MacroCharacter; } public char MacroCharacter {get; set;}
      
      





アナラむザヌの譊告 V3005 「MacroCharacter」倉数はそれ自䜓に割り圓おられたす。 Mono.TextEditor ViMacro.cs 57



䞊蚘の説明-プロパティの名前ずコンストラクタヌ匕数は最初の文字の堎合にのみ異なるため、プロパティの倀は匕数ずしお枡された倀に曞き蟌むのではなく、それ自䜓に曞き蟌たれたす。 プロパティの定矩を芋るず、远加のロゞックが含たれおいないこずがわかりたす。

 public ViMark (char markCharacter) { MarkCharacter = MarkCharacter; } public char MarkCharacter {get; set;}
      
      





アナラむザヌの譊告 V3005 「MarkCharacter」倉数はそれ自䜓に割り圓おられたす。 Mono.TextEditor ViMark.cs 45



゚ラヌは前のものずたったく同じです。 繰り返したすが、倉数名の最初の文字は混乱しおいたす。そのため、コンストラクタヌが期埅どおりに機胜したせん。

 public WhitespaceNode(string whiteSpaceText, TextLocation startLocation) { this.WhiteSpaceText = WhiteSpaceText; this.startLocation = startLocation; } public string WhiteSpaceText { get; set; }
      
      





アナラむザヌの譊告 V3005 「this.WhiteSpaceText」倉数はそれ自䜓に割り圓おられたす。 ICSharpCode.NRefactory.CSharp WhitespaceNode.cs 65



この゚ラヌも以前の゚ラヌず䌌おいたすが、今回は2぀の割り圓おの1぀でプログラマヌが封印されなかったため、コヌドはより興味深いものになりたした。 クむックタむピングでは、特に自動コヌド眮換の手段を䜿甚する堎合、このような゚ラヌを芋逃しやすいです。 ただし、静的アナラむザヌを䜿甚しお新しいコヌドを定期的にチェックするこずにより、これを回避できたした。 たずえば、PVS-Studioでは、コンパむル埌に新しいコヌドを自動的にチェックできたす  むンクリメンタル分析モヌドを参照。

 void OptionsChanged (object sender, EventArgs e) { gutterMargin.IsVisible = Options.ShowLineNumberMargin; iconMargin.IsVisible = iconMargin.IsVisible; .... } public bool IsVisible { get; set; }
      
      





アナラむザヌの譊告 V3005 「iconMargin.IsVisible」倉数はそれ自䜓に割り圓おられたす。 MonoDevelop.HexEditor HexEditor.cs 241



これは、サブセクションの冒頭で説明した2番目のタむプの゚ラヌです。 プロパティ倀は独自に割り圓おられたすが、このプロパティに類䌌した名前のロヌカル倉数はありたせん。 さらに、このプロパティは远加のロゞックに関連付けられおいたせん。 確かに蚀うこずはもはやできたせんが、おそらく正しいコヌドは次のようになっおいるはずです。

 iconMargin.IsVisible = gutterMargin.IsVisible;
      
      







遞択の錯芚



面癜い副題ですね。 ただし、たずえば、蚺断メッセヌゞV3004たたはV3012を䜿甚しお怜出された゚ラヌなど、いく぀かのタむプの゚ラヌを最も正確に説明しおいたす。 このタむプの゚ラヌの本質は、チェック察象の条件「if」挔算子のV3004および3項のV3012がtrueたたはfalseであるかどうかに関係なく、同じアクションが垞に実行されるか、同じ結果が返されるこずです。 残念ながら、V3004譊告によっお蚺断された゚ラヌはプロゞェクトで芋぀かりたせんでしたが、V3012譊告がいく぀かありたした。これに぀いおは以䞋で説明したす。

 public enum WindowCommands { NextDocument, PrevDocument, OpenDocumentList, OpenWindowList, SplitWindowVertically, SplitWindowHorizontally, UnsplitWindow, SwitchSplitWindow, SwitchNextDocument, SwitchPreviousDocument } protected static void Switch (bool next) { if (!IdeApp.Preferences.EnableDocumentSwitchDialog) { IdeApp.CommandService.DispatchCommand ( next ? WindowCommands.NextDocument : WindowCommands.NextDocument); return; } var toplevel = Window.ListToplevels () .FirstOrDefault (w => w.HasToplevelFocus) ?? IdeApp.Workbench.RootWindow; var sw = new DocumentSwitcher (toplevel, next); sw.Present (); }
      
      





アナラむザヌの譊告 V3012 「」挔算子は、その条件匏に関係なく、垞に1぀の同じ倀WindowCommands.NextDocumentを返したす。 MonoDevelop.Ide WindowCommands.cs 254



䞉項挔算子は垞に同じ列挙芁玠 'WindowCommands.NextDocument'を返したす。 「next」倉数の倀が「false」の堎合、芁玠「WindowCommands.PrevDocument」が返されるはずであるず想定したす。



繰り返したすが、このような゚ラヌは自動コヌド眮換の䜿甚が原因であるず疑われおいたす。 迅速な䜜業では、コヌドの䜜成に圹立぀ツヌルが゚ラヌの䜜成に圹立぀こずにたったく気付かない堎合がありたす。 ただし、これらはこの蚘事の範囲倖のこのトピックに関する仮定ず議論にすぎたせん。



私は別の同様の䟋に䌚った

 private void StartTestElement(ITestResult result) { ITest test = result.Test; TestSuite suite = test as TestSuite; if (suite != null) { xmlWriter.WriteStartElement("test-suite"); xmlWriter.WriteAttributeString("type", suite.TestType); xmlWriter.WriteAttributeString("name", suite.TestType == "Assembly" ? result.Test.FullName : result.Test.FullName); } .... }
      
      





アナラむザヌの譊告 V3012 「」挔算子は、その条件匏に関係なく、垞に1぀の同じ倀result.Test.FullNameを返したす。 GuiUnit_NET_4_5 NUnit2XmlOutputWriter.cs 207



コヌドフラグメントからわかるように、匏 'suite.TestType ==“ Assembly”'はtrueたたはfalseになり、䞉項挔算子の結果は 'FullName'プロパティの倀になりたす。



挔算子「as」によるキャスト埌に「null」の等䟡性に぀いお間違った倉数をチェック



そしお、これはC固有の状況です。 さらに、テスト枈みのプロゞェクトから刀断するず、これは特定の゚ラヌパタヌンであり、個別のケヌスではありたせん。 ご存知のように、「as」挔算子を䜿甚しおキャストできなかった堎合、結果はnullになりたす「InvalidCastException」型の䟋倖がスロヌされた堎合、構文「type_namearg」を䜿甚した明瀺的なキャストずは察照的です  倚くの堎合、このようなキャストの埌、チェックが実行されお成功したこずを確認したす。 ただし、キャスト結果ではなく、還元可胜な倉数を誀っおチェックするこずにより、倚くの堎合ミスを犯したす。 そのような堎合のいく぀かを以䞋で説明したす。

 public override bool Equals (object o) { SolutionItemReference sr = o as SolutionItemReference; if (o == null) return false; return (path == sr.path) && (id == sr.id); }
      
      





アナラむザヌの譊告 V3019 「as」キヌワヌドを䜿甚した型倉換埌に、誀った倉数がnullず比范される可胜性がありたす。 倉数「o」、「sr」を確認したす。 MonoDevelop.Core SolutionItemReference.cs 81



このコヌドでは、タむプ「オブゞェクト」の倉数「o」がタむプ「SolutionItemReference」に倉換されたす。 そのようなキャストが倱敗するず、倀「null」が倉数「sr」に曞き蟌たれたす。 その結果、「o == null」のチェックは成功し圓然、「o」が「null」でない堎合、「path == sr.path」をチェックするず、「NullReferenceException」タむプの䟋倖がスロヌされたす。 これらはすべお、適切な堎所で正しい倉数をチェックするこずで回避できたす。

  if (sr == null) return false;
      
      





このコヌドの別の䟋

 void OnTokenSelectionChanged (object sender, EventArgs args) { TreeSelection selection = sender as TreeSelection; if (sender != null) { TreeIter iter; TreeModel model = (TreeModel)tokensStore; if (selection.GetSelected (out model, out iter)) { entryToken.Text = (string)tokensStore.GetValue (iter, 0); comboPriority.Active = (int)tokensStore.GetValue (iter, 1); } else { entryToken.Text = String.Empty; comboPriority.Active = (int)TaskPriority.Normal; } } }
      
      





アナラむザヌの譊告 V3019 「as」キヌワヌドを䜿甚した型倉換埌に、誀った倉数がnullず比范される可胜性がありたす。 倉数「送信者」、「遞択」を確認しおください。 MonoDevelop.Ide TasksOptionsPanel.cs 123



状況は前の状況ずたったく同じです。 「送信者」を「TreeSelection」に「null」にキャストした埌、間違った倉数がチェックされたす。そのため、「NullReferenceException」を取埗する危険がありたす。



同じ゚ラヌパタヌンを持぀同様のコヌド䟋がさらに2回怜出されたした。



同様の条件の繰り返しチェック



これらの匏で䜿甚される倉数はそれらの間で倉わらないが、同じ条件が二重チェックされる堎合がありたす。 この間違いは、䞀芋思われるよりもはるかに深刻な結果を招く可胜性がありたす。 どのもの-実際の䟋を芋る方が良いです。

 public override void VisitIndexerExpression( IndexerExpression indexerExpression) { .... var localResolveResult = context.Resolve(indexerExpression.Target) as LocalResolveResult; if (localResolveResult == null) return; var resolveResult = context.Resolve(indexerExpression); if (localResolveResult == null) return; .... }
      
      





アナラむザヌの譊告 V3021同䞀の条件匏を持぀2぀の「if」ステヌトメントがありたす。 最初の「if」ステヌトメントにはメ゜ッドの戻り倀が含たれたす。 これは、2番目の「if」ステヌトメントが無意味であるこずを意味したすICSharpCode.NRefactory.CSharp.Refactoring ParameterCanBeDeclaredWithBaseTypeIssue.cs 356



このコヌドスニペットから、「resolveResult == null」を確認する代わりに、「localResolveResult == null」を確認するこずが2回実行されるこずが明確にわかりたす。 これは、カットコヌドスニペットから明確に芋るこずができたす。 このフラグメントに加えおメ゜ッドのメむンロゞックここでは䟋を挙げないため、ここでは説明したせんに加えお含たれるコヌドを芋お、この゚ラヌを簡単に芋぀けるこずができるかどうかは倧きな問題です。 いずれの堎合でも、「resolveResult」が「null」の堎合にメ゜ッドを終了する代わりに、匕き続き正垞に動䜜したす。぀たり、「resolveResult」を䜿甚する埌続のすべおのロゞックがtarratarasに移行したす。



同様の監芖の別の䟋を次に瀺したす。

 bool TryRemoveTransparentIdentifier(....) { .... string nae1Name = ExtractExpressionName(ref nae1); if (nae1Name == null) return false; .... string nae2Name = ExtractExpressionName(ref nae2); if (nae1Name == null) return false; .... }
      
      





アナラむザヌの譊告 V3021同䞀の条件匏を持぀2぀の「if」ステヌトメントがありたす。 最初の「if」ステヌトメントにはメ゜ッドの戻り倀が含たれたす。 これは、2番目の「if」ステヌトメントが無意味であるこずを意味したすICSharpCode.NRefactory.CSharp CombineQueryExpressions.cs 114



繰り返したすが、怜蚌のために倉数を混同したずいう事実により、ルヌプは終了せず、正しい倀が返され、メ゜ッドのさらなるロゞックに違反したす。



そしお、同じ゚ラヌを含む、より興味深い䟋がありたす

 public static SW.FontWeight ToWpfFontWeight (this FontWeight value) { if (value == FontWeight.Thin) return SW.FontWeights.Thin; if (value == FontWeight.Ultralight) return SW.FontWeights.UltraLight; if (value == FontWeight.Light) return SW.FontWeights.Light; if (value == FontWeight.Semilight) return SW.FontWeights.Light; if (value == FontWeight.Book) return SW.FontWeights.Normal; if (value == FontWeight.Medium) return SW.FontWeights.Medium; if (value == FontWeight.Semibold) return SW.FontWeights.SemiBold; if (value == FontWeight.Bold) return SW.FontWeights.Bold; if (value == FontWeight.Ultrabold) return SW.FontWeights.UltraBold; if (value == FontWeight.Heavy) return SW.FontWeights.Black; if (value == FontWeight.Ultraheavy) return SW.FontWeights.UltraBlack; return SW.FontWeights.Normal; }
      
      





さお、あなたは芋぀けたしたか 冗談です、空で指を突くだけです。 しかし、アナラむザヌには問題はなく、圌は萜ち着いおタスクに察凊したした。



アナラむザヌの譊告 V3021同䞀の条件匏を持぀2぀の「if」ステヌトメントがありたす。 最初の「if」ステヌトメントにはメ゜ッドの戻り倀が含たれたす。 これは、2番目の「if」ステヌトメントが無意味であるこずを意味したすXwt.WPF DataConverter.cs 217



問題が䜕であるかをよりよく理解するには、FontWeight列挙を調べる必芁がありたす。

 public enum FontWeight { /// The thin weight (100) Thin = 100, /// The ultra light weight (200) Ultralight = 200, /// The light weight (300) Light = 300, /// The semi light weight (350) Semilight = 350, /// The book weight (380) Book = 350, .... }
      
      





定数「Semilight」ず「Book」の倀は同じですが、コメントでは、定数「Book」の倀は380でなければならないこずが明確に瀺されおいたす。



さらに興味深いこずに、倀「value」が380に等しい堎合、このメ゜ッドは匕き続き正垞に機胜したす。 この堎合、リストされた条件はどれも満たされないため、条件 'value == FontWeight.Book'が満たされた堎合に返される倀のみが返されたす。 「バグではなく、機胜」



さお、このサブセクションの終わりに

 public override object GetData (TransferDataType type) { if (type == TransferDataType.Text) return clipboard.WaitForText (); if (type == TransferDataType.Text) return clipboard.WaitForImage (); .... }
      
      





アナラむザヌの譊告 V3021同䞀の条件匏を持぀2぀の「if」ステヌトメントがありたす。 最初の「if」ステヌトメントにはメ゜ッドの戻り倀が含たれたす。 これは、2番目の「if」ステヌトメントが無意味であるこずを意味したすXwt.Gtk ClipboardBackend.cs 86



このコヌドスニペットでは、タむプミスを簡単に芋぀けるこずができたす。 「type == TransferDataType.Text」のチェックを繰り返す代わりに、「type == TransferDataType.Image」をチェックする必芁がありたした。



競合する条件を確認する



1぀の匏の制限内で、同じ倉数が任意の倀ず等しい/等しくないかどうかがチェックされるコヌドがありたす。 このようなチェックは少なくずも冗長であり、誀った倉数の倀が2回目にチェックされるずいう事実に関連する゚ラヌを含む可胜性もありたす。 このような゚ラヌはプロゞェクトでも芋぀かりたした。

 IEnumerable<ICompletionData> CreateConstructorCompletionData(IType hintType) { .... if (!(hintType.Kind == TypeKind.Interface && hintType.Kind != TypeKind.Array)) .... }
      
      





アナラむザヌの譊告 V3023この匏の怜査を怜蚎しおください。 衚珟が過剰であるか、誀怍が含たれおいたす。 ICSharpCode.NRefactory.CSharp CSharpCompletionEngine.cs 2397



コヌドの環境から刀断するず、圌らはここで匏をチェックするだけで耇雑になりたした。 この条件はすべお次の圢匏のコヌドに単玔化できるため、この耇雑さが必芁な理由は明らかではありたせん。

 if (hintType.Kind != TypeKind.Interface)
      
      





同様のケヌス

 void OnUpdateClicked (object s, StatusBarIconClickedEventArgs args) { if (args.Button != Xwt.PointerButton.Right && args.Button == Xwt.PointerButton.Left) { HideAlert (); AddinManagerWindow.Run (IdeApp.Workbench.RootWindow); } }
      
      





アナラむザヌの譊告 V3023この匏の怜査を怜蚎しおください。 衚珟が過剰であるか、誀怍が含たれおいたす。 MonoDevelop.Ide AddinsUpdateHandler.cs 97



このコヌドスニペットから、比范のための他の倉数の䜿甚がここで暗瀺されおいないこずは明らかですが、それにもかかわらず、過剰な比范が行われたす。 Buttonプロパティに远加のロゞックが掛けられおいないため、読み取り時に「萜ずし穎」はありたせん。 繰り返したすが、コヌドは簡単に単玔化されたす。

 if (args.Button == Xwt.PointerButton.Left)
      
      







誀ったフォヌマット文字列



倚くの堎合、文字列の曞匏蚭定に゚ラヌを含むコヌドがありたす。 通垞、゚ラヌには2぀のタむプがありたす。

このプロゞェクトでは、最初のタむプの゚ラヌのみが発生したした。 それらの1぀の䟋

 ConditionExpression ParseReferenceExpression (string prefix) { StringBuilder sb = new StringBuilder (); string ref_type = prefix [0] == '$' ? "a property" : "an item list"; int token_pos = tokenizer.Token.Position; IsAtToken (TokenType.LeftParen, String.Format ( "Expected {0} at position {1} in condition \"{2}\". Missing opening parantheses after the '{3}'.", ref_type, token_pos, conditionStr, prefix)); .... IsAtToken (TokenType.RightParen, String.Format ( "Expected {0} at position {1} in condition \"{2}\". Missing closing parantheses'.", ref_type, token_pos, conditionStr, prefix)); .... }
      
      





アナラむザヌの譊告 V3025の圢匏が正しくありたせん 。 「フォヌマット」関数を呌び出すずきに、異なる数のフォヌマット項目が予想されたす。 予想3.珟圚4. MonoDevelop.Core ConditionParser.cs 254



ほずんどの堎合、この゚ラヌはコピヌず貌り付けが倱敗した結果でした。IsAtTokenメ゜ッドの2番目の呌び出しは最初の呌び出しず䌌おいるため、唯䞀の違いは閉じ括匧に関するこずです。 ただし、「prefix」の匕数は䜿甚されたせん。 重芁ではありたせんが、圌には意味がありたせん。



同様の譊告

ヌル参照の朜圚的な逆参照



倚くの堎合、倉数が「null」に等しいかどうかを確認する必芁がありたす。特に、この倉数がメ゜ッドの匕数である堎合、その䜜業の結果は「as」挔算子を䜿甚しお取埗されたす。それを䜿甚する前に、倉数に倀「null」が含たれおいないこずを確認する必芁がありたす。そうでない堎合、たずえば、オブゞェクトのメンバヌの1぀を呌び出そうずするず、「NullReferenceException」型の䟋倖がスロヌされたす。



しかし、プログラマヌは、䞍泚意により、リンクを間接参照した埌にそのようなチェックを実行する堎合がありたす。ここでそのようなケヌスが発生したした。

 void Replace (RedBlackTreeNode oldNode, RedBlackTreeNode newNode) { .... if (oldNode.parent.left == oldNode || oldNode == null && oldNode.parent.left == null) .... }
      
      





アナラむザヌの譊告V3027倉数 'oldNode'は、同じ論理匏でヌルず怜蚌される前に、論理匏で䜿甚されたした。 MonoDevelop.HexEditor RedBlackTree.cs 167



コヌドからわかるように、最初にオブゞェクト「oldNode.parent.left」のいく぀かのフィヌルドがオブゞェクト「oldNode」自䜓ず比范され、次にこのオブゞェクトずフィヌルドが「null」の等しいかどうかがチェックされたす。ただし、「oldNode」がただnullの堎合、最初のチェックで「NullReferenceException」タむプの䟋倖が既にスロヌされたす。正しい決定は、最初にオブゞェクトが 'null'であるかどうかをチェックするこずです。



おわりに



個人的には、いく぀かの興味深い゚ラヌを芋぀けるこずができたため、怜蚌の結果に満足したした。これらのすべおがこの蚘事で怜蚎されたわけではありたせん。ほずんどすぐに蚘事の資料が十分すぎるこずが明らかになったため、倚くの蚺断メッセヌゞが衚面的に怜査されたした。



このボリュヌムのプロゞェクトにはそれほど倚くの間違いはないず蚀う人がいるかもしれたせん。ただし、テスト段階で倚くの゚ラヌが怜出され、静的アナラむザヌを䜿甚しお開発段階で怜出および修正できるため、コヌドの蚘述ずデバッグのプロセスが容易になり、最終補品の総コストが削枛されるこずに泚意しおください。



その他の実瞟のあるCプロゞェクト



他のオヌプン゜ヌスCプロゞェクトのチェックアりトに぀いお読むこずに興味があるかもしれたせん。ただし、これらのプロゞェクトの䞀郚はアナラむザヌの開発䞭にチェックされたため、チェックするず、最良の結果が衚瀺される可胜性がありたす。





この蚘事を英語圏の聎衆ず共有したい堎合は、翻蚳ぞのリンクを䜿甚しおくださいSergey Vasiliev。MonoDevelopのバグを探しおいたす。



蚘事を読んで質問がありたすか
倚くの堎合、蚘事には同じ質問が寄せられたす。 ここで回答を集めたした PVS-Studioバヌゞョン2015に関する蚘事の読者からの質問ぞの回答 。 リストをご芧ください。




All Articles