65
65
import org .jetbrains .kotlin .utils .PathUtil ;
66
66
import org .jspecify .annotations .Nullable ;
67
67
import org .openrewrite .*;
68
+ import org .openrewrite .internal .ListUtils ;
68
69
import org .openrewrite .java .JavaParser ;
69
70
import org .openrewrite .java .internal .JavaTypeCache ;
70
71
import org .openrewrite .java .marker .JavaSourceSet ;
87
88
import java .util .function .Function ;
88
89
import java .util .regex .Matcher ;
89
90
import java .util .regex .Pattern ;
90
- import java .util .stream .Collectors ;
91
91
import java .util .stream .Stream ;
92
92
93
93
import static java .util .Collections .emptyList ;
101
101
import static org .jetbrains .kotlin .config .JVMConfigurationKeys .DO_NOT_CLEAR_BINDING_CONTEXT ;
102
102
import static org .jetbrains .kotlin .config .JVMConfigurationKeys .LINK_VIA_SIGNATURES ;
103
103
import static org .jetbrains .kotlin .incremental .IncrementalFirJvmCompilerRunnerKt .configureBaseRoots ;
104
+ import static org .openrewrite .kotlin .KotlinParser .SourcePathFromSourceTextResolver .determinePath ;
104
105
105
106
@ SuppressWarnings ("CommentedOutCode" )
106
107
@ RequiredArgsConstructor (access = AccessLevel .PRIVATE )
@@ -115,6 +116,9 @@ public class KotlinParser implements Parser {
115
116
@ Nullable
116
117
private final Collection <Path > classpath ;
117
118
119
+ @ Nullable
120
+ private final List <Input > dependsOn ;
121
+
118
122
private final List <NamedStyles > styles ;
119
123
private final boolean logCompilationWarningsAndErrors ;
120
124
private final JavaTypeCache typeCache ;
@@ -162,10 +166,11 @@ public Stream<SourceFile> parseInputs(Iterable<Input> sources, @Nullable Path re
162
166
// TODO: FIR and disposable may not be necessary using the IR.
163
167
Disposable disposable = Disposer .newDisposable ();
164
168
CompiledSource compilerCus ;
169
+ List <Input > acceptedInputs = ListUtils .concatAll (dependsOn , acceptedInputs (sources ).collect (toList ()));
165
170
try {
166
- compilerCus = parse (acceptedInputs ( sources ). collect ( Collectors . toList ()) , disposable , pctx );
171
+ compilerCus = parse (acceptedInputs , disposable , pctx );
167
172
} 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 ));
169
174
}
170
175
171
176
FirSession firSession = compilerCus .getFirSession ();
@@ -201,7 +206,8 @@ public Stream<SourceFile> parseInputs(Iterable<Input> sources, @Nullable Path re
201
206
return (SourceFile ) null ;
202
207
})
203
208
.limit (1 ))
204
- .filter (Objects ::nonNull );
209
+ .filter (Objects ::nonNull )
210
+ .filter (source -> !source .getSourcePath ().getFileName ().toString ().startsWith ("dependsOn-" ));
205
211
}
206
212
207
213
@ Override
@@ -252,6 +258,7 @@ public static class Builder extends Parser.Builder {
252
258
@ Nullable
253
259
private Collection <Path > classpath = emptyList ();
254
260
261
+ private List <Input > dependsOn = emptyList ();
255
262
private JavaTypeCache typeCache = new JavaTypeCache ();
256
263
private boolean logCompilationWarningsAndErrors ;
257
264
private final List <NamedStyles > styles = new ArrayList <>();
@@ -303,6 +310,13 @@ public Builder addClasspathEntry(Path classpath) {
303
310
return this ;
304
311
}
305
312
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
+
306
320
public Builder typeCache (JavaTypeCache typeCache ) {
307
321
this .typeCache = typeCache ;
308
322
return this ;
@@ -335,7 +349,7 @@ public Builder languageLevel(KotlinLanguageLevel languageLevel) {
335
349
336
350
@ Override
337
351
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 );
339
353
}
340
354
341
355
@ Override
@@ -609,4 +623,27 @@ private List<Integer> getCRLFLocations(String source) {
609
623
610
624
return cRLFIndices ;
611
625
}
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
+ }
612
649
}
0 commit comments