Skip to content
This repository was archived by the owner on May 12, 2025. It is now read-only.

Commit a467f7c

Browse files
tschutTiemen Schuttimtebeek
authored
Add .dependsOn method for KotlinParser (#617)
* Add .dependsOn method for KotlinParser * Add .dependsOn method for KotlinParser * Add basic testcase * Fix up sourcePath determine logic * Minor polish --------- Co-authored-by: Tiemen Schut <tschut@bol.com> Co-authored-by: Tim te Beek <tim@moderne.io>
1 parent 749f1f6 commit a467f7c

File tree

2 files changed

+85
-5
lines changed

2 files changed

+85
-5
lines changed

src/main/java/org/openrewrite/kotlin/KotlinParser.java

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
import org.jetbrains.kotlin.utils.PathUtil;
6666
import org.jspecify.annotations.Nullable;
6767
import org.openrewrite.*;
68+
import org.openrewrite.internal.ListUtils;
6869
import org.openrewrite.java.JavaParser;
6970
import org.openrewrite.java.internal.JavaTypeCache;
7071
import org.openrewrite.java.marker.JavaSourceSet;
@@ -87,7 +88,6 @@
8788
import java.util.function.Function;
8889
import java.util.regex.Matcher;
8990
import java.util.regex.Pattern;
90-
import java.util.stream.Collectors;
9191
import java.util.stream.Stream;
9292

9393
import static java.util.Collections.emptyList;
@@ -101,6 +101,7 @@
101101
import static org.jetbrains.kotlin.config.JVMConfigurationKeys.DO_NOT_CLEAR_BINDING_CONTEXT;
102102
import static org.jetbrains.kotlin.config.JVMConfigurationKeys.LINK_VIA_SIGNATURES;
103103
import static org.jetbrains.kotlin.incremental.IncrementalFirJvmCompilerRunnerKt.configureBaseRoots;
104+
import static org.openrewrite.kotlin.KotlinParser.SourcePathFromSourceTextResolver.determinePath;
104105

105106
@SuppressWarnings("CommentedOutCode")
106107
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@@ -115,6 +116,9 @@ public class KotlinParser implements Parser {
115116
@Nullable
116117
private final Collection<Path> classpath;
117118

119+
@Nullable
120+
private final List<Input> dependsOn;
121+
118122
private final List<NamedStyles> styles;
119123
private final boolean logCompilationWarningsAndErrors;
120124
private final JavaTypeCache typeCache;
@@ -162,10 +166,11 @@ public Stream<SourceFile> parseInputs(Iterable<Input> sources, @Nullable Path re
162166
// TODO: FIR and disposable may not be necessary using the IR.
163167
Disposable disposable = Disposer.newDisposable();
164168
CompiledSource compilerCus;
169+
List<Input> acceptedInputs = ListUtils.concatAll(dependsOn, acceptedInputs(sources).collect(toList()));
165170
try {
166-
compilerCus = parse(acceptedInputs(sources).collect(Collectors.toList()), disposable, pctx);
171+
compilerCus = parse(acceptedInputs, disposable, pctx);
167172
} catch (Exception e) {
168-
return acceptedInputs(sources).map(input -> ParseError.build(this, input, relativeTo, ctx, e));
173+
return acceptedInputs.stream().map(input -> ParseError.build(this, input, relativeTo, ctx, e));
169174
}
170175

171176
FirSession firSession = compilerCus.getFirSession();
@@ -201,7 +206,8 @@ public Stream<SourceFile> parseInputs(Iterable<Input> sources, @Nullable Path re
201206
return (SourceFile) null;
202207
})
203208
.limit(1))
204-
.filter(Objects::nonNull);
209+
.filter(Objects::nonNull)
210+
.filter(source -> !source.getSourcePath().getFileName().toString().startsWith("dependsOn-"));
205211
}
206212

207213
@Override
@@ -252,6 +258,7 @@ public static class Builder extends Parser.Builder {
252258
@Nullable
253259
private Collection<Path> classpath = emptyList();
254260

261+
private List<Input> dependsOn = emptyList();
255262
private JavaTypeCache typeCache = new JavaTypeCache();
256263
private boolean logCompilationWarningsAndErrors;
257264
private final List<NamedStyles> styles = new ArrayList<>();
@@ -303,6 +310,13 @@ public Builder addClasspathEntry(Path classpath) {
303310
return this;
304311
}
305312

313+
public Builder dependsOn(@Language("kotlin") String... inputsAsStrings) {
314+
this.dependsOn = Arrays.stream(inputsAsStrings)
315+
.map(input -> Input.fromString(determinePath("dependsOn-", input), input))
316+
.collect(toList());
317+
return this;
318+
}
319+
306320
public Builder typeCache(JavaTypeCache typeCache) {
307321
this.typeCache = typeCache;
308322
return this;
@@ -335,7 +349,7 @@ public Builder languageLevel(KotlinLanguageLevel languageLevel) {
335349

336350
@Override
337351
public KotlinParser build() {
338-
return new KotlinParser(resolvedClasspath(), styles, logCompilationWarningsAndErrors, typeCache, moduleName, languageLevel, isKotlinScript);
352+
return new KotlinParser(resolvedClasspath(), dependsOn, styles, logCompilationWarningsAndErrors, typeCache, moduleName, languageLevel, isKotlinScript);
339353
}
340354

341355
@Override
@@ -609,4 +623,27 @@ private List<Integer> getCRLFLocations(String source) {
609623

610624
return cRLFIndices;
611625
}
626+
627+
static class SourcePathFromSourceTextResolver {
628+
private static final Pattern packagePattern = Pattern.compile("^package\\s+(\\S+)");
629+
private static final Pattern classPattern = Pattern.compile("(class|interface|enum class)\\s*(<[^>]*>)?\\s+(\\w+)");
630+
private static final Pattern publicClassPattern = Pattern.compile("public\\s+" + classPattern.pattern());
631+
632+
private static Optional<String> matchClassPattern(Pattern pattern, String source) {
633+
Matcher classMatcher = pattern.matcher(source);
634+
if (classMatcher.find()) {
635+
return Optional.of(classMatcher.group(3));
636+
}
637+
return Optional.empty();
638+
}
639+
640+
static Path determinePath(String prefix, String sourceCode) {
641+
String className = matchClassPattern(publicClassPattern, sourceCode)
642+
.orElseGet(() -> matchClassPattern(classPattern, sourceCode)
643+
.orElse(Long.toString(System.nanoTime())));
644+
Matcher packageMatcher = packagePattern.matcher(sourceCode);
645+
String pkg = packageMatcher.find() ? packageMatcher.group(1).replace('.', '/') + "/" : "";
646+
return Paths.get(pkg, prefix + className + ".kt");
647+
}
648+
}
612649
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2023 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.kotlin;
17+
18+
import org.junit.jupiter.api.Test;
19+
import org.openrewrite.test.RewriteTest;
20+
21+
import static org.openrewrite.kotlin.Assertions.kotlin;
22+
23+
class KotlinParserTest implements RewriteTest {
24+
25+
@Test
26+
void classDefinitionFromDependsOn() {
27+
rewriteRun(
28+
spec -> spec.parser(KotlinParser.builder().dependsOn("""
29+
package foo.bar
30+
31+
class MyClass
32+
""")),
33+
kotlin(
34+
"""
35+
import foo.bar.MyClass
36+
37+
val myClass: MyClass? = null
38+
"""
39+
)
40+
);
41+
}
42+
43+
}

0 commit comments

Comments
 (0)