Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
10ecbc1
Initial scala plan
Jul 10, 2025
661449f
Initial scala foundation
Jul 11, 2025
e5a3102
Integrate Scala 3 compiler for literal parsing
Jul 11, 2025
fda70ff
Identifier parsing
Jul 11, 2025
880bd3c
feat(scala): implement binary expression parsing
Jul 11, 2025
7975df5
feat(scala): implement unary expression parsing
Jul 11, 2025
64d8a79
feat(scala): add parentheses test suite
Jul 11, 2025
244bb90
feat(scala): Add variable declaration support preserving formatting
jkschneider Jul 11, 2025
60a5198
docs(scala): Update implementation progress in Scala.md
jkschneider Jul 11, 2025
b5bbd08
fix(scala): Fix expression duplication in unary and postfix operators
jkschneider Jul 11, 2025
c30b359
feat(scala): Add basic compilation unit structure handling
jkschneider Jul 11, 2025
7a695fb
docs(scala): Update progress to 95% test passing rate
jkschneider Jul 11, 2025
34594e5
fix(scala): Fix comment handling using Space.format
jkschneider Jul 11, 2025
f393f34
Fix package declaration duplication issue in Scala parser
jkschneider Jul 11, 2025
b50e60f
feat(scala): Implement J.FieldAccess and J.MethodInvocation mapping
jkschneider Jul 12, 2025
5ca21fa
feat(scala): Implement control flow constructs (if/while/for)
jkschneider Jul 12, 2025
003791f
Block tesT
jkschneider Jul 12, 2025
6f5eaac
feat(scala): Implement basic class declarations with modifiers
jkschneider Jul 12, 2025
fce36df
feat(scala): Add constructor parameter support for classes
jkschneider Jul 12, 2025
3e7fd90
feat(scala): Fix extends/implements spacing and add comprehensive sup…
jkschneider Jul 12, 2025
42431d9
fix(scala): Fix printer issues for extends/implements support
jkschneider Jul 12, 2025
6a0cf40
feat(scala): Implement type parameter support for classes
jkschneider Jul 12, 2025
91d6b77
feat(scala): Implement object declarations (singleton and companion)
jkschneider Jul 12, 2025
a8f9977
feat(scala): Add basic for comprehension support mapping to J.ForEach…
jkschneider Jul 12, 2025
aa57da6
refactor(scala): Migrate S interface from Scala to Java
jkschneider Jul 12, 2025
eed9b79
More parser tests
jkschneider Jul 14, 2025
56705a0
feat(scala): Major improvements to Scala parser - 97.9% tests passing
jkschneider Jul 15, 2025
b4bda5f
fix(scala): Fix object with traits spacing issue in ScalaPrinter
jkschneider Jul 15, 2025
39735cb
More progress
jkschneider Jul 16, 2025
a75aaf9
fix(scala): Fix variable declarations with type annotations and compl…
jkschneider Jul 24, 2025
da8d12e
fix(scala): Fix J.NewClass mapping for constructor calls and anonymou…
jkschneider Aug 6, 2025
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
13 changes: 12 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,18 @@
"mcp__idea__open_file_in_editor",
"mcp__idea__replace_selected_text",
"mcp__idea__replace_specific_text",
"mcp__idea__search_in_files_content"
"mcp__idea__search_in_files_content",
"Bash(cat:*)",
"Bash(mkdir:*)",
"Bash(javac:*)",
"Bash(java:*)",
"Bash(scalac:*)",
"Bash(scala:*)",
"Bash(ls:*)",
"Bash(../gradlew test:*)",
"Bash(./gradlew :rewrite-scala:test --tests \"org.openrewrite.scala.tree.MethodInvocationTest.methodCallOnFieldAccess\" -i)",
"Bash(touch:*)",
"Bash(sed:*)"
],
"deny": []
}
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "rewrite-docs"]
path = rewrite-docs
url = https://github.com/openrewrite/rewrite-docs.git
5 changes: 5 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Active Development Plans

- **Scala Language Support**: See [Scala.md](./Scala.md) for the implementation plan and progress tracking.
- **Language Support Documentation**: As we implement Scala support, we're documenting the process in [Contributing Additional Language Support](./rewrite-docs/docs/authoring-recipes/contributing-language-support.md). This guide should be continuously updated with lessons learned during implementation.

## Project Overview

OpenRewrite is an automated refactoring ecosystem for source code that eliminates technical debt through AST-based transformations. The project uses a visitor pattern architecture where **Recipes** define transformations and **TreeVisitors** traverse and modify Abstract Syntax Trees (ASTs).
Expand Down
620 changes: 620 additions & 0 deletions Scala.md

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions TestComplexType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import org.openrewrite.java.tree.*;
import org.openrewrite.marker.Markers;
import java.util.Collections;

public class TestComplexType {
public static void main(String[] args) {
// Create a simple identifier "Int"
J.Identifier intId = new J.Identifier(
Tree.randomId(),
Space.EMPTY,
Markers.EMPTY,
Collections.emptyList(),
"Int",
null,
null
);

System.out.println("Identifier simpleName: " + intId.getSimpleName());
System.out.println("Identifier toString: " + intId);
}
}
1 change: 1 addition & 0 deletions rewrite-docs
Submodule rewrite-docs added at 48d5ef
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import org.openrewrite.marker.Markers;

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@c")
public interface Comment {
public interface Comment {
Markers getMarkers();
<C extends Comment> C withMarkers(Markers markers);

Expand Down
33 changes: 33 additions & 0 deletions rewrite-scala/TestAssignment.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import dotty.tools.dotc.ast.Trees.*
import dotty.tools.dotc.ast.untpd
import dotty.tools.dotc.core.Contexts.*
import dotty.tools.dotc.Driver
import dotty.tools.dotc.util.SourceFile
import dotty.tools.dotc.parsing.Parsers

@main def testAssignment(): Unit = {
val driver = new Driver
given Context = driver.getInitialContext

// Test simple assignment
val source1 = SourceFile.virtual("test.scala", "obj.field = 42")
val parser1 = new Parsers.Parser(source1)
val tree1 = parser1.parse()

println(s"Assignment AST: ${tree1.getClass.getSimpleName}")
tree1 match {
case pkg: untpd.PackageDef =>
pkg.stats.foreach { stat =>
println(s" Statement: ${stat.getClass.getSimpleName}")
stat match {
case app: untpd.Apply =>
println(s" Fun: ${app.fun}")
println(s" Args: ${app.args}")
case _ =>
println(s" Details: $stat")
}
}
case _ =>
println(s"Unexpected: $tree1")
}
}
54 changes: 54 additions & 0 deletions rewrite-scala/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
plugins {
id("org.openrewrite.build.language-library")
scala
}

dependencies {
api(project(":rewrite-java"))

// Scala 3 compiler (dotty) and library
implementation("org.scala-lang:scala3-compiler_3:latest.release")
implementation("org.scala-lang:scala3-library_3:latest.release")

compileOnly(project(":rewrite-test"))
compileOnly("org.slf4j:slf4j-api:1.7.+")

api("io.micrometer:micrometer-core:1.9.+")

api("org.jetbrains:annotations:latest.release")

api("com.fasterxml.jackson.core:jackson-annotations")

testImplementation(project(":rewrite-test"))
testImplementation(project(":rewrite-java-test"))
testImplementation("org.assertj:assertj-core:latest.release")
testImplementation("org.junit.jupiter:junit-jupiter-api:latest.release")
testImplementation("org.junit.jupiter:junit-jupiter-params:latest.release")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:latest.release")
}

// Configure Scala source sets and compilation order
sourceSets {
main {
scala {
srcDirs("src/main/scala")
}
}
}

// Configure mixed Java/Scala compilation
// Scala needs to see Java classes from the same module
tasks.named<ScalaCompile>("compileScala") {
// Include Java source files in Scala compilation
source(sourceSets.main.get().java)
// Scala compiler will compile both Java and Scala files together
classpath = sourceSets.main.get().compileClasspath
}

// Ensure Java compilation uses output from Scala compilation
// Since Scala already compiled Java files, we just need to ensure the classpath is correct
tasks.named<JavaCompile>("compileJava") {
dependsOn("compileScala")
// Exclude Java files from Java compilation since Scala already compiled them
exclude("**/*.java")
}
78 changes: 78 additions & 0 deletions rewrite-scala/src/main/java/org/openrewrite/scala/Assertions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2025 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openrewrite.scala;

import org.intellij.lang.annotations.Language;
import org.jspecify.annotations.Nullable;
import org.openrewrite.SourceFile;
import org.openrewrite.java.JavaParser;
import org.openrewrite.scala.tree.S;
import org.openrewrite.test.SourceSpec;
import org.openrewrite.test.SourceSpecs;

import java.util.function.Consumer;

import static org.openrewrite.java.Assertions.sourceSet;
import static org.openrewrite.test.SourceSpecs.dir;

public class Assertions {

private Assertions() {
}

private static ScalaParser.Builder scalaParser = ScalaParser.builder()
.classpath(JavaParser.runtimeClasspath())
.logCompilationWarningsAndErrors(true);

public static SourceSpecs scala(@Language("scala") @Nullable String before) {
return scala(before, s -> {
});
}

public static SourceSpecs scala(@Language("scala") @Nullable String before, Consumer<SourceSpec<S.CompilationUnit>> spec) {
SourceSpec<S.CompilationUnit> scala = new SourceSpec<>(S.CompilationUnit.class, null, scalaParser, before, null);
spec.accept(scala);
return scala;
}

public static SourceSpecs scala(@Language("scala") @Nullable String before, @Language("scala") @Nullable String after) {
return scala(before, after, s -> {
});
}

public static SourceSpecs scala(@Language("scala") @Nullable String before, @Language("scala") @Nullable String after,
Consumer<SourceSpec<S.CompilationUnit>> spec) {
SourceSpec<S.CompilationUnit> scala = new SourceSpec<>(S.CompilationUnit.class, null, scalaParser, before, s -> after);
spec.accept(scala);
return scala;
}

public static SourceSpecs srcMainScala(Consumer<SourceSpec<SourceFile>> spec, SourceSpecs... scalaSources) {
return dir("src/main/scala", spec, scalaSources);
}

public static SourceSpecs srcMainScala(SourceSpecs... scalaSources) {
return srcMainScala(spec -> sourceSet(spec, "main"), scalaSources);
}

public static SourceSpecs srcTestScala(Consumer<SourceSpec<SourceFile>> spec, SourceSpecs... scalaSources) {
return dir("src/test/scala", spec, scalaSources);
}

public static SourceSpecs srcTestScala(SourceSpecs... scalaSources) {
return srcTestScala(spec -> sourceSet(spec, "test"), scalaSources);
}
}
Loading