[Test] Move java generation utils to :compiler:tests-compiler-utils module
This commit is contained in:
committed by
TeamCityServer
parent
cb7b1652e7
commit
8689fc43cd
@@ -22,6 +22,7 @@ dependencies {
|
||||
testCompile(project(":compiler:cli"))
|
||||
testCompile(project(":compiler:cli-js"))
|
||||
testCompile(project(":compiler:serialization"))
|
||||
testCompile(project(":compiler:fir:entrypoint"))
|
||||
testCompile(projectTests(":compiler:test-infrastructure-utils"))
|
||||
testCompile(project(":kotlin-preloader"))
|
||||
testCompileOnly(intellijCoreDep()) { includeJars("intellij-core") }
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import java.io.PrintStream
|
||||
import java.io.PrintWriter
|
||||
|
||||
enum class TestsExceptionType(val postfix: String) {
|
||||
COMPILER_ERROR("compiler"),
|
||||
COMPILETIME_ERROR("compiletime"),
|
||||
RUNTIME_ERROR("runtime"),
|
||||
INFRASTRUCTURE_ERROR("infrastructure");
|
||||
|
||||
companion object {
|
||||
private val map = values().associateBy(TestsExceptionType::postfix)
|
||||
|
||||
fun fromValue(type: String) = map[type]
|
||||
}
|
||||
}
|
||||
|
||||
sealed class TestsError(val original: Throwable, val type: TestsExceptionType) : Error() {
|
||||
override fun toString(): String = original.toString()
|
||||
override fun getStackTrace(): Array<out StackTraceElement> = original.stackTrace
|
||||
override fun initCause(cause: Throwable?): Throwable = original.initCause(cause)
|
||||
override val cause: Throwable? get() = original.cause
|
||||
|
||||
// This function is called in the constructor of Throwable, where original is not yet initialized
|
||||
override fun fillInStackTrace(): Throwable? = @Suppress("UNNECESSARY_SAFE_CALL") original?.fillInStackTrace()
|
||||
|
||||
override fun setStackTrace(stackTrace: Array<out StackTraceElement>?) {
|
||||
original.stackTrace = stackTrace
|
||||
}
|
||||
|
||||
override fun printStackTrace() = original.printStackTrace()
|
||||
override fun printStackTrace(s: PrintStream?) = original.printStackTrace(s)
|
||||
override fun printStackTrace(s: PrintWriter?) = original.printStackTrace(s)
|
||||
}
|
||||
|
||||
class TestsCompilerError(original: Throwable) : TestsError(original, TestsExceptionType.COMPILER_ERROR)
|
||||
class TestsInfrastructureError(original: Throwable) : TestsError(original, TestsExceptionType.INFRASTRUCTURE_ERROR)
|
||||
class TestsCompiletimeError(original: Throwable) : TestsError(original, TestsExceptionType.COMPILETIME_ERROR)
|
||||
class TestsRuntimeError(original: Throwable) : TestsError(original, TestsExceptionType.RUNTIME_ERROR)
|
||||
+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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.fir
|
||||
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
|
||||
|
||||
class FirTestModuleInfo(
|
||||
override val name: Name = Name.identifier("TestModule"),
|
||||
val dependencies: MutableList<ModuleInfo> = mutableListOf(),
|
||||
override val platform: TargetPlatform = JvmPlatforms.unspecifiedJvmPlatform,
|
||||
override val analyzerServices: PlatformDependentAnalyzerServices = JvmPlatformAnalyzerServices
|
||||
) : ModuleInfo {
|
||||
override fun dependencies(): List<ModuleInfo> = dependencies
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.fir
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
|
||||
import org.jetbrains.kotlin.fir.session.FirSessionFactory
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
fun createSession(
|
||||
environment: KotlinCoreEnvironment,
|
||||
sourceScope: GlobalSearchScope,
|
||||
librariesScope: GlobalSearchScope = GlobalSearchScope.notScope(sourceScope),
|
||||
moduleName: String = "TestModule"
|
||||
): FirSession = createSession(environment.project, sourceScope, librariesScope, moduleName, environment::createPackagePartProvider)
|
||||
|
||||
fun createSession(
|
||||
project: Project,
|
||||
sourceScope: GlobalSearchScope,
|
||||
librariesScope: GlobalSearchScope,
|
||||
moduleName: String = "TestModule",
|
||||
packagePartProvider: (GlobalSearchScope) -> PackagePartProvider
|
||||
): FirSession {
|
||||
val moduleInfo = FirTestModuleInfo(name = Name.identifier(moduleName))
|
||||
val provider = FirProjectSessionProvider()
|
||||
return FirSessionFactory.createJavaModuleBasedSession(moduleInfo, provider, sourceScope, project).also {
|
||||
createSessionForDependencies(project, provider, moduleInfo, librariesScope, packagePartProvider)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSessionForDependencies(
|
||||
project: Project,
|
||||
provider: FirProjectSessionProvider,
|
||||
moduleInfo: FirTestModuleInfo,
|
||||
librariesScope: GlobalSearchScope,
|
||||
packagePartProvider: (GlobalSearchScope) -> PackagePartProvider
|
||||
) {
|
||||
val dependenciesInfo = FirTestModuleInfo(name = Name.identifier(moduleInfo.name.identifier + ".dependencies"))
|
||||
moduleInfo.dependencies.add(dependenciesInfo)
|
||||
FirSessionFactory.createLibrarySession(
|
||||
dependenciesInfo, provider, librariesScope, project, packagePartProvider(librariesScope)
|
||||
)
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.resolve.lazy
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.TestsCompiletimeError
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.CliBindingTrace
|
||||
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.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.container.ComponentProvider
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
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.TargetEnvironment
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
||||
|
||||
object JvmResolveUtil {
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun createContainer(
|
||||
environment: KotlinCoreEnvironment,
|
||||
files: Collection<KtFile> = emptyList(),
|
||||
targetEnvironment: TargetEnvironment = CompilerEnvironment
|
||||
): ComponentProvider =
|
||||
TopDownAnalyzerFacadeForJVM.createContainer(
|
||||
environment.project, files, NoScopeRecordCliBindingTrace(),
|
||||
environment.configuration, { PackagePartProvider.Empty }, ::FileBasedDeclarationProviderFactory,
|
||||
targetEnvironment
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
fun analyzeAndCheckForErrors(file: KtFile, environment: KotlinCoreEnvironment): AnalysisResult =
|
||||
analyzeAndCheckForErrors(setOf(file), environment)
|
||||
|
||||
@JvmStatic
|
||||
fun analyzeAndCheckForErrors(files: Collection<KtFile>, environment: KotlinCoreEnvironment): AnalysisResult =
|
||||
analyzeAndCheckForErrors(environment.project, files, environment.configuration, environment::createPackagePartProvider)
|
||||
|
||||
@JvmStatic
|
||||
fun analyzeAndCheckForErrors(
|
||||
project: Project,
|
||||
files: Collection<KtFile>,
|
||||
configuration: CompilerConfiguration,
|
||||
packagePartProvider: (GlobalSearchScope) -> PackagePartProvider,
|
||||
trace: BindingTrace = CliBindingTrace(),
|
||||
klibList: List<KotlinLibrary> = emptyList()
|
||||
): AnalysisResult {
|
||||
for (file in files) {
|
||||
try {
|
||||
AnalyzingUtils.checkForSyntacticErrors(file)
|
||||
} catch (e: Exception) {
|
||||
throw TestsCompiletimeError(e)
|
||||
}
|
||||
}
|
||||
|
||||
return analyze(project, files, configuration, packagePartProvider, trace, klibList).apply {
|
||||
try {
|
||||
AnalyzingUtils.throwExceptionOnErrors(bindingContext)
|
||||
} catch (e: Exception) {
|
||||
throw TestsCompiletimeError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun analyze(environment: KotlinCoreEnvironment): AnalysisResult =
|
||||
analyze(emptySet(), environment)
|
||||
|
||||
@JvmStatic
|
||||
fun analyze(file: KtFile, environment: KotlinCoreEnvironment): AnalysisResult =
|
||||
analyze(setOf(file), environment)
|
||||
|
||||
@JvmStatic
|
||||
fun analyze(files: Collection<KtFile>, environment: KotlinCoreEnvironment): AnalysisResult =
|
||||
analyze(files, environment, environment.configuration)
|
||||
|
||||
@JvmStatic
|
||||
fun analyze(files: Collection<KtFile>, environment: KotlinCoreEnvironment, configuration: CompilerConfiguration): AnalysisResult =
|
||||
analyze(environment.project, files, configuration, environment::createPackagePartProvider)
|
||||
|
||||
private fun analyze(
|
||||
project: Project,
|
||||
files: Collection<KtFile>,
|
||||
configuration: CompilerConfiguration,
|
||||
packagePartProviderFactory: (GlobalSearchScope) -> PackagePartProvider,
|
||||
trace: BindingTrace = CliBindingTrace(),
|
||||
klibList: List<KotlinLibrary> = emptyList()
|
||||
): AnalysisResult {
|
||||
return TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(
|
||||
project, files, trace, configuration, packagePartProviderFactory,
|
||||
klibList = klibList
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user