All Downloads are FREE. Search and download functionalities are using the official Maven repository.

airyfotr.linter_2.11.0.1.17.source-code.Warning.scala Maven / Gradle / Ivy

The newest version!
/**
 *   Copyright 2012 Foursquare Labs, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

package org.psywerx.hairyfotr

sealed abstract class Warning(val message: String) {
  def name: String = toString.takeWhile(_ != '(')
}

final object Warning {
  val All = Seq[Warning](
    AssigningOptionToNull,
    AvoidOptionCollectionSize,
    AvoidOptionMethod("", ""),
    AvoidOptionStringSize,
    BigDecimalNumberFormat,
    BigDecimalPrecisionLoss,
    CloseSourceFile,
    ContainsTypeMismatch("", ""),
    NumberInstanceOf(""),
    DecomposingEmptyCollection("", ""),
    ModuloByOne,
    DivideByOne,
    DivideByZero,
    ZeroDivideBy,
    DuplicateIfBranches,
    DuplicateKeyInMap,
    TransformNotMap(""),
    IdenticalCaseBodies(""),
    IdenticalCaseConditions,
    IdenticalIfCondition,
    IdenticalIfElseCondition,
    IdenticalStatements,
    IndexingWithNegativeNumber,
    InefficientUseOfListSize("", "", ""),
    IntDivisionAssignedToFloat,
    InvalidParamToRandomNextInt,
    InvalidStringConversion(""),
    InvalidStringFormat(""),
    InvariantCondition(true, ""),
    InvariantExtrema(true, true),
    InvariantReturn("", ""),
    JavaConverters,
    LikelyIndexOutOfBounds(""),
    MalformedSwap,
    MergeNestedIfs,
    OnceEvaluatedStatementsInBlockReturningFunction,
    OperationAlwaysProducesZero(""),
    OptionOfOption,
    PassPartialFunctionDirectly(""),
    UnitImplicitOrdering(""),
    PatternMatchConstant,
    PossibleLossOfPrecision(""),
    PreferIfToBooleanMatch,
    ProducesEmptyCollection,
    ReflexiveAssignment,
    ReflexiveComparison,
    RegexWarning("", true),
    StringMultiplicationByNonPositive,
    UndesirableTypeInference(""),
    UnextendedSealedTrait,
    UnlikelyEquality("lhs", "rhs", "=="),
    UnnecessaryMethodCall(""),
    UnnecessaryReturn,
    UnnecessaryStringIsEmpty,
    UnnecessaryStringNonEmpty,
    UnusedForLoopIteratorValue,
    UnusedParameter(Seq("unusedParameter"), "methodName"),
    UseHypot,
    UseLog1p,
    UseLog10,
    UseCbrt,
    UseSqrt,
    SuspiciousPow(0),
    UseExp,
    UseExpm1,
    UseAbsNotSqrtSquare,
    UseConditionDirectly(true),
    UseIfExpression(""),
    MergeMaps,
    FuncFirstThenMap(""),
    FilterFirstThenSort,
    UseMinOrMaxNotSort("", "", "", ""),
    UseMapNotFlatMap(""),
    UseFilterNotFlatMap(""),
    UseFlattenNotFilterOption("", "", ""),
    UseCountNotFilterLength("", ""),
    UseExistsNotCountCompare(""),
    UseGetOrElseOnOption(""),
    UseExistsNotFindIsDefined("", ("", false), ""),
    UseExistsNotFilterIsEmpty("", Nil, false, "", ""),
    UseFindNotFilterHead(""),
    UseContainsNotExistsEquals("", "", "", ""),
    UseQuantifierFuncNotFold("", "", ""),
    UseFuncNotReduce("", "", ""),
    UseFuncNotFold("", "", ""),
    UseFuncNotReverse("", ""),
    UseHeadNotApply(""),
    UseHeadOptionNotIf(""),
    UseInitNotReverseTailReverse(""),
    UseTakeRightNotReverseTakeReverse(""),
    UseLastNotApply(""),
    UseLastNotReverseHead("", true),
    UseLastOptionNotIf(""),
    UseIsNanNotNanComparison,
    UseIsNanNotSelfComparison,
    UseOptionGetOrElse("", ""),
    UseOptionOrNull("", ""),
    UseSignum,
    UseUntilNotToMinusOne,
    UseZipWithIndexNotZipIndices(""),
    VariableAssignedUnusedValue(""),
    WrapNullWithOption,
    YodaConditions,
    UnsafeAbs(""),
    TypeToType(""),
    EmptyStringInterpolator,
    UnlikelyToString(""),
    UnthrownException,
    SuspiciousMatches,
    IfDoWhile,
    FloatingPointNumericRange,
    UseGetOrElseNotPatMatch(""),
    UseOrElseNotPatMatch(""),
    UseOptionFlatMapNotPatMatch(""),
    UseOptionMapNotPatMatch(""),
    UseOptionFlattenNotPatMatch,
    UseOptionForeachNotPatMatch(""),
    UseOptionIsDefinedNotPatMatch,
    UseOptionIsEmptyNotPatMatch,
    UseOptionForallNotPatMatch(""),
    UseOptionExistsNotPatMatch("")
  )

  val AllNames = All.map(_.name)

  val NameToWarning: Map[String, Warning] = All.map(w => w.name -> w).toMap
}

case object UnextendedSealedTrait extends
  Warning("This sealed trait is never extended")
case class UnlikelyEquality(lhs: String, rhs: String, op: String) extends
  Warning(s"Comparing with $op on instances of unrelated types ${(lhs, rhs).toString}.")
case object UseLog1p extends
  Warning("Use math.log1p(x), instead of math.log(1 + x) for added accuracy when x is near 0.")
case object UseLog10 extends
  Warning("Use math.log10(x), instead of log(x)/log(10) for improved accuracy.")
case object UseExpm1 extends
  Warning("Use math.expm1(x), instead of math.exp(x) - 1 for added accuracy when x is near 0.")
case object UseHypot extends
  Warning("Use math.hypot(x, y), instead of sqrt(x^2 + y^2) for improved accuracy (but diminished performance).")
case object UseCbrt extends
  Warning("Use math.cbrt(x), instead of pow(x, 1/3) for improved accuracy and performance.")
case object UseSqrt extends
  Warning("Use math.sqrt(x), instead of pow(x, 1/2) for improved accuracy and performance.")
case class SuspiciousPow(pow: Double) extends
  Warning(s"This use of pow is suspicious, since the power is $pow.")
case object UseExp extends
  Warning("Use math.exp(x), instead of pow(E, x) for improved performance.")
case object UseAbsNotSqrtSquare extends
  Warning("Use math.abs(x) instead of math.sqrt(x^2).")
case object UseIsNanNotSelfComparison extends
  Warning("Use x.isNan instead of comparing x to itself.") // Turn all these x-es into varName
case object UseIsNanNotNanComparison extends
  Warning("Use x.isNan instead of comparing it to NaN (NaN == NaN is false, so this is always wrong).") // Error
case object UseSignum extends
  Warning("Did you mean to use the signum function here? (signum also avoids division by zero exceptions).")
case object BigDecimalNumberFormat extends
  Warning("This BigDecimal constructor will likely throw a NumberFormatException.") // Likely Exception
case object BigDecimalPrecisionLoss extends
  Warning("Possible loss of precision - use a string constant.")
case object ReflexiveAssignment extends
  Warning("Assigning a variable to itself?")
case object CloseSourceFile extends
  Warning("You should close the file stream after use. (Streams get garbage collected, but it is possible to open too many at once)")
case object JavaConverters extends
  Warning("Consider using the explicit collection.JavaConverters instead of implicit conversions in collection.JavaConversions.")
case class ContainsTypeMismatch(seqType: String, targetType: String) extends
  Warning(s"$seqType.contains($targetType) will probably return false, since the collection and target element are of unrelated types.")
case class NumberInstanceOf(tpe: String) extends
  Warning(s"Use to$tpe instead of asInstanceOf[$tpe].")
case object PatternMatchConstant extends
  Warning("Pattern matching on a constant value.")
case object PreferIfToBooleanMatch extends
  Warning("Pattern matching on Boolean is probably better written as an if statement.")
case class IdenticalCaseBodies(n: String) extends
  Warning(s"Bodies of $n neighbouring cases are identical and could be merged.")
case object IdenticalCaseConditions extends
  Warning("Identical case condition detected above. This case will never match.") // Why doesn't compiler catch this?
case object ReflexiveComparison extends
  Warning("Same expression on both sides of the comparison.")
case object YodaConditions extends
  Warning("Yoda conditions using you are.")
case class UseConditionDirectly(negated: Boolean = false) extends
  Warning(s"""Remove the if expression and use the ${if (negated) "negated " else ""}condition directly.""")
case class UseIfExpression(varName: String) extends
  Warning(s"Assign the result of the if expression to variable $varName directly.")
case object UnnecessaryElseBranch extends
  Warning("Since the if branch always returns, the code from the else branch can be moved out to reduce nesting.")
case object DuplicateIfBranches extends
  Warning("If statement branches have the same structure.")
case object IdenticalIfElseCondition extends
  Warning("This condition has appeared earlier in the if-else chain and will never hold here. (except for side-effecting conditions)")
case object MergeNestedIfs extends
  Warning("These two nested ifs can be merged into one.")
case class VariableAssignedUnusedValue(varName: String) extends
  Warning(s"Variable $varName has an unused value before this reassign.")
case object MalformedSwap extends
  Warning("Did you mean to swap these two variables?")
case object IdenticalIfCondition extends
  Warning("Two subsequent ifs have the same condition. (check if value has changed in between)")
case object IdenticalStatements extends
  Warning("You're doing the exact same thing twice or more.")
case object IndexingWithNegativeNumber extends
  Warning("Using a negative index for a collection.")
case object OptionOfOption extends
  Warning("Why would you need an Option of an Option?")
case class UndesirableTypeInference(inferredType: String) extends
  Warning(s"Inferred type $inferredType. (This might not be what you've intended)")
case object AssigningOptionToNull extends
  Warning("You probably meant None, not null.")
case object WrapNullWithOption extends
  Warning("Use Option(...), which automatically wraps null to None.")
case object AvoidOptionStringSize extends
  Warning("Did you mean to take the size of the string inside the Option?")
case object AvoidOptionCollectionSize extends
  Warning("Did you mean to take the size of the collection inside the Option?")
case class UseGetOrElseOnOption(varname: String) extends
  Warning(s"Use $varname.getOrElse(...) instead of $varname.orElse(Some(...)).get.")
case class UseOptionOrNull(varname: String, insteadOf: String) extends
  Warning(s"Use $varname.orNull or $varname.getOrElse(null) instead of if ($insteadOf) $varname.get else null.")
case class UseOptionGetOrElse(varname: String, insteadOf: String) extends
  Warning(s"Use $varname.getOrElse(...) instead of if ($insteadOf) $varname.get else ...")
case class UseExistsNotFindIsDefined(varName: String, replacement: (String, Boolean), isEmpty_isDefined: String) extends
  Warning(s"""Use ${Utils.toBang(replacement._2)}$varName.${replacement._1}(...) instead of $varName.find(...).$isEmpty_isDefined.""")
case class UseExistsNotFilterIsEmpty(varName: String, replacements: Seq[(String, Boolean, Boolean)], stmtNegated: Boolean, filter: String, empty: String) extends
  Warning(s"""Use ${
      replacements.map{
        case (rep, negStmt, negCond) => s"${Utils.toBang(negStmt)}$varName.$rep(${Utils.toBang(negCond)}...)"
      }.mkString(" or ")
    } instead of ${Utils.toBang(stmtNegated)}$varName.$filter(...).$empty.""")
case class UseFindNotFilterHead(varName: String) extends
  Warning(s"Unless there are side-effects, $varName.filter(...).headOption can be replaced by $varName.find(...).")
case class UseContainsNotExistsEquals(colName: String, valCmp: String, val1: String, val2: String) extends
  Warning(s"Use $colName.contains($valCmp) instead of $colName.exists($val1 == $val2)")
case class UseQuantifierFuncNotFold(varName: String, method: String, func: String) extends
  Warning(s"Unless there are side-effects, this $varName.$func can be replaced by $varName.$method.")
case class UseFuncNotReduce(varName: String, f: String, func: String) extends
  Warning(s"Use $varName.$f instead of $varName.$func.")
case class UseFuncNotFold(varName: String, f: String, func: String) extends
  Warning(s"Use $varName.$f instead of $varName.$func.")
case object MergeMaps extends
  Warning("Merge these two map operations.")
case class FuncFirstThenMap(methName: String) extends
  Warning(s"Use method $methName first, then map.")
case object FilterFirstThenSort extends
  Warning("Filter collection first, then sort it.")
case class UseMinOrMaxNotSort(colName: String, sortFunc: String, op: String, replacement: String) extends
  Warning(s"Use $colName.$replacement instead of $colName.$sortFunc.$op.")
case class UseMapNotFlatMap(varName: String) extends
  Warning(s"Use $varName.map(x => if (...) y else z) instead of $varName.flatMap(x => if (...) Collection(y) else Collection(z)).") // Clean up warning
case class UseFilterNotFlatMap(varName: String) extends
  Warning(s"Use $varName.filter(x => condition) instead of $varName.flatMap(x => if (condition) ... else ...).") // Clean up warning
case class AvoidOptionMethod(method: String, explanation: String = "") extends
  Warning(s"Using Option.$method is not recommended. $explanation")
case class TransformNotMap(varName: String) extends
  Warning(s"Use $varName.transform(...) instead of col = $varName.map(...).")
case object DuplicateKeyInMap extends
  Warning("This key has already been defined, and will override the previous mapping.")
case class InefficientUseOfListSize(varName: String, replacement: String, func: String) extends
  Warning(s"Use $varName.$replacement instead of comparing to $varName.$func. ($varName is a List, $func takes O(n) time)")
case object OnceEvaluatedStatementsInBlockReturningFunction extends
  Warning("You're passing a block that returns a function. The statements in this block, except the last one, will only be executed once.")
case object IntDivisionAssignedToFloat extends
  Warning("Integer division detected in an expression assigned to a floating point variable.")
case class UseFlattenNotFilterOption(varName: String, func1: String, func2: String) extends
  Warning(s"Use $varName.flatten instead of $varName.$func1(_.$func2).map(_.get).")
case class UseCountNotFilterLength(varName: String, func: String) extends
  Warning(s"Use $varName.count(...) instead of $varName.filter(...).$func")
case class UseExistsNotCountCompare(varName: String) extends
  Warning(s"Use $varName.exists(...) instead of $varName.count(...) compare.")
case class PassPartialFunctionDirectly(matchVar: String) extends
  Warning(s"You can pass the partial function in directly. (Remove `$matchVar match {`).")
case class UnitImplicitOrdering(function: String) extends
  Warning(s"Unit is returned here, so this $function will always return the first element.")
case class RegexWarning(errorMessage: String, error: Boolean = true) extends
  Warning("Regex pattern "+(if (error) "syntax error" else "warning")+s": $errorMessage.")
case class InvariantCondition(always: Boolean, doWhat: String) extends
  Warning(s"""This condition will ${ if (always) "always" else "never" } $doWhat.""")
case class DecomposingEmptyCollection(method: String, collection: String = "collection") extends
  Warning(s"Taking the $method of an empty $collection.")
case class InvariantExtrema(max: Boolean, returnsFirst: Boolean) extends
  Warning(s"""This ${ if (max) "max" else "min" } will always return the ${ if (returnsFirst) "first" else "second" } value""")
case class UnnecessaryMethodCall(method: String) extends
  Warning(s"This $method is always unnecessary.")
case object ProducesEmptyCollection extends
  Warning("The resulting collection will always be empty.")
case class OperationAlwaysProducesZero(operation: String) extends // TODO: merge with InvariantReturn?
  Warning(s"This $operation will always return 0.")
case object ModuloByOne extends
  Warning("Taking the modulo by one will return zero.")
case object DivideByOne extends
  Warning("Dividing by one will return the original number.")
case object DivideByZero extends
  Warning("Possible division by zero.")
case object ZeroDivideBy extends
  Warning("Division of zero will return zero.")
case object UseUntilNotToMinusOne extends
  Warning("Use (low until high) instead of (low to high-1).")
case object InvalidParamToRandomNextInt extends
  Warning("The parameter of this .nextInt might be lower than 1 here.") // Likely Exception
case object UnusedForLoopIteratorValue extends
  Warning("Iterator value is not used in the for loop's body.")
case object StringMultiplicationByNonPositive extends
  Warning("Multiplying a string with a value <= 0 will result in an empty string.")
case class LikelyIndexOutOfBounds(direction: String) extends
  Warning(s"You will likely use a $direction index.")
case object UnnecessaryReturn extends
  Warning("Scala has implicit return. You don't need a return statement at the end of a method.")
case class InvariantReturn(structure: String, returnValue: String) extends
  Warning(s"This $structure always returns the same value: $returnValue.")
case class UnusedParameter(parameters: Seq[String], method: String) extends
  Warning("Parameter" +
    (parameters match { case Seq(p) => " " + p + " is" case _ => "s (" + parameters.mkString(", ") + ") are" }) +
    s" not used in method $method.")
case class InvalidStringFormat(errorMessage: String, exception: Boolean = true) extends
  Warning(if (exception) s"This string format will throw: $errorMessage" else s"$errorMessage") // Likely Exception
case class InvalidStringConversion(conversionType: String) extends
  Warning(s"This String $conversionType conversion will likely fail.") // Likely Exception
case object UnnecessaryStringNonEmpty extends
  Warning("This string will never be empty.")
case object UnnecessaryStringIsEmpty extends
  Warning("This string will always be empty.")
case class PossibleLossOfPrecision(improvement: String) extends
  Warning(s"Possible loss of precision. $improvement")
case class UnsafeAbs(improvement: String) extends
  Warning(s"Possibly unsafe use of abs. $improvement.")
case class TypeToType(tpe: String) extends
  Warning(s"Using to$tpe on something that is already of type $tpe.")
case object EmptyStringInterpolator extends
  Warning("This string interpolation has no arguments.")
case class UnlikelyToString(tpe: String) extends
  Warning(s"Using toString on type $tpe is likely unintended.")
case object UnthrownException extends
  Warning("This exception was likely meant to be thrown here.")
case object SuspiciousMatches extends
  Warning("This regex starts with ^ or ends with $. The matches method always matches the entire string.")
case object IfDoWhile extends
  Warning("The if and the do-while loop have the same condition. Use a while loop.")
case object FloatingPointNumericRange extends
  Warning("Avoid NumericRange with floating point numbers, as results may differ depending on which methods are used to materialize it (apply vs. foreach).")
case class UseInitNotReverseTailReverse(varName: String) extends
  Warning(s"$varName.reverse.tail.reverse can be replaced by $varName.init.")
case class UseTakeRightNotReverseTakeReverse(varName: String) extends
  Warning(s"$varName.reverse.take(...).reverse can be replaced by $varName.takeRight(...).")
case class UseLastNotReverseHead(varName: String, option: Boolean) extends
  Warning(s"""$varName.reverse.head${if (option) "Option" else ""} can be replaced by $varName.last${if (option) "Option" else ""}.""")
case class UseFuncNotReverse(varName: String, func: String) extends
  Warning(s"""$varName.reverse.$func can be replaced by $varName.reverse${func.capitalize}.""")
case class UseHeadNotApply(varName: String) extends
  Warning(s"""It is idiomatic to use $varName.head instead of $varName(0) for List""")
case class UseLastNotApply(varName: String) extends
  Warning(s"""It is idiomatic to use $varName.last instead of $varName($varName.length - 1) for List""")
case class UseHeadOptionNotIf(varName: String) extends
  Warning(s"""if ($varName.nonEmpty) Some($varName.head) else None can be replaced by $varName.headOption""")
case class UseLastOptionNotIf(varName: String) extends
  Warning(s"""if ($varName.nonEmpty) Some($varName.last) else None can be replaced by $varName.lastOption""")
case class UseZipWithIndexNotZipIndices(varName: String) extends
  Warning(s"""$varName.zip($varName.indices) can be replaced with $varName.zipWithIndex""")
case class UseGetOrElseNotPatMatch(expr: String) extends
  Warning(s"""... match { Some(x) => x; None => $expr} can be replaced with .getOrElse($expr)""")
case class UseOrElseNotPatMatch(expr: String) extends
  Warning(s"""... match { Some(x) => Some(x); None => $expr} can be replaced with .orElse($expr)""")
case class UseOptionFlatMapNotPatMatch(expr: String) extends
  Warning(s"""... match { Some(x) => $expr; None => None} can be replaced with .flatMap($expr)""")
case class UseOptionMapNotPatMatch(expr: String) extends
  Warning(s"""... match { Some(x) => Some($expr); None => None} can be replaced with .map($expr)""")
case object UseOptionFlattenNotPatMatch extends
  Warning("""... match { Some(x) => x; None => None} can be replaced with .flatten""")
case class UseOptionForeachNotPatMatch(expr: String) extends
  Warning(s"""... match { Some(x) => $expr; None => {} } can be replaced with .foreach($expr)""")
case object UseOptionIsDefinedNotPatMatch extends
  Warning("""... match { Some(x) => true; None => false} can be replaced with .isDefined""")
case object UseOptionIsEmptyNotPatMatch extends
  Warning("""... match { Some(x) => false; None => true} can be replaced with .isEmpty""")
case class UseOptionForallNotPatMatch(expr: String) extends
  Warning(s"""... match { Some(x) => true; None => $expr} can be replaced with .forall($expr)""")
case class UseOptionExistsNotPatMatch(expr: String) extends
  Warning(s"""... match { Some(x) => false; None => $expr} can be replaced with .exists($expr)""")




© 2015 - 2024 Weber Informatics LLC | Privacy Policy