[Test] Move java generation utils to :compiler:tests-compiler-utils module
This commit is contained in:
committed by
TeamCityServer
parent
cb7b1652e7
commit
8689fc43cd
+138
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.jetbrains.kotlin.codegen;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiErrorElement;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
import org.jetbrains.kotlin.resolve.AnalyzingUtils;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class CodegenTestFiles {
|
||||
|
||||
@NotNull
|
||||
private final List<KtFile> psiFiles;
|
||||
@NotNull
|
||||
private final List<Pair<String, String>> expectedValues;
|
||||
@NotNull
|
||||
private final List<Object> scriptParameterValues;
|
||||
|
||||
private CodegenTestFiles(
|
||||
@NotNull List<KtFile> psiFiles,
|
||||
@NotNull List<Pair<String, String>> expectedValues,
|
||||
@NotNull List<Object> scriptParameterValues
|
||||
) {
|
||||
this.psiFiles = psiFiles;
|
||||
this.expectedValues = expectedValues;
|
||||
this.scriptParameterValues = scriptParameterValues;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public KtFile getPsiFile() {
|
||||
assert psiFiles.size() == 1;
|
||||
return psiFiles.get(0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Pair<String, String>> getExpectedValues() {
|
||||
return expectedValues;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Object> getScriptParameterValues() {
|
||||
return scriptParameterValues;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<KtFile> getPsiFiles() {
|
||||
return psiFiles;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static CodegenTestFiles create(@NotNull List<KtFile> ktFiles) {
|
||||
assert !ktFiles.isEmpty() : "List should have at least one file";
|
||||
return new CodegenTestFiles(ktFiles, Collections.emptyList(), Collections.emptyList());
|
||||
}
|
||||
|
||||
public static CodegenTestFiles create(Project project, String[] names) {
|
||||
return create(project, names, KtTestUtil.getTestDataPathBase());
|
||||
}
|
||||
|
||||
public static CodegenTestFiles create(Project project, String[] names, String testDataPath) {
|
||||
List<KtFile> files = new ArrayList<>(names.length);
|
||||
for (String name : names) {
|
||||
try {
|
||||
String content = KtTestUtil.doLoadFile(testDataPath + "/codegen/", name);
|
||||
KtFile file = KtTestUtil.createFile(name, content, project);
|
||||
files.add(file);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return create(files);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static CodegenTestFiles create(@NotNull String fileName, @NotNull String contentWithDiagnosticMarkup, @NotNull Project project) {
|
||||
// `rangesToDiagnosticNames` parameter is not-null only for diagnostic tests, it's using for lazy diagnostics
|
||||
String content = CheckerTestUtil.INSTANCE.parseDiagnosedRanges(contentWithDiagnosticMarkup, new ArrayList<>(), null);
|
||||
KtFile file = KtTestUtil.createFile(fileName, content, project);
|
||||
List<PsiErrorElement> ranges = AnalyzingUtils.getSyntaxErrorRanges(file);
|
||||
assert ranges.isEmpty() : "Syntax errors found in " + file + ": " + ranges;
|
||||
|
||||
List<Pair<String, String>> expectedValues = Lists.newArrayList();
|
||||
|
||||
Matcher matcher = Pattern.compile("// expected: (\\S+): (.*)").matcher(content);
|
||||
while (matcher.find()) {
|
||||
String fieldName = matcher.group(1);
|
||||
String expectedValue = matcher.group(2);
|
||||
expectedValues.add(Pair.create(fieldName, expectedValue));
|
||||
}
|
||||
|
||||
List<Object> scriptParameterValues = Lists.newArrayList();
|
||||
|
||||
if (file.isScript()) {
|
||||
Pattern scriptParametersPattern = Pattern.compile("param: (\\S.*)");
|
||||
Matcher scriptParametersMatcher = scriptParametersPattern.matcher(file.getText());
|
||||
|
||||
if (scriptParametersMatcher.find()) {
|
||||
String valueString = scriptParametersMatcher.group(1);
|
||||
String[] values = valueString.split(" ");
|
||||
|
||||
scriptParameterValues.add(values);
|
||||
}
|
||||
else {
|
||||
scriptParameterValues.add(ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
}
|
||||
}
|
||||
|
||||
return new CodegenTestFiles(Collections.singletonList(file), expectedValues, scriptParameterValues);
|
||||
}
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.io.FilesKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
|
||||
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime;
|
||||
import org.jetbrains.kotlin.test.Assertions;
|
||||
import org.jetbrains.kotlin.test.JvmCompilationUtils;
|
||||
import org.jetbrains.kotlin.test.KtAssert;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
|
||||
import org.jetbrains.kotlin.utils.StringsKt;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class CodegenTestUtil {
|
||||
private CodegenTestUtil() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ClassFileFactory generateFiles(@NotNull KotlinCoreEnvironment environment, @NotNull CodegenTestFiles files) {
|
||||
return GenerationUtils.compileFiles(files.getPsiFiles(), environment).getFactory();
|
||||
}
|
||||
|
||||
public static void assertThrows(
|
||||
@NotNull Method foo, @NotNull Class<? extends Throwable> exceptionClass, @Nullable Object instance, @NotNull Object... args
|
||||
) throws IllegalAccessException {
|
||||
boolean caught = false;
|
||||
try {
|
||||
foo.invoke(instance, args);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
caught = exceptionClass.isInstance(ex.getTargetException());
|
||||
}
|
||||
KtAssert.assertTrue(String.format("Exception of class %s must be thrown", exceptionClass.getName()), caught);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Method findDeclaredMethodByName(@NotNull Class<?> aClass, @NotNull String name) {
|
||||
Method result = findDeclaredMethodByNameOrNull(aClass, name);
|
||||
if (result == null) {
|
||||
throw new AssertionError("Method " + name + " is not found in " + aClass);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Method findDeclaredMethodByNameOrNull(@NotNull Class<?> aClass, @NotNull String name) {
|
||||
for (Method method : aClass.getDeclaredMethods()) {
|
||||
if (method.getName().equals(name)) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File compileJava(
|
||||
@NotNull List<String> fileNames,
|
||||
@NotNull List<String> additionalClasspath,
|
||||
@NotNull List<String> additionalOptions,
|
||||
@NotNull Assertions assertions
|
||||
) {
|
||||
try {
|
||||
File directory = KtTestUtil.tmpDir("java-classes");
|
||||
compileJava(fileNames, additionalClasspath, additionalOptions, directory, assertions);
|
||||
return directory;
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw ExceptionUtilsKt.rethrow(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void compileJava(
|
||||
@NotNull List<String> fileNames,
|
||||
@NotNull List<String> additionalClasspath,
|
||||
@NotNull List<String> additionalOptions,
|
||||
@NotNull File outDirectory,
|
||||
@NotNull Assertions assertions
|
||||
) {
|
||||
try {
|
||||
List<String> options = prepareJavacOptions(additionalClasspath, additionalOptions, outDirectory);
|
||||
JvmCompilationUtils.compileJavaFiles(CollectionsKt.map(fileNames, File::new), options, assertions);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw ExceptionUtilsKt.rethrow(e);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<String> prepareJavacOptions(
|
||||
@NotNull List<String> additionalClasspath,
|
||||
@NotNull List<String> additionalOptions,
|
||||
@NotNull File outDirectory
|
||||
) {
|
||||
List<String> classpath = new ArrayList<>();
|
||||
classpath.add(ForTestCompileRuntime.runtimeJarForTests().getPath());
|
||||
classpath.add(ForTestCompileRuntime.reflectJarForTests().getPath());
|
||||
classpath.add(KtTestUtil.getAnnotationsJar().getPath());
|
||||
classpath.addAll(additionalClasspath);
|
||||
|
||||
List<String> options = new ArrayList<>(Arrays.asList(
|
||||
"-classpath", StringsKt.join(classpath, File.pathSeparator),
|
||||
"-d", outDirectory.getPath()
|
||||
));
|
||||
options.addAll(additionalOptions);
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public static Method findTheOnlyMethod(@NotNull Class<?> aClass) {
|
||||
Method r = null;
|
||||
for (Method method : aClass.getMethods()) {
|
||||
if (method.getDeclaringClass().equals(Object.class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r != null) {
|
||||
throw new AssertionError("More than one public method in class " + aClass);
|
||||
}
|
||||
|
||||
r = method;
|
||||
}
|
||||
if (r == null) {
|
||||
throw new AssertionError("No public methods in class " + aClass);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Object getAnnotationAttribute(@NotNull Object annotation, @NotNull String name) {
|
||||
try {
|
||||
return annotation.getClass().getMethod(name).invoke(annotation);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw ExceptionUtilsKt.rethrow(e);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<String> findJavaSourcesInDirectory(@NotNull File directory) {
|
||||
List<String> javaFilePaths = new ArrayList<>(1);
|
||||
|
||||
FileUtil.processFilesRecursively(directory, file -> {
|
||||
if (file.isFile() && FilesKt.getExtension(file).equals(JavaFileType.DEFAULT_EXTENSION)) {
|
||||
javaFilePaths.add(file.getPath());
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return javaFilePaths;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElementFinder
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.ProjectScope
|
||||
import org.jetbrains.kotlin.TestsCompiletimeError
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmGeneratorExtensions
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory
|
||||
import org.jetbrains.kotlin.backend.jvm.jvmPhases
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.output.writeAllTo
|
||||
import org.jetbrains.kotlin.cli.js.messageCollectorLogger
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.NoScopeRecordCliBindingTrace
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.container.get
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.fir.analysis.FirAnalyzerFacade
|
||||
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver
|
||||
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendExtension
|
||||
import org.jetbrains.kotlin.fir.createSession
|
||||
import org.jetbrains.kotlin.ir.backend.jvm.jvmResolveLibraries
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.AnalyzingUtils
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.CompilerEnvironment
|
||||
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.util.DummyLogger
|
||||
import java.io.File
|
||||
|
||||
object GenerationUtils {
|
||||
@JvmStatic
|
||||
fun compileFileTo(ktFile: KtFile, environment: KotlinCoreEnvironment, output: File): ClassFileFactory =
|
||||
compileFilesTo(listOf(ktFile), environment, output)
|
||||
|
||||
@JvmStatic
|
||||
fun compileFilesTo(files: List<KtFile>, environment: KotlinCoreEnvironment, output: File): ClassFileFactory =
|
||||
compileFiles(files, environment).factory.apply {
|
||||
writeAllTo(output)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun compileFiles(
|
||||
files: List<KtFile>,
|
||||
environment: KotlinCoreEnvironment,
|
||||
classBuilderFactory: ClassBuilderFactory = ClassBuilderFactories.TEST,
|
||||
trace: BindingTrace = NoScopeRecordCliBindingTrace()
|
||||
): GenerationState =
|
||||
compileFiles(files, environment.configuration, classBuilderFactory, environment::createPackagePartProvider, trace)
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun compileFiles(
|
||||
files: List<KtFile>,
|
||||
configuration: CompilerConfiguration,
|
||||
classBuilderFactory: ClassBuilderFactory,
|
||||
packagePartProvider: (GlobalSearchScope) -> PackagePartProvider,
|
||||
trace: BindingTrace = NoScopeRecordCliBindingTrace()
|
||||
): GenerationState {
|
||||
val project = files.first().project
|
||||
val state = if (configuration.getBoolean(CommonConfigurationKeys.USE_FIR)) {
|
||||
compileFilesUsingFrontendIR(project, files, configuration, classBuilderFactory, packagePartProvider, trace)
|
||||
} else {
|
||||
compileFilesUsingStandardMode(project, files, configuration, classBuilderFactory, packagePartProvider, trace)
|
||||
}
|
||||
|
||||
// For JVM-specific errors
|
||||
try {
|
||||
AnalyzingUtils.throwExceptionOnErrors(state.collectedExtraJvmDiagnostics)
|
||||
} catch (e: Throwable) {
|
||||
throw TestsCompiletimeError(e)
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
private fun compileFilesUsingFrontendIR(
|
||||
project: Project,
|
||||
files: List<KtFile>,
|
||||
configuration: CompilerConfiguration,
|
||||
classBuilderFactory: ClassBuilderFactory,
|
||||
packagePartProvider: (GlobalSearchScope) -> PackagePartProvider,
|
||||
trace: BindingTrace
|
||||
): GenerationState {
|
||||
PsiElementFinder.EP.getPoint(project).unregisterExtension(JavaElementFinder::class.java)
|
||||
|
||||
val scope = GlobalSearchScope.filesScope(project, files.map { it.virtualFile })
|
||||
.uniteWith(TopDownAnalyzerFacadeForJVM.AllJavaSourcesInProjectScope(project))
|
||||
val librariesScope = ProjectScope.getLibrariesScope(project)
|
||||
val session = createSession(project, scope, librariesScope, "main", packagePartProvider)
|
||||
|
||||
// TODO: add running checkers and check that it's safe to compile
|
||||
val firAnalyzerFacade = FirAnalyzerFacade(session, configuration.languageVersionSettings, files)
|
||||
val extensions = JvmGeneratorExtensions()
|
||||
val (moduleFragment, symbolTable, sourceManager, components) = firAnalyzerFacade.convertToIr(extensions)
|
||||
val dummyBindingContext = NoScopeRecordCliBindingTrace().bindingContext
|
||||
|
||||
val codegenFactory = JvmIrCodegenFactory(configuration.get(CLIConfigurationKeys.PHASE_CONFIG) ?: PhaseConfig(jvmPhases))
|
||||
|
||||
// Create and initialize the test module and its dependencies
|
||||
val container = TopDownAnalyzerFacadeForJVM.createContainer(
|
||||
project, files, trace, configuration, packagePartProvider, ::FileBasedDeclarationProviderFactory, CompilerEnvironment,
|
||||
TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, files), emptyList()
|
||||
)
|
||||
val generationState = GenerationState.Builder(
|
||||
project, classBuilderFactory, container.get<ModuleDescriptor>(), dummyBindingContext, files, configuration
|
||||
).codegenFactory(
|
||||
codegenFactory
|
||||
).isIrBackend(
|
||||
true
|
||||
).jvmBackendClassResolver(
|
||||
FirJvmBackendClassResolver(components)
|
||||
).build()
|
||||
|
||||
generationState.beforeCompile()
|
||||
codegenFactory.generateModuleInFrontendIRMode(
|
||||
generationState, moduleFragment, symbolTable, sourceManager, extensions, FirJvmBackendExtension(session, components),
|
||||
)
|
||||
|
||||
generationState.factory.done()
|
||||
return generationState
|
||||
}
|
||||
|
||||
private fun compileFilesUsingStandardMode(
|
||||
project: Project,
|
||||
files: List<KtFile>,
|
||||
configuration: CompilerConfiguration,
|
||||
classBuilderFactory: ClassBuilderFactory,
|
||||
packagePartProvider: (GlobalSearchScope) -> PackagePartProvider,
|
||||
trace: BindingTrace
|
||||
): GenerationState {
|
||||
val logger = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)?.let { messageCollectorLogger(it) }
|
||||
?: DummyLogger
|
||||
val resolvedKlibs = configuration.get(JVMConfigurationKeys.KLIB_PATHS)?.let { klibPaths ->
|
||||
jvmResolveLibraries(klibPaths, logger)
|
||||
}
|
||||
|
||||
val analysisResult =
|
||||
JvmResolveUtil.analyzeAndCheckForErrors(
|
||||
project, files, configuration, packagePartProvider, trace,
|
||||
klibList = resolvedKlibs?.getFullList() ?: emptyList()
|
||||
)
|
||||
analysisResult.throwIfError()
|
||||
|
||||
return generateFiles(project, files, configuration, classBuilderFactory, analysisResult)
|
||||
}
|
||||
|
||||
fun generateFiles(
|
||||
project: Project,
|
||||
files: List<KtFile>,
|
||||
configuration: CompilerConfiguration,
|
||||
classBuilderFactory: ClassBuilderFactory,
|
||||
analysisResult: AnalysisResult,
|
||||
configureGenerationState: GenerationState.Builder.() -> Unit = {},
|
||||
): GenerationState {
|
||||
/* Currently Kapt3 only works with the old JVM backend, so disable IR for everything except actual bytecode generation. */
|
||||
val isIrBackend =
|
||||
classBuilderFactory.classBuilderMode == ClassBuilderMode.FULL && configuration.getBoolean(JVMConfigurationKeys.IR)
|
||||
val generationState = GenerationState.Builder(
|
||||
project, classBuilderFactory, analysisResult.moduleDescriptor, analysisResult.bindingContext,
|
||||
files, configuration
|
||||
).codegenFactory(
|
||||
if (isIrBackend)
|
||||
JvmIrCodegenFactory(configuration.get(CLIConfigurationKeys.PHASE_CONFIG) ?: PhaseConfig(jvmPhases))
|
||||
else DefaultCodegenFactory
|
||||
).isIrBackend(isIrBackend).apply(configureGenerationState).build()
|
||||
if (analysisResult.shouldGenerateCode) {
|
||||
KotlinCodegenFacade.compileCorrectFiles(generationState)
|
||||
}
|
||||
return generationState
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user