Linter est un plugin de compilateur d'analyse statique Scala qui ajoute des vérifications de compilation pour divers bogues, inefficacités et problèmes de style possibles.
Veuillez aider à soutenir le développement de Linter.
Ajoutez Linter à votre projet en ajoutant cette ligne à votre build.sbt :
addCompilerPlugin("org.psywerx.hairyfotr" %% "linter" % "0.1.17")
Si vous souhaitez toujours avoir les derniers modifications, des instantanés sont également disponibles:
resolvers += Resolver.sonatypeRepo("snapshots")
addCompilerPlugin("org.psywerx.hairyfotr" %% "linter" % "0.1-SNAPSHOT")
Ajoutez Linter à votre projet en mettant à jour votre pom.xml avec une section "CompilerPlugin".
<configuration>
<compilerPlugins>
<compilerPlugin>
<groupId>org.psywerx.hairyfotr</groupId>
<artifactId>linter_2.11</artifactId>
<version>0.1.17</version>
</compilerPlugin>
</compilerPlugins>
</configuration>
Utilisez votre méthode de construction habituelle et le plugin Jenkins Avernings.
Une autre façon possible d'utiliser Linter est de télécharger manuellement et d'utiliser ces pots instantanés:
Scala 2.12, Scala 2.11, Scala 2.10,
Scala 2.9.3 (obsolète)
terminal:
scalac -Xplugin:<path-to-linter-jar>.jar ...
sbt: (in build.sbt)
scalacOptions += "-Xplugin:<path-to-linter-jar>.jar"
maven: (in pom.xml inside scala-maven-plugin configuration)
<configuration>
<args>
<arg>-Xplugin:<path-to-linter-jar>.jar</arg>
</args>
</configuration>
Remarque: Si vous avez des instructions pour un autre outil de construction ou IDE, veuillez faire une demande de traction.
Pour désactiver l'affichage des noms de vérification dans la sortie, utilisez le commutateur PrintWarningNames:
scalacOptions += "-P:linter:printWarningNames:false"
Remarque: réglé sur true par défaut depuis la version 0.1.17
Les chèques peuvent être désactivés à l'aide d'une liste plus séparée des noms de contrôle:
scalacOptions += "-P:linter:disable:UseHypot+CloseSourceFile+OptionOfOption"
Ou seules des vérifications spécifiques peuvent être activées en utilisant:
scalacOptions += "-P:linter:enable-only:UseHypot+CloseSourceFile+OptionOfOption"
Si vous croyez que certains avertissements sont de faux positifs, vous pouvez les ignorer avec un commentaire de code:
scala > val x = math.pow( 5 , 1 / 3d ) + 1 / 0 // linter:ignore UseCbrt,DivideByZero // ignores UseCbrt and DivideByZero
< console > : 8 : warning : Integer division detected in an expression assigned to a floating point variable.
math.pow( 5 , 1 / 3d ) + 1 / 0 // linter:ignore UseCbrt,DivideByZero // ignores UseCbrt and DivideByZero
^
scala > val x = math.pow( 5 , 1 / 3d ) + 1 / 0 // linter:ignore // ignores all warningsRemarque: veuillez envisager de signaler les faux positifs afin qu'ils puissent être supprimés dans les futures versions.
UNEXTENDENDENSEALDTRAIT, IMBEALELYELDEquality, Uselog1p, Uselog10, useExpm1, usehypot, usecbrt, useqrt, suspectPow, useExp, useAbsNotsQrtsquare Reflexiveassignment, CloseSourcefile, Javaconverters, contenstypemimismatch, nombre IntanceOf, PatternMatchConstant, préfériftoboolianmatch, identiques-casebodies, identiques-casecondes, réflexiveComparison IdenticalIfelSEcondition, MergeneSesifs, variaBleassignedUnusedValue, malformedSwap, identiqueCcondition, identique statements, indexingwithnegativember, optionofoption, indéirableinginging UseOptiongetorelSe, useExistSnotFindisDefined, useExistsNotFilteRisempty, useFindnotFilterhead, useContainsNotexistSeSeSe Usemapnotflatmap, usefilternotflatmap, evitOptionMethod, transformnotmap, duplicateKeyInmap, inefficicientoflistSize, autrefois les stades en ouvrants PasspartialFunctionDadirectly, UnimpliterDering, RegexWarning, InvariantCondition, DecomposingEmptyCollection, Invariaritextrema, UncesentaryMethodcall, ProduceSemptyCollection, OperationwaysProduduceszero, Modulobyone, DivideByone, Dividebyzo Invalidparamtorandomnextint, inutiliséforloopiteratorValue, stringMultiplicationByNonPositive, probable indiquexoutofbounds, inutilesyreturn, invariantreturn, inutilisé, insensible, invalence, non-disposition, non-étage, non-étage, étalon, étalon innoce Unsefabeabs, typeTotype, videstringInterpolator, improbingytoString, UnhrownException, suspectmatches, passnullinTooption, ifdowhile, usetakerightNumericRange, useinitnoververseTailRewe UseHeadOptionNotif, uselastOptionNotif, usezipwithindexnotzipIndices, usegetorelSenotpatmatch, useorelSenotpatMatch, useOptionflatMapNotPatMatch, useOptionMapNotPatMatch, useOptionflattenNotpatmatch, useOptionNoEachNotpatmat UseOptioniSempTyNotPatMatch, useOptionForAllNotPatMatch, useOptionExistsNotpatMatch
Les liens ci-dessus passent actuellement au test pour ce chèque.
Un autre fichier à vérifier est Warning.scala
scala > if (a == 10 || b == 10 ) 0 else if (a == 20 && b == 10 ) 1 else 2
< console > : 10 : warning : This condition has appeared earlier in the if - else chain and will never hold here.
if (a == 10 || b == 10 ) 0 else if (a == 20 && b == 10 ) 1 else 2
^ scala > if (b > 4 ) ( 2 ,a) else ( 2 ,a)
< console > : 9 : warning : If statement branches have the same structure.
if (b > 4 ) ( 2 ,a) else ( 2 ,a)
^ scala > if (a == b) true else false
< console > : 9 : warning : Remove the if expression and use the condition directly.
if (a == b) true else false
^scala > (x,y) match { case (a, 5 ) if a > 5 => 0 case (c, 5 ) if c > 5 => 1 }
< console > : 10 : warning : Identical case condition detected above. This case will never match .
(x,y) match { case (a, 5 ) if a > 5 => 0 case (c, 5 ) if c > 5 => 1 }
^ scala > a match { case 3 => " hello " case 4 => " hello " case 5 => " hello " case _ => " how low " }
< console > : 9 : warning : Bodies of 3 neighbouring cases are identical and could be merged.
a match { case 3 => " hello " case 4 => " hello " case 5 => " hello " case _ => " how low " }
^ scala > bool match { case true => 0 case false => 1 }
< console > : 9 : warning : Pattern matching on Boolean is probably better written as an if statement.
a match { case true => 0 case false => 1 }
^scala > for (i <- 10 to 20 ) { if (i > 20 ) " " }
< console > : 8 : warning : This condition will never hold.
for (i <- 10 to 20 ) { if (i > 20 ) " " }
^ scala > for (i <- 1 to 10 ) { 1 / (i - 1 ) }
< console > : 8 : warning : You will likely divide by zero here.
for (i <- 1 to 10 ) { 1 / (i - 1 ) }
^ scala > { val a = List ( 1 , 2 , 3 ); for (i <- 1 to 10 ) { println(a(i)) } }
< console > : 8 : warning : You will likely use a too large index.
{ val a = List ( 1 , 2 , 3 ); for (i <- 1 to 10 ) { println(a(i)) } }
^scala > for (i <- 10 to 20 ) { if (i.toString.length == 3 ) " " }
< console > : 8 : warning : This condition will never hold.
for (i <- 10 to 20 ) { if (i.toString.length == 3 ) " " }
^ scala > { val a = " hello " + util. Random .nextString( 10 ) + " world " + util. Random .nextString( 10 ) + " ! " ; if (a contains " world " ) " " ; if (a startsWith " hell " ) " " }
< console > : 8 : warning : This contains will always returns the same value : true
{ val a = " hello " + util. Random .nextString( 10 ) + " world " + util. Random .nextString( 10 ) + " ! " ; if (a contains " world " ) " " ; if (a startsWith " hell " ) " " }
^
< console > : 8 : warning : This startsWith always returns the same value : true
{ val a = " hello " + util. Random .nextString( 10 ) + " world " + util. Random .nextString( 10 ) + " ! " ; if (a contains " world " ) " " ; if (a startsWith " hell " ) " " }
^ scala > str.replaceAll( " ? " , " . " )
< console > : 9 : warning : Regex pattern syntax error : Dangling meta character '?'
str.replaceAll( " ? " , " . " )
^log(1 + a) au lieu de log1p(a) scala > math.log( 1d + a)
< console > : 9 : warning : Use math.log1p(x), instead of math.log( 1 + x) for added accuracy when x is near 0 .
math.log( 1 + a)
^ scala > BigDecimal ( 0.555555555555555555555555555 )
< console > : 8 : warning : Possible loss of precision. Literal cannot be represented exactly by Double . ( 0.555555555555555555555555555 != 0.5555555555555556 )
BigDecimal ( 0.555555555555555555555555555 )
^scala > val a = Some ( List ( 1 , 2 , 3 )); if (a.size > 3 ) " "
< console > : 9 : warning : Did you mean to take the size of the collection inside the Option ?
if (a.size > 3 ) " "
^ scala > if (strOption.isDefined) strOption.get else " "
< console > : 9 : warning : Use strOption.getOrElse(...) instead of if (strOption.isDefined) strOption.get else ...
if (strOption.isDefined) strOption.get else " "
^scala > List ( 1 , 2 , 3 , 4 ).find(x => x % 2 == 0 ).isDefined
< console > : 8 : warning : Use col.exists(...) instead of col.find(...).isDefined.
List ( 1 , 2 , 3 , 4 ).find(x => x % 2 == 0 ).isDefined
^ scala > List ( 1 , 2 , 3 , 4 ).flatMap(x => if (x % 2 == 0 ) List (x) else Nil )
< console > : 8 : warning : Use col.filter(x => condition) instead of col.flatMap(x => if (condition) ... else ...).
List ( 1 , 2 , 3 , 4 ).flatMap(x => if (x % 2 == 0 ) List (x) else Nil )
^scala > def func ( b : Int , c : String , d : String ) = { println(b); b + c }
< console > : 7 : warning : Parameter d is not used in method func
def func ( b : Int , c : String , d : String ) = { println(b); b + c }
^ contains scala > List ( 1 , 2 , 3 ).contains( " 4 " )
< console > : 29 : warning : List [ Int ].contains( String ) will probably return false , since the collection and target element are of unrelated types.
List ( 1 , 2 , 3 ).contains( " 4 " )
^ == scala > Nil == None
< console > : 29 : warning : Comparing with == on instances of unrelated types (scala.collection.immutable. Nil . type , None . type ) will probably return false .
Nil == None
^ N'hésitez pas à ajouter vos propres idées ou à les implémenter. Tirez les demandes de bienvenue!
var a = 4; { val a = 5 } )func("arg1", force = true) )Listes de règles à partir d'autres outils d'analyse statique: