Statyczna analiza kodu dla języka Scala w SBT - część 1.

5 minut(y)

Statyczna analiza programu to analiza oprogramowania komputerowego wykonywanego bez faktycznego uruchamiania programów, w przeciwieństwie do analizy dynamicznej, która jest analizą wykonywaną na programach podczas ich wykonywania.

Termin ten jest zwykle stosowany do analizy wykonywanej przez zautomatyzowane narzędzie, analiza wykonywana przez człowieka jest nazywana przeglądem kodu.

Za wikipedią.

Jest to moja ulubiona część konfigurowania projektu, ponieważ odpowiednio dobrany zestaw wtyczek do statycznej analizy kodu potrafi znacząco skrócić czas potrzebny do zrobienia przeglądu kodu.

Wtyczki modyfikujące kod źródłowy

Z powodu ogromu różnego rodzaju wtyczek do statycznej analizy kodu dla języka Scala w tym poście skupię się tylko na wtyczkach modyfikujących kod źródłowy.

sbt-scalariform - sbt plugin adding support for source code formatting using Scalariform

sbt-scalariform to wtyczka sbt dodająca obsługę formatowania kodu źródłowego przy użyciu formatera kodu Scalariform

Dodajemy scalariform do pliku projektu/plugins.sbt:

addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.8.2")

Konfiguracja jest możliwa za pomocą:

  • zmiennej scalariformPreferences w pliku build.sbt
  • pliku .scalariform.conf

Formatowanie kodu jest wykonywane automatycznie podczas kompilacji:

sbt compile test:compile it:compile

Scalafmt - Code formatter for Scala

Scalafmt to formater kodu dla języka Scala.

Dodajemy scalafmt do pliku projektu/plugins.sbt:

addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "1.5.1")

Konfiguracja jest możliwa za pomocą pliku .scalafmt.conf, np.:

style=IntelliJ
maxColumn=80

Formatowanie domyślnie nie wykonuje się podczas kompilacji. Aby sformatować kod należy wykonać:

sbt scalafmtSbt scalafmt test:scalafmt it:scalafmt

Kolejno formatowany jest plik build.sbt, kod produkcyjny, testy jednostkowe i testy integracyjne.

Możliwe jest także tylko sprawdzenie czy kod jest sformatowany poprawnie za pomocą polecenia:

sbt scalafmtSbtCheck scalafmtCheck test:scalafmtCheck it:scalafmtCheck

Scalafix - Refactoring and linting tool for Scala

Scalafix to narzędzie do analizy statycznej kodu w języku Scala. Jest to jedyne narzędzie, które potrafi znalezione błędy poprawić.

Dodajemy scalafix do pliku projektu/plugins.sbt:

addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.0")

W pliku build.sbt dodajemy następujące linie:

  addCompilerPlugin(scalafixSemanticdb)
  scalacOptions ++= Seq(
    //"-Xfatal-warnings",   // it should be disabled for scalafix
     "-Ywarn-adapted-args", // for NoAutoTupling
     "-Ywarn-unused",       // for RemoveUnused
  )

Konfiguracja jest możliwa za pomocą pliku .scalafix.conf. Poniższa konfiguracja włącza wszystkie istniejące obecnie reguły:

rules = [

// Semantic Rules - Reguły semantyczne
  NoAutoTupling
  RemoveUnused

// Syntactic Rules - Reguły składniowe
  DisableSyntax
  LeakingImplicitClassVal
  NoValInForComprehension
  ProcedureSyntax
]

DisableSyntax.noVars = true
DisableSyntax.noThrows = true
DisableSyntax.noNulls = true
DisableSyntax.noReturns = true
DisableSyntax.noAsInstanceOf = true
DisableSyntax.noIsInstanceOf = true
DisableSyntax.noXml = true
DisableSyntax.noDefaultArgs = true
DisableSyntax.noFinalVal = true
DisableSyntax.noFinalize = true
DisableSyntax.noValPatterns = true
DisableSyntax.noUniversalEquality = true
DisableSyntax.noUniversalEqualityMessage = "== is unsafe since it allows comparing two unrelated types"
DisableSyntax.regex = []

Aby naprawić kod należy wykonać:

sbt scalafix test:scalafix it:scalafix

Kolejno naprawiany jest kod produkcyjny, testy jednostkowe i testy integracyjne.

Możliwe jest także tylko sprawdzenie czy kod nie zawiera błędów za pomocą polecenia:

sbt 'scalafix --check' 'test:scalafix --check' 'it:scalafix --check'

Podsumowanie

Wszystkie wymienione wyżej wtyczki dodałem do projektu resentiment.

Na chwilę obecna moje polecenie do zbudowania tego projektu to:

sbt clean compile test:compile it:compile re/test && \
sbt coverage reJVM/test reJS/test && \
sbt coverageReport

Wcześniej jednak powinienem wywołać polecenie refaktoryzującą i formatującą kod:

sbt scalafix test:scalafix it:scalafix && \
sbt scalafmtSbt scalafmt test:scalafmt it:scalafmt

Ewentualnie, gdy robię przegląd kodu mogę sprawdzić czy kod jest poprawny za pomocą polecenia:

sbt 'scalafix --check' 'test:scalafix --check' 'it:scalafix --check' && \
sbt scalafmtSbtCheck scalafmtCheck test:scalafmtCheck it:scalafmtCheck

Niestety ponieważ w testach używam porównania == musiałem zakomentować linię DisableSyntax.noUniversalEquality w pliku .scalafix.conf. Problem ten rozwiąże w następnym poście.

Zostaw komentarz