diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 3fc9c6d4..1540bdb3 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -14,6 +14,8 @@ jobs: - 2.12.19 - 2.13.13 - 2.13.14 + - 3.3.3 + - 3.4.2 steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 diff --git a/.gitignore b/.gitignore index 03ffde10..1a7e8982 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.class +*.tasty *.log # sbt specific @@ -22,4 +23,4 @@ target .metals metals.sbt -.bsp \ No newline at end of file +.bsp diff --git a/.scalafix-2.conf b/.scalafix-2.conf new file mode 100644 index 00000000..e6a9d861 --- /dev/null +++ b/.scalafix-2.conf @@ -0,0 +1,23 @@ +rules = [ +DisableSyntax, +LeakingImplicitClassVal, +NoAutoTupling, +NoValInForComprehension, +ProcedureSyntax, +RemoveUnused +] + +DisableSyntax.noVars = false +DisableSyntax.noThrows = false +DisableSyntax.noNulls = false +DisableSyntax.noReturns = true +DisableSyntax.noWhileLoops = true +DisableSyntax.noFinalize = true +DisableSyntax.noValPatterns = true +DisableSyntax.noUniversalEquality = false +DisableSyntax.noUniversalEqualityMessage = "== and != are unsafe since they allow comparing two unrelated types" +SortImports.blocks = [ +"java.", +"scala.", +"*" +] diff --git a/.scalafix.conf b/.scalafix.conf index e6a9d861..77c7a6d0 100644 --- a/.scalafix.conf +++ b/.scalafix.conf @@ -3,7 +3,6 @@ DisableSyntax, LeakingImplicitClassVal, NoAutoTupling, NoValInForComprehension, -ProcedureSyntax, RemoveUnused ] diff --git a/.scalafmt.conf b/.scalafmt.conf index 9de59fa7..82df8319 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,5 +1,5 @@ version = "3.8.3" -runner.dialect = scala213source3 +runner.dialect = scala3 maxColumn = 110 docstrings.style = Asterisk assumeStandardLibraryStripMargin = true diff --git a/README.md b/README.md index 8f087e44..a259414e 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,10 @@ Scapegoat ========= [![Codecov](https://img.shields.io/codecov/c/github/sksamuel/scapegoat)](https://codecov.io/gh/sksamuel/scapegoat) -[](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22scalac-scapegoat-plugin_2.11.12%22) -[](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22scalac-scapegoat-plugin_2.12.16%22) -[](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22scalac-scapegoat-plugin_2.13.12%22) +[](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22scalac-scapegoat-plugin_2.12.19%22) +[](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22scalac-scapegoat-plugin_2.13.14%22) +[](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22scalac-scapegoat-plugin_3.3.3%22) +[](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22scalac-scapegoat-plugin_3.4.2%22) [![Scala Steward badge](https://img.shields.io/badge/Scala_Steward-helping-blue.svg?style=flat&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAMAAAARSr4IAAAAVFBMVEUAAACHjojlOy5NWlrKzcYRKjGFjIbp293YycuLa3pYY2LSqql4f3pCUFTgSjNodYRmcXUsPD/NTTbjRS+2jomhgnzNc223cGvZS0HaSD0XLjbaSjElhIr+AAAAAXRSTlMAQObYZgAAAHlJREFUCNdNyosOwyAIhWHAQS1Vt7a77/3fcxxdmv0xwmckutAR1nkm4ggbyEcg/wWmlGLDAA3oL50xi6fk5ffZ3E2E3QfZDCcCN2YtbEWZt+Drc6u6rlqv7Uk0LdKqqr5rk2UCRXOk0vmQKGfc94nOJyQjouF9H/wCc9gECEYfONoAAAAASUVORK5CYII=)](https://scala-steward.org) Scapegoat is a Scala static code analyzer, which is more colloquially known as a code lint tool or linter. Scapegoat works in a similar vein to Java's [FindBugs](http://findbugs.sourceforge.net/) or [checkstyle](http://checkstyle.sourceforge.net/), or Scala's [Scalastyle](https://github.com/scalastyle/scalastyle). @@ -156,131 +157,132 @@ To suppress warnings globally for the project, use `disabledInspections` or `ove ### Inspections -There are currently 121 inspections. An overview list is given, followed by a more detailed description of each inspection after the list (todo: finish rest of detailed descriptions) - -| Name | Brief Description | Default Level | -|---------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------| -| ArrayEquals | Checks for comparison of arrays using `==` which will always return false | Info | -| ArraysInFormat | Checks for arrays passed to String.format | Error | -| ArraysToString | Checks for explicit toString calls on arrays | Warning | -| AsInstanceOf | Checks for use of `asInstanceOf` | Warning | -| AvoidOperatorOverload | Checks for mental symbolic method names | Info | -| AvoidSizeEqualsZero | Traversable.size can be slow for some data structure, prefer .isEmpty | Warning | -| AvoidSizeNotEqualsZero | Traversable.size can be slow for some data structure, prefer .nonEmpty | Warning | -| AvoidToMinusOne | Checks for loops that use `x to n-1` instead of `x until n` | Info | -| BigDecimalDoubleConstructor | Checks for use of `BigDecimal(double)` which can be unsafe | Warning | -| BigDecimalScaleWithoutRoundingMode | `setScale()` on a `BigDecimal` without setting the rounding mode can throw an exception | Warning | -| BooleanParameter | Checks for functions that have a Boolean parameter | Info | -| BoundedByFinalType | Looks for types with upper bounds of a final type | Warning | -| BrokenOddness | Checks for a % 2 == 1 for oddness because this fails on negative numbers | Warning | -| CatchException | Checks for try blocks that catch Exception | Warning | -| CatchExceptionImmediatelyRethrown | Checks for try-catch blocks that immediately rethrow caught exceptions. | Warning | -| CatchFatal | Checks for try blocks that catch fatal exceptions: VirtualMachineError, ThreadDeath, InterruptedException, LinkageError, ControlThrowable | Warning | -| CatchNpe | Checks for try blocks that catch null pointer exceptions | Error | -| CatchThrowable | Checks for try blocks that catch Throwable | Warning | -| ClassNames | Ensures class names adhere to the style guidelines | Info | -| CollectionIndexOnNonIndexedSeq | Checks for indexing on a Seq which is not an IndexedSeq | Warning | -| CollectionNamingConfusion | Checks for variables that are confusingly named | Info | -| CollectionNegativeIndex | Checks for negative access on a sequence eg `list.get(-1)` | Warning | -| CollectionPromotionToAny | Checks for collection operations that promote the collection to `Any` | Warning | -| ComparingFloatingPointTypes | Checks for equality checks on floating point types | Error | -| ComparingUnrelatedTypes | Checks for equality comparisons that cannot succeed | Error | -| ComparisonToEmptyList | Checks for code like `a == List()` or `a == Nil` | Info | -| ComparisonToEmptySet | Checks for code like `a == Set()` or `a == Set.empty` | Info | -| ComparisonWithSelf | Checks for equality checks with itself | Warning | -| ConstantIf | Checks for code where the if condition compiles to a constant | Warning | -| DivideByOne | Checks for divide by one, which always returns the original value | Warning | -| DoubleNegation | Checks for code like `!(!b)` | Info | -| DuplicateImport | Checks for import statements that import the same selector | Info | -| DuplicateMapKey | Checks for duplicate key names in Map literals | Warning | -| DuplicateSetValue | Checks for duplicate values in set literals | Warning | -| EitherGet | Checks for use of .get on Left or Right | Error | -| EmptyCaseClass | Checks for case classes like `case class Faceman()` | Info | -| EmptyFor | Checks for empty `for` loops | Warning | -| EmptyIfBlock | Checks for empty `if` blocks | Warning | -| EmptyInterpolatedString | Looks for interpolated strings that have no arguments | Error | -| EmptyMethod | Looks for empty methods | Warning | -| EmptySynchronizedBlock | Looks for empty synchronized blocks | Warning | -| EmptyTryBlock | Looks for empty try blocks | Warning | -| EmptyWhileBlock | Looks for empty while loops | Warning | -| ExistsSimplifiableToContains | `exists(x => x == b)` replaceable with `contains(b)` | Info | -| FilterDotHead | `.filter(x => ).head` can be replaced with `find(x => ) match { .. } ` | Info | -| FilterDotHeadOption | `.filter(x =>).headOption` can be replaced with `find(x => )` | Info | -| FilterDotIsEmpty | `.filter(x => ).isEmpty` can be replaced with `!exists(x => )` | Info | -| FilterDotSize | `.filter(x => ).size` can be replaced more concisely with with `count(x => )` | Info | -| FilterOptionAndGet | `.filter(_.isDefined).map(_.get)` can be replaced with `flatten` | Info | -| FinalModifierOnCaseClass | Using Case classes without `final` modifier can lead to surprising breakage | Info | -| FinalizerWithoutSuper | Checks for overridden finalizers that do not call super | Warning | -| FindAndNotEqualsNoneReplaceWithExists | `.find(x => ) != None` can be replaced with `exist(x => )` | Info | -| FindDotIsDefined | `find(x => ).isDefined` can be replaced with `exist(x => )` | Info | -| IllegalFormatString | Looks for invalid format strings | Error | -| ImpossibleOptionSizeCondition | Checks for code like `option.size > 2` which can never be true | Error | -| IncorrectNumberOfArgsToFormat | Checks for wrong number of arguments to `String.format` | Error | -| IncorrectlyNamedExceptions | Checks for exceptions that are not called *Exception and vice versa | Error | -| InvalidRegex | Checks for invalid regex literals | Info | -| IsInstanceOf | Checks for use of `isInstanceOf` | Warning | -| JavaConversionsUse | Checks for use of implicit Java conversions | Warning | -| ListAppend | Checks for List :+ which is O(n) | Info | -| ListSize | Checks for `List.size` which is O(n). | Info | -| LonelySealedTrait | Checks for sealed traits which have no implementation | Error | -| LooksLikeInterpolatedString | Finds strings that look like they should be interpolated but are not | Warning | -| MapGetAndGetOrElse | `Map.get(key).getOrElse(value)` can be replaced with `Map.getOrElse(key, value)` | Error | -| MaxParameters | Checks for methods that have over 10 parameters | Info | -| MethodNames | Warns on method names that don't adhere to the Scala style guidelines | Info | -| MethodReturningAny | Checks for defs that are defined or inferred to return `Any` | Warning | -| ModOne | Checks for `x % 1` which will always return `0` | Warning | -| NanComparison | Checks for `x == Double.NaN` which will always fail | Error | -| NegationIsEmpty | `!Traversable.isEmpty` can be replaced with `Traversable.nonEmpty` | Info | -| NegationNonEmpty | `!Traversable.nonEmpty` can be replaced with `Traversable.isEmpty` | Info | -| NoOpOverride | Checks for code that overrides parent method but simply calls super | Info | -| NullAssignment | Checks for use of `null` in assignments | Warning | -| NullParameter | Checks for use of `null` in method invocation | Warning | -| ObjectNames | Ensures object names adhere to the Scala style guidelines | Info | -| OptionGet | Checks for `Option.get` | Error | -| OptionSize | Checks for `Option.size` | Error | -| ParameterlessMethodReturnsUnit | Checks for `def foo : Unit` | Warning | -| PartialFunctionInsteadOfMatch | Warns when you could use a partial function directly instead of a match block | Info | -| PointlessTypeBounds | Finds type bounds of the form `[A <: Any]` or `[A >: Nothing]` | Warning | -| PreferMapEmpty | Checks for Map() when could use Map.empty | Info | -| PreferSeqEmpty | Checks for Seq() when could use Seq.empty | Info | -| PreferSetEmpty | Checks for Set() when could use Set.empty | Info | -| ProductWithSerializableInferred | Checks for vals that have `Product with Serializable` as their inferred type | Warning | -| PublicFinalizer | Checks for overridden finalizes that are public | Info | -| RedundantFinalModifierOnMethod | Redundant `final` modifier on method that cannot be overridden | Info | -| RedundantFinalModifierOnVar | Redundant `final` modifier on var that cannot be overridden | Info | -| RedundantFinalizer | Checks for empty finalizers. | Warning | -| RepeatedCaseBody | Checks for case statements which have the same body | Warning | -| RepeatedIfElseBody | Checks for the main branch and the else branch of an `if` being the same | Warning | -| ReverseFunc | `reverse` followed by `head`, `headOption`, `iterator`, or`map` can be replaced, respectively, with `last`, `lastOption`, `reverseIterator`, or `reverseMap` | Info | -| ReverseTailReverse | `.reverse.tail.reverse` can be replaced with `init` | Info | -| ReverseTakeReverse | `.reverse.take(...).reverse` can be replaced with `takeRight` | Info | -| SimplifyBooleanExpression | `b == false` can be simplified to `!b` | Info | -| StoreBeforeReturn | Checks for storing a value in a block, and immediately returning the value | Info | -| StripMarginOnRegex | Checks for .stripMargin on regex strings that contain a pipe | Error | -| SubstringZero | Checks for `String.substring(0)` | Info | -| SuspiciousMatchOnClassObject | Finds code where matching is taking place on class literals | Warning | -| SwallowedException | Finds catch blocks that don't handle caught exceptions | Warning | -| SwapSortFilter | `sort.filter` can be replaced with `filter.sort` for performance | Info | -| TryGet | Checks for use of `Try.get` | Error | -| TypeShadowing | Checks for shadowed type parameters in methods | Warning | -| UnnecessaryConversion | Checks for unnecessary `toInt` on instances of Int or `toString` on Strings, etc. | Warning | -| UnnecessaryIf | Checks for code like `if (expr) true else false` | Info | -| UnnecessaryReturnUse | Checks for use of `return` keyword in blocks | Info | -| UnreachableCatch | Checks for catch clauses that cannot be reached | Warning | -| UnsafeContains | Checks for `List.contains(value)` for invalid types | Error | -| UnsafeStringContains | Checks for `String.contains(value)` for invalid types | Error | -| UnsafeTraversableMethods | Check unsafe traversable method usages (head, tail, init, last, reduce, reduceLeft, reduceRight, max, maxBy, min, minBy) | Error | -| UnusedMethodParameter | Checks for unused method parameters | Warning | -| UseCbrt | Checks for use of `math.pow` for calculating `math.cbrt` | Info | -| UseExpM1 | Checks for use of `math.exp(x) - 1` instead of `math.expm1(x)` | Info | -| UseLog10 | Checks for use of `math.log(x)/math.log(10)` instead of `math.log10(x)` | Info | -| UseLog1P | Checks for use of `math.log(x + 1)` instead of `math.log1p(x)` | Info | -| UseSqrt | Checks for use of `math.pow` for calculating `math.sqrt` | Info | -| VarClosure | Finds closures that reference var | Warning | -| VarCouldBeVal | Checks for `var`s that could be declared as `val`s | Warning | -| VariableShadowing | Checks for multiple uses of the variable name in nested scopes | Warning | -| WhileTrue | Checks for code that uses a `while(true)` or `do { } while(true)` block. | Warning | -| ZeroNumerator | Checks for dividing by 0 by a number, eg `0 / x` which will always return `0` | Warning | +There are currently 121 inspections for Scala 2, and 1 for Scala 3. +An overview list is given, followed by a more detailed description of each inspection after the list (todo: finish rest of detailed descriptions) + +| Name | Brief Description | Default Level | Scala 2 | Scala 3 | +|---------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|---------|---------| +| ArrayEquals | Checks for comparison of arrays using `==` which will always return false | Info | Yes | No | +| ArraysInFormat | Checks for arrays passed to String.format | Error | Yes | No | +| ArraysToString | Checks for explicit toString calls on arrays | Warning | Yes | No | +| AsInstanceOf | Checks for use of `asInstanceOf` | Warning | Yes | No | +| AvoidOperatorOverload | Checks for mental symbolic method names | Info | Yes | No | +| AvoidSizeEqualsZero | Traversable.size can be slow for some data structure, prefer .isEmpty | Warning | Yes | No | +| AvoidSizeNotEqualsZero | Traversable.size can be slow for some data structure, prefer .nonEmpty | Warning | Yes | No | +| AvoidToMinusOne | Checks for loops that use `x to n-1` instead of `x until n` | Info | Yes | No | +| BigDecimalDoubleConstructor | Checks for use of `BigDecimal(double)` which can be unsafe | Warning | Yes | No | +| BigDecimalScaleWithoutRoundingMode | `setScale()` on a `BigDecimal` without setting the rounding mode can throw an exception | Warning | Yes | No | +| BooleanParameter | Checks for functions that have a Boolean parameter | Info | Yes | No | +| BoundedByFinalType | Looks for types with upper bounds of a final type | Warning | Yes | No | +| BrokenOddness | Checks for a % 2 == 1 for oddness because this fails on negative numbers | Warning | Yes | No | +| CatchException | Checks for try blocks that catch Exception | Warning | Yes | No | +| CatchExceptionImmediatelyRethrown | Checks for try-catch blocks that immediately rethrow caught exceptions. | Warning | Yes | No | +| CatchFatal | Checks for try blocks that catch fatal exceptions: VirtualMachineError, ThreadDeath, InterruptedException, LinkageError, ControlThrowable | Warning | Yes | No | +| CatchNpe | Checks for try blocks that catch null pointer exceptions | Error | Yes | No | +| CatchThrowable | Checks for try blocks that catch Throwable | Warning | Yes | No | +| ClassNames | Ensures class names adhere to the style guidelines | Info | Yes | No | +| CollectionIndexOnNonIndexedSeq | Checks for indexing on a Seq which is not an IndexedSeq | Warning | Yes | No | +| CollectionNamingConfusion | Checks for variables that are confusingly named | Info | Yes | No | +| CollectionNegativeIndex | Checks for negative access on a sequence eg `list.get(-1)` | Warning | Yes | No | +| CollectionPromotionToAny | Checks for collection operations that promote the collection to `Any` | Warning | Yes | No | +| ComparingFloatingPointTypes | Checks for equality checks on floating point types | Error | Yes | No | +| ComparingUnrelatedTypes | Checks for equality comparisons that cannot succeed | Error | Yes | No | +| ComparisonToEmptyList | Checks for code like `a == List()` or `a == Nil` | Info | Yes | No | +| ComparisonToEmptySet | Checks for code like `a == Set()` or `a == Set.empty` | Info | Yes | No | +| ComparisonWithSelf | Checks for equality checks with itself | Warning | Yes | No | +| ConstantIf | Checks for code where the if condition compiles to a constant | Warning | Yes | No | +| DivideByOne | Checks for divide by one, which always returns the original value | Warning | Yes | No | +| DoubleNegation | Checks for code like `!(!b)` | Info | Yes | No | +| DuplicateImport | Checks for import statements that import the same selector | Info | Yes | No | +| DuplicateMapKey | Checks for duplicate key names in Map literals | Warning | Yes | No | +| DuplicateSetValue | Checks for duplicate values in set literals | Warning | Yes | No | +| EitherGet | Checks for use of .get on Left or Right | Error | Yes | No | +| EmptyCaseClass | Checks for case classes like `case class Faceman()` | Info | Yes | No | +| EmptyFor | Checks for empty `for` loops | Warning | Yes | No | +| EmptyIfBlock | Checks for empty `if` blocks | Warning | Yes | No | +| EmptyInterpolatedString | Looks for interpolated strings that have no arguments | Error | Yes | No | +| EmptyMethod | Looks for empty methods | Warning | Yes | No | +| EmptySynchronizedBlock | Looks for empty synchronized blocks | Warning | Yes | No | +| EmptyTryBlock | Looks for empty try blocks | Warning | Yes | No | +| EmptyWhileBlock | Looks for empty while loops | Warning | Yes | No | +| ExistsSimplifiableToContains | `exists(x => x == b)` replaceable with `contains(b)` | Info | Yes | No | +| FilterDotHead | `.filter(x => ).head` can be replaced with `find(x => ) match { .. } ` | Info | Yes | No | +| FilterDotHeadOption | `.filter(x =>).headOption` can be replaced with `find(x => )` | Info | Yes | No | +| FilterDotIsEmpty | `.filter(x => ).isEmpty` can be replaced with `!exists(x => )` | Info | Yes | No | +| FilterDotSize | `.filter(x => ).size` can be replaced more concisely with with `count(x => )` | Info | Yes | No | +| FilterOptionAndGet | `.filter(_.isDefined).map(_.get)` can be replaced with `flatten` | Info | Yes | No | +| FinalModifierOnCaseClass | Using Case classes without `final` modifier can lead to surprising breakage | Info | Yes | No | +| FinalizerWithoutSuper | Checks for overridden finalizers that do not call super | Warning | Yes | No | +| FindAndNotEqualsNoneReplaceWithExists | `.find(x => ) != None` can be replaced with `exist(x => )` | Info | Yes | No | +| FindDotIsDefined | `find(x => ).isDefined` can be replaced with `exist(x => )` | Info | Yes | No | +| IllegalFormatString | Looks for invalid format strings | Error | Yes | No | +| ImpossibleOptionSizeCondition | Checks for code like `option.size > 2` which can never be true | Error | Yes | No | +| IncorrectNumberOfArgsToFormat | Checks for wrong number of arguments to `String.format` | Error | Yes | No | +| IncorrectlyNamedExceptions | Checks for exceptions that are not called *Exception and vice versa | Error | Yes | No | +| InvalidRegex | Checks for invalid regex literals | Info | Yes | No | +| IsInstanceOf | Checks for use of `isInstanceOf` | Warning | Yes | No | +| JavaConversionsUse | Checks for use of implicit Java conversions | Warning | Yes | No | +| ListAppend | Checks for List :+ which is O(n) | Info | Yes | No | +| ListSize | Checks for `List.size` which is O(n). | Info | Yes | No | +| LonelySealedTrait | Checks for sealed traits which have no implementation | Error | Yes | No | +| LooksLikeInterpolatedString | Finds strings that look like they should be interpolated but are not | Warning | Yes | No | +| MapGetAndGetOrElse | `Map.get(key).getOrElse(value)` can be replaced with `Map.getOrElse(key, value)` | Error | Yes | No | +| MaxParameters | Checks for methods that have over 10 parameters | Info | Yes | No | +| MethodNames | Warns on method names that don't adhere to the Scala style guidelines | Info | Yes | No | +| MethodReturningAny | Checks for defs that are defined or inferred to return `Any` | Warning | Yes | No | +| ModOne | Checks for `x % 1` which will always return `0` | Warning | Yes | No | +| NanComparison | Checks for `x == Double.NaN` which will always fail | Error | Yes | No | +| NegationIsEmpty | `!Traversable.isEmpty` can be replaced with `Traversable.nonEmpty` | Info | Yes | No | +| NegationNonEmpty | `!Traversable.nonEmpty` can be replaced with `Traversable.isEmpty` | Info | Yes | No | +| NoOpOverride | Checks for code that overrides parent method but simply calls super | Info | Yes | No | +| NullAssignment | Checks for use of `null` in assignments | Warning | Yes | No | +| NullParameter | Checks for use of `null` in method invocation | Warning | Yes | No | +| ObjectNames | Ensures object names adhere to the Scala style guidelines | Info | Yes | No | +| OptionGet | Checks for `Option.get` | Error | Yes | Yes | +| OptionSize | Checks for `Option.size` | Error | Yes | No | +| ParameterlessMethodReturnsUnit | Checks for `def foo : Unit` | Warning | Yes | No | +| PartialFunctionInsteadOfMatch | Warns when you could use a partial function directly instead of a match block | Info | Yes | No | +| PointlessTypeBounds | Finds type bounds of the form `[A <: Any]` or `[A >: Nothing]` | Warning | Yes | No | +| PreferMapEmpty | Checks for Map() when could use Map.empty | Info | Yes | No | +| PreferSeqEmpty | Checks for Seq() when could use Seq.empty | Info | Yes | No | +| PreferSetEmpty | Checks for Set() when could use Set.empty | Info | Yes | No | +| ProductWithSerializableInferred | Checks for vals that have `Product with Serializable` as their inferred type | Warning | Yes | No | +| PublicFinalizer | Checks for overridden finalizes that are public | Info | Yes | No | +| RedundantFinalModifierOnMethod | Redundant `final` modifier on method that cannot be overridden | Info | Yes | No | +| RedundantFinalModifierOnVar | Redundant `final` modifier on var that cannot be overridden | Info | Yes | No | +| RedundantFinalizer | Checks for empty finalizers. | Warning | Yes | No | +| RepeatedCaseBody | Checks for case statements which have the same body | Warning | Yes | No | +| RepeatedIfElseBody | Checks for the main branch and the else branch of an `if` being the same | Warning | Yes | No | +| ReverseFunc | `reverse` followed by `head`, `headOption`, `iterator`, or`map` can be replaced, respectively, with `last`, `lastOption`, `reverseIterator`, or `reverseMap` | Info | Yes | No | +| ReverseTailReverse | `.reverse.tail.reverse` can be replaced with `init` | Info | Yes | No | +| ReverseTakeReverse | `.reverse.take(...).reverse` can be replaced with `takeRight` | Info | Yes | No | +| SimplifyBooleanExpression | `b == false` can be simplified to `!b` | Info | Yes | No | +| StoreBeforeReturn | Checks for storing a value in a block, and immediately returning the value | Info | Yes | No | +| StripMarginOnRegex | Checks for .stripMargin on regex strings that contain a pipe | Error | Yes | No | +| SubstringZero | Checks for `String.substring(0)` | Info | Yes | No | +| SuspiciousMatchOnClassObject | Finds code where matching is taking place on class literals | Warning | Yes | No | +| SwallowedException | Finds catch blocks that don't handle caught exceptions | Warning | Yes | No | +| SwapSortFilter | `sort.filter` can be replaced with `filter.sort` for performance | Info | Yes | No | +| TryGet | Checks for use of `Try.get` | Error | Yes | No | +| TypeShadowing | Checks for shadowed type parameters in methods | Warning | Yes | No | +| UnnecessaryConversion | Checks for unnecessary `toInt` on instances of Int or `toString` on Strings, etc. | Warning | Yes | No | +| UnnecessaryIf | Checks for code like `if (expr) true else false` | Info | Yes | No | +| UnnecessaryReturnUse | Checks for use of `return` keyword in blocks | Info | Yes | No | +| UnreachableCatch | Checks for catch clauses that cannot be reached | Warning | Yes | No | +| UnsafeContains | Checks for `List.contains(value)` for invalid types | Error | Yes | No | +| UnsafeStringContains | Checks for `String.contains(value)` for invalid types | Error | Yes | No | +| UnsafeTraversableMethods | Check unsafe traversable method usages (head, tail, init, last, reduce, reduceLeft, reduceRight, max, maxBy, min, minBy) | Error | Yes | No | +| UnusedMethodParameter | Checks for unused method parameters | Warning | Yes | No | +| UseCbrt | Checks for use of `math.pow` for calculating `math.cbrt` | Info | Yes | No | +| UseExpM1 | Checks for use of `math.exp(x) - 1` instead of `math.expm1(x)` | Info | Yes | No | +| UseLog10 | Checks for use of `math.log(x)/math.log(10)` instead of `math.log10(x)` | Info | Yes | No | +| UseLog1P | Checks for use of `math.log(x + 1)` instead of `math.log1p(x)` | Info | Yes | No | +| UseSqrt | Checks for use of `math.pow` for calculating `math.sqrt` | Info | Yes | No | +| VarClosure | Finds closures that reference var | Warning | Yes | No | +| VarCouldBeVal | Checks for `var`s that could be declared as `val`s | Warning | Yes | No | +| VariableShadowing | Checks for multiple uses of the variable name in nested scopes | Warning | Yes | No | +| WhileTrue | Checks for code that uses a `while(true)` or `do { } while(true)` block. | Warning | Yes | No | +| ZeroNumerator | Checks for dividing by 0 by a number, eg `0 / x` which will always return `0` | Warning | Yes | No | ##### Arrays to string diff --git a/build.sbt b/build.sbt index 9132e02b..411e774a 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,3 @@ -// compiler plugins -addCompilerPlugin("org.scalameta" % "semanticdb-scalac" % "4.9.9" cross CrossVersion.full) - name := "scalac-scapegoat-plugin" organization := "com.sksamuel.scapegoat" description := "Scala compiler plugin for static code analysis" @@ -22,8 +19,8 @@ developers := List( ) ) -scalaVersion := "2.13.14" -crossScalaVersions := Seq("2.12.18", "2.12.19", "2.13.13", "2.13.14") +scalaVersion := "3.4.2" +crossScalaVersions := Seq("2.12.18", "2.12.19", "2.13.13", "2.13.14", "3.3.3", "3.4.2") autoScalaLibrary := false crossVersion := CrossVersion.full crossTarget := { @@ -31,11 +28,19 @@ crossTarget := { target.value / s"scala-${scalaVersion.value}" } versionScheme := Some("early-semver") +semanticdbEnabled := (scalaBinaryVersion.value == "3") +scalafixConfig := Some(file(if (scalaBinaryVersion.value == "3") ".scalafix.conf" else ".scalafix-2.conf")) // https://github.com/sksamuel/scapegoat/issues/298 ThisBuild / useCoursier := false -val scalac13Options = Seq( +val scala2Options = Seq( + "-Xlint", + "-Xlint:adapted-args", + "-Xlint:nullary-unit", +) + +val scalac13Options = scala2Options ++ Seq( "-Xlint:inaccessible", "-Xlint:infer-any", "-Xlint:strict-unsealed-patmat", @@ -43,13 +48,21 @@ val scalac13Options = Seq( "-Ywarn-unused", "-Xsource:3" ) -val scalac12Options = Seq( +val scalac12Options = scala2Options ++ Seq( "-Ywarn-inaccessible", "-Ywarn-infer-any", "-Xlint:nullary-override", "-Xmax-classfile-name", "254" ) +val scala3Options = Seq( + "-Ysafe-init", + "-Wnonunit-statement", + "-Wunused:all", + "-Wvalue-discard", + // Unused locals seem to wrong on Scala XML syntax + "-Wconf:msg=unused value of type scala.xml.NodeBuffer:silent", +) scalacOptions := { val common = Seq( @@ -58,13 +71,11 @@ scalacOptions := { "-feature", "-encoding", "utf8", - "-Xlint", - "-Xlint:adapted-args", - "-Xlint:nullary-unit" ) common ++ (scalaBinaryVersion.value match { case "2.12" => scalac12Options case "2.13" => scalac13Options + case "3" => scala3Options }) } javacOptions ++= Seq("-source", "1.8", "-target", "1.8") @@ -85,20 +96,33 @@ def check(code: String) = { """ libraryDependencies ++= Seq( - "org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided", - "org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided", "org.scala-lang.modules" %% "scala-xml" % "2.3.0" excludeAll ExclusionRule(organization = "org.scala-lang"), "org.scala-lang.modules" %% "scala-collection-compat" % "2.12.0" excludeAll ExclusionRule(organization = "org.scala-lang" ), - "org.scala-lang" % "scala-compiler" % scalaVersion.value % "test", - "org.scalatest" %% "scalatest" % "3.2.19" % "test", - "org.mockito" % "mockito-all" % "1.10.19" % "test", - "joda-time" % "joda-time" % "2.12.7" % "test", - "org.joda" % "joda-convert" % "2.2.3" % "test", - "org.slf4j" % "slf4j-api" % "2.0.13" % "test" + "org.scalatest" %% "scalatest" % "3.2.19" % "test", + "org.mockito" % "mockito-all" % "1.10.19" % "test", + "joda-time" % "joda-time" % "2.12.7" % "test", + "org.joda" % "joda-convert" % "2.2.3" % "test", + "org.slf4j" % "slf4j-api" % "2.0.13" % "test" ) +libraryDependencies ++= (if (scalaBinaryVersion.value == "3") { + Seq( + "org.scala-lang" %% "scala3-compiler" % scalaVersion.value % "provided", + "org.scala-lang" %% "scala3-compiler" % scalaVersion.value % "test" + ) + } else { + Seq( + "org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided", + "org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided", + "org.scala-lang" % "scala-compiler" % scalaVersion.value % "test", + compilerPlugin( + "org.scalameta" % "semanticdb-scalac" % "4.9.9" cross CrossVersion.full + ) + ) + }) + // Test Test / run / fork := true Test / logBuffered := false diff --git a/src/main/resources/plugin.properties b/src/main/resources/plugin.properties new file mode 100644 index 00000000..bcd94ba0 --- /dev/null +++ b/src/main/resources/plugin.properties @@ -0,0 +1 @@ +pluginClass=com.sksamuel.scapegoat.ScapegoatPlugin diff --git a/src/main/scala-2/com/sksamuel/scapegoat/FeedbackScala2.scala b/src/main/scala-2/com/sksamuel/scapegoat/FeedbackScala2.scala new file mode 100644 index 00000000..b4e3e2da --- /dev/null +++ b/src/main/scala-2/com/sksamuel/scapegoat/FeedbackScala2.scala @@ -0,0 +1,22 @@ +package com.sksamuel.scapegoat + +import scala.tools.nsc.reporters.Reporter +import scala.reflect.internal.util.Position + +class FeedbackScala2( + reporter: Reporter, + configuration: Configuration +) extends Feedback[Position](configuration) { + + protected def toSourcePath(pos: Position): String = pos.source.file.path + protected def toSourceLine(pos: Position): Int = pos.line + + override protected def report(pos: Position, level: Level, message: String): Unit = { + level match { + case Levels.Error => reporter.error(pos, message) + case Levels.Warning => reporter.warning(pos, message) + case Levels.Info => reporter.echo(pos, message) + case Levels.Ignore => () + } + } +} diff --git a/src/main/scala-2/com/sksamuel/scapegoat/Inspection.scala b/src/main/scala-2/com/sksamuel/scapegoat/Inspection.scala new file mode 100644 index 00000000..5fcdb9ee --- /dev/null +++ b/src/main/scala-2/com/sksamuel/scapegoat/Inspection.scala @@ -0,0 +1,18 @@ +package com.sksamuel.scapegoat + +/** + * @author + * Stephen Samuel + */ +abstract class Inspection( + override val text: String, + override val defaultLevel: Level, + override val description: String, + override val explanation: String +) extends InspectionBase { + + val self: Inspection = this + + def inspector(ctx: InspectionContext): Inspector + +} diff --git a/src/main/scala/com/sksamuel/scapegoat/Inspections.scala b/src/main/scala-2/com/sksamuel/scapegoat/Inspections.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/Inspections.scala rename to src/main/scala-2/com/sksamuel/scapegoat/Inspections.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/Inspection.scala b/src/main/scala-2/com/sksamuel/scapegoat/Inspector.scala similarity index 92% rename from src/main/scala/com/sksamuel/scapegoat/Inspection.scala rename to src/main/scala-2/com/sksamuel/scapegoat/Inspector.scala index aff3d585..56b39397 100644 --- a/src/main/scala/com/sksamuel/scapegoat/Inspection.scala +++ b/src/main/scala-2/com/sksamuel/scapegoat/Inspector.scala @@ -3,26 +3,6 @@ package com.sksamuel.scapegoat import scala.reflect.internal.util.Position import scala.tools.nsc.Global -/** - * @author - * Stephen Samuel - */ -abstract class Inspection( - val text: String, - val defaultLevel: Level, - val description: String, - val explanation: String -) { - - val self: Inspection = this - - def inspector(ctx: InspectionContext): Inspector - - def isEnabled: Boolean = true - - def name: String = getClass.getSimpleName -} - abstract class Inspector(val context: InspectionContext) { /** @@ -37,7 +17,7 @@ abstract class Inspector(val context: InspectionContext) { def postInspection(): Unit = () } -final case class InspectionContext(global: Global, feedback: Feedback) { +final case class InspectionContext(global: Global, feedback: Feedback[Position]) { def warn(pos: Position, inspection: Inspection): Unit = feedback.warn(pos, inspection, None, None) diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/AnyUse.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/AnyUse.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/AnyUse.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/AnyUse.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/AvoidToMinusOne.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/AvoidToMinusOne.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/AvoidToMinusOne.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/AvoidToMinusOne.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/BooleanParameter.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/BooleanParameter.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/BooleanParameter.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/BooleanParameter.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/DoubleNegation.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/DoubleNegation.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/DoubleNegation.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/DoubleNegation.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/EmptyCaseClass.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/EmptyCaseClass.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/EmptyCaseClass.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/EmptyCaseClass.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/FinalModifierOnCaseClass.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/FinalModifierOnCaseClass.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/FinalModifierOnCaseClass.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/FinalModifierOnCaseClass.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/LonelySealedTrait.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/LonelySealedTrait.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/LonelySealedTrait.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/LonelySealedTrait.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/MaxParameters.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/MaxParameters.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/MaxParameters.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/MaxParameters.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/NoOpOverride.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/NoOpOverride.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/NoOpOverride.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/NoOpOverride.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/PublicFinalizer.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/PublicFinalizer.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/PublicFinalizer.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/PublicFinalizer.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnMethod.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnMethod.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnMethod.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnMethod.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnVar.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnVar.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnVar.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnVar.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/TypeShadowing.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/TypeShadowing.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/TypeShadowing.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/TypeShadowing.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/VarClosure.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/VarClosure.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/VarClosure.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/VarClosure.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/VarUse.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/VarUse.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/VarUse.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/VarUse.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/VariableShadowing.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/VariableShadowing.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/VariableShadowing.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/VariableShadowing.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/ArrayEquals.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ArrayEquals.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/ArrayEquals.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ArrayEquals.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/AvoidSizeEqualsZero.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/AvoidSizeEqualsZero.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/AvoidSizeEqualsZero.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/AvoidSizeEqualsZero.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/AvoidSizeNotEqualsZero.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/AvoidSizeNotEqualsZero.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/AvoidSizeNotEqualsZero.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/AvoidSizeNotEqualsZero.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/CollectionIndexOnNonIndexedSeq.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionIndexOnNonIndexedSeq.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/CollectionIndexOnNonIndexedSeq.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionIndexOnNonIndexedSeq.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/CollectionNamingConfusion.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionNamingConfusion.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/CollectionNamingConfusion.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionNamingConfusion.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/CollectionNegativeIndex.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionNegativeIndex.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/CollectionNegativeIndex.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionNegativeIndex.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/CollectionPromotionToAny.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionPromotionToAny.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/CollectionPromotionToAny.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionPromotionToAny.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptyList.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptyList.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptyList.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptyList.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptySet.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptySet.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptySet.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptySet.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/DuplicateMapKey.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/DuplicateMapKey.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/DuplicateMapKey.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/DuplicateMapKey.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/DuplicateSetValue.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/DuplicateSetValue.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/DuplicateSetValue.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/DuplicateSetValue.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/ExistsSimplifiableToContains.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ExistsSimplifiableToContains.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/ExistsSimplifiableToContains.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ExistsSimplifiableToContains.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotHead.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotHead.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotHead.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotHead.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotHeadOption.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotHeadOption.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotHeadOption.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotHeadOption.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotIsEmpty.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotIsEmpty.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotIsEmpty.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotIsEmpty.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotSize.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotSize.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotSize.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotSize.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/FilterOptionAndGet.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterOptionAndGet.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/FilterOptionAndGet.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterOptionAndGet.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/FindAndNotEqualsNoneReplaceWithExists.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/FindAndNotEqualsNoneReplaceWithExists.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/FindAndNotEqualsNoneReplaceWithExists.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/FindAndNotEqualsNoneReplaceWithExists.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/FindDotIsDefined.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/FindDotIsDefined.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/FindDotIsDefined.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/FindDotIsDefined.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/JavaConversionsUse.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/JavaConversionsUse.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/JavaConversionsUse.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/JavaConversionsUse.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/ListAppend.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ListAppend.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/ListAppend.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ListAppend.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/ListSize.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ListSize.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/ListSize.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ListSize.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/MapGetAndGetOrElse.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/MapGetAndGetOrElse.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/MapGetAndGetOrElse.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/MapGetAndGetOrElse.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/NegationIsEmpty.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/NegationIsEmpty.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/NegationIsEmpty.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/NegationIsEmpty.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/NegationNonEmpty.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/NegationNonEmpty.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/NegationNonEmpty.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/NegationNonEmpty.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/NegativeSeqPad.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/NegativeSeqPad.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/NegativeSeqPad.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/NegativeSeqPad.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/PredefIterableIsMutable.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/PredefIterableIsMutable.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/PredefIterableIsMutable.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/PredefIterableIsMutable.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/PredefSeqIsMutable.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/PredefSeqIsMutable.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/PredefSeqIsMutable.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/PredefSeqIsMutable.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/PredefTraversableIsMutable.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/PredefTraversableIsMutable.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/PredefTraversableIsMutable.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/PredefTraversableIsMutable.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/PreferMapEmpty.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/PreferMapEmpty.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/PreferMapEmpty.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/PreferMapEmpty.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/PreferSeqEmpty.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/PreferSeqEmpty.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/PreferSeqEmpty.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/PreferSeqEmpty.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/PreferSetEmpty.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/PreferSetEmpty.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/PreferSetEmpty.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/PreferSetEmpty.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/ReverseFunc.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ReverseFunc.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/ReverseFunc.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ReverseFunc.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/ReverseTailReverse.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ReverseTailReverse.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/ReverseTailReverse.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ReverseTailReverse.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/ReverseTakeReverse.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ReverseTakeReverse.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/ReverseTakeReverse.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/ReverseTakeReverse.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/SwapSortFilter.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/SwapSortFilter.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/SwapSortFilter.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/SwapSortFilter.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/UnsafeContains.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/UnsafeContains.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/UnsafeContains.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/UnsafeContains.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/UnsafeTraversableMethods.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/UnsafeTraversableMethods.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/collections/UnsafeTraversableMethods.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/collections/UnsafeTraversableMethods.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/controlflow/RepeatedIfElseBody.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/controlflow/RepeatedIfElseBody.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/controlflow/RepeatedIfElseBody.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/controlflow/RepeatedIfElseBody.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/controlflow/WhileTrue.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/controlflow/WhileTrue.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/controlflow/WhileTrue.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/controlflow/WhileTrue.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/empty/EmptyFor.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyFor.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/empty/EmptyFor.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyFor.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/empty/EmptyIfBlock.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyIfBlock.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/empty/EmptyIfBlock.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyIfBlock.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/empty/EmptyMethod.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyMethod.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/empty/EmptyMethod.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyMethod.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/empty/EmptySynchronizedBlock.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptySynchronizedBlock.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/empty/EmptySynchronizedBlock.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptySynchronizedBlock.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/empty/EmptyTryBlock.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyTryBlock.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/empty/EmptyTryBlock.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyTryBlock.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/empty/EmptyWhileBlock.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyWhileBlock.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/empty/EmptyWhileBlock.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyWhileBlock.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/equality/ComparingFloatingPointTypes.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/equality/ComparingFloatingPointTypes.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/equality/ComparingFloatingPointTypes.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/equality/ComparingFloatingPointTypes.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/equality/ComparingUnrelatedTypes.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/equality/ComparingUnrelatedTypes.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/equality/ComparingUnrelatedTypes.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/equality/ComparingUnrelatedTypes.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/equality/ComparisonWithSelf.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/equality/ComparisonWithSelf.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/equality/ComparisonWithSelf.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/equality/ComparisonWithSelf.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/exception/CatchException.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchException.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/exception/CatchException.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchException.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/exception/CatchExceptionImmediatelyRethrown.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchExceptionImmediatelyRethrown.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/exception/CatchExceptionImmediatelyRethrown.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchExceptionImmediatelyRethrown.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/exception/CatchFatal.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchFatal.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/exception/CatchFatal.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchFatal.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/exception/CatchNpe.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchNpe.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/exception/CatchNpe.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchNpe.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/exception/CatchThrowable.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchThrowable.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/exception/CatchThrowable.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchThrowable.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/exception/IncorrectlyNamedExceptions.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/IncorrectlyNamedExceptions.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/exception/IncorrectlyNamedExceptions.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/IncorrectlyNamedExceptions.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/exception/SwallowedException.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/SwallowedException.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/exception/SwallowedException.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/SwallowedException.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/exception/UnreachableCatch.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/UnreachableCatch.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/exception/UnreachableCatch.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/exception/UnreachableCatch.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/imports/DuplicateImport.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/imports/DuplicateImport.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/imports/DuplicateImport.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/imports/DuplicateImport.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/imports/WildcardImport.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/imports/WildcardImport.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/imports/WildcardImport.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/imports/WildcardImport.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/inference/BoundedByFinalType.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/inference/BoundedByFinalType.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/inference/BoundedByFinalType.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/inference/BoundedByFinalType.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/inference/MethodReturningAny.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/inference/MethodReturningAny.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/inference/MethodReturningAny.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/inference/MethodReturningAny.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/inference/PointlessTypeBounds.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/inference/PointlessTypeBounds.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/inference/PointlessTypeBounds.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/inference/PointlessTypeBounds.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/inference/ProductWithSerializableInferred.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/inference/ProductWithSerializableInferred.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/inference/ProductWithSerializableInferred.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/inference/ProductWithSerializableInferred.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/matching/PartialFunctionInsteadOfMatch.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/matching/PartialFunctionInsteadOfMatch.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/matching/PartialFunctionInsteadOfMatch.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/matching/PartialFunctionInsteadOfMatch.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/matching/RepeatedCaseBody.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/matching/RepeatedCaseBody.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/matching/RepeatedCaseBody.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/matching/RepeatedCaseBody.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/matching/SuspiciousMatchOnClassObject.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/matching/SuspiciousMatchOnClassObject.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/matching/SuspiciousMatchOnClassObject.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/matching/SuspiciousMatchOnClassObject.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/math/BigDecimalDoubleConstructor.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/math/BigDecimalDoubleConstructor.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/math/BigDecimalDoubleConstructor.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/math/BigDecimalDoubleConstructor.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/math/BigDecimalScaleWithoutRoundingMode.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/math/BigDecimalScaleWithoutRoundingMode.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/math/BigDecimalScaleWithoutRoundingMode.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/math/BigDecimalScaleWithoutRoundingMode.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/math/BrokenOddness.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/math/BrokenOddness.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/math/BrokenOddness.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/math/BrokenOddness.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/math/DivideByOne.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/math/DivideByOne.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/math/DivideByOne.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/math/DivideByOne.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/math/ModOne.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/math/ModOne.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/math/ModOne.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/math/ModOne.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/math/NanComparison.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/math/NanComparison.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/math/NanComparison.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/math/NanComparison.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/math/UseCbrt.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/math/UseCbrt.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/math/UseCbrt.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/math/UseCbrt.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/math/UseExpM1.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/math/UseExpM1.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/math/UseExpM1.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/math/UseExpM1.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/math/UseLog10.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/math/UseLog10.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/math/UseLog10.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/math/UseLog10.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/math/UseLog1P.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/math/UseLog1P.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/math/UseLog1P.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/math/UseLog1P.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/math/UseSqrt.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/math/UseSqrt.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/math/UseSqrt.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/math/UseSqrt.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/math/ZeroNumerator.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/math/ZeroNumerator.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/math/ZeroNumerator.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/math/ZeroNumerator.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/naming/ClassNames.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/naming/ClassNames.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/naming/ClassNames.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/naming/ClassNames.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/naming/MethodNames.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/naming/MethodNames.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/naming/MethodNames.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/naming/MethodNames.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/naming/ObjectNames.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/naming/ObjectNames.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/naming/ObjectNames.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/naming/ObjectNames.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/nulls/NullAssignment.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/nulls/NullAssignment.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/nulls/NullAssignment.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/nulls/NullAssignment.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/nulls/NullParameter.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/nulls/NullParameter.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/nulls/NullParameter.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/nulls/NullParameter.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/option/EitherGet.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/option/EitherGet.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/option/EitherGet.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/option/EitherGet.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/option/ImpossibleOptionSizeCondition.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/option/ImpossibleOptionSizeCondition.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/option/ImpossibleOptionSizeCondition.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/option/ImpossibleOptionSizeCondition.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/option/OptionGet.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/option/OptionGet.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/option/OptionGet.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/option/OptionGet.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/option/OptionSize.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/option/OptionSize.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/option/OptionSize.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/option/OptionSize.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/string/ArraysInFormat.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/string/ArraysInFormat.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/string/ArraysInFormat.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/string/ArraysInFormat.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/string/ArraysToString.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/string/ArraysToString.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/string/ArraysToString.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/string/ArraysToString.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/string/EmptyInterpolatedString.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/string/EmptyInterpolatedString.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/string/EmptyInterpolatedString.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/string/EmptyInterpolatedString.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/string/IllegalFormatString.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/string/IllegalFormatString.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/string/IllegalFormatString.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/string/IllegalFormatString.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/string/IncorrectNumberOfArgsToFormat.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/string/IncorrectNumberOfArgsToFormat.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/string/IncorrectNumberOfArgsToFormat.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/string/IncorrectNumberOfArgsToFormat.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/string/InvalidRegex.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/string/InvalidRegex.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/string/InvalidRegex.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/string/InvalidRegex.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/string/LooksLikeInterpolatedString.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/string/LooksLikeInterpolatedString.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/string/LooksLikeInterpolatedString.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/string/LooksLikeInterpolatedString.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/string/StripMarginOnRegex.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/string/StripMarginOnRegex.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/string/StripMarginOnRegex.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/string/StripMarginOnRegex.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/string/SubstringZero.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/string/SubstringZero.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/string/SubstringZero.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/string/SubstringZero.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/string/UnsafeStringContains.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/string/UnsafeStringContains.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/string/UnsafeStringContains.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/string/UnsafeStringContains.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/style/AvoidOperatorOverload.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/style/AvoidOperatorOverload.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/style/AvoidOperatorOverload.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/style/AvoidOperatorOverload.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/style/ParameterlessMethodReturnsUnit.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/style/ParameterlessMethodReturnsUnit.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/style/ParameterlessMethodReturnsUnit.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/style/ParameterlessMethodReturnsUnit.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/style/SimplifyBooleanExpression.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/style/SimplifyBooleanExpression.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/style/SimplifyBooleanExpression.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/style/SimplifyBooleanExpression.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/ConstantIf.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/ConstantIf.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/ConstantIf.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/ConstantIf.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/RedundantFinalizer.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/RedundantFinalizer.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/RedundantFinalizer.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/RedundantFinalizer.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/StoreBeforeReturn.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/StoreBeforeReturn.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/StoreBeforeReturn.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/StoreBeforeReturn.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/UnnecessaryConversion.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/UnnecessaryConversion.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/UnnecessaryConversion.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/UnnecessaryConversion.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/UnnecessaryIf.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/UnnecessaryIf.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/UnnecessaryIf.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/UnnecessaryIf.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/UnnecessaryReturnUse.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/UnnecessaryReturnUse.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/UnnecessaryReturnUse.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/UnnecessaryReturnUse.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/UnusedMethodParameter.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/UnusedMethodParameter.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/UnusedMethodParameter.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/UnusedMethodParameter.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/VarCouldBeVal.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/VarCouldBeVal.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/unneccesary/VarCouldBeVal.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/unneccesary/VarCouldBeVal.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/unsafe/AsInstanceOf.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/unsafe/AsInstanceOf.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/unsafe/AsInstanceOf.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/unsafe/AsInstanceOf.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/unsafe/FinalizerWithoutSuper.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/unsafe/FinalizerWithoutSuper.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/unsafe/FinalizerWithoutSuper.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/unsafe/FinalizerWithoutSuper.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/unsafe/IsInstanceOf.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/unsafe/IsInstanceOf.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/unsafe/IsInstanceOf.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/unsafe/IsInstanceOf.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/unsafe/TryGet.scala b/src/main/scala-2/com/sksamuel/scapegoat/inspections/unsafe/TryGet.scala similarity index 100% rename from src/main/scala/com/sksamuel/scapegoat/inspections/unsafe/TryGet.scala rename to src/main/scala-2/com/sksamuel/scapegoat/inspections/unsafe/TryGet.scala diff --git a/src/main/scala/com/sksamuel/scapegoat/plugin.scala b/src/main/scala-2/com/sksamuel/scapegoat/plugin.scala similarity index 85% rename from src/main/scala/com/sksamuel/scapegoat/plugin.scala rename to src/main/scala-2/com/sksamuel/scapegoat/plugin.scala index 88ca96fd..6a149704 100644 --- a/src/main/scala/com/sksamuel/scapegoat/plugin.scala +++ b/src/main/scala-2/com/sksamuel/scapegoat/plugin.scala @@ -27,8 +27,9 @@ class ScapegoatPlugin(val global: Global) extends Plugin { override val optionsHelp: Option[String] = Some(Configuration.optionsHelp) } -class ScapegoatComponent(val global: Global, inspections: Seq[Inspection]) +class ScapegoatComponent(val global: Global, override val inspections: Seq[Inspection]) extends PluginComponent + with ScapegoatBasePlugin with TypingTransformers with Transform { @@ -36,7 +37,7 @@ class ScapegoatComponent(val global: Global, inspections: Seq[Inspection]) import global._ - var configuration: Configuration = null + override var configuration: Configuration = null val debug: Boolean = false var summary: Boolean = true @@ -47,19 +48,9 @@ class ScapegoatComponent(val global: Global, inspections: Seq[Inspection]) override val runsAfter: List[String] = List("typer") override val runsBefore = List[String]("patmat") - def disableAll: Boolean = configuration.disabledInspections.exists(_.compareToIgnoreCase("all") == 0) + lazy val feedback = new FeedbackScala2(global.reporter, configuration) - def activeInspections: Seq[Inspection] = { - if (configuration.enabledInspections.isEmpty) - (inspections ++ configuration.customInspectors) - .filterNot(inspection => configuration.disabledInspections.contains(inspection.name)) - else - (inspections ++ configuration.customInspectors) - .filter(inspection => configuration.enabledInspections.contains(inspection.name)) - } - lazy val feedback = new Feedback(global.reporter, configuration) - - def writeReport(isDisabled: Boolean, reportName: String, writer: (File, Feedback) => File): Unit = { + def writeReport(isDisabled: Boolean, reportName: String, writer: (File, Feedback[_]) => File): Unit = { if (!isDisabled) { configuration.dataDir.foreach { outputDir => val output = writer(outputDir, feedback) diff --git a/src/main/scala-3/com/sksamuel/scapegoat/FeedbackDotty.scala b/src/main/scala-3/com/sksamuel/scapegoat/FeedbackDotty.scala new file mode 100644 index 00000000..990b04ff --- /dev/null +++ b/src/main/scala-3/com/sksamuel/scapegoat/FeedbackDotty.scala @@ -0,0 +1,22 @@ +package com.sksamuel.scapegoat + +import dotty.tools.dotc.core.Contexts.Context +import dotty.tools.dotc.core.Decorators.toMessage +import dotty.tools.dotc.reporting.Diagnostic +import dotty.tools.dotc.util.SourcePosition + +class FeedbackDotty(configuration: Configuration)(using ctx: Context) + extends Feedback[SourcePosition](configuration) { + + protected def toSourcePath(pos: SourcePosition): String = pos.source().path() + protected def toSourceLine(pos: SourcePosition): Int = pos.line + protected def report(pos: SourcePosition, level: Level, message: String): Unit = { + level match { + case Levels.Error => ctx.reporter.report(Diagnostic.Error(message, pos)) + case Levels.Warning => ctx.reporter.report(Diagnostic.Warning(message.toMessage, pos)) + case Levels.Info => ctx.reporter.report(Diagnostic.Info(message, pos)) + case Levels.Ignore => () + } + } + +} diff --git a/src/main/scala-3/com/sksamuel/scapegoat/Inspection.scala b/src/main/scala-3/com/sksamuel/scapegoat/Inspection.scala new file mode 100644 index 00000000..0070927e --- /dev/null +++ b/src/main/scala-3/com/sksamuel/scapegoat/Inspection.scala @@ -0,0 +1,18 @@ +package com.sksamuel.scapegoat + +import dotty.tools.dotc.ast.tpd +import dotty.tools.dotc.core.Contexts.Context +import dotty.tools.dotc.util.SourcePosition + +abstract class Inspection( + val text: String, + val defaultLevel: Level, + val description: String, + val explanation: String +) extends InspectionBase { + + val self: Inspection = this + + def inspect(feedback: Feedback[SourcePosition], tree: tpd.Tree)(using Context): Unit + +} diff --git a/src/main/scala-3/com/sksamuel/scapegoat/InspectionTraverser.scala b/src/main/scala-3/com/sksamuel/scapegoat/InspectionTraverser.scala new file mode 100644 index 00000000..21a9b9b8 --- /dev/null +++ b/src/main/scala-3/com/sksamuel/scapegoat/InspectionTraverser.scala @@ -0,0 +1,14 @@ +package com.sksamuel.scapegoat + +import dotty.tools.dotc.ast.tpd.* +import dotty.tools.dotc.core.Contexts.Context +import dotty.tools.dotc.util.NoSource + +abstract class InspectionTraverser extends TreeTraverser { + + extension (tree: Tree)(using Context) + def asSnippet: Option[String] = tree.source match + case NoSource => None + case _ => Some(tree.source.content().slice(tree.sourcePos.start, tree.sourcePos.end).mkString) + +} diff --git a/src/main/scala-3/com/sksamuel/scapegoat/Inspections.scala b/src/main/scala-3/com/sksamuel/scapegoat/Inspections.scala new file mode 100644 index 00000000..945eb501 --- /dev/null +++ b/src/main/scala-3/com/sksamuel/scapegoat/Inspections.scala @@ -0,0 +1,11 @@ +package com.sksamuel.scapegoat + +import com.sksamuel.scapegoat.inspections.option._ + +object Inspections { + + final val inspections: List[Inspection] = List( + new OptionGet + ) + +} diff --git a/src/main/scala-3/com/sksamuel/scapegoat/Plugin.scala b/src/main/scala-3/com/sksamuel/scapegoat/Plugin.scala new file mode 100644 index 00000000..5af777d6 --- /dev/null +++ b/src/main/scala-3/com/sksamuel/scapegoat/Plugin.scala @@ -0,0 +1,118 @@ +package com.sksamuel.scapegoat + +import java.io.File + +import com.sksamuel.scapegoat.io.IOUtils +import dotty.tools.dotc.CompilationUnit +import dotty.tools.dotc.ast.tpd +import dotty.tools.dotc.core.Contexts.Context +import dotty.tools.dotc.plugins.{PluginPhase, StandardPlugin} +import dotty.tools.dotc.reporting.Diagnostic +import dotty.tools.dotc.reporting.Diagnostic.{Error, Info, Warning} +import dotty.tools.dotc.transform.PatternMatcher +import dotty.tools.dotc.typer.TyperPhase +import dotty.tools.dotc.util.NoSourcePosition + +class ScapegoatPlugin extends StandardPlugin { + + override def name: String = "scapegoat" + + override def description: String = "scapegoat compiler plugin" + + override val optionsHelp: Option[String] = Some(Configuration.optionsHelp) + + override def init(options: List[String]): List[PluginPhase] = { + val config = Configuration.fromPluginOptions(options) + new ScapegoatPhase(config, Inspections.inspections) :: Nil + } + +} + +class ScapegoatPhase(var configuration: Configuration, override val inspections: Seq[Inspection]) + extends PluginPhase + with ScapegoatBasePlugin { + + import tpd.* + + private[scapegoat] var feedback: Option[FeedbackDotty] = None + + override def phaseName: String = "scapegoat" + + override val runsAfter: Set[String] = Set(TyperPhase.name) + + override val runsBefore: Set[String] = Set(PatternMatcher.name) + + override def runOn(units: List[CompilationUnit])(using runCtx: Context): List[CompilationUnit] = { + import dotty.tools.dotc.core.Decorators.toMessage + + if (disableAll) { + runCtx.reporter.report(Info("[scapegoat] All inspections disabled", NoSourcePosition)) + units + } else { + if (configuration.verbose) { + runCtx.reporter.report( + Info(s"Running with ${activeInspections.size} active inspections", NoSourcePosition) + ) + } + + val feedbackDotty = new FeedbackDotty(configuration) + feedback = Some(feedbackDotty) + val ran = super.runOn(units) + + val errors = feedbackDotty.errors.size + val warns = feedbackDotty.warns.size + val infos = feedbackDotty.infos.size + val msg = s"[scapegoat] Analysis complete: $errors errors $warns warns $infos infos" + val level: Diagnostic = + if (errors > 0) + Diagnostic.Error(msg, NoSourcePosition) + else if (warns > 0) + Diagnostic.Warning(msg.toMessage, NoSourcePosition) + else + Diagnostic.Info(msg, NoSourcePosition) + runCtx.reporter.report(level) + + val reports = configuration.reports + writeReport(reports.disableHTML, "HTML", feedbackDotty, IOUtils.writeHTMLReport) + writeReport(reports.disableXML, "XML", feedbackDotty, IOUtils.writeXMLReport) + writeReport( + reports.disableScalastyleXML, + "Scalastyle XML", + feedbackDotty, + IOUtils.writeScalastyleReport + ) + writeReport(reports.disableMarkdown, "Markdown", feedbackDotty, IOUtils.writeMarkdownReport) + writeReport( + reports.disableGitlabCodeQuality, + "GitLab Code Quality", + feedbackDotty, + IOUtils.writeGitlabCodeQualityReport + ) + + ran + } + } + + override def transformUnit(tree: tpd.Tree)(using ctx: Context): tpd.Tree = { + activeInspections.foreach { inspection => + feedback.foreach(f => inspection.inspect(f, tree)) + } + tree + } + + private def writeReport( + reportDisabled: Boolean, + reportName: String, + feedback: FeedbackDotty, + writer: (File, Feedback[?]) => File + )(using ctx: Context): Unit = { + if (!reportDisabled) { + configuration.dataDir.foreach { outputDir => + val output = writer(outputDir, feedback) + if (configuration.verbose) + ctx.reporter.report(Info(s"[scapegoat] Written $reportName report [$output]", NoSourcePosition)) + } + } + } + +} diff --git a/src/main/scala-3/com/sksamuel/scapegoat/inspections/option/OptionGet.scala b/src/main/scala-3/com/sksamuel/scapegoat/inspections/option/OptionGet.scala new file mode 100644 index 00000000..a2b6099f --- /dev/null +++ b/src/main/scala-3/com/sksamuel/scapegoat/inspections/option/OptionGet.scala @@ -0,0 +1,34 @@ +package com.sksamuel.scapegoat.inspections.option + +import com.sksamuel.scapegoat.* +import dotty.tools.dotc.ast.Trees.* +import dotty.tools.dotc.ast.tpd +import dotty.tools.dotc.core.Contexts.Context +import dotty.tools.dotc.core.StdNames.* +import dotty.tools.dotc.util.SourcePosition + +class OptionGet + extends Inspection( + text = "Use of Option.get", + defaultLevel = Levels.Error, + description = "Checks for use of Option.get.", + explanation = + "Using Option.get defeats the purpose of using Option in the first place. Use the following instead: Option.getOrElse, Option.fold, pattern matching or don't take the value out of the container and map over it to transform it." + ) { + + import tpd.* + + def inspect(feedback: Feedback[SourcePosition], tree: tpd.Tree)(using ctx: Context): Unit = { + val traverser = new InspectionTraverser { + def traverse(tree: Tree)(using Context): Unit = { + tree match { + case Select(left, nme.get) + if left.tpe.typeSymbol.lastKnownDenotation.fullName.toString == "scala.Option" => + feedback.warn(tree.sourcePos, self, tree.asSnippet) + case _ => traverseChildren(tree) + } + } + } + traverser.traverse(tree) + } +} diff --git a/src/main/scala/com/sksamuel/scapegoat/CorePlugin.scala b/src/main/scala/com/sksamuel/scapegoat/CorePlugin.scala new file mode 100644 index 00000000..a1d9c833 --- /dev/null +++ b/src/main/scala/com/sksamuel/scapegoat/CorePlugin.scala @@ -0,0 +1,23 @@ +package com.sksamuel.scapegoat + +/** + * Shareable logic for the compiler plugin between Scala 2 and 3 + */ +abstract trait ScapegoatBasePlugin { + + var configuration: Configuration + val inspections: Seq[Inspection] + + // Tests override inspections which doesn't play nice with initialization order. + private lazy val allInspections = inspections ++ configuration.customInspectors + + def disableAll: Boolean = configuration.disabledInspections.exists(_.compareToIgnoreCase("all") == 0) + + def activeInspections: Seq[Inspection] = { + if (configuration.enabledInspections.isEmpty) + allInspections.filterNot(inspection => configuration.disabledInspections.contains(inspection.name)) + else + allInspections.filter(inspection => configuration.enabledInspections.contains(inspection.name)) + } + +} diff --git a/src/main/scala/com/sksamuel/scapegoat/Feedback.scala b/src/main/scala/com/sksamuel/scapegoat/Feedback.scala index 497ba24a..ff0e71f7 100644 --- a/src/main/scala/com/sksamuel/scapegoat/Feedback.scala +++ b/src/main/scala/com/sksamuel/scapegoat/Feedback.scala @@ -1,15 +1,12 @@ package com.sksamuel.scapegoat import scala.collection.mutable.ListBuffer -import scala.reflect.internal.util.Position -import scala.tools.nsc.reporters.Reporter /** * @author * Stephen Samuel */ -class Feedback( - reporter: Reporter, +abstract class Feedback[T]( configuration: Configuration ) { @@ -27,7 +24,7 @@ class Feedback( def warnings(level: Level): Seq[Warning] = warnings.filter(_.level == level) def warn( - pos: Position, + pos: T, inspection: Inspection, snippet: Option[String] = None, adhocExplanation: Option[String] = None @@ -45,11 +42,11 @@ class Feedback( case _ => level } - val sourceFileFull = pos.source.file.path + val sourceFileFull = toSourcePath(pos) val sourceFileNormalized = normalizeSourceFile(sourceFileFull) val warning = Warning( text = text, - line = pos.line, + line = toSourceLine(pos), level = adjustedLevel, sourceFileFull = sourceFileFull, sourceFileNormalized = sourceFileNormalized, @@ -61,19 +58,19 @@ class Feedback( if (shouldPrint(warning)) { val snippetText = snippet.fold("")("\n " + _ + "\n") - val report = s"""[scapegoat] [$name] $text - | $explanation$snippetText""".stripMargin + val msg = s"""[scapegoat] [$name] $text + | $explanation$snippetText""".stripMargin - adjustedLevel match { - case Levels.Error => reporter.error(pos, report) - case Levels.Warning => reporter.warning(pos, report) - case Levels.Info => reporter.echo(pos, report) - case Levels.Ignore => () - } + report(pos, adjustedLevel, msg) } } - private def normalizeSourceFile(sourceFile: String): String = { + protected def toSourcePath(pos: T): String + protected def toSourceLine(pos: T): Int + + protected def report(pos: T, level: Level, message: String): Unit + + private[scapegoat] def normalizeSourceFile(sourceFile: String): String = { val sourcePrefix = configuration.sourcePrefix val indexOf = sourceFile.indexOf(sourcePrefix) val fullPrefix = if (sourcePrefix.endsWith("/")) sourcePrefix else s"$sourcePrefix/" @@ -81,23 +78,3 @@ class Feedback( packageAndFile.replace('/', '.').replace('\\', '.') } } - -final case class Warning( - text: String, - line: Int, - level: Level, - sourceFileFull: String, - sourceFileNormalized: String, - snippet: Option[String], - explanation: String, - inspection: String -) { - def hasMinimalLevelOf(minimalLevel: Level): Boolean = { - minimalLevel match { - case Levels.Ignore => throw new IllegalArgumentException("Ignore cannot be minimal level") - case Levels.Info => this.level.higherOrEqualTo(Levels.Info) - case Levels.Warning => this.level.higherOrEqualTo(Levels.Warning) - case Levels.Error => this.level.higherOrEqualTo(Levels.Error) - } - } -} diff --git a/src/main/scala/com/sksamuel/scapegoat/InspectionBase.scala b/src/main/scala/com/sksamuel/scapegoat/InspectionBase.scala new file mode 100644 index 00000000..fad4e06c --- /dev/null +++ b/src/main/scala/com/sksamuel/scapegoat/InspectionBase.scala @@ -0,0 +1,17 @@ +package com.sksamuel.scapegoat + +/** + * @author + * Stephen Samuel + */ +trait InspectionBase { + + val text: String + val defaultLevel: Level + val description: String + val explanation: String + + def isEnabled: Boolean = true + + def name: String = getClass.getSimpleName +} diff --git a/src/main/scala/com/sksamuel/scapegoat/Warning.scala b/src/main/scala/com/sksamuel/scapegoat/Warning.scala new file mode 100644 index 00000000..741f3e4f --- /dev/null +++ b/src/main/scala/com/sksamuel/scapegoat/Warning.scala @@ -0,0 +1,21 @@ +package com.sksamuel.scapegoat + +final case class Warning( + text: String, + line: Int, + level: Level, + sourceFileFull: String, + sourceFileNormalized: String, + snippet: Option[String], + explanation: String, + inspection: String +) { + def hasMinimalLevelOf(minimalLevel: Level): Boolean = { + minimalLevel match { + case Levels.Ignore => throw new IllegalArgumentException("Ignore cannot be minimal level") + case Levels.Info => this.level.higherOrEqualTo(Levels.Info) + case Levels.Warning => this.level.higherOrEqualTo(Levels.Warning) + case Levels.Error => this.level.higherOrEqualTo(Levels.Error) + } + } +} diff --git a/src/main/scala/com/sksamuel/scapegoat/io/GitlabCodeQualityReportWriter.scala b/src/main/scala/com/sksamuel/scapegoat/io/GitlabCodeQualityReportWriter.scala index ac680a90..f557a6af 100644 --- a/src/main/scala/com/sksamuel/scapegoat/io/GitlabCodeQualityReportWriter.scala +++ b/src/main/scala/com/sksamuel/scapegoat/io/GitlabCodeQualityReportWriter.scala @@ -14,7 +14,7 @@ object GitlabCodeQualityReportWriter extends ReportWriter { override protected def fileName: String = "scapegoat-gitlab.json" - override protected def generate(feedback: Feedback): String = { + override protected def generate(feedback: Feedback[_]): String = { val md5Digest = MessageDigest.getInstance("MD5") toCodeQualityElements(feedback.warningsWithMinimalLevel, sys.env.get("CI_PROJECT_DIR"), md5Digest) .map(_.toJsonArrayElement) diff --git a/src/main/scala/com/sksamuel/scapegoat/io/HtmlReportWriter.scala b/src/main/scala/com/sksamuel/scapegoat/io/HtmlReportWriter.scala index cd809977..10c8147e 100644 --- a/src/main/scala/com/sksamuel/scapegoat/io/HtmlReportWriter.scala +++ b/src/main/scala/com/sksamuel/scapegoat/io/HtmlReportWriter.scala @@ -90,7 +90,7 @@ object HtmlReportWriter extends ReportWriter { - private def body(reporter: Feedback): Elem = + private def body(reporter: Feedback[_]): Elem =

Scapegoat Inspections

@@ -137,7 +137,7 @@ object HtmlReportWriter extends ReportWriter { } } - private def toHTML(reporter: Feedback): Elem = + private def toHTML(reporter: Feedback[_]): Elem = {header}{body(reporter)} @@ -145,5 +145,5 @@ object HtmlReportWriter extends ReportWriter { private def decorateCode(text: String): Elem = XML.loadString(s"${text.replaceAll("`([^`]*)`", "$1")}") - override protected def generate(feedback: Feedback): String = toHTML(feedback).toString() + override protected def generate(feedback: Feedback[_]): String = toHTML(feedback).toString() } diff --git a/src/main/scala/com/sksamuel/scapegoat/io/IOUtils.scala b/src/main/scala/com/sksamuel/scapegoat/io/IOUtils.scala index 3084aec1..41798234 100644 --- a/src/main/scala/com/sksamuel/scapegoat/io/IOUtils.scala +++ b/src/main/scala/com/sksamuel/scapegoat/io/IOUtils.scala @@ -9,18 +9,18 @@ import com.sksamuel.scapegoat.Feedback * Stephen Samuel */ object IOUtils { - def writeHTMLReport(targetDir: File, reporter: Feedback): File = + def writeHTMLReport(targetDir: File, reporter: Feedback[_]): File = HtmlReportWriter.write(targetDir, reporter) - def writeXMLReport(targetDir: File, reporter: Feedback): File = + def writeXMLReport(targetDir: File, reporter: Feedback[_]): File = XmlReportWriter.write(targetDir, reporter) - def writeScalastyleReport(targetDir: File, reporter: Feedback): File = + def writeScalastyleReport(targetDir: File, reporter: Feedback[_]): File = ScalastyleReportWriter.write(targetDir, reporter) - def writeMarkdownReport(targetDir: File, reporter: Feedback): File = + def writeMarkdownReport(targetDir: File, reporter: Feedback[_]): File = MarkdownReportWriter.write(targetDir, reporter) - def writeGitlabCodeQualityReport(targetDir: File, reporter: Feedback): File = + def writeGitlabCodeQualityReport(targetDir: File, reporter: Feedback[_]): File = GitlabCodeQualityReportWriter.write(targetDir, reporter) } diff --git a/src/main/scala/com/sksamuel/scapegoat/io/MarkdownReportWriter.scala b/src/main/scala/com/sksamuel/scapegoat/io/MarkdownReportWriter.scala index 27463a54..8c8e6e90 100644 --- a/src/main/scala/com/sksamuel/scapegoat/io/MarkdownReportWriter.scala +++ b/src/main/scala/com/sksamuel/scapegoat/io/MarkdownReportWriter.scala @@ -5,7 +5,7 @@ import com.sksamuel.scapegoat.{Feedback, Levels, Warning} object MarkdownReportWriter extends ReportWriter { override protected def fileName: String = "scapegoat.md" - override protected def generate(reporter: Feedback): String = { + override protected def generate(reporter: Feedback[_]): String = { s"""# Scapegoat Inspections | |**Errors**: ${reporter.warnings(Levels.Error).size.toString} @@ -20,7 +20,7 @@ object MarkdownReportWriter extends ReportWriter { |""".stripMargin } - private def renderAll(reporter: Feedback): String = + private def renderAll(reporter: Feedback[_]): String = reporter.warningsWithMinimalLevel.map(renderWarning).mkString("\n") private def renderWarning(warning: Warning): String = { diff --git a/src/main/scala/com/sksamuel/scapegoat/io/ReportWriter.scala b/src/main/scala/com/sksamuel/scapegoat/io/ReportWriter.scala index bbf501e8..60ebb524 100644 --- a/src/main/scala/com/sksamuel/scapegoat/io/ReportWriter.scala +++ b/src/main/scala/com/sksamuel/scapegoat/io/ReportWriter.scala @@ -8,7 +8,7 @@ trait ReportWriter { protected def fileName: String - protected def generate(feedback: Feedback): String + protected def generate(feedback: Feedback[_]): String private def serialize(file: File, str: String): Unit = { val out = new BufferedWriter(new FileWriter(file)) @@ -16,7 +16,7 @@ trait ReportWriter { out.close() } - def write(targetDir: File, feedback: Feedback): File = { + def write(targetDir: File, feedback: Feedback[_]): File = { targetDir.mkdirs() val file = new File(s"${targetDir.getAbsolutePath}/$fileName") serialize(file, generate(feedback)) diff --git a/src/main/scala/com/sksamuel/scapegoat/io/ScalastyleReportWriter.scala b/src/main/scala/com/sksamuel/scapegoat/io/ScalastyleReportWriter.scala index 970b840a..e1d0cf6f 100644 --- a/src/main/scala/com/sksamuel/scapegoat/io/ScalastyleReportWriter.scala +++ b/src/main/scala/com/sksamuel/scapegoat/io/ScalastyleReportWriter.scala @@ -11,7 +11,7 @@ object ScalastyleReportWriter extends ReportWriter { override protected val fileName = "scapegoat-scalastyle.xml" - private def toXML(feedback: Feedback): Node = + private def toXML(feedback: Feedback[_]): Node = {feedback.warningsWithMinimalLevel.groupBy(_.sourceFileFull).map(fileToXml)} @@ -30,5 +30,5 @@ object ScalastyleReportWriter extends ReportWriter { warning.inspection } snippet={warning.snippet.orNull} explanation={warning.explanation}> - override protected def generate(feedback: Feedback): String = toXML(feedback).toString() + override protected def generate(feedback: Feedback[_]): String = toXML(feedback).toString() } diff --git a/src/main/scala/com/sksamuel/scapegoat/io/XmlReportWriter.scala b/src/main/scala/com/sksamuel/scapegoat/io/XmlReportWriter.scala index 9792a2b1..4450ae06 100644 --- a/src/main/scala/com/sksamuel/scapegoat/io/XmlReportWriter.scala +++ b/src/main/scala/com/sksamuel/scapegoat/io/XmlReportWriter.scala @@ -12,7 +12,7 @@ object XmlReportWriter extends ReportWriter { override protected val fileName = "scapegoat.xml" - private def toXML(feedback: Feedback): Node = { + private def toXML(feedback: Feedback[_]): Node = { @@ -25,5 +25,5 @@ object XmlReportWriter extends ReportWriter { warning.explanation } level={warning.level.toString} file={warning.sourceFileNormalized} inspection={warning.inspection}/> - override protected def generate(feedback: Feedback): String = toXML(feedback).toString() + override protected def generate(feedback: Feedback[_]): String = toXML(feedback).toString() } diff --git a/src/test/scala/com/sksamuel/scapegoat/AllInspectionsTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/AllInspectionsTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/AllInspectionsTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/AllInspectionsTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/FeedbackTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/FeedbackTest.scala similarity index 84% rename from src/test/scala/com/sksamuel/scapegoat/FeedbackTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/FeedbackTest.scala index 5b2c7a8c..54c4312e 100644 --- a/src/test/scala/com/sksamuel/scapegoat/FeedbackTest.scala +++ b/src/test/scala-2/com/sksamuel/scapegoat/FeedbackTest.scala @@ -23,7 +23,7 @@ class FeedbackTest extends AnyFreeSpec with Matchers with OneInstancePerTest wit override def inspector(ctx: InspectionContext): Inspector = ??? } - "Feedback" - { + "FeedbackScala2" - { "should report to reporter" - { "for error" in { val inspection = new DummyInspection( @@ -33,7 +33,8 @@ class FeedbackTest extends AnyFreeSpec with Matchers with OneInstancePerTest wit "This is explanation." ) val reporter = new StoreReporter(new Settings()) - val feedback = new Feedback(reporter, testConfiguration(consoleOutput = true, defaultSourcePrefix)) + val feedback = + new FeedbackScala2(reporter, testConfiguration(consoleOutput = true, defaultSourcePrefix)) feedback.warn(position, inspection) reporter.infos should have size 1 val info = reporter.infos.head @@ -50,7 +51,8 @@ class FeedbackTest extends AnyFreeSpec with Matchers with OneInstancePerTest wit "This is explanation." ) val reporter = new StoreReporter(new Settings()) - val feedback = new Feedback(reporter, testConfiguration(consoleOutput = true, defaultSourcePrefix)) + val feedback = + new FeedbackScala2(reporter, testConfiguration(consoleOutput = true, defaultSourcePrefix)) feedback.warn(position, inspection) reporter.infos should have size 1 val info = reporter.infos.head @@ -67,7 +69,8 @@ class FeedbackTest extends AnyFreeSpec with Matchers with OneInstancePerTest wit "This is explanation." ) val reporter = new StoreReporter(new Settings()) - val feedback = new Feedback(reporter, testConfiguration(consoleOutput = true, defaultSourcePrefix)) + val feedback = + new FeedbackScala2(reporter, testConfiguration(consoleOutput = true, defaultSourcePrefix)) feedback.warn(position, inspection) reporter.infos should have size 1 val info = reporter.infos.head @@ -79,29 +82,27 @@ class FeedbackTest extends AnyFreeSpec with Matchers with OneInstancePerTest wit "should use proper paths" - { "for `src/main/scala`" in { - val normalizeSourceFile = PrivateMethod[String](Symbol("normalizeSourceFile")) val reporter = new StoreReporter(new Settings()) - val feedback = new Feedback(reporter, testConfiguration(consoleOutput = true, defaultSourcePrefix)) + val feedback = + new FeedbackScala2(reporter, testConfiguration(consoleOutput = true, defaultSourcePrefix)) val source = "src/main/scala/com/sksamuel/scapegoat/Test.scala" - val result = feedback invokePrivate normalizeSourceFile(source) + val result = feedback.normalizeSourceFile(source) result should ===("com.sksamuel.scapegoat.Test.scala") } "for `app`" in { - val normalizeSourceFile = PrivateMethod[String](Symbol("normalizeSourceFile")) val reporter = new StoreReporter(new Settings()) - val feedback = new Feedback(reporter, testConfiguration(consoleOutput = true, "app/")) + val feedback = new FeedbackScala2(reporter, testConfiguration(consoleOutput = true, "app/")) val source = "app/com/sksamuel/scapegoat/Test.scala" - val result = feedback invokePrivate normalizeSourceFile(source) + val result = feedback.normalizeSourceFile(source) result should ===("com.sksamuel.scapegoat.Test.scala") } "should add trailing / to the sourcePrefix automatically" in { - val normalizeSourceFile = PrivateMethod[String](Symbol("normalizeSourceFile")) val reporter = new StoreReporter(new Settings()) - val feedback = new Feedback(reporter, testConfiguration(consoleOutput = true, "app/custom")) + val feedback = new FeedbackScala2(reporter, testConfiguration(consoleOutput = true, "app/custom")) val source = "app/custom/com/sksamuel/scapegoat/Test.scala" - val result = feedback invokePrivate normalizeSourceFile(source) + val result = feedback.normalizeSourceFile(source) result should ===("com.sksamuel.scapegoat.Test.scala") } } @@ -135,7 +136,10 @@ class FeedbackTest extends AnyFreeSpec with Matchers with OneInstancePerTest wit val inspections = Seq(inspectionError, inspectionWarning, inspectionInfo, inspectionIgnored) val reporter = new StoreReporter(new Settings()) val feedback = - new Feedback(reporter, testConfiguration(consoleOutput = true, defaultSourcePrefix, Levels.Info)) + new FeedbackScala2( + reporter, + testConfiguration(consoleOutput = true, defaultSourcePrefix, Levels.Info) + ) inspections.foreach(inspection => feedback.warn(position, inspection)) feedback.warningsWithMinimalLevel.length should be(3) } @@ -167,7 +171,7 @@ class FeedbackTest extends AnyFreeSpec with Matchers with OneInstancePerTest wit ) val inspections = Seq(inspectionError, inspectionWarning, inspectionInfo, inspectionIgnored) val reporter = new StoreReporter(new Settings()) - val feedback = new Feedback( + val feedback = new FeedbackScala2( reporter, testConfiguration(consoleOutput = false, defaultSourcePrefix, Levels.Warning) ) @@ -205,7 +209,10 @@ class FeedbackTest extends AnyFreeSpec with Matchers with OneInstancePerTest wit val inspections = Seq(inspectionError, inspectionWarning, inspectionInfo, inspectionIgnored) val reporter = new StoreReporter(new Settings()) val feedback = - new Feedback(reporter, testConfiguration(consoleOutput = false, defaultSourcePrefix, Levels.Error)) + new FeedbackScala2( + reporter, + testConfiguration(consoleOutput = false, defaultSourcePrefix, Levels.Error) + ) inspections.foreach(inspection => feedback.warn(position, inspection)) feedback.warningsWithMinimalLevel.length should be(1) feedback.warningsWithMinimalLevel.map(_.level) should contain only (Seq(Levels.Error): _*) diff --git a/src/test/scala/com/sksamuel/scapegoat/InspectionTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/InspectionTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/InspectionTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/InspectionTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/PluginRunner.scala b/src/test/scala-2/com/sksamuel/scapegoat/PluginRunner.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/PluginRunner.scala rename to src/test/scala-2/com/sksamuel/scapegoat/PluginRunner.scala diff --git a/src/test/scala-2/com/sksamuel/scapegoat/ScalaVersion.scala b/src/test/scala-2/com/sksamuel/scapegoat/ScalaVersion.scala new file mode 100644 index 00000000..2d1939a5 --- /dev/null +++ b/src/test/scala-2/com/sksamuel/scapegoat/ScalaVersion.scala @@ -0,0 +1,7 @@ +package com.sksamuel.scapegoat + +object ScalaVersion { + + val version: Int = 2 + +} diff --git a/src/test/scala/com/sksamuel/scapegoat/ScapegoatTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/ScapegoatTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/ScapegoatTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/ScapegoatTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/TestConfiguration.scala b/src/test/scala-2/com/sksamuel/scapegoat/TestConfiguration.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/TestConfiguration.scala rename to src/test/scala-2/com/sksamuel/scapegoat/TestConfiguration.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/AnyUseTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/AnyUseTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/AnyUseTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/AnyUseTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/AsInstanceOfTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/AsInstanceOfTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/AsInstanceOfTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/AsInstanceOfTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/AvoidToMinusOneTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/AvoidToMinusOneTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/AvoidToMinusOneTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/AvoidToMinusOneTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/BooleanParameterTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/BooleanParameterTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/BooleanParameterTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/BooleanParameterTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/ConstantIfTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/ConstantIfTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/ConstantIfTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/ConstantIfTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/DoubleNegationTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/DoubleNegationTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/DoubleNegationTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/DoubleNegationTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/EitherGetTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/EitherGetTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/EitherGetTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/EitherGetTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/FinalModifierOnCaseClassTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/FinalModifierOnCaseClassTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/FinalModifierOnCaseClassTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/FinalModifierOnCaseClassTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/FinalizerWithoutSuperTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/FinalizerWithoutSuperTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/FinalizerWithoutSuperTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/FinalizerWithoutSuperTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/IsInstanceOfTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/IsInstanceOfTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/IsInstanceOfTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/IsInstanceOfTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/LonelySealedTraitTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/LonelySealedTraitTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/LonelySealedTraitTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/LonelySealedTraitTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/MaxParameterTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/MaxParameterTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/MaxParameterTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/MaxParameterTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/MethodReturningAnyTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/MethodReturningAnyTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/MethodReturningAnyTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/MethodReturningAnyTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/PublicFinalizerTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/PublicFinalizerTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/PublicFinalizerTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/PublicFinalizerTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnMethodTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnMethodTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnMethodTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnMethodTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnVarTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnVarTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnVarTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/RedundantFinalModifierOnVarTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/TryGetTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/TryGetTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/TryGetTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/TryGetTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/TypeShadowingTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/TypeShadowingTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/TypeShadowingTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/TypeShadowingTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/VarClosureTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/VarClosureTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/VarClosureTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/VarClosureTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/VarCouldBeValTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/VarCouldBeValTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/VarCouldBeValTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/VarCouldBeValTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/VarUseTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/VarUseTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/VarUseTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/VarUseTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/VariableShadowingTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/VariableShadowingTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/VariableShadowingTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/VariableShadowingTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/WhileTrueTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/WhileTrueTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/WhileTrueTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/WhileTrueTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/ArrayEqualsTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ArrayEqualsTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/ArrayEqualsTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ArrayEqualsTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/AvoidSizeEqualsZeroTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/AvoidSizeEqualsZeroTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/AvoidSizeEqualsZeroTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/AvoidSizeEqualsZeroTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/AvoidSizeNotEqualsZeroTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/AvoidSizeNotEqualsZeroTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/AvoidSizeNotEqualsZeroTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/AvoidSizeNotEqualsZeroTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/CollectionIndexOnNonIndexedSeqTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionIndexOnNonIndexedSeqTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/CollectionIndexOnNonIndexedSeqTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionIndexOnNonIndexedSeqTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/CollectionNamingConfusionTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionNamingConfusionTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/CollectionNamingConfusionTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionNamingConfusionTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/CollectionNegativeIndexTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionNegativeIndexTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/CollectionNegativeIndexTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionNegativeIndexTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/CollectionPromotionToAnyTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionPromotionToAnyTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/CollectionPromotionToAnyTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/CollectionPromotionToAnyTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptyListTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptyListTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptyListTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptyListTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptySetTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptySetTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptySetTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ComparisonToEmptySetTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/DuplicateMapKeyTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/DuplicateMapKeyTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/DuplicateMapKeyTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/DuplicateMapKeyTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/DuplicateSetValueTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/DuplicateSetValueTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/DuplicateSetValueTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/DuplicateSetValueTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/ExistsSimplifiableToContainsTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ExistsSimplifiableToContainsTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/ExistsSimplifiableToContainsTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ExistsSimplifiableToContainsTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotHeadOptionTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotHeadOptionTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotHeadOptionTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotHeadOptionTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotHeadTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotHeadTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotHeadTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotHeadTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotIsEmptyTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotIsEmptyTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotIsEmptyTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotIsEmptyTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotSizeTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotSizeTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/FilterDotSizeTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterDotSizeTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/FilterOptionAndGetTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterOptionAndGetTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/FilterOptionAndGetTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/FilterOptionAndGetTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/FindAndNotEqualsNoneReplaceWithExistsTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/FindAndNotEqualsNoneReplaceWithExistsTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/FindAndNotEqualsNoneReplaceWithExistsTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/FindAndNotEqualsNoneReplaceWithExistsTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/FindDotIsDefinedTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/FindDotIsDefinedTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/FindDotIsDefinedTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/FindDotIsDefinedTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/JavaConversionsUseTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/JavaConversionsUseTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/JavaConversionsUseTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/JavaConversionsUseTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/ListAppendTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ListAppendTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/ListAppendTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ListAppendTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/ListSizeTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ListSizeTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/ListSizeTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ListSizeTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/MapGetAndGetOrElseTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/MapGetAndGetOrElseTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/MapGetAndGetOrElseTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/MapGetAndGetOrElseTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/NegationIsEmptyTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/NegationIsEmptyTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/NegationIsEmptyTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/NegationIsEmptyTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/NegationNonEmptyTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/NegationNonEmptyTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/NegationNonEmptyTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/NegationNonEmptyTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/NegativeSeqPadTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/NegativeSeqPadTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/NegativeSeqPadTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/NegativeSeqPadTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/PredefIterableIsMutableTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/PredefIterableIsMutableTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/PredefIterableIsMutableTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/PredefIterableIsMutableTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/PredefSeqIsMutableTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/PredefSeqIsMutableTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/PredefSeqIsMutableTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/PredefSeqIsMutableTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/PredefTraversableIsMutableTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/PredefTraversableIsMutableTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/PredefTraversableIsMutableTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/PredefTraversableIsMutableTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/PreferMapEmptyTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/PreferMapEmptyTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/PreferMapEmptyTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/PreferMapEmptyTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/PreferSeqEmptyTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/PreferSeqEmptyTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/PreferSeqEmptyTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/PreferSeqEmptyTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/PreferSetEmptyTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/PreferSetEmptyTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/PreferSetEmptyTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/PreferSetEmptyTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/ReverseFuncTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ReverseFuncTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/ReverseFuncTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ReverseFuncTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/ReverseTailReverseTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ReverseTailReverseTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/ReverseTailReverseTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ReverseTailReverseTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/ReverseTakeReverseTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ReverseTakeReverseTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/ReverseTakeReverseTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/ReverseTakeReverseTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/SwapSortFilterTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/SwapSortFilterTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/SwapSortFilterTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/SwapSortFilterTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/UnsafeContainsTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/UnsafeContainsTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/UnsafeContainsTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/UnsafeContainsTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/UnsafeTraversableMethodsTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/UnsafeTraversableMethodsTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/collections/UnsafeTraversableMethodsTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/collections/UnsafeTraversableMethodsTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/controlflow/RepeatedIfElseBodyTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/controlflow/RepeatedIfElseBodyTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/controlflow/RepeatedIfElseBodyTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/controlflow/RepeatedIfElseBodyTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/empty/EmptyCaseClassTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyCaseClassTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/empty/EmptyCaseClassTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyCaseClassTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/empty/EmptyForTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyForTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/empty/EmptyForTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyForTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/empty/EmptyIfBlockTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyIfBlockTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/empty/EmptyIfBlockTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyIfBlockTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/empty/EmptyMethodTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyMethodTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/empty/EmptyMethodTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyMethodTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/empty/EmptySynchronizedBlockTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptySynchronizedBlockTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/empty/EmptySynchronizedBlockTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptySynchronizedBlockTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/empty/EmptyTryBlockTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyTryBlockTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/empty/EmptyTryBlockTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyTryBlockTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/empty/EmptyWhileBlockTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyWhileBlockTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/empty/EmptyWhileBlockTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/EmptyWhileBlockTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/empty/RedundantFinalizerTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/RedundantFinalizerTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/empty/RedundantFinalizerTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/empty/RedundantFinalizerTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/equality/ComparingFloatingPointTypesTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/equality/ComparingFloatingPointTypesTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/equality/ComparingFloatingPointTypesTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/equality/ComparingFloatingPointTypesTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/equality/ComparingUnrelatedTypesTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/equality/ComparingUnrelatedTypesTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/equality/ComparingUnrelatedTypesTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/equality/ComparingUnrelatedTypesTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/equality/ComparisonWithSelfInspectionTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/equality/ComparisonWithSelfInspectionTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/equality/ComparisonWithSelfInspectionTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/equality/ComparisonWithSelfInspectionTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/exception/CatchExceptionImmediatelyRethrownTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchExceptionImmediatelyRethrownTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/exception/CatchExceptionImmediatelyRethrownTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchExceptionImmediatelyRethrownTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/exception/CatchExceptionTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchExceptionTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/exception/CatchExceptionTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchExceptionTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/exception/CatchFatalTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchFatalTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/exception/CatchFatalTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchFatalTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/exception/CatchNpeTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchNpeTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/exception/CatchNpeTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchNpeTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/exception/CatchThrowableTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchThrowableTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/exception/CatchThrowableTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/CatchThrowableTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/exception/IncorrectlyNamedExceptionsTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/IncorrectlyNamedExceptionsTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/exception/IncorrectlyNamedExceptionsTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/IncorrectlyNamedExceptionsTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/exception/SwallowedExceptionTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/SwallowedExceptionTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/exception/SwallowedExceptionTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/SwallowedExceptionTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/exception/UnreachableCatchTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/UnreachableCatchTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/exception/UnreachableCatchTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/exception/UnreachableCatchTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/imports/DuplicateImportTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/imports/DuplicateImportTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/imports/DuplicateImportTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/imports/DuplicateImportTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/imports/WildcardImportTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/imports/WildcardImportTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/imports/WildcardImportTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/imports/WildcardImportTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/inferrence/BoundedByFinalTypeTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/inferrence/BoundedByFinalTypeTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/inferrence/BoundedByFinalTypeTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/inferrence/BoundedByFinalTypeTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/inferrence/PointlessTypeBoundsTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/inferrence/PointlessTypeBoundsTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/inferrence/PointlessTypeBoundsTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/inferrence/PointlessTypeBoundsTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/inferrence/ProductWithSerializableInferredTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/inferrence/ProductWithSerializableInferredTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/inferrence/ProductWithSerializableInferredTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/inferrence/ProductWithSerializableInferredTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/matching/PartialFunctionInsteadOfMatchTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/matching/PartialFunctionInsteadOfMatchTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/matching/PartialFunctionInsteadOfMatchTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/matching/PartialFunctionInsteadOfMatchTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/matching/RepeatedCaseBodyTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/matching/RepeatedCaseBodyTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/matching/RepeatedCaseBodyTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/matching/RepeatedCaseBodyTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/matching/SuspiciousMatchOnClassObjectTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/matching/SuspiciousMatchOnClassObjectTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/matching/SuspiciousMatchOnClassObjectTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/matching/SuspiciousMatchOnClassObjectTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/math/BigDecimalDoubleConstructorTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/math/BigDecimalDoubleConstructorTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/math/BigDecimalDoubleConstructorTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/math/BigDecimalDoubleConstructorTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/math/BigDecimalScaleWithoutRoundingModeTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/math/BigDecimalScaleWithoutRoundingModeTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/math/BigDecimalScaleWithoutRoundingModeTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/math/BigDecimalScaleWithoutRoundingModeTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/math/BrokenOddnessTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/math/BrokenOddnessTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/math/BrokenOddnessTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/math/BrokenOddnessTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/math/DivideByOneTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/math/DivideByOneTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/math/DivideByOneTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/math/DivideByOneTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/math/ModOneTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/math/ModOneTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/math/ModOneTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/math/ModOneTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/math/NanComparisonTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/math/NanComparisonTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/math/NanComparisonTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/math/NanComparisonTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/math/UseCbrtTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/math/UseCbrtTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/math/UseCbrtTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/math/UseCbrtTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/math/UseExpM1Test.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/math/UseExpM1Test.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/math/UseExpM1Test.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/math/UseExpM1Test.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/math/UseLog10Test.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/math/UseLog10Test.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/math/UseLog10Test.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/math/UseLog10Test.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/math/UseLog1PTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/math/UseLog1PTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/math/UseLog1PTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/math/UseLog1PTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/math/UseSqrtTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/math/UseSqrtTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/math/UseSqrtTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/math/UseSqrtTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/math/ZeroNumeratorTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/math/ZeroNumeratorTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/math/ZeroNumeratorTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/math/ZeroNumeratorTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/names/ClassNamesTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/names/ClassNamesTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/names/ClassNamesTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/names/ClassNamesTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/names/MethodNamesTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/names/MethodNamesTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/names/MethodNamesTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/names/MethodNamesTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/names/ObjectNamesTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/names/ObjectNamesTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/names/ObjectNamesTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/names/ObjectNamesTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/nulls/NullAssignmentTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/nulls/NullAssignmentTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/nulls/NullAssignmentTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/nulls/NullAssignmentTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/nulls/NullParameterTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/nulls/NullParameterTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/nulls/NullParameterTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/nulls/NullParameterTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/option/ImpossibleOptionSizeConditionTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/option/ImpossibleOptionSizeConditionTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/option/ImpossibleOptionSizeConditionTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/option/ImpossibleOptionSizeConditionTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/option/OptionGetTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/option/OptionGetTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/option/OptionGetTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/option/OptionGetTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/option/OptionSizeTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/option/OptionSizeTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/option/OptionSizeTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/option/OptionSizeTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/string/ArraysInFormatTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/string/ArraysInFormatTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/string/ArraysInFormatTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/string/ArraysInFormatTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/string/ArraysToStringTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/string/ArraysToStringTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/string/ArraysToStringTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/string/ArraysToStringTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/string/EmptyInterpolatedStringTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/string/EmptyInterpolatedStringTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/string/EmptyInterpolatedStringTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/string/EmptyInterpolatedStringTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/string/IllegalFormatStringTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/string/IllegalFormatStringTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/string/IllegalFormatStringTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/string/IllegalFormatStringTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/string/IncorrectNumberOfArgsToFormatTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/string/IncorrectNumberOfArgsToFormatTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/string/IncorrectNumberOfArgsToFormatTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/string/IncorrectNumberOfArgsToFormatTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/string/InvalidRegexTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/string/InvalidRegexTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/string/InvalidRegexTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/string/InvalidRegexTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/string/LooksLikeInterpolatedStringTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/string/LooksLikeInterpolatedStringTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/string/LooksLikeInterpolatedStringTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/string/LooksLikeInterpolatedStringTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/string/StripMarginOnRegexTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/string/StripMarginOnRegexTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/string/StripMarginOnRegexTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/string/StripMarginOnRegexTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/string/SubstringZeroTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/string/SubstringZeroTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/string/SubstringZeroTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/string/SubstringZeroTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/string/UnsafeStringContainsTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/string/UnsafeStringContainsTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/string/UnsafeStringContainsTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/string/UnsafeStringContainsTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/style/AvoidOperatorOverloadTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/style/AvoidOperatorOverloadTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/style/AvoidOperatorOverloadTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/style/AvoidOperatorOverloadTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/style/ParameterlessMethodReturnsUnitTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/style/ParameterlessMethodReturnsUnitTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/style/ParameterlessMethodReturnsUnitTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/style/ParameterlessMethodReturnsUnitTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/style/SimplifyBooleanExpressionTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/style/SimplifyBooleanExpressionTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/style/SimplifyBooleanExpressionTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/style/SimplifyBooleanExpressionTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/unnecessary/NoOpOverrideTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/unnecessary/NoOpOverrideTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/unnecessary/NoOpOverrideTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/unnecessary/NoOpOverrideTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/unnecessary/StoreBeforeReturnTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/unnecessary/StoreBeforeReturnTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/unnecessary/StoreBeforeReturnTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/unnecessary/StoreBeforeReturnTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/unnecessary/UnnecessaryConversionTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/unnecessary/UnnecessaryConversionTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/unnecessary/UnnecessaryConversionTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/unnecessary/UnnecessaryConversionTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/unnecessary/UnnecessaryIfTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/unnecessary/UnnecessaryIfTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/unnecessary/UnnecessaryIfTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/unnecessary/UnnecessaryIfTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/unnecessary/UnnecessaryReturnUseTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/unnecessary/UnnecessaryReturnUseTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/unnecessary/UnnecessaryReturnUseTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/unnecessary/UnnecessaryReturnUseTest.scala diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/unnecessary/UnusedMethodParameterTest.scala b/src/test/scala-2/com/sksamuel/scapegoat/inspections/unnecessary/UnusedMethodParameterTest.scala similarity index 100% rename from src/test/scala/com/sksamuel/scapegoat/inspections/unnecessary/UnusedMethodParameterTest.scala rename to src/test/scala-2/com/sksamuel/scapegoat/inspections/unnecessary/UnusedMethodParameterTest.scala diff --git a/src/test/scala-3/com/sksamuel/scapegoat/DottyRunner.scala b/src/test/scala-3/com/sksamuel/scapegoat/DottyRunner.scala new file mode 100644 index 00000000..2357035d --- /dev/null +++ b/src/test/scala-3/com/sksamuel/scapegoat/DottyRunner.scala @@ -0,0 +1,98 @@ +package com.sksamuel.scapegoat + +import java.io.File +import java.io.FileNotFoundException +import java.nio.charset.StandardCharsets +import java.nio.file.Files + +import dotty.tools.dotc.Driver +import dotty.tools.dotc.core.Contexts +import dotty.tools.dotc.core.Contexts.ContextBase +import dotty.tools.dotc.plugins.{Plugin, PluginPhase, Plugins} +import dotty.tools.dotc.reporting.Reporter +import dotty.tools.dotc.reporting.Reporter.NoReporter + +class TestingScapegoatPlugin extends ScapegoatPlugin { + + var scapegoatPhase: Option[ScapegoatPhase] = None + + override def init(options: List[String]): List[PluginPhase] = { + val phases = super.init(options) + scapegoatPhase = phases.headOption.map(_.asInstanceOf[ScapegoatPhase]) + phases + } + + def feedback: FeedbackDotty = scapegoatPhase.get.feedback.get + +} + +class TestingScapegoat extends ContextBase with Plugins { + + private val scapegoat: TestingScapegoatPlugin = new TestingScapegoatPlugin + + override protected def loadRoughPluginsList(using Contexts.Context): List[Plugin] = + scapegoat :: super.loadRoughPluginsList + + def feedback: FeedbackDotty = scapegoat.feedback +} + +class DottyRunner(val inspection: Class[? <: Inspection]) extends Driver { + + private val dottyVersion: String = dotty.tools.dotc.config.Properties.versionNumberString + private val scalaVersion: String = util.Properties.versionNumberString + + private val classPath: List[String] = getScalaJars.map(_.getAbsolutePath) :+ sbtCompileDir.getAbsolutePath + + private val testingContext: TestingScapegoat = new TestingScapegoat + + override protected def initCtx: Contexts.Context = testingContext.initialCtx + + def compileCodeSnippet(source: String): FeedbackDotty = { + val targetDir = Files.createTempDirectory("scapegoat").toFile + val sourceFile = Files + .write(Files.createTempFile("scapegoat_snippet", ".scala"), source.getBytes(StandardCharsets.UTF_8)) + .toFile + sourceFile.deleteOnExit() + targetDir.deleteOnExit() + val _ = process( + Array[String]( + "-Xplugin-require:scapegoat", + "-P:scapegoat:enabledInspections:" + inspection.getSimpleName, + "-P:scapegoat:verbose:true", + "-P:scapegoat:reports:none", + "-d", + targetDir.getAbsolutePath, + "-classpath", + classPath.mkString(File.pathSeparator), + sourceFile.getAbsolutePath + ), + // Silence the compiler output and only rely on feedback results + NoReporter + ) + testingContext.feedback + } + + private def getScalaJars: List[File] = { + val scalaJars = List("scala3-library_3") + findIvyJar("org.scala-lang", "scala-library", scalaVersion) :: scalaJars.map(findScalaJar) + } + + private def findScalaJar(artifactId: String): File = findIvyJar("org.scala-lang", artifactId, dottyVersion) + + private def findIvyJar(groupId: String, artifactId: String, version: String): File = { + val userHome = System.getProperty("user.home") + val sbtHome = userHome + "/.ivy2" + val jarPath = + sbtHome + "/cache/" + groupId + "/" + artifactId + "/jars/" + artifactId + "-" + version + ".jar" + val file = new File(jarPath) + if (file.exists) file + else throw new FileNotFoundException(s"Could not locate [$jarPath].") + } + + private def sbtCompileDir: File = { + val dir = new File("./target/scala-" + dottyVersion + "/classes") + if (dir.exists) dir + else throw new FileNotFoundException(s"Could not locate SBT compile directory for plugin files [$dir]") + } + +} diff --git a/src/test/scala-3/com/sksamuel/scapegoat/FeedbackDottyTest.scala b/src/test/scala-3/com/sksamuel/scapegoat/FeedbackDottyTest.scala new file mode 100644 index 00000000..b1881873 --- /dev/null +++ b/src/test/scala-3/com/sksamuel/scapegoat/FeedbackDottyTest.scala @@ -0,0 +1,92 @@ +package com.sksamuel.scapegoat + +import com.sksamuel.scapegoat.inspections.option.OptionGet +import dotty.tools.dotc.core.Contexts.Context +import dotty.tools.dotc.core.Contexts.ContextBase +import dotty.tools.dotc.interfaces.Diagnostic +import dotty.tools.dotc.reporting.StoreReporter +import dotty.tools.dotc.util.NoSourcePosition +import org.scalatest.freespec.AnyFreeSpec +import org.scalatest.matchers.should + +class FeedbackDottyTest extends AnyFreeSpec with should.Matchers { + + private val configuration = Configuration( + dataDir = None, + disabledInspections = Nil, + enabledInspections = Nil, + ignoredFiles = Nil, + consoleOutput = true, + verbose = true, + reports = Reports(false, false, false, false, false), + customInspectors = Nil, + sourcePrefix = "", + minimalLevel = Levels.Info, + overrideLevels = Map.empty + ) + + "FeedbackDotty" - { + "override inspection levels" - { + "all takes priority" in { + implicit val ctx: Context = (new ContextBase).initialCtx + val feedback = FeedbackDotty( + configuration.copy(overrideLevels = + Map( + "all" -> Levels.Info, + "OptionGet" -> Levels.Warning + ) + ) + ) + feedback.warn(NoSourcePosition, new OptionGet()) + feedback.warnings(Levels.Info).size.shouldBe(1) + } + "able to downgrade errors" in { + implicit val ctx: Context = (new ContextBase).initialCtx + val feedback = FeedbackDotty( + configuration.copy(overrideLevels = + Map( + "OptionGet" -> Levels.Warning + ) + ) + ) + feedback.warn(NoSourcePosition, new OptionGet()) + feedback.warnings(Levels.Warning).size.shouldBe(1) + } + } + + "report to compiler" - { + "error" in { + val reporter = new StoreReporter() + implicit val ctx: Context = (new ContextBase).initialCtx.fresh.setReporter(reporter) + val feedback = FeedbackDotty(configuration) + val inspection = new OptionGet() + feedback.warn(NoSourcePosition, inspection) + reporter.pendingMessages.headOption.map(_.level).shouldBe(Some(Diagnostic.ERROR)) + } + "warning" in { + val reporter = new StoreReporter() + implicit val ctx: Context = (new ContextBase).initialCtx.fresh.setReporter(reporter) + val feedback = FeedbackDotty(configuration.copy(overrideLevels = Map("OptionGet" -> Levels.Warning))) + val inspection = new OptionGet() + feedback.warn(NoSourcePosition, inspection) + reporter.pendingMessages.headOption.map(_.level).shouldBe(Some(Diagnostic.WARNING)) + } + "info" in { + val reporter = new StoreReporter() + implicit val ctx: Context = (new ContextBase).initialCtx.fresh.setReporter(reporter) + val feedback = FeedbackDotty(configuration.copy(overrideLevels = Map("OptionGet" -> Levels.Info))) + val inspection = new OptionGet() + feedback.warn(NoSourcePosition, inspection) + reporter.pendingMessages.headOption.map(_.level).shouldBe(Some(Diagnostic.INFO)) + } + "ignore" in { + val reporter = new StoreReporter() + implicit val ctx: Context = (new ContextBase).initialCtx.fresh.setReporter(reporter) + val feedback = FeedbackDotty(configuration.copy(overrideLevels = Map("OptionGet" -> Levels.Ignore))) + val inspection = new OptionGet() + feedback.warn(NoSourcePosition, inspection) + reporter.pendingMessages.isEmpty.shouldBe(true) + } + } + } +} diff --git a/src/test/scala-3/com/sksamuel/scapegoat/InspectionTest.scala b/src/test/scala-3/com/sksamuel/scapegoat/InspectionTest.scala new file mode 100644 index 00000000..e5bc82f2 --- /dev/null +++ b/src/test/scala-3/com/sksamuel/scapegoat/InspectionTest.scala @@ -0,0 +1,38 @@ +package com.sksamuel.scapegoat + +import org.scalatest.OneInstancePerTest +import org.scalatest.freespec.AnyFreeSpec +import org.scalatest.matchers.should.Matchers + +abstract class InspectionTest(inspection: Class[? <: Inspection]) + extends AnyFreeSpec + with OneInstancePerTest + with Matchers: + + extension (ws: Seq[Warning]) + /** + * Erases (inspection level) constant fields or temporary file based fields. + * @return + * Normalized Seq of Warnings that focus on being assertable reliably + */ + def assertable: Seq[Warning] = ws.map { w => + w.copy( + text = "text", + sourceFileFull = "sourceFileFull", + sourceFileNormalized = "sourceFileNormalized", + explanation = "explanation" + ) + } + + def warning(line: Int, level: Level, snippet: Option[String]): Warning = Warning( + text = "text", + line = line, + level = level, + sourceFileFull = "sourceFileFull", + sourceFileNormalized = "sourceFileNormalized", + snippet = snippet, + explanation = "explanation", + inspection = inspection.getCanonicalName + ) + + val runner = new DottyRunner(inspection) diff --git a/src/test/scala-3/com/sksamuel/scapegoat/ScalaVersion.scala b/src/test/scala-3/com/sksamuel/scapegoat/ScalaVersion.scala new file mode 100644 index 00000000..70c0452c --- /dev/null +++ b/src/test/scala-3/com/sksamuel/scapegoat/ScalaVersion.scala @@ -0,0 +1,7 @@ +package com.sksamuel.scapegoat + +object ScalaVersion { + + val version: Int = 3 + +} diff --git a/src/test/scala-3/com/sksamuel/scapegoat/ScapegoatPhaseTest.scala b/src/test/scala-3/com/sksamuel/scapegoat/ScapegoatPhaseTest.scala new file mode 100644 index 00000000..f575606c --- /dev/null +++ b/src/test/scala-3/com/sksamuel/scapegoat/ScapegoatPhaseTest.scala @@ -0,0 +1,100 @@ +package com.sksamuel.scapegoat + +import java.io.File +import java.nio.file.Files + +import dotty.tools.dotc.core.Contexts.Context +import dotty.tools.dotc.core.Contexts.ContextBase +import org.scalatest.freespec.AnyFreeSpec +import org.scalatest.matchers.should + +class ScapegoatPhaseTest extends AnyFreeSpec with should.Matchers { + + private def configuration(reports: Reports): (File, Configuration) = { + val tmpDir = Files.createTempDirectory("scapegoat").toFile + tmpDir.deleteOnExit() + val configuration = Configuration( + dataDir = Some(tmpDir), + disabledInspections = Nil, + enabledInspections = Nil, + ignoredFiles = Nil, + consoleOutput = false, + verbose = true, + reports = reports, + customInspectors = Nil, + sourcePrefix = "", + minimalLevel = Levels.Info, + overrideLevels = Map.empty + ) + (tmpDir, configuration) + } + + private val noReports = Reports( + disableXML = true, + disableHTML = true, + disableScalastyleXML = true, + disableMarkdown = true, + disableGitlabCodeQuality = true + ) + + "ScapegoatPhase" - { + + "be disablable" in { + val (outputDir, config) = configuration(reports = noReports.copy(disableHTML = false)) + val phase = new ScapegoatPhase(config.copy(disabledInspections = List("all")), Nil) + implicit val ctx: Context = (new ContextBase).initialCtx + + val _ = phase.runOn(Nil) + + assert(outputDir.listFiles().size === 0) + } + + "generate reports" - { + "should generate html report" in { + val (outputDir, config) = configuration(reports = noReports.copy(disableHTML = false)) + val phase = new ScapegoatPhase(config, Nil) + implicit val ctx: Context = (new ContextBase).initialCtx + + val _ = phase.runOn(Nil) + + assert(new File(outputDir, "scapegoat.html").exists() === true) + } + "should generate xml report" in { + val (outputDir, config) = configuration(reports = noReports.copy(disableXML = false)) + val phase = new ScapegoatPhase(config, Nil) + implicit val ctx: Context = (new ContextBase).initialCtx + + val _ = phase.runOn(Nil) + + assert(new File(outputDir, "scapegoat.xml").exists() === true) + } + "should generate scalastyle report" in { + val (outputDir, config) = configuration(reports = noReports.copy(disableScalastyleXML = false)) + val phase = new ScapegoatPhase(config, Nil) + implicit val ctx: Context = (new ContextBase).initialCtx + + val _ = phase.runOn(Nil) + + assert(new File(outputDir, "scapegoat-scalastyle.xml").exists() === true) + } + "should generate markdown report" in { + val (outputDir, config) = configuration(reports = noReports.copy(disableMarkdown = false)) + val phase = new ScapegoatPhase(config, Nil) + implicit val ctx: Context = (new ContextBase).initialCtx + + val _ = phase.runOn(Nil) + + assert(new File(outputDir, "scapegoat.md").exists() === true) + } + "should generate gitlab code quality report" in { + val (outputDir, config) = configuration(reports = noReports.copy(disableGitlabCodeQuality = false)) + val phase = new ScapegoatPhase(config, Nil) + implicit val ctx: Context = (new ContextBase).initialCtx + + val _ = phase.runOn(Nil) + + assert(new File(outputDir, "scapegoat-gitlab.json").exists() === true) + } + } + } +} diff --git a/src/test/scala-3/com/sksamuel/scapegoat/inspections/option/OptionGetTest.scala b/src/test/scala-3/com/sksamuel/scapegoat/inspections/option/OptionGetTest.scala new file mode 100644 index 00000000..56f0d6d7 --- /dev/null +++ b/src/test/scala-3/com/sksamuel/scapegoat/inspections/option/OptionGetTest.scala @@ -0,0 +1,22 @@ +package com.sksamuel.scapegoat.inspections.option + +import com.sksamuel.scapegoat.{InspectionTest, Levels, Warning} + +class OptionGetTest extends InspectionTest(classOf[OptionGet]) { + + "option.get use" - { + "should report warning" in { + + val code = """class Test { + val o = Option("sammy") + o.get + } """.stripMargin + + val feedback = runner.compileCodeSnippet(code) + feedback.errors.assertable shouldEqual Seq( + warning(2, Levels.Error, Some("o.get")) + ).assertable + } + } + +} diff --git a/src/test/scala/com/sksamuel/scapegoat/ReadmeTest.scala b/src/test/scala/com/sksamuel/scapegoat/ReadmeTest.scala index b3b2f5ad..94d9ba1d 100644 --- a/src/test/scala/com/sksamuel/scapegoat/ReadmeTest.scala +++ b/src/test/scala/com/sksamuel/scapegoat/ReadmeTest.scala @@ -19,12 +19,18 @@ class ReadmeTest extends AnyFreeSpec with Matchers { .drop(1) .takeWhile(l => l.trim.nonEmpty) .map(_.split("\\|")) - .collect { case Array(_, className, _, level) => - className.trim -> level.trim + .collect { case Array(_, className, _, level, scala2, scala3) => + className.trim -> (level.trim, scala2.trim.contains("Yes"), scala3.trim.contains("Yes")) } + .filter { case (_, (_, scala2, scala3)) => + scala2 == (ScalaVersion.version == 2) || scala3 == (ScalaVersion.version == 3) || (!scala2 && !scala3) + } + .map { case (name, (level, _, _)) => name -> level } val inspectionNamesAndLevels = - Inspections.inspections.map(i => i.getClass.getSimpleName -> i.defaultLevel.toString).toSet + Inspections.inspections + .map(i => i.getClass.getSimpleName -> i.defaultLevel.toString) + .toSet "README" - { "should be up to date" in { @@ -44,7 +50,11 @@ class ReadmeTest extends AnyFreeSpec with Matchers { } "should have correct number of inspections" in { - val Pattern = raw"There are currently (\d+?) inspections.*".r + val Pattern = if (ScalaVersion.version == 2) { + raw"There are currently (\d+?) inspections.*".r + } else { + raw"There are currently \d+ inspections.*, and (\d+?) for Scala 3\.".r + } readme.collect { case Pattern(n) => n.toInt shouldBe inspectionNamesAndLevels.size } diff --git a/src/test/scala/com/sksamuel/scapegoat/WarningTest.scala b/src/test/scala/com/sksamuel/scapegoat/WarningTest.scala new file mode 100644 index 00000000..049373eb --- /dev/null +++ b/src/test/scala/com/sksamuel/scapegoat/WarningTest.scala @@ -0,0 +1,35 @@ +package com.sksamuel.scapegoat + +import org.scalatest.freespec.AnyFreeSpec + +class WarningTest extends AnyFreeSpec { + + private val warning = com.sksamuel.scapegoat.Warning( + "text", + 1, + Levels.Info, + "sourceFileFull", + "sourceFileNormalized", + None, + "explanation", + "inspection" + ) + + "Warning" - { + "hasMinimalLevelOf" - { + "info >= info" in { + assert(warning.hasMinimalLevelOf(Levels.Info) === true) + } + "info < warning" in { + assert(warning.hasMinimalLevelOf(Levels.Warning) === false) + } + "info < error" in { + assert(warning.hasMinimalLevelOf(Levels.Error) === false) + } + "error > warning" in { + assert(warning.copy(level = Levels.Error).hasMinimalLevelOf(Levels.Warning) === true) + } + } + } + +}