Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Reformat with scalafmt 2.10.3
eee86deac5688735d1b88226a196c4aa7c271210
102 changes: 102 additions & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//description of properties: https://scalameta.org/scalafmt/docs/configuration.html
version = "3.10.3"
runner.dialect = Scala213Source3
maxColumn = 120

continuationIndent {
defnSite = 2
ctorSite = 2
extendSite = 2
withSiteRelativeToExtends = 2
}

align.preset = none

binPack {
parentConstructors = OnelineIfPrimaryOneline
literalsSingleLine = false
}

newlines {
alwaysBeforeMultilineDef = false
afterCurlyLambda = preserve
implicitParamListModifierPrefer = after
penalizeSingleSelectMultiArgList = false
avoidForSimpleOverflow = [punct, tooLong]
afterInfix = some
}

rewrite.rules = [AvoidInfix, SortModifiers, SortImports, PreferCurlyFors, RedundantParens, RedundantBraces]
rewrite.sortModifiers.order = ["override", "private", "protected", "implicit", "final", "sealed", "abstract", "lazy"]
rewrite.redundantBraces {
stringInterpolation = true
generalExpressions = false
methodBodies = true
includeUnitMethods = false
parensForOneLineApply = true
}

trailingCommas = multiple
importSelectors = singleLine

optIn {
breakChainOnFirstMethodDot = false
# - if newlines.source is missing or keep:
# - if true, will keep existing line breaks around annotations
# - if newlines.source is fold:
# - if true, will break before the entity being annotatated
# - will not force break between consecutive annotations
# - if newlines.source is unfold:
# - if true, will break between consecutive annotations
# - will always break before the entity being annotatated
annotationNewlines = false
}

rewrite.neverInfix.excludeFilters = [
until
to
by
eq
ne
"should.*"
"contain.*"
"must.*"
in
ignore
be
taggedAs
thrownBy
synchronized
have
when
size
only
noneOf
oneElementOf
noElementsOf
atLeastOneElementOf
atMostOneElementOf
allElementsOf
inOrderElementsOf
theSameElementsAs
//below extends default
theSameElementsInOrderAs
like
zip
orElse
getOrElse
matchOpt
map
flatMap
]

xmlLiterals.assumeFormatted = true
project.git = true
danglingParentheses.exclude = [
// "class", //with that, trailling comma don't work in class definition
"trait"
]
verticalMultiline {
atDefnSite = true
newlineAfterOpenParen = true
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ final class AnalyzerPlugin(val global: Global) extends Plugin { plugin =>
val jdkVersionRegex = option.substring(option.indexOf('=') + 1)
val javaVersion = System.getProperty("java.version", "")
if (!javaVersion.matches(jdkVersionRegex)) {
global.reporter.error(NoPosition,
s"This project must be compiled on JDK version that matches $jdkVersionRegex but got $javaVersion")
global.reporter.error(
NoPosition,
s"This project must be compiled on JDK version that matches $jdkVersionRegex but got $javaVersion",
)
}
} else {
val level = option.charAt(0) match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ abstract class AnalyzerRule(val global: Global, val name: String, defaultLevel:
var argument: String = _

protected def classType(fullName: String): Type =
try rootMirror.staticClass(fullName).asType.toType.erasure catch {
try rootMirror.staticClass(fullName).asType.toType.erasure
catch {
case _: ScalaReflectionException => NoType
}

protected def analyzeTree(fun: PartialFunction[Tree, Unit])(tree: Tree): Unit =
try fun.applyOrElse(tree, (_: Tree) => ()) catch {
try fun.applyOrElse(tree, (_: Tree) => ())
catch {
case NonFatal(t) =>
val sw = new StringWriter
t.printStackTrace(new PrintWriter(sw))
Expand All @@ -33,7 +35,7 @@ abstract class AnalyzerRule(val global: Global, val name: String, defaultLevel:
message: String,
category: WarningCategory = WarningCategory.Lint,
site: Symbol = NoSymbol,
level: Level = this.level
level: Level = this.level,
): Unit =
level match {
case Level.Off =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ class Any2StringAdd(g: Global) extends AnalyzerRule(g, "any2stringadd", Level.Of
def analyze(unit: CompilationUnit): Unit = {
unit.body.foreach(analyzeTree {
case t if t.symbol == any2stringaddSym =>
report(t.pos, "concatenating arbitrary values with strings is disabled, " +
"use explicit toString or string interpolation")
report(
t.pos,
"concatenating arbitrary values with strings is disabled, " + "use explicit toString or string interpolation",
)
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,15 @@ class BadSingletonComponent(g: Global) extends AnalyzerRule(g, "badSingletonComp
if (componentsTpe != NoType) {
object traverser extends Traverser {
override def traverse(tree: Tree): Unit = tree match {
case mdef@DefDef(_, _, Nil, Nil, _, Unwrap(app@Apply(_, List(arg, _))))
if app.symbol == cachedSym && mdef.symbol.owner.isClass && ThisType(mdef.symbol.owner) <:< componentsTpe =>
case mdef @ DefDef(_, _, Nil, Nil, _, Unwrap(app @ Apply(_, List(arg, _))))
if app.symbol == cachedSym && mdef.symbol.owner.isClass &&
ThisType(mdef.symbol.owner) <:< componentsTpe =>
traverse(arg)
case t if t.symbol == cachedSym =>
report(t.pos, "singleton(...) macro can only be used as a body of a parameterless method in a Components trait implementation")
report(
t.pos,
"singleton(...) macro can only be used as a body of a parameterless method in a Components trait implementation",
)
case _ =>
super.traverse(tree)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class CatchThrowable(g: Global) extends AnalyzerRule(g, "catchThrowable", Level.
case CaseDef(Alternative(trees), _, _) => trees.foreach(checkTree)
case CaseDef(Bind(_, Alternative(trees)), _, _) => trees.foreach(checkTree)
// CaseDef generated from a custom handler has NoPosition
case cd@CaseDef(pat, _, _) if cd.pos != NoPosition => checkTree(pat)
case cd @ CaseDef(pat, _, _) if cd.pos != NoPosition => checkTree(pat)
case _ =>
}
case _ =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ class CheckBincompat(g: Global) extends AnalyzerRule(g, "bincompat") {

def analyze(unit: CompilationUnit): Unit =
unit.body.foreach(analyzeTree {
case tree@(_: Ident | _: Select | _: New) if tree.symbol != null &&
tree.symbol.annotations.exists(_.tree.tpe <:< bincompatAnnotType) =>
report(tree.pos, "Symbols annotated as @bincompat exist only for binary compatibility " +
"and should not be used directly")
case tree @ (_: Ident | _: Select | _: New)
if tree.symbol != null && tree.symbol.annotations.exists(_.tree.tpe <:< bincompatAnnotType) =>
report(
tree.pos,
"Symbols annotated as @bincompat exist only for binary compatibility " + "and should not be used directly",
)
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ class CheckMacroPrivate(g: Global) extends AnalyzerRule(g, "macroPrivate") {
def analyzeTree(tree: Tree): Unit = analyzer.macroExpandee(tree) match {
case `tree` | EmptyTree =>
tree match {
case _: Ident | _: Select | _: SelectFromTypeTree | _: New
if tree.symbol != null && tree.pos != NoPosition =>
case _: Ident | _: Select | _: SelectFromTypeTree | _: New if tree.symbol != null && tree.pos != NoPosition =>

val sym = tree.symbol
val macroPrivate = (sym :: sym.overrides).iterator
.flatMap(_.annotations).exists(_.tree.tpe <:< macroPrivateAnnotTpe)
.flatMap(_.annotations)
.exists(_.tree.tpe <:< macroPrivateAnnotTpe)
if (macroPrivate) {
report(tree.pos, s"$sym can only be used in macro-generated code")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ class ConstantDeclarations(g: Global) extends AnalyzerRule(g, "constantDeclarati
import global._

def analyze(unit: CompilationUnit): Unit = unit.body.foreach {
case t@ValDef(_, name, tpt, rhs)
if t.symbol.hasGetter && t.symbol.owner.isEffectivelyFinal =>
case t @ ValDef(_, name, tpt, rhs) if t.symbol.hasGetter && t.symbol.owner.isEffectivelyFinal =>

val getter = t.symbol.getterIn(t.symbol.owner)
if (getter.isPublic && getter.isStable && getter.overrides.isEmpty) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ class DiscardedMonixTask(g: Global) extends AnalyzerRule(g, "discardedMonixTask"
checkDiscardedTask(prefix, discarded = false)
checkDiscardedTask(body, discarded)

case _: Ident | _: Select | _: Apply | _: TypeApply if discarded &&
tree.tpe != null && tree.tpe <:< monixTaskTpe && !(tree.tpe <:< definitions.NullTpe) =>
report(tree.pos, "discarded Monix Task - this is probably a mistake because the Task must be run for its side effects")
case _: Ident | _: Select | _: Apply | _: TypeApply
if discarded && tree.tpe != null && tree.tpe <:< monixTaskTpe && !(tree.tpe <:< definitions.NullTpe) =>
report(
tree.pos,
"discarded Monix Task - this is probably a mistake because the Task must be run for its side effects",
)

case tree =>
tree.children.foreach(checkDiscardedTask(_, discarded = false))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ExplicitGenerics(g: Global) extends AnalyzerRule(g, "explicitGenerics") {
def analyzeTree(tree: Tree): Unit = analyzer.macroExpandee(tree) match {
case `tree` | EmptyTree =>
tree match {
case t@TypeApply(pre, args) if requiresExplicitGenerics(pre.symbol) =>
case t @ TypeApply(pre, args) if requiresExplicitGenerics(pre.symbol) =>
val inferredTypeParams = args.forall {
case tt: TypeTree => tt.original == null || tt.original == EmptyTree
case _ => false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ class FinalCaseClasses(g: Global) extends AnalyzerRule(g, "finalCaseClasses", Le
if (isInner) {
report(cd.pos, "Case classes should be marked as final")
} else {
report(cd.pos, "Case classes should be marked as final. Due to the SI-4440 bug, it cannot be done here. Consider moving the case class to the companion object", level = Info)
report(
cd.pos,
"Case classes should be marked as final. Due to the SI-4440 bug, it cannot be done here. Consider moving the case class to the companion object",
level = Info,
)
}
case _ =>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class FinalValueClasses(g: Global) extends AnalyzerRule(g, "finalValueClasses",
case cd: ClassDef if !cd.mods.hasFlag(Flag.FINAL) =>
val tpe = cd.symbol.typeSignature

if (tpe.baseClasses.contains(anyValTpe.typeSymbol) ) {
if (tpe.baseClasses.contains(anyValTpe.typeSymbol)) {
report(cd.pos, "Value classes should be marked as final")
}
case _ =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ class ImplicitParamDefaults(g: Global) extends AnalyzerRule(g, "implicitParamDef
}
case _ =>
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ class ImplicitTypes(g: Global) extends AnalyzerRule(g, "implicitTypes") {
import global._

def analyze(unit: CompilationUnit): Unit = unit.body.foreach {
case t@ValOrDefDef(mods, _, tpt@TypeTree(), _) if tpt.original == null && mods.isImplicit && !mods.isSynthetic =>
case t @ ValOrDefDef(mods, _, tpt @ TypeTree(), _)
if tpt.original == null && mods.isImplicit && !mods.isSynthetic =>
report(t.pos, s"Implicit definitions must have type annotated explicitly")
case _ =>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class ImplicitValueClasses(g: Global) extends AnalyzerRule(g, "implicitValueClas

if (!inheritsAnyVal && !inheritsOtherClass && hasExactlyOneParam && !paramIsValueClass) {
val isNestedClass =
//implicit classes are always nested classes, so we want to check if the outer class's an object
// implicit classes are always nested classes, so we want to check if the outer class's an object
/*cd.symbol.isNestedClass &&*/ !cd.symbol.isStatic

val message = "Implicit classes should always extend AnyVal to become value classes" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ class ImportJavaUtil(g: Global) extends AnalyzerRule(g, "importJavaUtil") {
import global._

def analyze(unit: CompilationUnit): Unit = {
unit.body.foreach(analyzeTree {
case tree@q"import java.util" =>
report(tree.pos, "Don't import java.util: either import with rename (e.g. import java.{util => ju}) " +
"or use type aliases from JavaInterop (e.g. JList, JSet, etc)")
unit.body.foreach(analyzeTree { case tree @ q"import java.util" =>
report(
tree.pos,
"Don't import java.util: either import with rename (e.g. import java.{util => ju}) " +
"or use type aliases from JavaInterop (e.g. JList, JSet, etc)",
)
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,20 @@ final class NothingAsFunctionArgument(g: Global) extends AnalyzerRule(g, "nothin

import global.*

def analyze(unit: CompilationUnit): Unit = unit.body.foreach(analyzeTree {
case Apply(f: Tree, args: List[Tree]) =>
args.zip(f.tpe.params).foreach {
case (arg, param) if definitions.isFunctionType(param.tpe) && arg.tpe <:< definitions.NothingTpe =>
report(arg.pos,
s"""
def analyze(unit: CompilationUnit): Unit = unit.body.foreach(analyzeTree { case Apply(f: Tree, args: List[Tree]) =>
args.zip(f.tpe.params).foreach {
case (arg, param) if definitions.isFunctionType(param.tpe) && arg.tpe <:< definitions.NothingTpe =>
report(
arg.pos,
s"""
|A value of type `Nothing` was passed where a function is expected.
|If you intended to throw an exception, wrap it in a function literal (e.g. `_ => throw ex` instead of `throw ex`).
|If you are using a mocking framework, provide a mock function with the correct type (e.g. `any[${show(param.tpe)}]`).
|""".stripMargin
)
case (_, _) =>
}
|If you are using a mocking framework, provide a mock function with the correct type (e.g. `any[${show(
param.tpe
)}]`).
|""".stripMargin,
)
case (_, _) =>
}
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@ class ValueEnumExhaustiveMatch(g: Global) extends AnalyzerRule(g, "valueEnumExha

def analyze(unit: CompilationUnit): Unit = if (valueEnumTpe != NoType) {
unit.body.foreach(analyzeTree {
case tree@Match(selector, cases) if selector.tpe <:< valueEnumTpe =>
case tree @ Match(selector, cases) if selector.tpe <:< valueEnumTpe =>
val expectedCompanionTpe = TypeRef(miscPackageTpe, valueEnumCompanionSym, List(selector.tpe))
val companion = selector.tpe.typeSymbol.companion
val companionTpe = companion.toType
if (companionTpe <:< expectedCompanionTpe) {
val unmatched = new mutable.LinkedHashSet[Symbol]
companionTpe.decls.iterator
.filter(s => s.isVal && s.isFinal && !s.isLazy && s.typeSignature <:< selector.tpe)
.map(_.getterIn(companion)).filter(_.isPublic).foreach(unmatched.add)
.map(_.getterIn(companion))
.filter(_.isPublic)
.foreach(unmatched.add)

def findMatchedEnums(pattern: Tree): Unit = pattern match {
case Bind(_, body) => findMatchedEnums(body)
Expand Down
Loading
Loading