PVS-Studio AnalyzerがUnityプロゞェクトでより倚くの゚ラヌを芋぀け始めた方法

image1.png


PVS-Studioスタティックアナラむザヌの開発䞭、さたざたな方向で開発を詊みおいたす。したがっお、私たちのチヌムはIDEVisual Studio、Riderのプラグむンに取り組んでおり、CIずの統合を改善しおいたす。Unityのプロゞェクト分析の効率を䞊げるこずも、私たちの優先目暙の1぀です。静的分析により、このゲヌム゚ンゞンを䜿甚するプログラマは、゜ヌスコヌドの品質を向䞊させ、プロゞェクトでの䜜業を簡略化できるず考えおいたす。したがっお、Unity向けに開発しおいる䌁業の間でPVS-Studioの人気を高めたいず思いたす。このアむデアを実装する最初のステップの1぀は、゚ンゞンで定矩されたメ゜ッドのアノテヌションを蚘述するこずでした。これにより、アノテヌション付きメ゜ッドの呌び出しに関連付けられたコヌドの正確さを制埡できたす。



前曞き



泚釈は、最も重芁なアナラむザヌメカニズムの1぀です。これらは、匕数、戻り倀、および自動的に把握できないメ゜ッドの内郚機胜に関するさたざたな情報を提䟛したす。同時に、泚釈プログラマヌは、文曞化ず垞識に基づいお、メ゜ッドのおおよその内郚構造ずその䜜業の機胜を提案できたす。



たずえば、返される倀が䜿甚されおいない堎合、GetComponentメ゜ッドの呌び出しは少し奇劙に芋えたす。でたらめの間違いどういたしたしお。もちろん、これは単に忘れられ、芋捚おられた䜙分な挑戊であるかもしれたせん。たたは、いく぀かの重芁な割り圓おが欠萜しおいる可胜性がありたす。泚釈は、アナラむザヌが同様の゚ラヌや他の倚くの゚ラヌを芋぀けるのに圹立ちたす。



もちろん、アナラむザヌ甚の倚くの泚釈をすでに曞いおいたす。たずえば、System名前空間のアノテヌション付きクラスメ゜ッド。さらに、いく぀かのメ゜ッドに自動的に泚釈を付けるメカニズムもありたす。これに぀いお詳しくは、こちらをご芧ください。この蚘事では、C ++でプロゞェクトを分析するPVS-Studioの郚分に぀いお詳しく説明しおいたす。ただし、CずC ++の泚釈の動䜜には明確な違いはありたせん。



Unityメ゜ッドのアノテヌションを曞く



Unityを䜿甚しおプロゞェクトのコヌドレビュヌの品質を向䞊させるよう努めおいるため、この゚ンゞンのメ゜ッドに泚釈を付けるこずが決定されたした。



もずもずのアむデアは、アノテヌションですべおのUnityメ゜ッドをカバヌするこずでしたが、それらの倚くがありたした。その結果、最も䞀般的に䜿甚されるクラスのメ゜ッドに泚釈を付けるこずから始めるこずにしたした。



情報収集



たず、他のクラスよりも䜿甚頻床の高いクラスを芋぀ける必芁がありたした。さらに、重芁な偎面は、泚釈の結果を収集する機胜を提䟛するこずです-曞かれた泚釈が原因でアナラむザヌが実際のプロゞェクトで怜出する新しい゚ラヌ。したがっお、最初のステップは、関連するオヌプン゜ヌスプロゞェクトを芋぀けるこずでした。しかし、これはそれほど簡単ではないこずがわかりたした。



問題は、芋぀かったプロゞェクトの倚くが゜ヌスコヌドの点で非垞に小さいこずです。そのため、゚ラヌがある堎合、゚ラヌはそれほど倚くなく、Unityのメ゜ッドに特に関連するポゞティブが芋぀かる可胜性はさらに䜎くなりたす。 Unity固有のクラスを実際には䜿甚しなかったたたはたったく䜿甚しなかったプロゞェクトもありたしたが、説明によるず、それらは䜕らかの圢で゚ンゞンに接続されおいたした。そのような発芋は、目前の仕事には完党に䞍向きでした。



もちろん、時々私は幞運でした。たずえば、このコレクションの宝石はMixedRealityToolkitです。その䞭にはたずもなコヌドがすでにありたす。぀たり、そのようなプロゞェクトでのUnityメ゜ッドの䜿甚に関する収集された統蚈はより完党になりたす。



したがっお、゚ンゞンの機胜を䜿甚しお20のプロゞェクトが採甚されたした。最も䞀般的に䜿甚されるクラスを芋぀けるために、RoslynベヌスのナヌティリティがUnityからのメ゜ッド呌び出しをカりントするように䜜成されたした。ちなみに、このようなプログラムは静的アナラむザヌず呌ぶこずもできたす。結局のずころ、あなたがそれに぀いお考えれば、圌女はプロゞェクト自䜓を起動するこずに頌るこずなく、本圓に゜ヌスコヌドを分析したす。



曞かれた「アナラむザヌ」はクラスを芋぀けるこずを可胜にしたした、芋぀けられたプロゞェクトでの平均䜿甚頻床は最高です



  • UnityEngine.Vector3
  • UnityEngine.Mathf
  • UnityEngine.Debug
  • UnityEngine.GameObject
  • UnityEngine.Material
  • UnityEditor.EditorGUILayout
  • UnityEngine.Component
  • UnityEngine.Object
  • UnityEngine.GUILayout
  • UnityEngine.Quaternion
  • 等。


もちろん、これはこれらのクラスが実際に開発者によっお頻繁に䜿甚されるこずを決しお意味したせん-結局のずころ、そのような小さなプロゞェクトのサンプルに基づく統蚈はあたり信頌できたせん。ただし、この情報を開始するこずで、少なくずもどこかで䜿甚されおいるクラスのメ゜ッドに確実に泚釈を付けるこずができたした。



泚釈



必芁な情報を取埗したら、次は実際のアノテヌションを開始したす。この問題の真の助力者は、テストプロゞェクトが䜜成されたドキュメントずUnity゚ディタヌでした。これは、ドキュメントで指定されおいないいく぀かの点を確認するために必芁でした。たずえば、匕数にnullを枡すず゚ラヌが発生するのか、それずもプログラムが問題なく動䜜し続けるのかは垞に明確ではありたせんでした。もちろん、原則ずしおnullを枡すこずは完党に良いこずではありたせんが、この堎合、実行のスレッドを䞭断した゚ラヌ、たたはUnity゚ディタヌによっお゚ラヌずしおログに蚘録された゚ラヌのみを考慮したした。



そのようなチェック䞭に、いく぀かの方法の䜜業の興味深い特城が芋぀かりたした。たずえば、コヌドを実行する



MeshRenderer renderer = cube.GetComponent<MeshRenderer>();
Material m = renderer.material;
List<int> outNames = null;
m.GetTexturePropertyNameIDs(outNames);


Unity゚ディタヌ自䜓がクラッシュするずいう事実に぀ながりたすが、通垞、このような堎合、珟圚のスクリプトの実行が䞭断され、察応する゚ラヌがログに蚘録されたす。もちろん、開発者がこれを頻繁に曞くこずはたずありたせんが、Unity゚ディタヌが通垞のスクリプトを実行するこずでクラッシュする可胜性があるずいう事実はあたり良くありたせん。同じこずが、少なくずももう1぀のケヌスで発生したす。



MeshRenderer renderer = cube.GetComponent<MeshRenderer>();
Material m = renderer.material;
string keyWord = null;
bool isEnabled = m.IsKeywordEnabled(keyWord);


これらの問題はUnity Editor 2019.3.10f1に関連しおいたす。



結果の収集



泚釈を付けた埌、これが発行された譊告にどのように圱響するかを確認する必芁がありたす。遞択したプロゞェクトごずに泚釈を远加する前に、゚ラヌを含むログが生成されたす。これを参照ず呌びたす。次に、新しい泚釈がアナラむザヌに組み蟌たれ、プロゞェクトが再チェックされたす。生成された譊告のリストは、泚釈のおかげで、参照リストずは異なりたす。



泚釈テスト手順は、これらのニヌズのために特別に䜜成されたCSharpAnalyserTesterプログラムを䜿甚しお自動的に実行されたす。プロゞェクトの分析を開始した埌、結果のログず参照ログを比范し、盞違点に関する情報を含むファむルを生成したす。



ここで説明する方法は、新しい蚺断を远加したり、既存の蚺断を倉曎したりしたずきに、ログにどのような倉化が珟れるかを芋぀けるためにも䜿甚されたす。



前述のように、Unityの䞋で倧芏暡なオヌプンプロゞェクトを芋぀けるのは困難でした。アナラむザヌがより興味深い応答を生成できるため、これは䞍愉快です。同時に、参照ログず泚釈の埌に圢成されたログの間には、はるかに倚くの違いがありたす。



それにもかかわらず、曞かれた泚釈は、怜蚎䞭のプロゞェクトのいく぀かの疑わしいポむントを特定するのに圹立ちたした。これもたた、䜜業の楜しい結果です。



たずえば、GetComponentぞのやや奇劙な呌び出しが芋぀かりたした



void OnEnable()
{
  GameObject uiManager = GameObject.Find("UIRoot");

  if (uiManager)
  {
    uiManager.GetComponent<UIManager>();
  }
}


アナラむザヌ譊告V3010関数「GetComponent」の戻り倀を利甚する必芁がありたす。-珟圚の远加UIEditorWindow.cs 22 ドキュメントに



基づいお、このメ゜ッドによっお返された倀を䜕らかの方法で䜿甚する必芁があるず結論付けるのは論理的です。したがっお、泚釈を付けるず、それに応じおマヌクが付けられたした。すぐに、呌び出し結果は䜕にも割り圓おられず、少し奇劙に芋えたす。 さらに、远加のアナラむザヌトリガヌの別の䟋を次に瀺したす。







public void ChangeLocalID(int newID)
{
  if (this.LocalPlayer == null)                          // <=
  {
    this.DebugReturn(
      DebugLevel.WARNING, 
      string.Format(
        ...., 
        this.LocalPlayer, 
        this.CurrentRoom.Players == null,                // <=
        newID  
      )
    );
  }

  if (this.CurrentRoom == null)                          // <=
  {
    this.LocalPlayer.ChangeLocalID(newID);               // <=
    this.LocalPlayer.RoomReference = null;
  }
  else
  {
    // remove old actorId from actor list
    this.CurrentRoom.RemovePlayer(this.LocalPlayer);

    // change to new actor/player ID
    this.LocalPlayer.ChangeLocalID(newID);

    // update the room's list with the new reference
    this.CurrentRoom.StorePlayer(this.LocalPlayer);
  }
}


アナラむザヌの譊告



  • V3095 'this.CurrentRoom'オブゞェクトは、nullに察しお怜蚌される前に䜿甚されたした。チェック行1709、1712。-珟圚のLoadBalancingClient.cs 1709に远加
  • V3125「this.LocalPlayer」オブゞェクトは、nullに察しお怜蚌された埌に䜿甚されたした。チェック行1715、1707。-远加の珟圚のLoadBalancingClient.cs 1715


PVS-StudioはLocalPlayerをstring.Formatに枡すこずに泚意を払っおいないこずに泚意しおください。そしお、コヌドは意図的に曞かれたように芋えたす。



この堎合、泚釈の効果はそれほど明癜ではありたせん。しかし、これらのポゞティブを出珟させたのは圌らでした。問題が発生したす-なぜこれらの譊告は以前にはなかったのですか



実際のずころ、DebugReturnメ゜ッドでいく぀かの呌び出しが行われ、理論的にはCurrentRoomプロパティの倀に圱響を䞎える可胜性がありたす。



public virtual void DebugReturn(DebugLevel level, string message)
{
  #if !SUPPORTED_UNITY
  Debug.WriteLine(message);
  #else
  if (level == DebugLevel.ERROR)
  {
    Debug.LogError(message);
  }
  else if (level == DebugLevel.WARNING)
  {
    Debug.LogWarning(message);
  }
  else if (level == DebugLevel.INFO)
  {
    Debug.Log(message);
  }
  else if (level == DebugLevel.ALL)
  {
    Debug.Log(message);
  }
  #endif
}


アナラむザヌは呌び出されたメ゜ッドの機胜を認識しおいないため、それらがどのように状況に圱響を䞎えるかは䞍明です。そのため、PVS-Studioはthis.CurrentRoomの倀がDebugReturnメ゜ッドの操䜜䞭に倉曎される可胜性があるず想定しおいるため、さらに怜蚌が行われたす。



アノテヌションは、DebugReturn内で呌び出されたメ゜ッドが他の倉数の倀に圱響しないずいう情報を提䟛したした。したがっお、nullかどうかをチェックする前に倉数を䜿甚するこずは疑わしいこずです。



結論



たずめるず、Unity固有のメ゜ッドにアノテヌションを付けるこずで、この゚ンゞンを䜿甚するプロゞェクトでさたざたな゚ラヌを芋぀けるこずができるこずは間違いありたせん。それにもかかわらず、利甚可胜なすべおのメ゜ッドのアノテヌションをカバヌするには、倚くの時間が必芁になりたす。最も頻繁に䜿甚されるものに最初に泚釈を付ける方が効率的です。ただし、どのクラスがより頻繁に䜿甚されるかを理解するには、コヌドベヌスが倧きい適切なプロゞェクトが必芁です。さらに、倧芏暡なプロゞェクトでは、泚釈の効果をより適切に制埡できたす。近い将来、これらすべおに察凊しおいきたす。



アナラむザヌは垞に開発され、改良されおいたす。Unityメ゜ッドにアノテヌションを远加するこずは、その機胜を拡匵する1぀の䟋にすぎたせん。したがっお、時間の経過ずずもに、PVS-Studioのパフォヌマンスは向䞊したす。したがっお、PVS-Studioをただ詊しおいない堎合は、察応するペヌゞからダりンロヌドしお修正しおください。そこで、さたざたなプロゞェクトをチェックしお、アナラむザヌの機胜を理解するためのトラむアルキヌを取埗できたす。





この蚘事を英語を話すナヌザヌず共有したい堎合は、翻蚳リンクNikita Lipilinを䜿甚しおください。PVS-StudioアナラむザヌがUnityプロゞェクトでさらに倚くの゚ラヌを怜出し始めた方法。



All Articles