ErrorProne.NET. Część 1

Dawno już miałem zamiar zrobić analizator, który pomógłby w przechwytywaniu błędów, w różnym stopniu specyficznych dla platformy .NET. Wiele takich błędów świetnie przechwytuje R#, ale przecież zawsze chce się czegoś swojego, prawda? Poza tym, analizatory Roslyn ulegają bezszwowej integracji do procesu kompilacji, mogą być używane w nocy (*) i mogą zawierać reguły specyficzne dla Twojego produktu.

sty 12, 2017 1813
Dawno już miałem zamiar zrobić analizator, który pomógłby w przechwytywaniu błędów, w różnym stopniu specyficznych dla platformy .NET. Wiele takich błędów świetnie przechwytuje R#, ale przecież zawsze chce się czegoś swojego, prawda? Poza tym, analizatory Roslyn ulegają bezszwowej integracji do procesu kompilacji, mogą być używane w nocy (*) i mogą zawierać reguły specyficzne dla Twojego produktu.

Tak więc, bazując na ideach z R# i z podobnej biblioteki dla Java od Google'a pod nazwą Error Prone, zabrałem się do roboty. Poniżej przedstawiam pierwszą część rezultatów mojej pracy.

Wywołanie metod pure

Brak <obserwacji> wyników wywołania metody pure jest jednym z najczęstszych błędów zachodzących w trakcie testów lokalnych. Problem polega na tym, że po prostu czytając kod, trudno z wyprzedzeniem powiedzieć czy wywołanie someCollection.Union(anotherCollection) jest <pure> i zwraca nową kolekcję czy zmienia oryginalną.

Oto przykłady działania tej reguły:

ErrorProne1.jpg

Ta reguła uwzględnia szereg znanych typów z BCL, które są gwarantownie niemodyfikowalne i zawierają wyłącznie reguły <pure>. Uwzględnia także atrybut PureAttribute, którym możesz zaznaczyć dowolną metodę. Dodałem też parę heurystyk: wszystkie typy o prefiksie Immutable uważa się za niemodyfikowalne, wszystkie metody o prefiksie With, który zwraca typ pierwszego argumentu oraz wszystkie metody rozszerzające typy niemodyfikowalne są pure. Z tą regułą zdarza się błąd false-positive, ale nie jest ich wiele, a korzyści są wystarczające.

Niestety, na razie nie wiadomo, w jaki sposób wykorzystać istniejące adnotacje "czystości" z biblioteki Code Contracts i trzeba się zastanowić, jak zrobić rozwiązanie bardziej rozszerzalnym. Chociaż nawet teraz reguła wynalazła kilkanaście mniejszych błędów w kodzie mojego projektu (wszystkie były w testach i kodzie wtórnym, a jednak).

Tworzenie obiektów bez zapisywania wartości

Szczególnym przypadkiem poprzedniej reguły jest reguła, która szuka wywołań konstruktorów obiektów, nie używając wyniku typu new SomeObject();

Niestety, nie można wydawać ostrzeżeń dla każdego niezależnego wywołania new, ponieważ ludzie często robią straszne rzeczy w postaci jakichś operacji z efektami ubocznymi w konstruktorach. Chociaż w niektórych przypadkach można z pewnością powiedzieć, że konstruktor nie ma żadnych efektów ubocznych. Dotyczy to wywołań konstruktorów typów wartości domyślnych, kolekcji, obiektów prymitywnych oraz typów niemodyfikowalnych.

ErrorProne2.jpg

Istnieje szczególny przypadek tej reguły, który generuje błąd podczas tworzenia obiektu wyjątku:

ErrorProne3.jpg

Formatowanie łańcuchów

Jeszcze jeden popularny rodzaj błędów stanowią niewłaściwe argumenty podczas wywołania string.Format i podobnych metod. Tak, częstotliwość użycia string.Format znacznie spadła po ukazaniu się string interpolation w C# 6.0, ale jest sporo przestarzałego kodu, a łańcuchy formatu są często używane w innych miejscach.

ErrorProne.NET zawiera trzy reguły:
  • Argumenty nieznane w łańcuchu formatu
  • Argumenty zbędne, których nie używa się w łańcuchu formatu
  • Nieprawidłowy łańcuch formatu

(Owszem, drugi problem nie występuje podczas wykonania i nie powoduje generacji wyjątku FormatException, jednak, IMHO, to może tylko ukryć błędy i może występować w praktyce nawet częściej niż pozostałe opcje. Właśnie ta reguła pomogła w znalezieniu jawnego buga w kodzie Roslyn. Oto ticket dla zainteresowanych).

Argumenty nieznane:

ErrorProne4.jpg

Argumnety zbędne:

ErrorProne5.jpg

Nieprawidłowy łańcuch formatu:

ErrorProne6.jpg

Istnieje także odrębna reguła weryfikująca wzorzec wyrażenia regularnego:

ErrorProne7.jpg

Zwróć uwagę, że reguła uwzględnia atrybut JetBrains.Annotations.StringFormatMethodAttribute, który możesz otrzymać poprzez NuGet albo po prostu stworzyć taki atrybut w swoim własnym kodzie (używany jest taki sobie duck typing).

-----------------

(*) Tak, wiem, że istnieje ReSharper Command Line Tools.

Wnioski

Zdaję sobie sprawę, że na rynku jest sporo podobnych narzędzi; trudno konkurować z R# czy analizatorami od PVS-Studio i nie miałem takiego celu. Po prostu zadanie jest bardzo ciekawe i chciałem zebrać w jednym miejscu cenne analizatory, które będą przydatne tu i teraz w moich własnych projektach oraz w projektach moich kolegów.

Tutaj znalazła się tylko część reguł wspieranych przez ErrorProne.NET, a więc ciąg dalszy nastąpi w drugiej części;)

Linki


Sergey Teplyakov
Specjalista w dziedzinach .Net, C++ i Architektury aplikacji

Udostępnij


Masz jeszcze jakieś pytania?
Skontaktuj się z nami
Thank you.
Your request has been received.