Skip to content

Commit

Permalink
Merged branch idea243.release-vasil/lambdas into idea243.release
Browse files Browse the repository at this point in the history
  • Loading branch information
builduser committed Nov 20, 2024
2 parents a5f6c6d + 59d6139 commit 0cc0897
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -846,8 +846,20 @@ object ScalaPositionManager {
isGenerateAnonfun211(element) && !isInsideMacro(element)
}

def lambdasOnLine(file: PsiFile, lineNumber: Int): Seq[PsiElement] = {
positionsOnLine(file, lineNumber).filter(isLambda)
def lambdasOnLine(file: PsiFile, lineNumber: Int): Seq[PsiElement] =
filterLambdasOnLine(file, lineNumber, positionsOnLine(file, lineNumber))

def filterLambdasOnLine(file: PsiFile, lineNumber: Int, positions: Seq[PsiElement]): Seq[PsiElement] = {
val document = file.getFileDocument
positions.filter(isLambda).filter {
case f: ScFunctionExpr =>
f.result.exists { body =>
val range = body.getTextRange
val startLine = document.getLineNumber(range.getStartOffset)
startLine == lineNumber
}
case _ => true
}
}

def isIndyLambda(m: Method): Boolean = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import com.intellij.xdebugger.breakpoints.{XLineBreakpoint, XLineBreakpointType}
import com.intellij.xdebugger.impl.XSourcePositionImpl
import com.intellij.xdebugger.impl.breakpoints.XLineBreakpointImpl
import com.intellij.xdebugger.{XDebuggerUtil, XSourcePosition}
import org.jetbrains.annotations.{Nls, NotNull, Nullable}
import org.jetbrains.annotations.{NotNull, Nullable}
import org.jetbrains.concurrency.{AsyncPromise, Promise}
import org.jetbrains.java.debugger.breakpoints.properties.JavaLineBreakpointProperties
import org.jetbrains.plugins.scala.ScalaLanguage
Expand Down Expand Up @@ -85,19 +85,10 @@ class ScalaLineBreakpointType extends JavaLineBreakpointType("scala-line", Debug
case sf: ScalaFile => sf
case _ => return Collections.emptyList()
}
val document = file.getFileDocument
val line = position.getLine

val originalLambdas = ScalaPositionManager.lambdasOnLine(file, line)
val lambdas = originalLambdas.filter {
case f: ScFunctionExpr =>
f.result.exists { body =>
val range = body.getTextRange
val startLine = document.getLineNumber(range.getStartOffset)
startLine == line
}
case _ => true
}
val positionsOnLine = ScalaPositionManager.positionsOnLine(file, line)
val lambdas = ScalaPositionManager.filterLambdasOnLine(file, line, positionsOnLine)

if (lambdas.isEmpty) return Collections.emptyList()

Expand All @@ -107,14 +98,15 @@ class ScalaLineBreakpointType extends JavaLineBreakpointType("scala-line", Debug

val method = findContainingDefinition(elementAtLine, lambdas)

val extraPriorityForLambdas = positionsOnLine.sizeCompare(lambdas) == 0
for ((lambda, ordinal) <- lambdas.zipWithIndex) {
val element = lambda match {
case f: ScFunctionExpr => f.result.getOrElse(f)
case e => e
}
res.addLast(new ExactScalaBreakpointVariant(XSourcePositionImpl.createByElement(element), element, ordinal))
res.addLast(new LambdaScalaBreakpointVariant(XSourcePositionImpl.createByElement(element), element, ordinal, extraPriorityForLambdas))
}
res.addFirst(new ExactScalaBreakpointVariant(position, method.orNull, -1))
res.addFirst(new LineScalaBreakpointVariant(position, method.orNull))
res.addFirst(new JavaBreakpointVariant(position, lambdas.size)) //adding all variants
res
}
Expand Down Expand Up @@ -213,35 +205,36 @@ class ScalaLineBreakpointType extends JavaLineBreakpointType("scala-line", Debug

override def getPriority: Int = super.getPriority + 1

private class ExactScalaBreakpointVariant(position: XSourcePosition, @Nullable element: PsiElement, @Nullable lambdaOrdinal: Integer)
extends ExactJavaBreakpointVariant(position, element, lambdaOrdinal) {
private final class LineScalaBreakpointVariant(position: XSourcePosition, @Nullable method: PsiElement)
extends LineJavaBreakpointVariant(position, method, -1) {

private val isLambda: Boolean = (lambdaOrdinal ne null) && lambdaOrdinal > -1

override def getIcon: Icon = {
if (isLambda) AllIcons.Nodes.Function
else element match {
case e @ (_: PsiMethod | _: PsiClass | _: PsiFile) => e.getIcon(0)
case _ => AllIcons.Debugger.Db_set_breakpoint
}
override def getIcon: Icon = method match {
case e @ (_: PsiMethod | _: PsiClass | _: PsiFile) => e.getIcon(0)
case _ => AllIcons.Debugger.Db_set_breakpoint
}

@Nls
override def getText: String = {
if (isLambda) super.getText
else {
element match {
case c: ScClass => DebuggerBundle.message("breakpoint.location.constructor.of", c.name)
case ed: ScEarlyDefinitions =>
val clazz = PsiTreeUtil.getParentOfType(ed, classOf[ScTypeDefinition])
if (clazz != null) DebuggerBundle.message("breakpoint.location.early.definitions.of", clazz.name)
else DebuggerBundle.message("breakpoint.location.line.in.containing.block")
case (_: ScFunction) & (named: ScNamedElement) => DebuggerBundle.message("breakpoint.location.line.in.function", named.name)
case _: ScalaFile => DebuggerBundle.message("breakpoint.location.line.in.containing.file")
case _ => DebuggerBundle.message("breakpoint.location.line.in.containing.block")
}
}
override def getText: String = method match {
case c: ScClass => DebuggerBundle.message("breakpoint.location.constructor.of", c.name)
case ed: ScEarlyDefinitions =>
val clazz = PsiTreeUtil.getParentOfType(ed, classOf[ScTypeDefinition])
if (clazz != null) DebuggerBundle.message("breakpoint.location.early.definitions.of", clazz.name)
else DebuggerBundle.message("breakpoint.location.line.in.containing.block")
case (_: ScFunction) & (named: ScNamedElement) => DebuggerBundle.message("breakpoint.location.line.in.function", named.name)
case _: ScalaFile => DebuggerBundle.message("breakpoint.location.line.in.containing.file")
case _ => DebuggerBundle.message("breakpoint.location.line.in.containing.block")
}

override def isLowPriority(firstLineElement: PsiElement): Boolean =
firstLineElement.elementType == ScalaTokenTypes.tDOT
}

private final class LambdaScalaBreakpointVariant(position: XSourcePosition, @Nullable element: PsiElement, lambdaOrdinal: Int, hasExtraPriority: Boolean)
extends LambdaJavaBreakpointVariant(position, element, lambdaOrdinal) {

override def getPriority(project: Project): Int = {
val priority = super.getPriority(project)
val extraPriorty = if (hasExtraPriority) 50 else 0
priority + extraPriorty
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package org.jetbrains.plugins.scala.debugger.exactBreakpoints

import com.intellij.psi.search.GlobalSearchScope
import com.intellij.xdebugger.XDebuggerUtil
import org.jetbrains.plugins.scala.ScalaVersion
import org.jetbrains.plugins.scala.debugger.ScalaDebuggerTestCase
import org.jetbrains.plugins.scala.debugger.breakpoints.ScalaLineBreakpointType
import org.jetbrains.plugins.scala.extensions.inReadAction
import org.jetbrains.plugins.scala.lang.psi.impl.ScalaPsiManager

import scala.jdk.CollectionConverters._

abstract class PriorityTestBase extends ScalaDebuggerTestCase {

protected def assertVariantPriorities(className: String = getTestName(false))(lineNumber: Int, priorities: Int*): Unit = inReadAction {
val manager = ScalaPsiManager.instance(getProject)
val psiClass = manager.getCachedClass(GlobalSearchScope.allScope(getProject), className)
val psiFile = psiClass.map(_.getContainingFile).getOrElse(throw new AssertionError(s"Could not find class $className"))
val virtualFile = psiFile.getVirtualFile
val scalaBreakpointType = XDebuggerUtil.getInstance().findBreakpointType(classOf[ScalaLineBreakpointType])
val xSourcePosition = XDebuggerUtil.getInstance().createPosition(virtualFile, lineNumber)
val actual = scalaBreakpointType.computeVariants(getProject, xSourcePosition).asScala.map(_.getPriority(getProject)).toSeq
assertEquals(priorities, actual)
}

addSourceFile("LineHasPriority.scala",
"""object LineHasPriority {
| def main(args: Array[String]): Unit = {
| println(Seq(1, 2, 3).map(x => x * 2))
| }
|}
|""".stripMargin)

def testLineHasPriority(): Unit = {
assertVariantPriorities()(2, 101, 101, 101)
}

addSourceFile("LineIsLowPriority.scala",
"""object LineIsLowPriority {
| def main(args: Array[String]): Unit = {
| Seq(1, 2, 3)
| .map { x => x + 1 }
| .map(_ + 1)
| .foreach(println)
| }
|}
|""".stripMargin)

def testLineIsLowPriority(): Unit = {
assertVariantPriorities()(3, 101, 51, 101)
assertVariantPriorities()(4, 101, 51, 101)
assertVariantPriorities()(5, 101, 51, 101)
}

addSourceFile("ExtraPriorityForLambda.scala",
"""object ExtraPriorityForLambda {
| def main(args: Array[String]): Unit = {
| Seq(1, 2, 3).map(
| x => x + 1
| ).map {
| ({({_ + 2})})
| }.map {
| x => x + 1
| }
| }
|}
|""".stripMargin)

def testExtraPriorityForLambda(): Unit = {
assertVariantPriorities()(3, 101, 101, 151)
assertVariantPriorities()(5, 101, 101, 151)
assertVariantPriorities()(7, 101, 101, 151)
}

addSourceFile("TwoLambdasOnLine.scala",
"""object TwoLambdasOnLine {
| def main(args: Array[String]): Unit = {
| Seq(1, 2, 3)
| .map(x => x + 1).map(x => x + 2)
| }
|}
|""".stripMargin)

def testTwoLambdasOnLine(): Unit = {
assertVariantPriorities()(3, 101, 51, 101, 101)
}
}

class PriorityTest_2_11 extends PriorityTestBase {
override protected def supportedIn(version: ScalaVersion): Boolean = version == ScalaVersion.Latest.Scala_2_11
}

class PriorityTest_2_12 extends PriorityTestBase {
override protected def supportedIn(version: ScalaVersion): Boolean = version == ScalaVersion.Latest.Scala_2_12
}

class PriorityTest_2_13 extends PriorityTestBase {
override protected def supportedIn(version: ScalaVersion): Boolean = version == ScalaVersion.Latest.Scala_2_13
}

class PriorityTest_3_3 extends PriorityTestBase {
override protected def supportedIn(version: ScalaVersion): Boolean = version == ScalaVersion.Latest.Scala_3_3
}

class PriorityTest_3_4 extends PriorityTestBase {
override protected def supportedIn(version: ScalaVersion): Boolean = version == ScalaVersion.Latest.Scala_3_4
}

class PriorityTest_3_5 extends PriorityTestBase {
override protected def supportedIn(version: ScalaVersion): Boolean = version == ScalaVersion.Latest.Scala_3_5
}

class PriorityTest_3_6 extends PriorityTestBase {
override protected def supportedIn(version: ScalaVersion): Boolean = version == ScalaVersion.Latest.Scala_3_6
}

class PriorityTest_3_RC extends PriorityTestBase {
override protected def supportedIn(version: ScalaVersion): Boolean = version == ScalaVersion.Latest.Scala_3_LTS_RC
}

class PriorityTest_3_Next_RC extends PriorityTestBase {
override protected def supportedIn(version: ScalaVersion): Boolean = version == ScalaVersion.Latest.Scala_3_Next_RC
}

0 comments on commit 0cc0897

Please sign in to comment.