Linter เป็นปลั๊กอินคอมไพเลอร์การวิเคราะห์สกาล่าซึ่งเพิ่มการตรวจสอบเวลาคอมไพล์สำหรับข้อบกพร่องที่เป็นไปได้ความไร้ประสิทธิภาพและปัญหาสไตล์
โปรดช่วยสนับสนุนการพัฒนาของ Linter
เพิ่ม linter ลงในโครงการของคุณโดยเพิ่มบรรทัดนี้เข้ากับ build.sbt ของคุณ:
addCompilerPlugin("org.psywerx.hairyfotr" %% "linter" % "0.1.17")
หากคุณต้องการเปลี่ยนแปลงล่าสุดสแน็ปช็อตก็พร้อม:
resolvers += Resolver.sonatypeRepo("snapshots")
addCompilerPlugin("org.psywerx.hairyfotr" %% "linter" % "0.1-SNAPSHOT")
เพิ่ม linter ลงในโครงการของคุณโดยการอัปเดต pom.xml ของคุณด้วยส่วน "CompilerPlugin"
<configuration>
<compilerPlugins>
<compilerPlugin>
<groupId>org.psywerx.hairyfotr</groupId>
<artifactId>linter_2.11</artifactId>
<version>0.1.17</version>
</compilerPlugin>
</compilerPlugins>
</configuration>
ใช้วิธีการสร้างตามปกติของคุณและปลั๊กอินคำเตือนของเจนกินส์
อีกวิธีที่เป็นไปได้ในการใช้ Linter คือการดาวน์โหลดด้วยตนเองและใช้ขวดสแน็ปช็อตเหล่านี้:
Scala 2.12, Scala 2.11, Scala 2.10
Scala 2.9.3 (ล้าสมัย)
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>
หมายเหตุ: หากคุณมีคำแนะนำสำหรับเครื่องมือสร้างหรือ IDE อื่นโปรดทำการร้องขอการดึง
ในการปิดใช้งานการแสดงชื่อตรวจสอบในเอาต์พุตให้ใช้สวิตช์ PrintWarningNames:
scalacOptions += "-P:linter:printWarningNames:false"
หมายเหตุ: ตั้งค่าเป็นจริงตามค่าเริ่มต้นตั้งแต่เวอร์ชัน 0.1.17
การตรวจสอบสามารถปิดใช้งานได้โดยใช้รายการตรวจสอบที่คั่นด้วยบวก:
scalacOptions += "-P:linter:disable:UseHypot+CloseSourceFile+OptionOfOption"
หรือการตรวจสอบเฉพาะเท่านั้นที่สามารถเปิดใช้งานได้โดยใช้:
scalacOptions += "-P:linter:enable-only:UseHypot+CloseSourceFile+OptionOfOption"
หากคุณเชื่อว่าคำเตือนบางอย่างเป็นข้อดีที่ผิดพลาดคุณสามารถเพิกเฉยต่อความคิดเห็นของรหัส:
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 warningsหมายเหตุ: โปรดพิจารณาการรายงานผลบวกที่ผิดพลาดเพื่อให้สามารถลบออกในเวอร์ชันอนาคตได้
unextendedSealEdTrait, ความไม่เท่าเทียมกัน, uselog1p, uselog10, useExpm1, useHypot, usecbrt, useqrt, discikenpow, useExp, useabsnotsqrtsquare reflexiveassignment, closesourcefile, javaconverters, containstypemismatch, numberinstanceof, patternmatchconstant, preferiftobooleanmatch, amealcasebodies, enhilecaseconditions, reflexiveComparison, yodaconditions amealifelsecondition, mergenestedifs, variableassignedunusedValue, malformedswap, amealifcondication, amealystatements, indexingingnetwithnegativenumber, optiveofoption, undimearabletogentions การใช้งาน useoptiongetorelse, useexistsnotfindisdefined, useexistsnotnotfilterisempty, usefindnotfilterhead, usecontainnotexisterals, usequantifierfunnnotfold, usefuncnotreduce, usefuncnotfold, mergemaps, funcfirstthenmap usefilternotflatmap, ideoptionmethod, transformnotmap, duplicate keyInmap, ไม่มีผู้เล่นที่ไม่มีประสิทธิภาพ Regexwarning, Invariantcondition, DecomposeMposingEmpyCollection, Invariantextrema, ไม่จำเป็น, การผลิต, emptycollection, Operationalwaysproduceszero, modulobyone, divideByone, Dividebyzero, Zerodivideby StringMultiPlicationBynonPositive, น่าจะเป็นไปได้, ไม่จำเป็น, ไม่จำเป็น, ค่าคงที่, พารามิเตอร์ที่ไม่ได้ใช้, invalidStringFormat, InvalidStringConversion, ไม่จำเป็น UnthrownException, DisciquicMatches, Passingnullintooption, Ifdowhile, FloatingPointNumericRange, useinitnotNotReversetailReverse, usetakerightnotReversetakerEverse, uselastnotreversehead, useLASTOPTIONTIONTIONTIONTIONTIP usegetorelsenotpatmatch, useorelsenotpatmatch, useoptionflatmapnotpatmatch, useoptionmapnotpatmatch, useoptionflattennotpatmatch, useoptionforeachnotpatmatch, useoptionisdefinednotpatmatch, ใช้งาน
ลิงค์ด้านบนไปที่การทดสอบสำหรับการตรวจสอบนั้น
ไฟล์อื่นที่ต้องตรวจสอบคือ 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) แทน 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
^ อย่าลังเลที่จะเพิ่มความคิดของคุณเองหรือใช้สิ่งเหล่านี้ ยินดีต้อนรับการร้องขอ!
var a = 4; { val a = 5 } )func("arg1", force = true) )รายการกฎจากเครื่องมือวิเคราะห์แบบคงที่อื่น ๆ :