Skip to content
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

bugfix: Add name field to distinguish different action data #6980

Merged
merged 1 commit into from
Nov 29, 2024
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package scala.meta.internal.metals

import java.{util => ju}
import javax.annotation.Nullable

import scala.meta.internal.metals.newScalaFile.NewFileTypes
Expand Down Expand Up @@ -629,21 +628,6 @@ object ServerCommands {
|""".stripMargin,
)

final case class ConvertToNamedArgsRequest(
position: TextDocumentPositionParams,
argIndices: ju.List[Integer],
)
val ConvertToNamedArguments =
new ParametrizedCommand[ConvertToNamedArgsRequest](
"convert-to-named-arguments",
"Convert positional arguments to named ones",
"""|Whenever a user chooses code action to convert to named arguments, this command is later run to
|determine the parameter names of all unnamed arguments and insert names at the correct locations.
|""".stripMargin,
"""|Object with [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) of the target Apply and `numUnnamedArgs` (int)
|""".stripMargin,
)

val InsertInferredMethod =
new ParametrizedCommand[TextDocumentPositionParams](
"insert-inferred-method",
Expand Down Expand Up @@ -751,7 +735,6 @@ object ServerCommands {
CancelCompile,
CascadeCompile,
CleanCompile,
ConvertToNamedArguments,
CopyWorksheetOutput,
DiscoverMainClasses,
DiscoverTestSuites,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package scala.meta.internal.metals.codeactions
import scala.annotation.nowarn
import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import scala.reflect.ClassTag

import scala.meta.internal.metals.JsonParser
import scala.meta.internal.metals.MetalsEnrichments._
import scala.meta.internal.metals.ParametrizedCommand
import scala.meta.pc.CancelToken
Expand All @@ -18,6 +20,33 @@ trait CodeAction {
*/
def kind: String

private def className = this.getClass().getSimpleName()
protected trait CodeActionResolveData {
this: Product =>

/**
* Name is neccessary to identify what code action is being resolved.
*
* Gson will attempt to fill this field during deserialization,
* but if it's the wrong data the name will be wrong.
*/
val codeActionName: String = className

def notNullFields: Boolean = this.productIterator.forall(_ != null)
}

protected def parseData[T <: CodeActionResolveData](
codeAction: l.CodeAction
)(implicit clsTag: ClassTag[T]): Option[T] = {
val parser = new JsonParser.Of[T]
codeAction.getData() match {
case parser.Jsonized(data)
if data.codeActionName == className && data.notNullFields =>
Some(data)
case _ => None
}
}

/**
* The CodeActionId for this code action, if applicable. CodeActionId is only
* used for code actions that require the use of the presentation compiler.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ final class CodeActionProvider(
new CreateCompanionObjectCodeAction(trees, buffers),
new ExtractMethodCodeAction(trees, compilers),
new InlineValueCodeAction(trees, compilers, languageClient),
new ConvertToNamedArguments(trees, compilers, languageClient),
new ConvertToNamedArguments(trees, compilers),
new FlatMapToForComprehensionCodeAction(trees, buffers),
new MillifyDependencyCodeAction(buffers),
new MillifyScalaCliDependencyCodeAction(buffers),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import scala.meta.Term
import scala.meta.Tree
import scala.meta.XtensionSyntax
import scala.meta.internal.metals.Compilers
import scala.meta.internal.metals.JsonParser.XtensionSerializableToJson
import scala.meta.internal.metals.MetalsEnrichments._
import scala.meta.internal.metals.ServerCommands
import scala.meta.internal.metals.clients.language.MetalsLanguageClient
import scala.meta.internal.metals.codeactions.CodeAction
import scala.meta.internal.metals.codeactions.CodeActionBuilder
import scala.meta.internal.metals.logging
Expand All @@ -22,39 +21,40 @@ import org.eclipse.{lsp4j => l}
class ConvertToNamedArguments(
trees: Trees,
compilers: Compilers,
languageClient: MetalsLanguageClient,
) extends CodeAction {

import ConvertToNamedArguments._

case class ConvertToNamedArgsData(
position: l.TextDocumentPositionParams,
argIndices: java.util.List[Integer],
) extends CodeActionResolveData

override val kind: String = l.CodeActionKind.RefactorRewrite

override type CommandData = ServerCommands.ConvertToNamedArgsRequest

override def command: Option[ActionCommand] = Some(
ServerCommands.ConvertToNamedArguments
)

override def handleCommand(
data: ServerCommands.ConvertToNamedArgsRequest,
token: CancelToken,
)(implicit ec: ExecutionContext): Future[Unit] = {
val uri = data.position.getTextDocument().getUri()
for {
edits <- compilers.convertToNamedArguments(
data.position,
data.argIndices,
token,
)
_ = logging.logErrorWhen(
edits.isEmpty(),
s"Could not find the correct names for arguments at ${data.position} with indices ${data.argIndices.asScala
.mkString(",")}",
)
workspaceEdit = new l.WorkspaceEdit(Map(uri -> edits).asJava)
_ <- languageClient
.applyEdit(new l.ApplyWorkspaceEditParams(workspaceEdit))
.asScala
} yield ()
override def resolveCodeAction(codeAction: l.CodeAction, token: CancelToken)(
implicit ec: ExecutionContext
): Option[Future[l.CodeAction]] = {
parseData[ConvertToNamedArgsData](codeAction) match {
case Some(data) =>
val uri = data.position.getTextDocument().getUri()
val result = for {
edits <- compilers.convertToNamedArguments(
data.position,
data.argIndices,
token,
)
_ = logging.logErrorWhen(
edits.isEmpty(),
s"Could not find the correct names for arguments at ${data.position} with indices ${data.argIndices.asScala
.mkString(",")}",
)
workspaceEdit = new l.WorkspaceEdit(Map(uri -> edits).asJava)
_ = codeAction.setEdit(workspaceEdit)
} yield codeAction
Some(result)
case None => None
}
}

private def getTermWithArgs(
Expand Down Expand Up @@ -146,19 +146,16 @@ class ConvertToNamedArguments(
params.getTextDocument(),
new l.Position(apply.app.pos.endLine, apply.app.pos.endColumn),
)
val command =
ServerCommands.ConvertToNamedArguments.toLsp(
ServerCommands
.ConvertToNamedArgsRequest(
position,
apply.argIndices.map(Integer.valueOf).asJava,
)
val data =
ConvertToNamedArgsData(
position,
apply.argIndices.map(Integer.valueOf).asJava,
)

val codeAction = CodeActionBuilder.build(
title = title(methodName(apply.app, isFirst = true)),
kind = l.CodeActionKind.RefactorRewrite,
command = Some(command),
data = Some(data.toJsonObject),
)

Future.successful(Seq(codeAction))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import scala.meta.Template
import scala.meta.Term
import scala.meta.Tree
import scala.meta.internal.metals.Compilers
import scala.meta.internal.metals.JsonParser
import scala.meta.internal.metals.JsonParser.XtensionSerializableToJson
import scala.meta.internal.metals.MetalsEnrichments._
import scala.meta.internal.metals.logging
Expand All @@ -23,24 +22,20 @@ class ExtractMethodCodeAction(
trees: Trees,
compilers: Compilers,
) extends CodeAction {
ExtractMethodCodeAction

private val parser = new JsonParser.Of[ExtractMethodParams]

private case class ExtractMethodParams(
private case class ExtractMethodData(
param: l.TextDocumentIdentifier,
range: l.Range,
extractPosition: l.Position,
)
) extends CodeActionResolveData

override def kind: String = l.CodeActionKind.RefactorExtract

override def resolveCodeAction(codeAction: l.CodeAction, token: CancelToken)(
implicit ec: ExecutionContext
): Option[Future[l.CodeAction]] = {
val data = codeAction.getData()
data match {
case parser.Jsonized(data) =>
parseData[ExtractMethodData](codeAction) match {
case Some(data) =>
val doc = data.param
val uri = doc.getUri()
val modifiedCodeAction = for {
Expand Down Expand Up @@ -109,7 +104,7 @@ class ExtractMethodCodeAction(
head.pos.toLsp.getStart(),
expr.pos.toLsp.getEnd(),
)
val data = ExtractMethodParams(
val data = ExtractMethodData(
params.getTextDocument(),
exprRange,
defnPos.pos.toLsp.getStart(),
Expand Down