Skip to content

Commit

Permalink
Added MethodReturningAny
Browse files Browse the repository at this point in the history
  • Loading branch information
t1b00 committed Aug 14, 2024
1 parent 6e5059a commit 2a8a9a3
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 0 deletions.
29 changes: 29 additions & 0 deletions input/src/main/scala/fix/MethodReturningAny.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
rule = MethodReturningAny
*/
package fix

object MethodReturningAny {

def inferredAny(value: Boolean) = { // assert: MethodReturningAny
if (value) "This is a string" // returns a String
else 42 // returns an Int
}

// This method returns Any in Scala 2 and should be flagged. It returns Int | String in Scala 3 and will also be flagged.
// See rule for more precisions.

def test: Any = 1 // assert: MethodReturningAny

def foo: Int = 4 // scalafix: ok;
def boo: String = "sam" // scalafix: ok;

trait A {
def foo: AnyRef = "foo" // assert: MethodReturningAny
}
class B extends A {
override def foo: AnyRef = "overridden foo" // scalafix: ok;
}


}
37 changes: 37 additions & 0 deletions rules/src/main/scala/fix/MethodReturningAny.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
rule = MethodReturningAny
*/
package fix

import scalafix.lint.LintSeverity
import scalafix.v1._

import scala.meta._

class MethodReturningAny extends SemanticRule("MethodReturningAny") {

private def diag(pos: Position) = Diagnostic(
"",
"Checks for functions that are defined to return Any.",
pos,
"Method returns Any. Consider using a more specialized type.",
LintSeverity.Error
)

override def fix(implicit doc: SemanticDocument): Patch = {
doc.tree.collect {
// Note: this rule is limited since there is no type inference done, we cannot use synthetics either since they
// do not seem to provide information about definitions and return types. This rule is thus limited to the type put by the developer.
case t @ Defn.Def.After_4_6_0(mods, _, _, Some(Type.Name("Any" | "AnyRef")), _) if !mods.exists(m => m.toString() == "override") => Patch.lint(diag(t.pos))
case t @ Defn.Def.After_4_6_0(mods, _, _, None, _) if !mods.exists(m => m.toString() == "override") =>
t.symbol.info.collect(s => s.signature match {
// Type was inferred to be Any or AnyRef
case MethodSignature(_, _, TypeRef(_, tpe, _)) if SymbolMatcher.exact("scala/Any#", "scala/AnyRef#").matches(tpe) => Patch.lint(diag(t.pos))
case MethodSignature(_, _, UnionType(_)) => Patch.lint(diag(t.pos))
// Flag soft (i.e. compiler inferred) UnionTypes, as chances are the user would not want that.
// If a UnionType is actually desired, one can simply add the type explicitly. The ParamClauseGroup would not be None in that case.
case _ => Patch.empty
}).getOrElse(Patch.empty)
}.asPatch
}
}

0 comments on commit 2a8a9a3

Please sign in to comment.