Skip to content

Commit b691272

Browse files
authored
Merge pull request #1737 from LaurenceWarne/add-edit-to-api
Add textEdits method to ScalafixPatch
2 parents d647c59 + 285a014 commit b691272

File tree

6 files changed

+106
-3
lines changed

6 files changed

+106
-3
lines changed

scalafix-cli/src/main/scala/scalafix/internal/interfaces/ScalafixFileEvaluationImpl.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,10 @@ object ScalafixFileEvaluationImpl {
143143
ctx: RuleCtx,
144144
index: Option[v0.SemanticdbIndex]
145145
): ScalafixFileEvaluationImpl = {
146-
val scalafixPatches = patches.map(ScalafixPatchImpl.apply)
146+
val indexOrEmpty = index.getOrElse(v0.SemanticdbIndex.empty)
147+
val scalafixPatches = patches.map { p =>
148+
ScalafixPatchImpl(p)(args, ctx, indexOrEmpty)
149+
}
147150
ScalafixFileEvaluationImpl(
148151
originalPath = originalPath,
149152
fixedOpt = fixed,

scalafix-cli/src/main/scala/scalafix/internal/interfaces/ScalafixPatchImpl.scala

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,26 @@ package scalafix.internal.interfaces
22

33
import scalafix.Patch
44
import scalafix.interfaces.ScalafixPatch
5+
import scalafix.interfaces.ScalafixTextEdit
6+
import scalafix.internal.patch.PatchInternals
7+
import scalafix.internal.v1.ValidatedArgs
8+
import scalafix.v0
9+
import scalafix.v0.RuleCtx
510

6-
case class ScalafixPatchImpl(patch: Patch) extends ScalafixPatch
11+
case class ScalafixPatchImpl(patch: Patch)(
12+
args: ValidatedArgs,
13+
ctx: RuleCtx,
14+
index: v0.SemanticdbIndex
15+
) extends ScalafixPatch {
16+
17+
override def textEdits(): Array[ScalafixTextEdit] =
18+
PatchInternals
19+
.treePatchApply(patch)(ctx, index)
20+
.map { t =>
21+
ScalafixTextEditImpl(
22+
PositionImpl.fromScala(t.tok.pos),
23+
t.newTok
24+
): ScalafixTextEdit
25+
}
26+
.toArray
27+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package scalafix.internal.interfaces
2+
3+
import scalafix.interfaces.ScalafixPosition
4+
import scalafix.interfaces.ScalafixTextEdit
5+
6+
final case class ScalafixTextEditImpl(
7+
position: ScalafixPosition,
8+
newText: String
9+
) extends ScalafixTextEdit
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
package scalafix.interfaces;
22

3-
public interface ScalafixPatch {}
3+
public interface ScalafixPatch {
4+
/**
5+
*
6+
* @return This patch as an array of text edits.
7+
*/
8+
default ScalafixTextEdit[] textEdits() {
9+
throw new UnsupportedOperationException("textEdits() is not implemented");
10+
}
11+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package scalafix.interfaces;
2+
3+
public interface ScalafixTextEdit {
4+
ScalafixPosition position();
5+
6+
String newText();
7+
}

scalafix-tests/unit/src/test/scala/scalafix/tests/interfaces/ScalafixArgumentsSuite.scala

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,61 @@ class ScalafixArgumentsSuite extends AnyFunSuite with DiffAssertions {
517517
assert(run.failed.toOption.map(_.getMessage) == Some(expectedErrorMessage))
518518
}
519519

520+
test("textEdits returns patch as edits") {
521+
val cwd: Path = StringFS
522+
.string2dir(
523+
"""|/src/Main2.scala
524+
|import scala.concurrent.duration
525+
|import scala.concurrent.Future
526+
|
527+
|object Main extends App {
528+
| import scala.concurrent.Await
529+
| println("test");
530+
| println("ok")
531+
|}""".stripMargin,
532+
charset
533+
)
534+
.toNIO
535+
val src = cwd.resolve("src")
536+
537+
val run = api
538+
.withRules(List("CommentFileNonAtomic", "CommentFileAtomic").asJava)
539+
.withSourceroot(src)
540+
541+
val fileEvaluation = run.evaluate().getFileEvaluations.head
542+
val patches = fileEvaluation.getPatches
543+
544+
// CommentFileNonAtomic produces two patches which in turn produce one
545+
// token patch each, whilst CommentFileAtomic produces one patch which
546+
// in turn produces two token patches
547+
val Array(nonAtomicEditArray1, nonAtomicEditArray2, atomicEditArray) =
548+
patches.map(_.textEdits()).sortBy(_.length)
549+
550+
// Check the above holds
551+
assert(nonAtomicEditArray1.length == 1 && nonAtomicEditArray2.length == 1)
552+
assert(atomicEditArray.length == 2)
553+
554+
// Check the offsets for the atomic edits look ok (e.g. they're zero-based)
555+
val Array(atomicEdit1, atomicEdit2) =
556+
atomicEditArray.sortBy(_.position.startLine)
557+
assert(
558+
atomicEdit1.position.startLine == 0 && atomicEdit1.position.startColumn == 0
559+
)
560+
assert(
561+
atomicEdit2.position.startLine == 7 && atomicEdit2.position.startColumn == 1
562+
)
563+
564+
// Check the same holds for the non-atomic edit pair
565+
val Array(nonAtomicEdit1, nonAtomicEdit2) =
566+
(nonAtomicEditArray1 ++ nonAtomicEditArray2).sortBy(_.position.startLine)
567+
assert(
568+
nonAtomicEdit1.position.startLine == 0 && nonAtomicEdit1.position.startColumn == 0
569+
)
570+
assert(
571+
nonAtomicEdit2.position.startLine == 7 && nonAtomicEdit2.position.startColumn == 1
572+
)
573+
}
574+
520575
def removeUnsuedRule(): SemanticRule = {
521576
val config = RemoveUnusedConfig.default
522577
new RemoveUnused(config)

0 commit comments

Comments
 (0)