From 8f87eaef69d53709f4eeaaf4a816582983aeeac0 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 21 Jan 2025 15:45:16 +0100 Subject: [PATCH 1/8] refactor: Use codeAction interface for most code actions [Cherry-picked 8d3c8ca1a717d82d6d60a564557fb4abdc756941] --- .../tools/pc/ScalaPresentationCompiler.scala | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala b/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala index 218d92c38ffa..f8480c0e9784 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala @@ -55,6 +55,14 @@ case class ScalaPresentationCompiler( completionItemPriority: CompletionItemPriority = (_: String) => 0, ) extends PresentationCompiler: + override def supportedCodeActions(): ju.List[String] = List( + CodeActionId.ConvertToNamedArguments, + CodeActionId.ImplementAbstractMembers, + CodeActionId.ExtractMethod, + CodeActionId.InlineValue, + CodeActionId.InsertInferredType + ).asJava + def this() = this("", None, Nil, Nil) val scalaVersion = BuildInfo.scalaVersion @@ -67,6 +75,42 @@ case class ScalaPresentationCompiler( .map(StdReportContext(_, _ => buildTargetName, reportsLevel)) .getOrElse(EmptyReportContext) + override def codeAction[T]( + params: OffsetParams, + codeActionId: String, + codeActionPayload: Optional[T] + ): CompletableFuture[ju.List[TextEdit]] = { + (codeActionId, codeActionPayload.asScala) match { + case ( + CodeActionId.ConvertToNamedArguments, + Some(argIndices: ju.List[_]) + ) => + val payload = argIndices.asScala.collect { case i: Integer => + i.toInt + }.toSet + convertToNamedArguments(params, payload) + case (CodeActionId.ImplementAbstractMembers, _) => + implementAbstractMembers(params) + case (CodeActionId.InsertInferredType, _) => + insertInferredType(params) + case (CodeActionId.InlineValue, _) => + inlineValue(params) + case (CodeActionId.ExtractMethod, Some(extractionPos: OffsetParams)) => + params match { + case range: RangeParams => + extractMethod(range, extractionPos) + case _ => + CompletableFuture.failedFuture( + new IllegalArgumentException(s"Expected range parameters") + ) + } + case (id, _) => + CompletableFuture.failedFuture( + new IllegalArgumentException(s"Unsupported action id $id") + ) + } + } + override def withCompletionItemPriority( priority: CompletionItemPriority ): PresentationCompiler = @@ -348,6 +392,12 @@ case class ScalaPresentationCompiler( override def convertToNamedArguments( params: OffsetParams, argIndices: ju.List[Integer] + ): CompletableFuture[ju.List[l.TextEdit]] = + convertToNamedArguments(params, argIndices.asScala.toSet.map(_.toInt)) + + def convertToNamedArguments( + params: OffsetParams, + argIndices: Set[Int] ): CompletableFuture[ju.List[l.TextEdit]] = val empty: Either[String, List[l.TextEdit]] = Right(List()) (compilerAccess @@ -355,7 +405,7 @@ case class ScalaPresentationCompiler( new ConvertToNamedArgumentsProvider( pc.compiler(), params, - argIndices.asScala.map(_.toInt).toSet + argIndices ).convertToNamedArguments }) .thenApplyAsync { From ef28c6793083d6b8c2961fe686d63f000a9ade3d Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 21 Jan 2025 15:47:13 +0100 Subject: [PATCH 2/8] Update ScalaPresentationCompiler.scala [Cherry-picked 31f5b4ed4faa570a43cdc0773b0d4642f56c3185] --- .../dotty/tools/pc/ScalaPresentationCompiler.scala | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala b/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala index f8480c0e9784..b3f8bba78953 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala @@ -79,15 +79,14 @@ case class ScalaPresentationCompiler( params: OffsetParams, codeActionId: String, codeActionPayload: Optional[T] - ): CompletableFuture[ju.List[TextEdit]] = { - (codeActionId, codeActionPayload.asScala) match { + ): CompletableFuture[ju.List[TextEdit]] = + (codeActionId, codeActionPayload.asScala) match case ( CodeActionId.ConvertToNamedArguments, Some(argIndices: ju.List[_]) ) => - val payload = argIndices.asScala.collect { case i: Integer => - i.toInt - }.toSet + val payload = + argIndices.asScala.collect { case i: Integer => i.toInt }.toSet convertToNamedArguments(params, payload) case (CodeActionId.ImplementAbstractMembers, _) => implementAbstractMembers(params) @@ -108,8 +107,6 @@ case class ScalaPresentationCompiler( CompletableFuture.failedFuture( new IllegalArgumentException(s"Unsupported action id $id") ) - } - } override def withCompletionItemPriority( priority: CompletionItemPriority From 1eace6680585678a0f0be518780a9d48a239d503 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 21 Jan 2025 16:11:10 +0100 Subject: [PATCH 3/8] bugfix: Show implicit chained calls in inlay hints [Cherry-picked a40b9999804393c85ee6e68d4d66e6a61dd68509] --- .../dotty/tools/pc/PcInlayHintsProvider.scala | 81 ++++++++++-- .../pc/tests/inlayHints/InlayHintsSuite.scala | 117 +++++++++++++++++- 2 files changed, 185 insertions(+), 13 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala index 9c0e6bcfa9d8..4b1b3f5fe7ba 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala @@ -80,15 +80,15 @@ class PcInlayHintsProvider( LabelPart(")") :: Nil, InlayHintKind.Parameter, ) - case ImplicitParameters(symbols, pos, allImplicit) => - val labelParts = symbols.map(s => List(labelPart(s, s.decodedName))) - val label = - if allImplicit then labelParts.separated("(using ", ", ", ")") - else labelParts.separated(", ") + case ImplicitParameters(trees, pos) => inlayHints.add( adjustPos(pos).toLsp, - label, - InlayHintKind.Parameter, + ImplicitParameters.partsFromImplicitArgs(trees).map((label, maybeSymbol) => + maybeSymbol match + case Some(symbol) => labelPart(symbol, label) + case None => LabelPart(label) + ), + InlayHintKind.Parameter ) case ValueOf(label, pos) => inlayHints.add( @@ -221,12 +221,8 @@ object ImplicitParameters: case Apply(fun, args) if args.exists(isSyntheticArg) && !tree.sourcePos.span.isZeroExtent && !args.exists(isQuotes(_)) => val (implicitArgs, providedArgs) = args.partition(isSyntheticArg) - val allImplicit = providedArgs.isEmpty || providedArgs.forall { - case Ident(name) => name == nme.MISSING - case _ => false - } val pos = implicitArgs.head.sourcePos - Some(implicitArgs.map(_.symbol), pos, allImplicit) + Some(implicitArgs, pos) case _ => None } else None @@ -242,6 +238,67 @@ object ImplicitParameters: private def isQuotes(tree: Tree)(using Context) = tree.tpe.typeSymbol == defn.QuotesClass + def partsFromImplicitArgs(trees: List[Tree])(using Context): List[(String, Option[Symbol])] = { + @tailrec + def recurseImplicitArgs( + currentArgs: List[Tree], + remainingArgsLists: List[List[Tree]], + parts: List[(String, Option[Symbol])] + ): List[(String, Option[Symbol])] = + (currentArgs, remainingArgsLists) match { + case (Nil, Nil) => parts + case (Nil, headArgsList :: tailArgsList) => + if (headArgsList.isEmpty) { + recurseImplicitArgs( + headArgsList, + tailArgsList, + (")", None) :: parts + ) + } else { + recurseImplicitArgs( + headArgsList, + tailArgsList, + (", ", None) :: (")", None) :: parts + ) + } + case (arg :: remainingArgs, remainingArgsLists) => + arg match { + case Apply(fun, args) => + val applyLabel = (fun.symbol.decodedName, Some(fun.symbol)) + recurseImplicitArgs( + args, + remainingArgs :: remainingArgsLists, + ("(", None) :: applyLabel :: parts + ) + case t if t.isTerm => + val termLabel = (t.symbol.decodedName, Some(t.symbol)) + if (remainingArgs.isEmpty) + recurseImplicitArgs( + remainingArgs, + remainingArgsLists, + termLabel :: parts + ) + else + recurseImplicitArgs( + remainingArgs, + remainingArgsLists, + (", ", None) :: termLabel :: parts + ) + case _ => + recurseImplicitArgs( + remainingArgs, + remainingArgsLists, + parts + ) + } + } + ((")", None) :: recurseImplicitArgs( + trees, + Nil, + List(("(using ", None)) + )).reverse + } + end ImplicitParameters object ValueOf: diff --git a/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala index ce9a89f313ef..8aa885149852 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala @@ -937,7 +937,122 @@ class InlayHintsSuite extends BaseInlayHintsSuite { | given A = A() | implicit def bar(using a: A): B[A] = B[A]() | def foo(using b: B[A]): String = "aaa" - | val g: String = foo/*(using bar<<(5:15)>>)*/ + | val g: String = foo/*(using bar<<(5:15)>>(given_A<<(4:8)>>))*/ |""".stripMargin ) + + @Test def `multiple-params-list` = + check( + """|object Main { + | case class A() + | case class B() + | implicit val theA: A = A() + | def foo(b: B)(implicit a: A): String = "aaa" + | val g: String = foo(B()) + |} + |""".stripMargin, + """|object Main { + | case class A() + | case class B() + | implicit val theA: A = A() + | def foo(b: B)(implicit a: A): String = "aaa" + | val g: String = foo(B())/*(using theA<<(4:15)>>)*/ + |} + |""".stripMargin, + ) + + @Test def `implicit-chain` = + check( + """|object Main{ + | def hello()(implicit string: String, integer: Int, long: Long): String = { + | println(s"Hello $string, $long, $integer!") + | } + | implicit def theString(implicit i: Int): String = i.toString + | implicit def theInt(implicit l: Long): Int = l + | implicit val theLong: Long = 42 + | hello() + |} + |""".stripMargin, + """|object Main{ + | def hello()(implicit string: String, integer: Int, long: Long): String = { + | println(s"Hello $string, $long, $integer!") + | } + | implicit def theString(implicit i: Int): String = i.toString + | implicit def theInt(implicit l: Long): Int = l + | implicit val theLong: Long = 42 + | hello()/*(using theString<<(5:15)>>(theInt<<(6:15)>>(theLong<<(7:15)>>)), theInt<<(6:15)>>(theLong<<(7:15)>>), theLong<<(7:15)>>)*/ + |} + |""".stripMargin, + ) + + @Test def `implicit-parameterless-def` = + check( + """|object Main{ + | def hello()(implicit string: String, integer: Int, long: Long): String = { + | println(s"Hello $string, $long, $integer!") + | } + | implicit def theString(implicit i: Int): String = i.toString + | implicit def theInt: Int = 43 + | implicit def theLong: Long = 42 + | hello() + |} + |""".stripMargin, + """|object Main{ + | def hello()(implicit string: String, integer: Int, long: Long): String = { + | println(s"Hello $string, $long, $integer!") + | } + | implicit def theString(implicit i: Int): String = i.toString + | implicit def theInt: Int = 43 + | implicit def theLong: Long = 42 + | hello()/*(using theString<<(5:15)>>(theInt<<(6:15)>>), theInt<<(6:15)>>, theLong<<(7:15)>>)*/ + |} + |""".stripMargin, + ) + + @Test def `implicit-fn` = + check( + """|object Main{ + | implicit def stringLength(s: String): Int = s.length + | implicitly[String => Int] + | + | implicit val namedStringLength: String => Long = (s: String) => s.length.toLong + | implicitly[String => Long] + |} + |""".stripMargin, + """|object Main{ + | implicit def stringLength(s: String): Int = s.length + | implicitly[String => Int] + | + | implicit val namedStringLength: String => Long = (s: String) => s.length.toLong + | implicitly[String => Long]/*(using namedStringLength<<(5:15)>>)*/ + |} + |""".stripMargin, + ) + + @Test def `implicit-fn2` = + check( + """|object Main{ + | implicit def stringLength(s: String, i: Int): Int = s.length + | implicitly[(String, Int) => Int] + |} + |""".stripMargin, + """|object Main{ + | implicit def stringLength(s: String, i: Int): Int = s.length + | implicitly[(String, Int) => Int] + |} + |""".stripMargin, + ) + + @Test def `strip-margin` = + check( + """|object Main{ + | "".stripMargin + |} + |""".stripMargin, + """|package test + |object Main{ + | /*augmentString<>(*/""/*)*/.stripMargin + |} + |""".stripMargin + ) } From 7d2d89ec93ca5897de2ae10b83cb2150e0e12572 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 21 Jan 2025 16:32:43 +0100 Subject: [PATCH 4/8] improvement: Make including detail in completion label configurable [Cherry-picked eaa827eef7b15ad0bebc76f8dcb83b44a02b0102] --- .../pc/completions/CompletionProvider.scala | 4 +- .../CompletionWithoutDetailsSuite.scala | 120 ++++++++++++++++++ 2 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionWithoutDetailsSuite.scala diff --git a/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala index adaeadb12978..28519debec63 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala @@ -218,7 +218,9 @@ class CompletionProvider( // related issue https://github.com/lampepfl/scala3/issues/11941 lazy val kind: CompletionItemKind = underlyingCompletion.completionItemKind val description = underlyingCompletion.description(printer) - val label = underlyingCompletion.labelWithDescription(printer) + val label = + if config.isDetailIncludedInLabel then completion.labelWithDescription(printer) + else completion.label val ident = underlyingCompletion.insertText.getOrElse(underlyingCompletion.label) lazy val isInStringInterpolation = diff --git a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionWithoutDetailsSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionWithoutDetailsSuite.scala new file mode 100644 index 000000000000..f265b5393ccc --- /dev/null +++ b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionWithoutDetailsSuite.scala @@ -0,0 +1,120 @@ +package dotty.tools.pc.tests.completion + +import dotty.tools.pc.base.BaseCompletionSuite + +import scala.meta.internal.pc.PresentationCompilerConfigImpl +import scala.meta.pc.PresentationCompilerConfig + +import org.junit.Test + +class CompletionWithoutDetailsSuite extends BaseCompletionSuite: + + override def config: PresentationCompilerConfig = + PresentationCompilerConfigImpl().copy( + isDetailIncludedInLabel = false + ) + + @Test def `scope` = + check( + """ + |object A { + | Lis@@ + |}""".stripMargin, + """|List + |List + |List + |List + |ListUI + |""".stripMargin, + includeDetail = false, + topLines = Some(5) + ) + + @Test def `scope-detail` = + check( + """ + |object A { + | Lis@@ + |}""".stripMargin, + """|List[A](elems: A*): List[A] + |List scala.collection.immutable + |List java.awt + |List java.util + |ListUI javax.swing.plaf + |""".stripMargin, + includeDetail = true, + topLines = Some(5) + ) + + @Test def member = + check( + """ + |object A { + | List.emp@@ + |}""".stripMargin, + """ + |empty + |""".stripMargin, + includeDetail = false + ) + + @Test def extension = + check( + """ + |object A { + | "".stripSu@@ + |}""".stripMargin, + """|stripSuffix + |""".stripMargin, + includeDetail = false + ) + + @Test def tparam = + check( + """ + |class Foo[A] { + | def identity[B >: A](a: B): B = a + |} + |object Foo { + | new Foo[Int].ident@@ + |}""".stripMargin, + """|identity + |""".stripMargin, + includeDetail = false + ) + + @Test def tparam1 = + check( + """ + |class Foo[A] { + | def identity(a: A): A = a + |} + |object Foo { + | new Foo[Int].ident@@ + |}""".stripMargin, + """|identity + |""".stripMargin, + includeDetail = false + ) + + @Test def tparam2 = + check( + """ + |object A { + | Map.empty[Int, String].getOrEl@@ + |} + |""".stripMargin, + """|getOrElse + |""".stripMargin, + includeDetail = false + ) + + @Test def pkg = + check( + """ + |import scala.collection.conc@@ + |""".stripMargin, + """|concurrent + |""".stripMargin, + includeDetail = false + ) \ No newline at end of file From ee17a016df4a3c87e50354ffc55ee3b914013491 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 21 Jan 2025 16:39:01 +0100 Subject: [PATCH 5/8] fix: deduplicate scaladoc [Cherry-picked 7e50b1efc8f316cfbcac6609a56aec300bc88ce3] --- .../src/main/dotty/tools/pc/CompletionItemResolver.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/CompletionItemResolver.scala b/presentation-compiler/src/main/dotty/tools/pc/CompletionItemResolver.scala index 291ffe1fec30..ffd7377c8181 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/CompletionItemResolver.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/CompletionItemResolver.scala @@ -75,7 +75,7 @@ object CompletionItemResolver extends ItemResolver: else gsymDoc else val companionDoc = docs(companion) - if companionDoc.isEmpty() then gsymDoc + if companionDoc.isEmpty() || companionDoc == gsymDoc then gsymDoc else if gsymDoc.isEmpty() then companionDoc else List( From fa4b9399e0041fc7c93bd2c834c2506f099f76d9 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 21 Jan 2025 16:48:34 +0100 Subject: [PATCH 6/8] fix: don't look for overshadow conflicts for symbols not in the scope [Cherry-picked 6187ac02a23e1fb848dbbd0518e4e87681e583b8] --- .../tools/pc/PcInlineValueProviderImpl.scala | 23 +++---- .../pc/tests/edit/InlineValueSuite.scala | 61 +++++++++++++++++++ 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/PcInlineValueProviderImpl.scala b/presentation-compiler/src/main/dotty/tools/pc/PcInlineValueProviderImpl.scala index bbba44d0d84f..fc4b53e60bbd 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/PcInlineValueProviderImpl.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/PcInlineValueProviderImpl.scala @@ -18,6 +18,7 @@ import dotty.tools.dotc.interactive.Interactive import dotty.tools.dotc.interactive.InteractiveDriver import dotty.tools.dotc.util.SourcePosition import dotty.tools.pc.utils.InteractiveEnrichments.* +import dotty.tools.pc.IndexedContext.Result import org.eclipse.lsp4j as l @@ -49,7 +50,9 @@ final class PcInlineValueProviderImpl( DefinitionTree(defn, pos) } .toRight(Errors.didNotFindDefinition) - symbols = symbolsUsedInDefn(definition.tree.rhs) + path = Interactive.pathTo(unit.tpdTree, definition.tree.rhs.span)(using newctx) + indexedContext = IndexedContext(Interactive.contextOfPath(path)(using newctx)) + symbols = symbolsUsedInDefn(definition.tree.rhs).filter(indexedContext.lookupSym(_) == Result.InScope) references <- getReferencesToInline(definition, allOccurences, symbols) yield val (deleteDefinition, refsEdits) = references @@ -111,27 +114,25 @@ final class PcInlineValueProviderImpl( val adjustedEnd = extend(pos.end - 1, ')', 1) + 1 text.slice(adjustedStart, adjustedEnd).mkString - private def symbolsUsedInDefn( - rhs: Tree - ): List[Symbol] = + private def symbolsUsedInDefn(rhs: Tree): Set[Symbol] = def collectNames( - symbols: List[Symbol], + symbols: Set[Symbol], tree: Tree - ): List[Symbol] = + ): Set[Symbol] = tree match case id: (Ident | Select) if !id.symbol.is(Synthetic) && !id.symbol.is(Implicit) => - tree.symbol :: symbols + symbols + tree.symbol case _ => symbols - val traverser = new DeepFolder[List[Symbol]](collectNames) - traverser(List(), rhs) + val traverser = new DeepFolder[Set[Symbol]](collectNames) + traverser(Set(), rhs) end symbolsUsedInDefn private def getReferencesToInline( definition: DefinitionTree, allOccurences: List[Occurence], - symbols: List[Symbol] + symbols: Set[Symbol] ): Either[String, (Boolean, List[Reference])] = val defIsLocal = definition.tree.symbol.ownersIterator .drop(1) @@ -156,7 +157,7 @@ final class PcInlineValueProviderImpl( private def makeRefsEdits( refs: List[Occurence], - symbols: List[Symbol] + symbols: Set[Symbol] ): Either[String, List[Reference]] = val newctx = driver.currentCtx.fresh.setCompilationUnit(unit) def buildRef(occurrence: Occurence): Either[String, Reference] = diff --git a/presentation-compiler/test/dotty/tools/pc/tests/edit/InlineValueSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/edit/InlineValueSuite.scala index 0cec3952a7ef..cee0aada9f86 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/edit/InlineValueSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/edit/InlineValueSuite.scala @@ -301,6 +301,47 @@ class InlineValueSuite extends BaseCodeActionSuite with CommonMtagsEnrichments: |}""".stripMargin ) + + @Test def `i6924` = + checkEdit( + """|object O { + | def test(n: Int) = { + | val isOne = n == 1 + | <>sOne + | } + |} + |""".stripMargin, + """|object O { + | def test(n: Int) = { + | n == 1 + | } + |} + |""".stripMargin + ) + + @Test def `i6924-2` = + checkEdit( + """|object O { + | def ==(o: O) = false + |} + |object P { + | def test() = { + | val isOne = O == O + | <>sOne + | } + |} + |""".stripMargin, + """|object O { + | def ==(o: O) = false + |} + |object P { + | def test() = { + | O == O + | } + |} + |""".stripMargin + ) + @Test def `scoping-packages` = checkError( """|package a @@ -346,6 +387,26 @@ class InlineValueSuite extends BaseCodeActionSuite with CommonMtagsEnrichments: InlineErrors.variablesAreShadowed("A.k") ) + @Test def `bad-scoping-3` = + checkError( + """|class T { + | val a = 1 + |} + | + |class O { + | val t = new T() + | import t._ + | val bb = a + a + | + | class Inner { + | val a = 123 + | val cc = <>b + | } + |} + |""".stripMargin, + InlineErrors.variablesAreShadowed("T.a") + ) + def checkEdit( original: String, expected: String, From d4bccf031d0e5c9424631ed2be22da9bcc01ec53 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 21 Jan 2025 16:58:50 +0100 Subject: [PATCH 7/8] fix: don't show incorrect docs for inner methods [Cherry-picked 9a028cdca1a4b0e35f698f1e53db50d32bd31953] --- .../tools/pc/utils/InteractiveEnrichments.scala | 15 ++++++++++----- .../tools/pc/tests/hover/HoverDocSuite.scala | 12 ++++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala b/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala index 66080a363d51..b65f23fae40f 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala @@ -1,5 +1,7 @@ package dotty.tools.pc.utils +import java.util.Optional + import scala.annotation.tailrec import scala.meta.internal.jdk.CollectionConverters.* import scala.meta.internal.mtags.CommonMtagsEnrichments @@ -272,11 +274,14 @@ object InteractiveEnrichments extends CommonMtagsEnrichments: symbol.maybeOwner.companion, ).filter(_ != NoSymbol) ++ symbol.allOverriddenSymbols else symbol.allOverriddenSymbols - val documentation = search.documentation( - sym, - () => parentSymbols.iterator.map(toSemanticdbSymbol).toList.asJava, - contentType, - ) + val documentation = + if symbol.isLocal then Optional.empty + else + search.documentation( + sym, + () => parentSymbols.iterator.map(toSemanticdbSymbol).toList.asJava, + contentType, + ) documentation.nn.toScala end symbolDocumentation end extension diff --git a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverDocSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverDocSuite.scala index fc9b6835e319..a82fa73865c8 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverDocSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverDocSuite.scala @@ -254,3 +254,15 @@ class HoverDocSuite extends BaseHoverSuite: |Found documentation for _empty_/Alpha# |""".stripMargin, ) + + @Test def `i7093` = + check( + """|object O: + | /** Ooopsie daisy */ + | val computeLogicOwners: Unit = + | /** This is a comment */ + | <> + | ??? + |""".stripMargin, + """def logicOwners: Nothing""".hover.stripMargin + ) From 32de1cc7574ae2a32268540d6eff40234fc1cd4b Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Wed, 22 Jan 2025 11:54:25 +0100 Subject: [PATCH 8/8] adjust for Java 8 and fix doc test [Cherry-picked d1a150af4873dcccaccc6e3f3cd7b901071fc3b2] --- .../tools/pc/ScalaPresentationCompiler.scala | 15 +++++++-------- .../tools/pc/tests/hover/HoverNamedArgSuite.scala | 1 - 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala b/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala index b3f8bba78953..a44c16ecc748 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala @@ -98,15 +98,14 @@ case class ScalaPresentationCompiler( params match { case range: RangeParams => extractMethod(range, extractionPos) - case _ => - CompletableFuture.failedFuture( - new IllegalArgumentException(s"Expected range parameters") - ) + case _ => failedFuture(new IllegalArgumentException(s"Expected range parameters")) } - case (id, _) => - CompletableFuture.failedFuture( - new IllegalArgumentException(s"Unsupported action id $id") - ) + case (id, _) => failedFuture(new IllegalArgumentException(s"Unsupported action id $id")) + + private def failedFuture[T](e: Throwable): CompletableFuture[T] = + val f = new CompletableFuture[T]() + f.completeExceptionally(e) + f override def withCompletionItemPriority( priority: CompletionItemPriority diff --git a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverNamedArgSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverNamedArgSuite.scala index 182f8e1e0644..9f9e11725447 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverNamedArgSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverNamedArgSuite.scala @@ -29,7 +29,6 @@ class HoverNamedArgSuite extends BaseHoverSuite: """|```scala |named: Int |``` - |Found documentation for a/b.foo().(named) |""".stripMargin )