Skip to content

IDE: fix signature help for Java and Scala 2 methods #5927

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -355,12 +355,18 @@ class Definitions {
lazy val Predef_undefinedR: TermRef = ScalaPredefModule.requiredMethodRef(nme.???)
def Predef_undefined(implicit ctx: Context): Symbol = Predef_undefinedR.symbol

def SubTypeClass(implicit ctx: Context): Symbol =
def SubTypeClass(implicit ctx: Context): ClassSymbol =
if (isNewCollections)
ctx.requiredClass("scala.<:<")
else
ScalaPredefModule.requiredClass("<:<")

def DummyImplicitClass(implicit ctx: Context): ClassSymbol =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my own understanding: Why was this class moved?

Copy link
Member Author

@smarter smarter Feb 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved it along with <:< and =:= in scala/scala#7350 to keep Predef as lean as possible, classes can be defined at the top-level so I didn't see why these ones in particular should be nested in Predef.

if (isNewCollections)
ctx.requiredClass("scala.DummyImplicit")
else
ScalaPredefModule.requiredClass("DummyImplicit")

lazy val ScalaRuntimeModuleRef: TermRef = ctx.requiredModuleRef("scala.runtime.ScalaRunTime")
def ScalaRuntimeModule(implicit ctx: Context): Symbol = ScalaRuntimeModuleRef.symbol
def ScalaRuntimeClass(implicit ctx: Context): ClassSymbol = ScalaRuntimeModule.moduleClass.asClass
Expand Down
45 changes: 27 additions & 18 deletions compiler/src/dotty/tools/dotc/util/Signatures.scala
Original file line number Diff line number Diff line change
Expand Up @@ -80,27 +80,36 @@ object Signatures {
val symbol = denot.symbol
val docComment = ParsedComment.docOf(symbol)
val classTree = symbol.topLevelClass.asClass.rootTree
val isImplicit: TermName => Boolean = tpd.defPath(symbol, classTree).lastOption match {
case Some(DefDef(_, _, paramss, _, _)) =>
val flatParams = paramss.flatten
name => flatParams.find(_.name == name).map(_.symbol.is(Implicit)).getOrElse(false)
case _ =>
_ => false

def toParamss(tp: MethodType)(implicit ctx: Context): List[List[Param]] = {
val rest = tp.resType match {
case res: MethodType =>
// Hide parameter lists consisting only of CanBuildFrom or DummyImplicit,
// we can remove the CanBuildFrom special-case once we switch to the 2.13 standard library.
if (res.resultType.isParameterless &&
res.isImplicitMethod &&
res.paramInfos.forall(info =>
info.classSymbol.fullName.toString == "scala.collection.generic.CanBuildFrom" ||
info.classSymbol.derivesFrom(ctx.definitions.DummyImplicitClass)))
Nil
else
toParamss(res)
case _ =>
Nil
}
val params = tp.paramNames.zip(tp.paramInfos).map { case (name, info) =>
Signatures.Param(name.show,
info.widenTermRefExpr.show,
docComment.flatMap(_.paramDoc(name)),
isImplicit = tp.isImplicitMethod)
}

params :: rest
}

denot.info.stripPoly match {
case tpe: MethodType =>
val infos = {
tpe.paramInfoss.zip(tpe.paramNamess).map { case (infos, names) =>
infos.zip(names).map { case (info, name) =>
Signatures.Param(name.show,
info.widenTermRefExpr.show,
docComment.flatMap(_.paramDoc(name)),
isImplicit = isImplicit(name))
}
}
}

val paramss = toParamss(tpe)
val typeParams = denot.info match {
case poly: PolyType =>
poly.paramNames.zip(poly.paramInfos).map { case (x, y) => x.show + y.show }
Expand All @@ -115,7 +124,7 @@ object Signatures {
val signature =
Signatures.Signature(name,
typeParams,
infos,
paramss,
returnType,
docComment.map(_.mainDoc))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,56 @@ import dotty.tools.dotc.util.Signatures.{Param => P, Signature => S}

class SignatureHelpTest {

@Test def fromJava: Unit = {
val signature =
S("codePointAt", Nil, List(List(P("x$0", "Int"))), Some("Int"))
code"""object O {
"hello".codePointAt($m1)
}""".withSource
.signatureHelp(m1, List(signature), Some(0), 0)
}

@Test def fromScala2: Unit = {
val applySig =
S("apply[A]", Nil, List(List(P("xs", "A*"))), Some("List[A]"))
val mapSig =
S("map[B, That]", Nil, List(List(P("f", "A => B"))), Some("That"))
code"""object O {
List($m1)
List(1, 2, 3).map($m2)
}""".withSource
.signatureHelp(m1, List(applySig), Some(0), 0)
.signatureHelp(m2, List(mapSig), Some(0), 0)
}

/** Implicit parameter lists consisting solely of DummyImplicits are hidden. */
@Test def hiddenDummyParams: Unit = {
val foo1Sig =
S("foo1", Nil, List(List(P("param0", "Int"))), Some("Int"))
val foo2Sig =
S("foo2", Nil, List(List(P("param0", "Int"))), Some("Int"))
val foo3Sig =
S("foo3", Nil, List(List(P("param0", "Int")),
List(P("dummy", "DummyImplicit"))), Some("Int"))
val foo4Sig =
S("foo4", Nil, List(List(P("param0", "Int")),
List(P("x", "Int", isImplicit = true), P("dummy", "DummyImplicit", isImplicit = true))), Some("Int"))
code"""object O {
def foo1(param0: Int)(implicit dummy: DummyImplicit): Int = ???
def foo2(param0: Int)(implicit dummy1: DummyImplicit, dummy2: DummyImplicit): Int = ???
def foo3(param0: Int)(dummy: DummyImplicit): Int = ???
def foo4(param0: Int)(implicit x: Int, dummy: DummyImplicit): Int = ???
foo1($m1)
foo2($m2)
foo3($m3)
foo4($m4)
}""".withSource
.signatureHelp(m1, List(foo1Sig), Some(0), 0)
.signatureHelp(m2, List(foo2Sig), Some(0), 0)
.signatureHelp(m3, List(foo3Sig), Some(0), 0)
.signatureHelp(m4, List(foo4Sig), Some(0), 0)
}

@Test def singleParam: Unit = {
val signature =
S("foo", Nil, List(List(P("param0", "Int"))), Some("Int"))
Expand Down