diff --git a/.idea/misc.xml b/.idea/misc.xml
index 8f4e3ebc3de..b6513e71f2e 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -52,7 +52,13 @@
-
+
diff --git a/.idea/runConfigurations/Generate_Tests.xml b/.idea/runConfigurations/Generate_Tests.xml
new file mode 100644
index 00000000000..2e6cf6fc804
--- /dev/null
+++ b/.idea/runConfigurations/Generate_Tests.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/tools.protobuf.xml b/.idea/tools.protobuf.xml
new file mode 100644
index 00000000000..c42da106537
--- /dev/null
+++ b/.idea/tools.protobuf.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReadMe.md b/ReadMe.md
index 08d1c6d58a0..1283f41ba67 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -1,6 +1,6 @@
[](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
-[](https://teamcity.jetbrains.com/viewType.html?buildTypeId=bt345&branch_Kotlin=%3Cdefault%3E&tab=buildTypeStatusDiv)
+[](https://teamcity.jetbrains.com/viewType.html?buildTypeId=Kotlin_dev_Compiler&branch_Kotlin_dev=%3Cdefault%3E&tab=buildTypeStatusDiv)
[](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.jetbrains.kotlin%22)
[](http://www.apache.org/licenses/LICENSE-2.0)
@@ -40,6 +40,8 @@ In order to build Kotlin distribution you need to have:
For local development, if you're not working on bytecode generation or the standard library, it's OK to have only JDK 8 installed, and to point all of the environment variables mentioned above to your JDK 8 installation.
+You also can use [Gradle properties](https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_properties_and_system_properties) to setup JDK_* variables.
+
> Note: The JDK 6 for MacOS is not available on Oracle's site. You can [download it here](https://support.apple.com/kb/DL1572).
## Building
@@ -85,8 +87,6 @@ Refer to [libraries/ReadMe.md](libraries/ReadMe.md) for details.
Working with the Kotlin project requires IntelliJ IDEA 2017.3. You can download an Early Access Preview version of IntelliJ IDEA 2017.3 [here](https://www.jetbrains.com/idea/nextversion/).
-The [root Kotlin project](https://github.com/JetBrains/kotlin) should be imported into IDEA as gradle project.
-
To import the project in Intellij choose project directory in Open project dialog. Then, after project opened, Select
`File` -> `New...` -> `Module from Existing Sources` in the menu, and select `build.gradle.kts` file in the project's root folder.
@@ -127,6 +127,11 @@ Also the [JavaScript translation](https://github.com/JetBrains/kotlin/blob/maste
Some of the code in the standard library is created by generating code from templates. See the [README](libraries/stdlib/ReadMe.md) in the stdlib section for how run the code generator. The existing templates can be used as examples for creating new ones.
+### Running specific generated tests
+
+If you need to debug a specific generated test, ensure that you have the `Working directory` in your IntelliJ run configuration set
+to the root directory of this project. If you don't, every test you try to run will fail with a `No such file or directory` exception.
+
## Submitting patches
The best way to submit a patch is to [fork the project on github](https://help.github.com/articles/fork-a-repo/) then send us a
diff --git a/build-common/build.gradle.kts b/build-common/build.gradle.kts
index 44cf00a7674..43ccbff7f5e 100644
--- a/build-common/build.gradle.kts
+++ b/build-common/build.gradle.kts
@@ -24,6 +24,8 @@ sourceSets {
}
runtimeJar()
+sourcesJar()
+javadocJar()
testsJar()
diff --git a/build-common/test/org/jetbrains/kotlin/serialization/js/ast/DebugJsAstProtoBuf.java b/build-common/test/org/jetbrains/kotlin/serialization/js/ast/DebugJsAstProtoBuf.java
index 5ee90c76468..8f32bf61ac4 100644
--- a/build-common/test/org/jetbrains/kotlin/serialization/js/ast/DebugJsAstProtoBuf.java
+++ b/build-common/test/org/jetbrains/kotlin/serialization/js/ast/DebugJsAstProtoBuf.java
@@ -211,6 +211,22 @@ public final class DebugJsAstProtoBuf {
* UNBOX_CHAR = 4;
*/
UNBOX_CHAR(3, 4),
+ /**
+ * SUSPEND_CALL = 5;
+ */
+ SUSPEND_CALL(4, 5),
+ /**
+ * COROUTINE_RESULT = 6;
+ */
+ COROUTINE_RESULT(5, 6),
+ /**
+ * COROUTINE_CONTROLLER = 7;
+ */
+ COROUTINE_CONTROLLER(6, 7),
+ /**
+ * COROUTINE_RECEIVER = 8;
+ */
+ COROUTINE_RECEIVER(7, 8),
;
/**
@@ -229,6 +245,22 @@ public final class DebugJsAstProtoBuf {
* UNBOX_CHAR = 4;
*/
public static final int UNBOX_CHAR_VALUE = 4;
+ /**
+ * SUSPEND_CALL = 5;
+ */
+ public static final int SUSPEND_CALL_VALUE = 5;
+ /**
+ * COROUTINE_RESULT = 6;
+ */
+ public static final int COROUTINE_RESULT_VALUE = 6;
+ /**
+ * COROUTINE_CONTROLLER = 7;
+ */
+ public static final int COROUTINE_CONTROLLER_VALUE = 7;
+ /**
+ * COROUTINE_RECEIVER = 8;
+ */
+ public static final int COROUTINE_RECEIVER_VALUE = 8;
public final int getNumber() { return value; }
@@ -239,6 +271,10 @@ public final class DebugJsAstProtoBuf {
case 2: return WRAP_FUNCTION;
case 3: return TO_BOXED_CHAR;
case 4: return UNBOX_CHAR;
+ case 5: return SUSPEND_CALL;
+ case 6: return COROUTINE_RESULT;
+ case 7: return COROUTINE_CONTROLLER;
+ case 8: return COROUTINE_RECEIVER;
default: return null;
}
}
@@ -49361,10 +49397,12 @@ public final class DebugJsAstProtoBuf {
"t.Fragment*@\n\013SideEffects\022\021\n\rAFFECTS_STA" +
"TE\020\001\022\024\n\020DEPENDS_ON_STATE\020\002\022\010\n\004PURE\020\003*?\n\016" +
"InlineStrategy\022\017\n\013AS_FUNCTION\020\000\022\014\n\010IN_PL" +
- "ACE\020\001\022\016\n\nNOT_INLINE\020\002*c\n\017SpecialFunction" +
- "\022\032\n\026DEFINE_INLINE_FUNCTION\020\001\022\021\n\rWRAP_FUN" +
- "CTION\020\002\022\021\n\rTO_BOXED_CHAR\020\003\022\016\n\nUNBOX_CHAR" +
- "\020\004B\024B\022DebugJsAstProtoBuf"
+ "ACE\020\001\022\016\n\nNOT_INLINE\020\002*\275\001\n\017SpecialFunctio" +
+ "n\022\032\n\026DEFINE_INLINE_FUNCTION\020\001\022\021\n\rWRAP_FU" +
+ "NCTION\020\002\022\021\n\rTO_BOXED_CHAR\020\003\022\016\n\nUNBOX_CHA" +
+ "R\020\004\022\020\n\014SUSPEND_CALL\020\005\022\024\n\020COROUTINE_RESUL" +
+ "T\020\006\022\030\n\024COROUTINE_CONTROLLER\020\007\022\026\n\022COROUTI" +
+ "NE_RECEIVER\020\010B\024B\022DebugJsAstProtoBuf"
};
org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
diff --git a/build.gradle.kts b/build.gradle.kts
index 920d9dd71df..592dc6498cd 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -6,11 +6,11 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
buildscript {
- val repos = listOf(
+ val repos = listOfNotNull(
System.getProperty("bootstrap.kotlin.repo"),
"https://repo.gradle.org/gradle/repo",
"https://plugins.gradle.org/m2",
- "http://repository.jetbrains.com/utils/").filterNotNull()
+ "http://repository.jetbrains.com/utils/")
extra["bootstrapKotlinVersion"] = bootstrapKotlinVersion
@@ -105,7 +105,6 @@ extra["JDK_9"] = jdkPathIfFound("9")
extra["versions.protobuf-java"] = "2.6.1"
extra["versions.javax.inject"] = "1"
extra["versions.jsr305"] = "1.3.9"
-extra["versions.cli-parser"] = "1.1.2"
extra["versions.jansi"] = "1.16"
extra["versions.jline"] = "3.3.1"
extra["versions.junit"] = "4.12"
diff --git a/buildSrc/src/main/kotlin/instrument.kt b/buildSrc/src/main/kotlin/instrument.kt
new file mode 100644
index 00000000000..31a5408f5c5
--- /dev/null
+++ b/buildSrc/src/main/kotlin/instrument.kt
@@ -0,0 +1,170 @@
+@file:Suppress("unused") // usages in build scripts are not tracked properly
+
+/*
+ * 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.
+ */
+
+import org.gradle.api.Project
+import org.gradle.api.artifacts.ProjectDependency
+import org.gradle.api.file.ConfigurableFileCollection
+import org.gradle.api.file.FileCollection
+import org.gradle.api.internal.ConventionTask
+import org.gradle.api.plugins.ExtensionAware
+import org.gradle.api.plugins.JavaPluginConvention
+import org.gradle.api.tasks.*
+import org.gradle.api.tasks.compile.AbstractCompile
+import org.gradle.kotlin.dsl.*
+import java.io.File
+
+fun Project.configureInstrumentation() {
+ plugins.matching { it::class.java.canonicalName.startsWith("org.jetbrains.kotlin.gradle.plugin") }.all {
+ // When we change the output classes directory, Gradle will automatically configure
+ // the test compile tasks to use the instrumented classes. Normally this is fine,
+ // however, it causes problems for Kotlin projects:
+
+ // The "internal" modifier can be used to restrict access to the same module.
+ // To make it possible to use internal methods from the main source set in test classes,
+ // the Kotlin Gradle plugin adds the original output directory of the Java task
+ // as "friendly directory" which makes it possible to access internal members
+ // of the main module. Also this directory should be available on classpath during compilation
+
+ // This fails when we change the classes dir. The easiest fix is to prepend the
+ // classes from the "friendly directory" to the compile classpath.
+ val testCompile = tasks.findByName("compileTestKotlin") as AbstractCompile?
+ testCompile?.doFirst {
+ val mainSourceSet = the().sourceSets.getByName("main")
+ testCompile.classpath = (testCompile.classpath
+ - mainSourceSet.output.classesDirs
+ + files((mainSourceSet as ExtensionAware).extra.get("classesDirsCopy")))
+ }
+ }
+
+ afterEvaluate {
+ the().sourceSets.all { sourceSetParam ->
+ // This copy will ignore filters, but they are unlikely to be used.
+ val classesDirs = (sourceSetParam.output.classesDirs as ConfigurableFileCollection).from as Collection
+
+ val classesDirsCopy = project.files(classesDirs.toTypedArray()).filter { it.exists() }
+ (sourceSetParam as ExtensionAware).extra.set("classesDirsCopy", classesDirsCopy)
+
+ logger.info("Saving old sources dir for project ${project.name}")
+ val instrumentedClassesDir = File(project.buildDir, "classes/${sourceSetParam.name}-instrumented")
+ (sourceSetParam.output.classesDirs as ConfigurableFileCollection).setFrom(instrumentedClassesDir)
+ val instrumentTask = project.tasks.create(sourceSetParam.getTaskName("instrument", "classes"), IntelliJInstrumentCodeTask::class.java)
+ instrumentTask.apply {
+ dependsOn(sourceSetParam.classesTaskName).onlyIf { !classesDirsCopy.isEmpty }
+ sourceSet = sourceSetParam
+ originalClassesDirs = classesDirsCopy
+ output = instrumentedClassesDir
+ }
+
+ instrumentTask.outputs.dir(instrumentedClassesDir)
+ // Ensure that our task is invoked when the source set is built
+ sourceSetParam.compiledBy(instrumentTask)
+ @Suppress("UNUSED_EXPRESSION")
+ true
+ }
+ }
+}
+
+@CacheableTask
+open class IntelliJInstrumentCodeTask : ConventionTask() {
+ companion object {
+ private const val FILTER_ANNOTATION_REGEXP_CLASS = "com.intellij.ant.ClassFilterAnnotationRegexp"
+ private const val LOADER_REF = "java2.loader"
+ }
+
+ var sourceSet: SourceSet? = null
+
+ @Input
+ var originalClassesDirs: FileCollection? = null
+
+ @get:InputFiles
+ val sourceDirs: FileCollection
+ get() = project.files(sourceSet!!.allSource.srcDirs.filter { !sourceSet!!.resources.contains(it) && it.exists() })
+
+ @get:OutputDirectory
+ var output: File? = null
+
+ @TaskAction
+ fun instrumentClasses() {
+ logger.info("input files are: ${originalClassesDirs?.joinToString("; ", transform = { "'${it.name}'${if (it.exists()) "" else " (does not exists)" }"})}")
+ copyOriginalClasses()
+
+ val classpath = project.ideaSdkDeps("javac2.jar", "jdom.jar", "asm-all.jar", "jgoodies-forms.jar")
+
+ ant.withGroovyBuilder {
+ "taskdef"("name" to "instrumentIdeaExtensions",
+ "classpath" to classpath.asPath,
+ "loaderref" to LOADER_REF,
+ "classname" to "com.intellij.ant.InstrumentIdeaExtensions")
+ }
+
+ logger.info("Compiling forms and instrumenting code with nullability preconditions")
+ val instrumentNotNull = prepareNotNullInstrumenting(classpath)
+ instrumentCode(sourceDirs, instrumentNotNull)
+ }
+
+ private fun copyOriginalClasses() {
+ project.copy {
+ from(originalClassesDirs)
+ into(output)
+ }
+ }
+
+ private fun prepareNotNullInstrumenting(classpath: ConfigurableFileCollection): Boolean {
+ ant.withGroovyBuilder {
+ "typedef"("name" to "skip",
+ "classpath" to classpath.asPath,
+ "loaderref" to LOADER_REF,
+ "classname" to FILTER_ANNOTATION_REGEXP_CLASS)
+ }
+ return true
+ }
+
+ private fun instrumentCode(srcDirs: FileCollection, instrumentNotNull: Boolean) {
+ val headlessOldValue = System.setProperty("java.awt.headless", "true")
+
+ // Instrumentation needs to have access to sources of forms for inclusion
+ val depSourceDirectorySets = project.configurations["compile"].dependencies.withType(ProjectDependency::class.java)
+ .map { p -> p.dependencyProject.the().sourceSets.getByName("main").allSource.sourceDirectories }
+ val instrumentationClasspath =
+ depSourceDirectorySets.fold(sourceSet!!.compileClasspath) { acc, v -> acc + v }.asPath.also {
+ logger.info("Using following dependency source dirs: $it")
+ }
+
+ logger.info("Running instrumentIdeaExtensions with srcdir=${srcDirs.asPath}}, destdir=$output and classpath=$instrumentationClasspath")
+
+ ant.withGroovyBuilder {
+ "instrumentIdeaExtensions"("srcdir" to srcDirs.asPath,
+ "destdir" to output,
+ "classpath" to instrumentationClasspath,
+ "includeantruntime" to false,
+ "instrumentNotNull" to instrumentNotNull) {
+ if (instrumentNotNull) {
+ ant.withGroovyBuilder {
+ "skip"("pattern" to "kotlin/Metadata")
+ }
+ }
+ }
+ }
+
+ if (headlessOldValue != null) {
+ System.setProperty("java.awt.headless", headlessOldValue)
+ } else {
+ System.clearProperty("java.awt.headless")
+ }
+ }
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/jdksFinder.kt b/buildSrc/src/main/kotlin/jdksFinder.kt
index d8677660167..ae4607a1a2d 100644
--- a/buildSrc/src/main/kotlin/jdksFinder.kt
+++ b/buildSrc/src/main/kotlin/jdksFinder.kt
@@ -19,7 +19,8 @@ data class JdkId(val explicit: Boolean, val majorVersion: JdkMajorVersion, var v
fun Project.getConfiguredJdks(): List {
val res = arrayListOf()
for (jdkMajorVersion in JdkMajorVersion.values()) {
- val explicitJdkEnvVal = System.getenv(jdkMajorVersion.name)
+ val explicitJdkEnvVal = findProperty(jdkMajorVersion.name)?.toString()
+ ?: System.getenv(jdkMajorVersion.name)
?: jdkAlternativeVarNames[jdkMajorVersion]?.mapNotNull { System.getenv(it) }?.firstOrNull()
?: continue
val explicitJdk = File(explicitJdkEnvVal)
diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/CodegenUtil.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/CodegenUtil.kt
index 576c587717f..f2a99c572b7 100644
--- a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/CodegenUtil.kt
+++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/CodegenUtil.kt
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
@@ -161,4 +162,8 @@ object CodegenUtil {
(1..arity).joinToString(prefix = "callableReferenceFakeCall(", separator = ", ", postfix = ")") { "p$it" }
return KtPsiFactory(project, markGenerated = false).createExpression(fakeFunctionCall) as KtCallExpression
}
+
+ @JvmStatic
+ fun getActualDeclarations(file: KtFile): List =
+ file.declarations.filterNot(KtDeclaration::hasExpectModifier)
}
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java
index 840793fe7cb..40af774d941 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java
@@ -103,9 +103,7 @@ import java.util.*;
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isInt;
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
-import static org.jetbrains.kotlin.codegen.CodegenUtilKt.extractReificationArgument;
-import static org.jetbrains.kotlin.codegen.CodegenUtilKt.isPossiblyUninitializedSingleton;
-import static org.jetbrains.kotlin.codegen.CodegenUtilKt.unwrapInitialSignatureDescriptor;
+import static org.jetbrains.kotlin.codegen.CodegenUtilKt.*;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.*;
@@ -1611,7 +1609,7 @@ public class ExpressionCodegen extends KtVisitor impleme
return null;
}
- public void returnExpression(KtExpression expr) {
+ public void returnExpression(@NotNull KtExpression expr) {
boolean isBlockedNamedFunction = expr instanceof KtBlockExpression && expr.getParent() instanceof KtNamedFunction;
FunctionDescriptor originalSuspendLambdaDescriptor = getOriginalSuspendLambdaDescriptorFromContext(context);
@@ -1644,7 +1642,7 @@ public class ExpressionCodegen extends KtVisitor impleme
}
}
- private static boolean endsWithReturn(KtElement bodyExpression) {
+ private static boolean endsWithReturn(@NotNull KtElement bodyExpression) {
if (bodyExpression instanceof KtBlockExpression) {
List statements = ((KtBlockExpression) bodyExpression).getStatements();
return statements.size() > 0 && statements.get(statements.size() - 1) instanceof KtReturnExpression;
@@ -1653,7 +1651,7 @@ public class ExpressionCodegen extends KtVisitor impleme
return bodyExpression instanceof KtReturnExpression;
}
- private static boolean isLambdaVoidBody(KtElement bodyExpression, Type returnType) {
+ private static boolean isLambdaVoidBody(@NotNull KtElement bodyExpression, @NotNull Type returnType) {
if (bodyExpression instanceof KtBlockExpression) {
PsiElement parent = bodyExpression.getParent();
if (parent instanceof KtFunctionLiteral) {
@@ -2658,6 +2656,15 @@ public class ExpressionCodegen extends KtVisitor impleme
return cur;
}
+ private boolean canSkipArrayCopyForSpreadArgument(KtExpression spreadArgument) {
+ ResolvedCall extends CallableDescriptor> resolvedCall = CallUtilKt.getResolvedCall(spreadArgument, bindingContext);
+ if (resolvedCall == null) return false;
+
+ CallableDescriptor calleeDescriptor = resolvedCall.getResultingDescriptor();
+ return (calleeDescriptor instanceof ConstructorDescriptor) ||
+ CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall) ||
+ (DescriptorUtils.getFqName(calleeDescriptor).asString().equals("kotlin.arrayOfNulls"));
+ }
@NotNull
public StackValue genVarargs(@NotNull VarargValueArgument valueArgument, @NotNull KotlinType outType) {
@@ -2680,10 +2687,13 @@ public class ExpressionCodegen extends KtVisitor impleme
if (size == 1) {
Type arrayType = getArrayType(arrayOfReferences ? AsmTypes.OBJECT_TYPE : elementType);
return StackValue.operation(type, adapter -> {
- gen(arguments.get(0).getArgumentExpression(), type);
- v.dup();
- v.arraylength();
- v.invokestatic("java/util/Arrays", "copyOf", Type.getMethodDescriptor(arrayType, arrayType, Type.INT_TYPE), false);
+ KtExpression spreadArgument = arguments.get(0).getArgumentExpression();
+ gen(spreadArgument, type);
+ if (!canSkipArrayCopyForSpreadArgument(spreadArgument)) {
+ v.dup();
+ v.arraylength();
+ v.invokestatic("java/util/Arrays", "copyOf", Type.getMethodDescriptor(arrayType, arrayType, Type.INT_TYPE), false);
+ }
if (arrayOfReferences) {
v.checkcast(type);
}
@@ -3904,7 +3914,9 @@ public class ExpressionCodegen extends KtVisitor impleme
boolean isGetter = OperatorNameConventions.GET.equals(operationDescriptor.getName());
- Callable callable = resolveToCallable(operationDescriptor, false, isGetter ? resolvedGetCall : resolvedSetCall);
+ ResolvedCall resolvedCall = isGetter ? resolvedGetCall : resolvedSetCall;
+ assert resolvedCall != null : "No resolved call for " + operationDescriptor;
+ Callable callable = resolveToCallable(accessibleFunctionDescriptor(resolvedCall), false, resolvedCall);
Callable callableMethod = resolveToCallableMethod(operationDescriptor, false);
Type[] argumentTypes = callableMethod.getParameterTypes();
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionGenerationStrategy.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionGenerationStrategy.java
index 70e647d1220..d11e209f615 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionGenerationStrategy.java
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionGenerationStrategy.java
@@ -20,6 +20,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.codegen.context.MethodContext;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.psi.KtDeclarationWithBody;
+import org.jetbrains.kotlin.psi.KtExpression;
+import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
@@ -49,7 +51,9 @@ public abstract class FunctionGenerationStrategy {
@Override
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
- codegen.returnExpression(declaration.getBodyExpression());
+ KtExpression bodyExpression = declaration.getBodyExpression();
+ assert bodyExpression != null : "Function has no body: " + PsiUtilsKt.getElementTextWithContext(declaration);
+ codegen.returnExpression(bodyExpression);
}
}
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java
index f9b35847729..25b92ce0b9a 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java
@@ -813,27 +813,37 @@ public abstract class MemberCodegen()
- for (declaration in element.declarations) {
- when (declaration) {
- is KtNamedFunction -> {
- val functionDescriptor = bindingContext.get(BindingContext.FUNCTION, declaration)
- members.add(functionDescriptor ?: throw AssertionError("Function ${declaration.name} is not bound in ${element.name}"))
- }
- is KtProperty -> {
- val property = bindingContext.get(BindingContext.VARIABLE, declaration)
- members.add(property ?: throw AssertionError("Property ${declaration.name} is not bound in ${element.name}"))
- }
- }
- }
-
- val extension = JvmSerializerExtension(v.serializationBindings, state)
- val serializer = DescriptorSerializer.createTopLevel(extension)
- val builder = serializer.packagePartProto(packageFragment.fqName, members)
- extension.serializeJvmPackage(builder, partType)
- val packageProto = builder.build()
+ val (serializer, packageProto) = PackagePartCodegen.serializePackagePartMembers(this, partType)
val extraFlags = if (shouldGeneratePartHierarchy) JvmAnnotationNames.METADATA_MULTIFILE_PARTS_INHERIT_FLAG else 0
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java
index 7a635d9a4ec..4245c86fa24 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java
@@ -22,6 +22,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.backend.common.CodegenUtil;
import org.jetbrains.kotlin.codegen.context.PackageContext;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
@@ -31,7 +32,6 @@ import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
import org.jetbrains.kotlin.psi.*;
-import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
import org.jetbrains.org.objectweb.asm.Type;
@@ -98,9 +98,7 @@ public class PackageCodegenImpl implements PackageCodegen {
List classOrObjects = new ArrayList<>();
- for (KtDeclaration declaration : file.getDeclarations()) {
- if (PsiUtilsKt.hasExpectModifier(declaration)) continue;
-
+ for (KtDeclaration declaration : CodegenUtil.getActualDeclarations(file)) {
if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction || declaration instanceof KtTypeAlias) {
generatePackagePart = true;
}
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java
index 67057075f71..7df705e0c07 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java
@@ -17,22 +17,21 @@
package org.jetbrains.kotlin.codegen;
import com.intellij.util.ArrayUtil;
+import kotlin.Pair;
import kotlin.Unit;
+import kotlin.collections.CollectionsKt;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.kotlin.backend.common.CodegenUtil;
import org.jetbrains.kotlin.codegen.annotation.AnnotatedSimple;
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext;
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
-import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor;
-import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor;
-import org.jetbrains.kotlin.descriptors.VariableDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.Annotated;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl;
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader;
import org.jetbrains.kotlin.psi.*;
-import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.serialization.DescriptorSerializer;
import org.jetbrains.kotlin.serialization.ProtoBuf;
@@ -88,9 +87,7 @@ public class PackagePartCodegen extends MemberCodegen {
@Override
protected void generateBody() {
- for (KtDeclaration declaration : element.getDeclarations()) {
- if (PsiUtilsKt.hasExpectModifier(declaration)) continue;
-
+ for (KtDeclaration declaration : CodegenUtil.getActualDeclarations(element)) {
if (declaration instanceof KtNamedFunction || declaration instanceof KtProperty || declaration instanceof KtTypeAlias) {
genSimpleMember(declaration);
}
@@ -103,34 +100,42 @@ public class PackagePartCodegen extends MemberCodegen {
@Override
protected void generateKotlinMetadataAnnotation() {
- List members = new ArrayList<>();
- for (KtDeclaration declaration : element.getDeclarations()) {
- if (declaration instanceof KtNamedFunction) {
- SimpleFunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, declaration);
- members.add(functionDescriptor);
- }
- else if (declaration instanceof KtProperty) {
- VariableDescriptor property = bindingContext.get(BindingContext.VARIABLE, declaration);
- members.add(property);
- }
- else if (declaration instanceof KtTypeAlias) {
- TypeAliasDescriptor typeAlias = bindingContext.get(BindingContext.TYPE_ALIAS, declaration);
- members.add(typeAlias);
- }
- }
-
- JvmSerializerExtension extension = new JvmSerializerExtension(v.getSerializationBindings(), state);
- DescriptorSerializer serializer = DescriptorSerializer.createTopLevel(extension);
- ProtoBuf.Package.Builder builder = serializer.packagePartProto(element.getPackageFqName(), members);
- extension.serializeJvmPackage(builder, packagePartType);
- ProtoBuf.Package packageProto = builder.build();
+ Pair serializedPart = serializePackagePartMembers(this, packagePartType);
WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.FILE_FACADE, 0, av -> {
- writeAnnotationData(av, serializer, packageProto);
+ writeAnnotationData(av, serializedPart.getFirst(), serializedPart.getSecond());
return Unit.INSTANCE;
});
}
+ @NotNull
+ protected static Pair serializePackagePartMembers(
+ @NotNull MemberCodegen extends KtFile> codegen,
+ @NotNull Type packagePartType
+ ) {
+ BindingContext bindingContext = codegen.bindingContext;
+ List members = CollectionsKt.mapNotNull(CodegenUtil.getActualDeclarations(codegen.element), declaration -> {
+ if (declaration instanceof KtNamedFunction) {
+ return bindingContext.get(BindingContext.FUNCTION, declaration);
+ }
+ else if (declaration instanceof KtProperty) {
+ return bindingContext.get(BindingContext.VARIABLE, declaration);
+ }
+ else if (declaration instanceof KtTypeAlias) {
+ return bindingContext.get(BindingContext.TYPE_ALIAS, declaration);
+ }
+
+ return null;
+ });
+
+ JvmSerializerExtension extension = new JvmSerializerExtension(codegen.v.getSerializationBindings(), codegen.state);
+ DescriptorSerializer serializer = DescriptorSerializer.createTopLevel(extension);
+ ProtoBuf.Package.Builder builder = serializer.packagePartProto(codegen.element.getPackageFqName(), members);
+ extension.serializeJvmPackage(builder, packagePartType);
+
+ return new Pair<>(serializer, builder.build());
+ }
+
@Override
protected void generateSyntheticPartsAfterBody() {
generateSyntheticAccessors();
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java
index cf8f4a5a6da..7fbb9ed385c 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java
@@ -179,6 +179,19 @@ public abstract class StackValue {
return type == Type.VOID_TYPE ? none() : new OnStack(type);
}
+ @NotNull
+ public static StackValue integerConstant(int value, @NotNull Type type) {
+ if (type == Type.LONG_TYPE) {
+ return constant(Long.valueOf(value), type);
+ }
+ else if (type == Type.BYTE_TYPE || type == Type.SHORT_TYPE || type == Type.INT_TYPE) {
+ return constant(Integer.valueOf(value), type);
+ }
+ else {
+ throw new AssertionError("Unexpected integer type: " + type);
+ }
+ }
+
@NotNull
public static StackValue constant(@Nullable Object value, @NotNull Type type) {
if (type == Type.BOOLEAN_TYPE) {
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt
index 83c5786ac46..6cad1404b95 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.psi.KtFunction
+import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -70,6 +71,6 @@ class SuspendFunctionGenerationStrategy(
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
this.codegen = codegen
- codegen.returnExpression(declaration.bodyExpression)
+ codegen.returnExpression(declaration.bodyExpression ?: error("Function has no body: " + declaration.getElementTextWithContext()))
}
}
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/processUninitializedStores.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/processUninitializedStores.kt
index 5e5983dc629..5e3c9641ab7 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/processUninitializedStores.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/processUninitializedStores.kt
@@ -16,10 +16,8 @@
package org.jetbrains.kotlin.codegen.coroutines
-import org.jetbrains.kotlin.codegen.optimization.common.CustomFramesMethodAnalyzer
-import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
-import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
-import org.jetbrains.kotlin.codegen.optimization.common.insnListOf
+import org.jetbrains.kotlin.codegen.optimization.common.*
+import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.*
@@ -71,124 +69,161 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
* - restore constructor arguments
*/
internal fun processUninitializedStores(methodNode: MethodNode) {
- val interpreter = UninitializedNewValueMarkerInterpreter()
- val frames = CustomFramesMethodAnalyzer("fake", methodNode, interpreter, ::UninitializedNewValueFrame).analyze()
-
- for ((index, insn) in methodNode.instructions.toArray().withIndex()) {
- val frame = frames[index] ?: continue
- val uninitializedValue = frame.getUninitializedValueForConstructorCall(insn) ?: continue
-
- val copyUsages: Set = interpreter.uninitializedValuesToCopyUsages[uninitializedValue.newInsn]!!
- assert(copyUsages.size > 0) { "At least DUP copy operation expected" }
-
- // Value generated by NEW wasn't store to local/field (only DUPed)
- if (copyUsages.size == 1) continue
-
- (copyUsages + uninitializedValue.newInsn).forEach {
- methodNode.instructions.remove(it)
- }
-
- val indexOfConstructorArgumentFromTopOfStack = Type.getArgumentTypes((insn as MethodInsnNode).desc).size
- val storedTypes = arrayListOf()
- var nextVarIndex = methodNode.maxLocals
-
- for (i in 0 until indexOfConstructorArgumentFromTopOfStack) {
- val value = frame.getStack(frame.stackSize - 1 - i)
- val type = value.type
- methodNode.instructions.insertBefore(insn, VarInsnNode(type.getOpcode(Opcodes.ISTORE), nextVarIndex))
- nextVarIndex += type.size
- storedTypes.add(type)
- }
- methodNode.maxLocals = Math.max(methodNode.maxLocals, nextVarIndex)
-
- methodNode.instructions.insertBefore(insn, insnListOf(
- TypeInsnNode(Opcodes.NEW, uninitializedValue.newInsn.desc),
- InsnNode(Opcodes.DUP)
- ))
-
- for (type in storedTypes.reversed()) {
- nextVarIndex -= type.size
- methodNode.instructions.insertBefore(insn, VarInsnNode(type.getOpcode(Opcodes.ILOAD), nextVarIndex))
- }
- }
+ UninitializedStoresProcessor(methodNode, forCoroutines = true).run()
}
-private class UninitializedNewValue(
- val newInsn: TypeInsnNode, val internalName: String
-) : StrictBasicValue(Type.getObjectType(internalName)) {
- override fun toString() = "UninitializedNewValue(internalName='$internalName')"
-}
+class UninitializedStoresProcessor(private val methodNode: MethodNode, private val forCoroutines: Boolean) {
+ private val isInSpecialMethod = methodNode.name == "" || methodNode.name == ""
-private class UninitializedNewValueFrame(nLocals: Int, nStack: Int) : Frame(nLocals, nStack) {
- override fun execute(insn: AbstractInsnNode, interpreter: Interpreter?) {
- val replaceTopValueWithInitialized = getUninitializedValueForConstructorCall(insn) != null
+ fun run() {
+ val interpreter = UninitializedNewValueMarkerInterpreter()
- super.execute(insn, interpreter)
+ val frames = CustomFramesMethodAnalyzer(
+ "fake", methodNode, interpreter,
+ this::UninitializedNewValueFrame
+ ).analyze()
- if (replaceTopValueWithInitialized) {
- // Drop top value
- val value = pop() as UninitializedNewValue
+ for ((index, insn) in methodNode.instructions.toArray().withIndex()) {
+ val frame = frames[index] ?: continue
+ val uninitializedValue = frame.getUninitializedValueForConstructorCall(insn) ?: continue
- // uninitialized value become initialized after call
- push(StrictBasicValue(value.type))
+ val newInsn = uninitializedValue.newInsn
+ val copyUsages: Set = interpreter.uninitializedValuesToCopyUsages[newInsn]!!
+ assert(copyUsages.isNotEmpty()) { "At least DUP copy operation expected" }
+
+ // Value generated by NEW wasn't store to local/field (only DUPed)
+ if (copyUsages.size == 1) continue
+
+ methodNode.instructions.run {
+ removeAll(copyUsages)
+ if (forCoroutines) {
+ remove(newInsn)
+ }
+ else {
+ // Replace 'NEW C' instruction with "manual" initialization of class 'C':
+ // LDC [typeName for C]
+ // INVOKESTATIC java/lang/Class.forName (Ljava/lang/String;)Ljava/lang/Class;
+ // POP
+ val typeNameForClass = newInsn.desc.replace('/', '.')
+ insertBefore(newInsn, LdcInsnNode(typeNameForClass))
+ insertBefore(
+ newInsn,
+ MethodInsnNode(
+ Opcodes.INVOKESTATIC,
+ "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;",
+ false
+ )
+ )
+ set(newInsn, InsnNode(Opcodes.POP))
+ }
+ }
+
+ val indexOfConstructorArgumentFromTopOfStack = Type.getArgumentTypes((insn as MethodInsnNode).desc).size
+ val storedTypes = arrayListOf()
+ var nextVarIndex = methodNode.maxLocals
+
+ for (i in 0 until indexOfConstructorArgumentFromTopOfStack) {
+ val value = frame.getStack(frame.stackSize - 1 - i)
+ val type = value.type
+ methodNode.instructions.insertBefore(insn, VarInsnNode(type.getOpcode(Opcodes.ISTORE), nextVarIndex))
+ nextVarIndex += type.size
+ storedTypes.add(type)
+ }
+ methodNode.maxLocals = Math.max(methodNode.maxLocals, nextVarIndex)
+
+ methodNode.instructions.insertBefore(insn, insnListOf(
+ TypeInsnNode(Opcodes.NEW, newInsn.desc),
+ InsnNode(Opcodes.DUP)
+ ))
+
+ for (type in storedTypes.reversed()) {
+ nextVarIndex -= type.size
+ methodNode.instructions.insertBefore(insn, VarInsnNode(type.getOpcode(Opcodes.ILOAD), nextVarIndex))
+ }
}
}
-}
-/**
- * @return value generated by NEW that used as 0-th argument of constructor call or null if current instruction is not constructor call
- */
-private fun Frame.getUninitializedValueForConstructorCall(
- insn: AbstractInsnNode
-): UninitializedNewValue? {
- if (!insn.isConstructorCall()) return null
+ private inner class UninitializedNewValueFrame(nLocals: Int, nStack: Int) : Frame(nLocals, nStack) {
+ override fun execute(insn: AbstractInsnNode, interpreter: Interpreter?) {
+ val replaceTopValueWithInitialized = getUninitializedValueForConstructorCall(insn) != null
- assert(insn.opcode == Opcodes.INVOKESPECIAL) { "Expected opcode Opcodes.INVOKESPECIAL for , but ${insn.opcode} found" }
- val paramsCountIncludingReceiver = Type.getArgumentTypes((insn as MethodInsnNode).desc).size + 1
- val newValue = getStack(stackSize - (paramsCountIncludingReceiver + 1)) as? UninitializedNewValue ?: error("Expected value generated with NEW")
+ super.execute(insn, interpreter)
- assert(getStack(stackSize - paramsCountIncludingReceiver) is UninitializedNewValue) {
- "Next value after NEW should be one generated by DUP"
+ if (replaceTopValueWithInitialized) {
+ // Drop top value
+ val value = pop() as UninitializedNewValue
+
+ // uninitialized value become initialized after call
+ push(StrictBasicValue(value.type))
+ }
+ }
}
- return newValue
-}
+ /**
+ * @return value generated by NEW that used as 0-th argument of constructor call or null if current instruction is not constructor call
+ */
+ private fun Frame.getUninitializedValueForConstructorCall(insn: AbstractInsnNode): UninitializedNewValue? {
+ if (!insn.isConstructorCall()) return null
-private fun AbstractInsnNode.isConstructorCall() = this is MethodInsnNode && this.name == ""
+ assert(insn.opcode == Opcodes.INVOKESPECIAL) { "Expected opcode Opcodes.INVOKESPECIAL for , but ${insn.opcode} found" }
+ val paramsCountIncludingReceiver = Type.getArgumentTypes((insn as MethodInsnNode).desc).size + 1
+ val newValue = peek(paramsCountIncludingReceiver) as? UninitializedNewValue ?:
+ if (isInSpecialMethod)
+ return null
+ else
+ error("Expected value generated with NEW")
-private class UninitializedNewValueMarkerInterpreter : OptimizationBasicInterpreter() {
- val uninitializedValuesToCopyUsages = hashMapOf>()
- override fun newOperation(insn: AbstractInsnNode): BasicValue? {
- if (insn.opcode == Opcodes.NEW) {
- uninitializedValuesToCopyUsages.getOrPut(insn) { mutableSetOf() }
- return UninitializedNewValue(insn as TypeInsnNode, insn.desc)
+ assert(peek(paramsCountIncludingReceiver - 1) is UninitializedNewValue) {
+ "Next value after NEW should be one generated by DUP"
}
- return super.newOperation(insn)
+
+ return newValue
}
- override fun copyOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? {
- if (value is UninitializedNewValue) {
- uninitializedValuesToCopyUsages[value.newInsn]!!.add(insn)
- return value
- }
- return super.copyOperation(insn, value)
+ private class UninitializedNewValue(
+ val newInsn: TypeInsnNode,
+ val internalName: String
+ ) : StrictBasicValue(Type.getObjectType(internalName)) {
+ override fun toString() = "UninitializedNewValue(internalName='$internalName')"
}
- override fun merge(v: BasicValue, w: BasicValue): BasicValue {
- if (v === w) return v
- if (v === StrictBasicValue.UNINITIALIZED_VALUE || w === StrictBasicValue.UNINITIALIZED_VALUE) {
- return StrictBasicValue.UNINITIALIZED_VALUE
+
+ private fun AbstractInsnNode.isConstructorCall() = this is MethodInsnNode && this.name == ""
+
+ private class UninitializedNewValueMarkerInterpreter : OptimizationBasicInterpreter() {
+ val uninitializedValuesToCopyUsages = hashMapOf>()
+ override fun newOperation(insn: AbstractInsnNode): BasicValue? {
+ if (insn.opcode == Opcodes.NEW) {
+ uninitializedValuesToCopyUsages.getOrPut(insn) { mutableSetOf() }
+ return UninitializedNewValue(insn as TypeInsnNode, insn.desc)
+ }
+ return super.newOperation(insn)
}
- if (v is UninitializedNewValue || w is UninitializedNewValue) {
- if ((v as? UninitializedNewValue)?.newInsn !== (w as? UninitializedNewValue)?.newInsn) {
- // Merge of two different ANEW result is possible, but such values should not be used further
+ override fun copyOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? {
+ if (value is UninitializedNewValue) {
+ uninitializedValuesToCopyUsages[value.newInsn]!!.add(insn)
+ return value
+ }
+ return super.copyOperation(insn, value)
+ }
+
+ override fun merge(v: BasicValue, w: BasicValue): BasicValue {
+ if (v === w) return v
+ if (v === StrictBasicValue.UNINITIALIZED_VALUE || w === StrictBasicValue.UNINITIALIZED_VALUE) {
return StrictBasicValue.UNINITIALIZED_VALUE
}
- return v
- }
+ if (v is UninitializedNewValue || w is UninitializedNewValue) {
+ if ((v as? UninitializedNewValue)?.newInsn !== (w as? UninitializedNewValue)?.newInsn) {
+ // Merge of two different ANEW result is possible, but such values should not be used further
+ return StrictBasicValue.UNINITIALIZED_VALUE
+ }
- return super.merge(v, w)
+ return v
+ }
+
+ return super.merge(v, w)
+ }
}
}
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/MandatoryMethodTransforker.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/FixStackWithLabelNormalizationMethodTransformer.kt
similarity index 100%
rename from compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/MandatoryMethodTransforker.kt
rename to compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/FixStackWithLabelNormalizationMethodTransformer.kt
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationClassBuilderFactory.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationClassBuilderFactory.java
index 3a8223e869e..812944c12a7 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationClassBuilderFactory.java
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationClassBuilderFactory.java
@@ -17,9 +17,7 @@
package org.jetbrains.kotlin.codegen.optimization;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.kotlin.codegen.ClassBuilder;
import org.jetbrains.kotlin.codegen.ClassBuilderFactory;
-import org.jetbrains.kotlin.codegen.ClassBuilderMode;
import org.jetbrains.kotlin.codegen.DelegatingClassBuilderFactory;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.kt
index 33c62a48c77..04663015d31 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.kt
@@ -17,9 +17,9 @@
package org.jetbrains.kotlin.codegen.optimization
import org.jetbrains.kotlin.codegen.TransformationMethodVisitor
-import org.jetbrains.kotlin.codegen.optimization.boxing.StackPeepholeOptimizationsTransformer
-import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantBoxingMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.boxing.PopBackwardPropagationTransformer
+import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantBoxingMethodTransformer
+import org.jetbrains.kotlin.codegen.optimization.boxing.StackPeepholeOptimizationsTransformer
import org.jetbrains.kotlin.codegen.optimization.common.prepareForEmitting
import org.jetbrains.kotlin.codegen.optimization.nullCheck.RedundantNullCheckMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.transformer.CompositeMethodTransformer
@@ -35,11 +35,10 @@ class OptimizationMethodVisitor(
signature: String?,
exceptions: Array?
) : TransformationMethodVisitor(delegate, access, name, desc, signature, exceptions) {
-
override fun performTransformations(methodNode: MethodNode) {
- MANDATORY_METHOD_TRANSFORMER.transform("fake", methodNode)
+ normalizationMethodTransformer.transform("fake", methodNode)
if (canBeOptimized(methodNode) && !disableOptimization) {
- OPTIMIZATION_TRANSFORMER.transform("fake", methodNode)
+ optimizationTransformer.transform("fake", methodNode)
}
methodNode.prepareForEmitting()
}
@@ -47,12 +46,13 @@ class OptimizationMethodVisitor(
companion object {
private val MEMORY_LIMIT_BY_METHOD_MB = 50
- private val MANDATORY_METHOD_TRANSFORMER = CompositeMethodTransformer(
+ val normalizationMethodTransformer = CompositeMethodTransformer(
FixStackWithLabelNormalizationMethodTransformer(),
+ UninitializedStoresMethodTransformer(),
MethodVerifier("AFTER mandatory stack transformations")
)
- private val OPTIMIZATION_TRANSFORMER = CompositeMethodTransformer(
+ val optimizationTransformer = CompositeMethodTransformer(
CapturedVarsOptimizationMethodTransformer(),
RedundantNullCheckMethodTransformer(),
RedundantCheckCastEliminationMethodTransformer(),
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/UninitializedStoresMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/UninitializedStoresMethodTransformer.kt
new file mode 100644
index 00000000000..aab689820fa
--- /dev/null
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/UninitializedStoresMethodTransformer.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.optimization
+
+import org.jetbrains.kotlin.codegen.coroutines.UninitializedStoresProcessor
+import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
+import org.jetbrains.org.objectweb.asm.tree.MethodNode
+
+class UninitializedStoresMethodTransformer : MethodTransformer() {
+ override fun transform(internalClassName: String, methodNode: MethodNode) {
+ UninitializedStoresProcessor(methodNode, forCoroutines = false).run()
+ }
+}
\ No newline at end of file
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt
index 77fb229f4d8..adb8fe84bcb 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt
@@ -214,3 +214,6 @@ internal inline fun AbstractInsnNode.isInsn(opcod
internal inline fun AbstractInsnNode.takeInsnIf(opcode: Int, condition: T.() -> Boolean): T? =
takeIf { it.opcode == opcode }?.safeAs()?.takeIf { it.condition() }
+fun InsnList.removeAll(nodes: Collection) {
+ for (node in nodes) remove(node)
+}
\ No newline at end of file
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/transformer/CompositeMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/transformer/CompositeMethodTransformer.kt
index 5726321e506..e2e40b47b59 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/transformer/CompositeMethodTransformer.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/transformer/CompositeMethodTransformer.kt
@@ -18,8 +18,15 @@ package org.jetbrains.kotlin.codegen.optimization.transformer
import org.jetbrains.org.objectweb.asm.tree.MethodNode
-open class CompositeMethodTransformer(private vararg val transformers: MethodTransformer) : MethodTransformer() {
+open class CompositeMethodTransformer(private val transformers: List) : MethodTransformer() {
+ constructor(vararg transformers: MethodTransformer?) : this(transformers.filterNotNull())
+
override fun transform(internalClassName: String, methodNode: MethodNode) {
transformers.forEach { it.transform(internalClassName, methodNode) }
}
+
+ companion object {
+ inline fun build(builder: MutableList.() -> Unit) =
+ CompositeMethodTransformer(ArrayList().apply { builder() })
+ }
}
\ No newline at end of file
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/forLoop/ForInUntilConstantRangeLoopGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/forLoop/ForInUntilConstantRangeLoopGenerator.kt
index 37d870157bb..23872324fee 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/forLoop/ForInUntilConstantRangeLoopGenerator.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/forLoop/ForInUntilConstantRangeLoopGenerator.kt
@@ -18,10 +18,8 @@ package org.jetbrains.kotlin.codegen.range.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
-import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
-import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
class ForInUntilConstantRangeLoopGenerator(
@@ -36,5 +34,5 @@ class ForInUntilConstantRangeLoopGenerator(
codegen.generateReceiverValue(from, false)
override fun generateTo(): StackValue =
- StackValue.constant(untilValue, asmElementType)
+ StackValue.integerConstant(untilValue, asmElementType)
}
\ No newline at end of file
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt
index 6a9269e3275..9da8888b465 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt
@@ -179,7 +179,6 @@ class GenerationState @JvmOverloads constructor(
val generateParametersMetadata: Boolean = configuration.getBoolean(JVMConfigurationKeys.PARAMETERS_METADATA)
-
val shouldInlineConstVals = languageVersionSettings.supportsFeature(LanguageFeature.InlineConstVals)
init {
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java
index 9f941e06e52..a02a16fb7b5 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java
@@ -831,11 +831,11 @@ public class KotlinTypeMapper {
JvmCodegenUtil.isJvm8InterfaceWithDefaults(ownerForDefault, isJvm8Target, isJvm8TargetWithDefaults);
}
- public static boolean isAccessor(@NotNull CallableMemberDescriptor descriptor) {
+ public static boolean isAccessor(@Nullable CallableMemberDescriptor descriptor) {
return descriptor instanceof AccessorForCallableDescriptor>;
}
- public static boolean isStaticAccessor(@NotNull CallableMemberDescriptor descriptor) {
+ public static boolean isStaticAccessor(@Nullable CallableMemberDescriptor descriptor) {
if (descriptor instanceof AccessorForConstructorDescriptor) return false;
return isAccessor(descriptor);
}
diff --git a/compiler/build.gradle.kts b/compiler/build.gradle.kts
index 590f0f65671..668cf867fa6 100644
--- a/compiler/build.gradle.kts
+++ b/compiler/build.gradle.kts
@@ -32,7 +32,8 @@ val testDistProjects = listOf(
":kotlin-daemon-client",
":kotlin-preloader",
":plugins:android-extensions-compiler",
- ":kotlin-ant")
+ ":kotlin-ant",
+ ":kotlin-annotations-jvm")
dependencies {
depDistProjects.forEach {
@@ -82,36 +83,85 @@ projectTest {
evaluationDependsOn(":compiler:tests-common-jvm6")
-fun Project.codegenTest(taskName: String, body: Test.() -> Unit): Test = projectTest(taskName) {
+fun Project.codegenTest(taskName: String, jdk: String, body: Test.() -> Unit): Test = projectTest(taskName) {
dependsOn(*testDistProjects.map { "$it:dist" }.toTypedArray())
workingDir = rootDir
- environment("TEST_SERVER_CLASSES_DIRS", project(":compiler:tests-common-jvm6").the().sourceSets.getByName("main").output.classesDirs.asPath)
- filter.includeTestsMatching("org.jetbrains.kotlin.codegen.CodegenJdkCommonTestSuite*")
+
+ filter.includeTestsMatching("org.jetbrains.kotlin.codegen.BlackBoxCodegenTestGenerated*")
+ filter.includeTestsMatching("org.jetbrains.kotlin.codegen.BlackBoxInlineCodegenTestGenerated*")
+ filter.includeTestsMatching("org.jetbrains.kotlin.codegen.CompileKotlinAgainstInlineKotlinTestGenerated*")
+ filter.includeTestsMatching("org.jetbrains.kotlin.codegen.CompileKotlinAgainstKotlinTestGenerated*")
+ filter.includeTestsMatching("org.jetbrains.kotlin.codegen.BlackBoxAgainstJavaCodegenTestGenerated*")
+
+ if (jdk == "JDK_9") {
+ jvmArgs = listOf("--add-opens", "java.desktop/javax.swing=ALL-UNNAMED", "--add-opens", "java.base/java.io=ALL-UNNAMED")
+ }
body()
+ doFirst {
+ val jdkPath = project.property(jdk) ?: error("$jdk is not optional to run this test")
+ executable = "$jdkPath/bin/java"
+ println("Running test with $executable")
+ }
+}.also {
+ task(taskName.replace(Regex("-[a-z]"), { it.value.takeLast(1).toUpperCase() })) {
+ dependsOn(it)
+ group = "verification"
+ }
}
-codegenTest("codegen-target6-jvm6-test") {
+codegenTest("codegen-target6-jvm6-test", "JDK_18") {
+ dependsOn(":compiler:tests-common-jvm6:build")
+
+ //TODO make port flexible
+ val port = "5100"
+ var jdkProcess: Process? = null
+
+ doFirst {
+ logger.info("Configuring JDK 6 server...")
+ val jdkPath = project.property("JDK_16") ?: error("JDK_16 is not optional to run this test")
+ val executable = "$jdkPath/bin/java"
+ val main = "org.jetbrains.kotlin.test.clientserver.TestProcessServer"
+
+ val classpath = getSourceSetsFrom(":compiler:tests-common-jvm6")["main"].output.asPath + ":" +
+ getSourceSetsFrom(":kotlin-stdlib")["main"].output.asPath + ":" +
+ getSourceSetsFrom(":kotlin-stdlib")["builtins"].output.asPath + ":" +
+ getSourceSetsFrom(":kotlin-test:kotlin-test-jvm")["main"].output.asPath
+
+ logger.debug("Server classpath: $classpath")
+
+ val builder = ProcessBuilder(executable, "-cp", classpath, main, port)
+ builder.directory(rootDir)
+
+ builder.inheritIO()
+ builder.redirectErrorStream(true)
+
+ logger.info("Starting JDK 6 server $executable")
+ jdkProcess = builder.start()
+
+ }
systemProperty("kotlin.test.default.jvm.target", "1.6")
systemProperty("kotlin.test.java.compilation.target", "1.6")
- systemProperty("kotlin.test.box.in.separate.process.port", "5100")
+ systemProperty("kotlin.test.box.in.separate.process.port", port)
+
+ doLast {
+ logger.info("Stopping JDK 6 server...")
+ jdkProcess?.destroy()
+ }
}
-codegenTest("codegen-target6-jvm9-test") {
+codegenTest("codegen-target6-jvm9-test", "JDK_9") {
systemProperty("kotlin.test.default.jvm.target", "1.6")
- jvmArgs = listOf("--add-opens", "java.desktop/javax.swing=ALL-UNNAMED", "--add-opens", "java.base/java.io=ALL-UNNAMED")
}
-codegenTest("codegen-target8-jvm8-test") {
+codegenTest("codegen-target8-jvm8-test", "JDK_18") {
systemProperty("kotlin.test.default.jvm.target", "1.8")
}
-codegenTest("codegen-target8-jvm9-test") {
+codegenTest("codegen-target8-jvm9-test", "JDK_9") {
systemProperty("kotlin.test.default.jvm.target", "1.8")
- jvmArgs = listOf("--add-opens", "java.desktop/javax.swing=ALL-UNNAMED", "--add-opens", "java.base/java.io=ALL-UNNAMED")
}
-codegenTest("codegen-target9-jvm9-test") {
+codegenTest("codegen-target9-jvm9-test", "JDK_9") {
systemProperty("kotlin.test.default.jvm.target", "1.8")
systemProperty("kotlin.test.substitute.bytecode.1.8.to.1.9", "true")
- jvmArgs = listOf("--add-opens", "java.desktop/javax.swing=ALL-UNNAMED", "--add-opens", "java.base/java.io=ALL-UNNAMED")
}
diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt
index b6d1acacbef..a3a61b0f608 100644
--- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt
+++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt
@@ -48,11 +48,12 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
var sourceMapPrefix: String? by FreezableVar(null)
@Argument(
- value = "-source-map-source-roots",
+ value = "-source-map-base-dirs",
+ deprecatedName = "-source-map-source-roots",
valueDescription = "",
description = "Base directories which are used to calculate relative paths to source files in source map"
)
- var sourceMapSourceRoots: String? by FreezableVar(null)
+ var sourceMapBaseDirs: String? by FreezableVar(null)
@GradleOption(DefaultValues.JsSourceMapContentModes::class)
@Argument(
diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt
index e5cdd88c0dc..4a291c984ce 100644
--- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt
+++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.AnalysisFlag
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.utils.Jsr305State
+import org.jetbrains.kotlin.utils.ReportLevel
class K2JVMCompilerArguments : CommonCompilerArguments() {
companion object {
@@ -165,10 +166,15 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
@Argument(
value = "-Xjsr305",
deprecatedName = "-Xjsr305-annotations",
- valueDescription = "{ignore|strict|warn}",
- description = "Specify global behavior for JSR-305 nullability annotations: ignore, treat as other supported nullability annotations, or report a warning"
+ valueDescription = "{ignore|strict|warn}" +
+ "|under-migration:{ignore-strict-warn}" +
+ "|@:{ignore|strict|warn}",
+ description = "Specify behaviors for JSR-305 nullability annotations for: " +
+ "global, annotated with @UnderMigration or custom annotation " +
+ "with specific value: ignore, treat as other supported nullability annotations, or report a warning. " +
+ "Note that strict value is experimental yet"
)
- var jsr305: String? by FreezableVar(Jsr305State.DEFAULT.description)
+ var jsr305: Array? by FreezableVar(null)
@Argument(
value = "-Xno-exception-on-explicit-equals-for-boxed-null",
@@ -181,20 +187,81 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
override fun configureAnalysisFlags(collector: MessageCollector): MutableMap, Any> {
val result = super.configureAnalysisFlags(collector)
+ result[AnalysisFlag.jsr305] = parseJsr305(collector)
+ return result
+ }
- if (jsr305 == "enable") {
- collector.report(
- CompilerMessageSeverity.STRONG_WARNING,
- "Option 'enable' for -Xjsr305 flag is deprecated. Please use 'strict' instead"
- )
- result.put(AnalysisFlag.jsr305, Jsr305State.STRICT)
+ fun parseJsr305(collector: MessageCollector): Jsr305State {
+ var global: ReportLevel? = null
+ var migration: ReportLevel? = null
+ val userDefined = mutableMapOf()
+
+ fun parseJsr305UnderMigration(collector: MessageCollector, item: String): ReportLevel? {
+ val rawState = item.split(":").takeIf { it.size == 2 }?.get(1)
+ return ReportLevel.findByDescription(rawState) ?: reportUnrecognizedJsr305(collector, item).let { null }
}
- else {
- Jsr305State.findByDescription(jsr305)?.let {
- result.put(AnalysisFlag.jsr305, it)
+
+ jsr305?.forEach { item ->
+ when {
+ item.startsWith("@") -> {
+ val (name, state) = parseJsr305UserDefined(collector, item) ?: return@forEach
+ val current = userDefined[name]
+ if (current != null) {
+ reportDuplicateJsr305(collector, "@$name:${current.description}", item)
+ return@forEach
+ }
+ userDefined[name] = state
+ }
+ item.startsWith("under-migration") -> {
+ if (migration != null) {
+ reportDuplicateJsr305(collector, "under-migration:${migration?.description}", item)
+ return@forEach
+ }
+
+ migration = parseJsr305UnderMigration(collector, item)
+ }
+ item == "enable" -> {
+ collector.report(
+ CompilerMessageSeverity.STRONG_WARNING,
+ "Option 'enable' for -Xjsr305 flag is deprecated. Please use 'strict' instead"
+ )
+ if (global != null) return@forEach
+
+ global = ReportLevel.STRICT
+ }
+ else -> {
+ if (global != null) {
+ reportDuplicateJsr305(collector, global!!.description, item)
+ return@forEach
+ }
+ global = ReportLevel.findByDescription(item)
+ }
}
}
- return result
+ val state = Jsr305State(global ?: ReportLevel.WARN, migration, userDefined)
+ return if (state == Jsr305State.DISABLED) Jsr305State.DISABLED else state
+ }
+
+ private fun reportUnrecognizedJsr305(collector: MessageCollector, item: String) {
+ collector.report(CompilerMessageSeverity.ERROR, "Unrecognized -Xjsr305 value: $item")
+ }
+
+ private fun reportDuplicateJsr305(collector: MessageCollector, first: String, second: String) {
+ collector.report(CompilerMessageSeverity.ERROR, "Conflict duplicating -Xjsr305 value: $first, $second")
+ }
+
+ private fun parseJsr305UserDefined(collector: MessageCollector, item: String): Pair? {
+ val (name, rawState) = item.substring(1).split(":").takeIf { it.size == 2 } ?: run {
+ reportUnrecognizedJsr305(collector, item)
+ return null
+ }
+
+ val state = ReportLevel.findByDescription(rawState) ?: run {
+ reportUnrecognizedJsr305(collector, item)
+ return null
+ }
+
+ return name to state
}
}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java
index 1d2f6786a7d..f6afab2fbc8 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java
@@ -175,8 +175,9 @@ public abstract class CLICompiler extends CLI
configuration.put(CLIConfigurationKeys.IS_API_VERSION_EXPLICIT, true);
}
+ MessageCollector collector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY);
if (apiVersion.compareTo(languageVersion) > 0) {
- configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(
+ collector.report(
ERROR,
"-api-version (" + apiVersion.getVersionString() + ") cannot be greater than " +
"-language-version (" + languageVersion.getVersionString() + ")",
@@ -185,7 +186,7 @@ public abstract class CLICompiler extends CLI
}
if (!languageVersion.isStable()) {
- configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(
+ collector.report(
STRONG_WARNING,
"Language version " + languageVersion.getVersionString() + " is experimental, there are " +
"no backwards compatibility guarantees for new language and library features",
@@ -206,7 +207,7 @@ public abstract class CLICompiler extends CLI
CommonConfigurationKeysKt.setLanguageVersionSettings(configuration, new LanguageVersionSettingsImpl(
languageVersion,
ApiVersion.createByLanguageVersion(apiVersion),
- arguments.configureAnalysisFlags(configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)),
+ arguments.configureAnalysisFlags(collector),
extraLanguageFeatures
));
}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java
index 04926cb3d11..24b6088880d 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java
@@ -357,8 +357,8 @@ public class K2JSCompiler extends CLICompiler {
configuration.put(JSConfigurationKeys.SOURCE_MAP_PREFIX, arguments.getSourceMapPrefix());
}
- String sourceMapSourceRoots = arguments.getSourceMapSourceRoots() != null ?
- arguments.getSourceMapSourceRoots() :
+ String sourceMapSourceRoots = arguments.getSourceMapBaseDirs() != null ?
+ arguments.getSourceMapBaseDirs() :
calculateSourceMapSourceRoot(messageCollector, arguments);
List sourceMapSourceRootList = StringUtil.split(sourceMapSourceRoots, File.pathSeparator);
configuration.put(JSConfigurationKeys.SOURCE_MAP_SOURCE_ROOTS, sourceMapSourceRootList);
@@ -367,7 +367,7 @@ public class K2JSCompiler extends CLICompiler {
if (arguments.getSourceMapPrefix() != null) {
messageCollector.report(WARNING, "source-map-prefix argument has no effect without source map", null);
}
- if (arguments.getSourceMapSourceRoots() != null) {
+ if (arguments.getSourceMapBaseDirs() != null) {
messageCollector.report(WARNING, "source-map-source-root argument has no effect without source map", null);
}
}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/ClasspathRootsResolver.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/ClasspathRootsResolver.kt
index 46cd58d5360..95c66a1b292 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/ClasspathRootsResolver.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/ClasspathRootsResolver.kt
@@ -39,7 +39,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.isValidJavaFqName
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
-import java.io.File
+import org.jetbrains.kotlin.resolve.jvm.modules.KOTLIN_STDLIB_MODULE_NAME
import java.io.IOException
import java.util.jar.Attributes
import java.util.jar.Manifest
@@ -51,55 +51,82 @@ class ClasspathRootsResolver(
private val additionalModules: List,
private val contentRootToVirtualFile: (JvmContentRoot) -> VirtualFile?,
private val javaModuleFinder: CliJavaModuleFinder,
- private val requireStdlibModule: Boolean
+ private val requireStdlibModule: Boolean,
+ private val outputDirectory: VirtualFile?
) {
val javaModuleGraph = JavaModuleGraph(javaModuleFinder)
data class RootsAndModules(val roots: List, val modules: List)
- fun convertClasspathRoots(contentRoots: List): RootsAndModules {
- val result = mutableListOf()
+ private data class RootWithPrefix(val root: VirtualFile, val packagePrefix: String?)
- val modules = ArrayList()
+ fun convertClasspathRoots(contentRoots: List): RootsAndModules {
+ val javaSourceRoots = mutableListOf()
+ val jvmClasspathRoots = mutableListOf()
+ val jvmModulePathRoots = mutableListOf()
for (contentRoot in contentRoots) {
if (contentRoot !is JvmContentRoot) continue
val root = contentRootToVirtualFile(contentRoot) ?: continue
-
when (contentRoot) {
- is JavaSourceRoot -> {
- val modularRoot = modularSourceRoot(root)
- if (modularRoot != null) {
- modules += modularRoot
- }
- else {
- result += JavaRoot(root, JavaRoot.RootType.SOURCE, contentRoot.packagePrefix?.let { prefix ->
- if (isValidJavaFqName(prefix)) FqName(prefix)
- else null.also {
- report(STRONG_WARNING, "Invalid package prefix name is ignored: $prefix")
- }
- })
- }
- }
- is JvmClasspathRoot -> {
- result += JavaRoot(root, JavaRoot.RootType.BINARY)
- }
- is JvmModulePathRoot -> {
- val module = modularBinaryRoot(root, contentRoot.file)
- if (module != null) {
- modules += module
- }
- }
+ is JavaSourceRoot -> javaSourceRoots += RootWithPrefix(root, contentRoot.packagePrefix)
+ is JvmClasspathRoot -> jvmClasspathRoots += root
+ is JvmModulePathRoot -> jvmModulePathRoots += root
else -> error("Unknown root type: $contentRoot")
}
}
+ return computeRoots(javaSourceRoots, jvmClasspathRoots, jvmModulePathRoots)
+ }
+
+ private fun computeRoots(
+ javaSourceRoots: List,
+ jvmClasspathRoots: List,
+ jvmModulePathRoots: List
+ ): RootsAndModules {
+ val result = mutableListOf()
+ val modules = mutableListOf()
+
+ val hasOutputDirectoryInClasspath = outputDirectory in jvmClasspathRoots || outputDirectory in jvmModulePathRoots
+
+ for ((root, packagePrefix) in javaSourceRoots) {
+ val modularRoot = modularSourceRoot(root, hasOutputDirectoryInClasspath)
+ if (modularRoot != null) {
+ modules += modularRoot
+ }
+ else {
+ result += JavaRoot(root, JavaRoot.RootType.SOURCE, packagePrefix?.let { prefix ->
+ if (isValidJavaFqName(prefix)) FqName(prefix)
+ else null.also {
+ report(STRONG_WARNING, "Invalid package prefix name is ignored: $prefix")
+ }
+ })
+ }
+ }
+
+ for (root in jvmClasspathRoots) {
+ result += JavaRoot(root, JavaRoot.RootType.BINARY)
+ }
+
+ val outputDirectoryAddedAsPartOfModule = modules.any { module -> module.moduleRoots.any { it.file == outputDirectory } }
+
+ for (root in jvmModulePathRoots) {
+ // Do not add output directory as a separate module if we're compiling an explicit named module.
+ // It's going to be included as a root of our module in modularSourceRoot.
+ if (outputDirectoryAddedAsPartOfModule && root == outputDirectory) continue
+
+ val module = modularBinaryRoot(root)
+ if (module != null) {
+ modules += module
+ }
+ }
+
addModularRoots(modules, result)
return RootsAndModules(result, modules)
}
- private fun modularSourceRoot(root: VirtualFile): JavaModule.Explicit? {
+ private fun findSourceModuleInfo(root: VirtualFile): Pair? {
val moduleInfoFile =
when {
root.isDirectory -> root.findChild(PsiJavaModule.MODULE_INFO_FILE)
@@ -109,10 +136,21 @@ class ClasspathRootsResolver(
val psiFile = psiManager.findFile(moduleInfoFile) ?: return null
val psiJavaModule = psiFile.children.singleOrNull { it is PsiJavaModule } as? PsiJavaModule ?: return null
- return JavaModule.Explicit(JavaModuleInfo.create(psiJavaModule), root, moduleInfoFile, isBinary = false)
+
+ return moduleInfoFile to psiJavaModule
}
- private fun modularBinaryRoot(root: VirtualFile, originalFile: File): JavaModule? {
+ private fun modularSourceRoot(root: VirtualFile, hasOutputDirectoryInClasspath: Boolean): JavaModule.Explicit? {
+ val (moduleInfoFile, psiJavaModule) = findSourceModuleInfo(root) ?: return null
+ val sourceRoot = JavaModule.Root(root, isBinary = false)
+ val roots =
+ if (hasOutputDirectoryInClasspath)
+ listOf(sourceRoot, JavaModule.Root(outputDirectory!!, isBinary = true))
+ else listOf(sourceRoot)
+ return JavaModule.Explicit(JavaModuleInfo.create(psiJavaModule), roots, moduleInfoFile)
+ }
+
+ private fun modularBinaryRoot(root: VirtualFile): JavaModule? {
val isJar = root.fileSystem.protocol == StandardFileSystems.JAR_PROTOCOL
val manifest: Attributes? by lazy(NONE) { readManifestAttributes(root) }
@@ -124,22 +162,25 @@ class ClasspathRootsResolver(
if (moduleInfoFile != null) {
val moduleInfo = JavaModuleInfo.read(moduleInfoFile) ?: return null
- return JavaModule.Explicit(moduleInfo, root, moduleInfoFile, isBinary = true)
+ return JavaModule.Explicit(moduleInfo, listOf(JavaModule.Root(root, isBinary = true)), moduleInfoFile)
}
// Only .jar files can be automatic modules
if (isJar) {
+ val moduleRoot = listOf(JavaModule.Root(root, isBinary = true))
+
val automaticModuleName = manifest?.getValue(AUTOMATIC_MODULE_NAME)
if (automaticModuleName != null) {
- return JavaModule.Automatic(automaticModuleName, root)
+ return JavaModule.Automatic(automaticModuleName, moduleRoot)
}
+ val originalFile = VfsUtilCore.virtualToIoFile(root)
val moduleName = LightJavaModule.moduleName(originalFile.nameWithoutExtension)
if (moduleName.isEmpty()) {
report(ERROR, "Cannot infer automatic module name for the file", VfsUtilCore.getVirtualFileForJar(root) ?: root)
return null
}
- return JavaModule.Automatic(moduleName, root)
+ return JavaModule.Automatic(moduleName, moduleRoot)
}
return null
@@ -156,7 +197,9 @@ class ClasspathRootsResolver(
}
private fun addModularRoots(modules: List, result: MutableList) {
- val sourceModules = modules.filterIsInstance().filterNot(JavaModule::isBinary)
+ // In current implementation, at most one source module is supported. This can be relaxed in the future if we support another
+ // compilation mode, similar to java's --module-source-path
+ val sourceModules = modules.filterIsInstance().filter(JavaModule::isSourceModule)
if (sourceModules.size > 1) {
for (module in sourceModules) {
report(ERROR, "Too many source module declarations found", module.moduleInfoFile)
@@ -169,11 +212,15 @@ class ClasspathRootsResolver(
if (existing == null) {
javaModuleFinder.addUserModule(module)
}
- else if (module.moduleRoot != existing.moduleRoot) {
- val jar = VfsUtilCore.getVirtualFileForJar(module.moduleRoot) ?: module.moduleRoot
- val existingPath = (VfsUtilCore.getVirtualFileForJar(existing.moduleRoot) ?: existing.moduleRoot).path
+ else if (module.moduleRoots != existing.moduleRoots) {
+ fun JavaModule.getRootFile() =
+ moduleRoots.firstOrNull()?.file?.let { VfsUtilCore.getVirtualFileForJar(it) ?: it }
+
+ val thisFile = module.getRootFile()
+ val existingFile = existing.getRootFile()
+ val atExistingPath = if (existingFile == null) "" else " at: ${existingFile.path}"
report(STRONG_WARNING, "The root is ignored because a module with the same name '${module.name}' " +
- "has been found earlier on the module path at: $existingPath", jar)
+ "has been found earlier on the module path$atExistingPath", thisFile)
}
}
@@ -212,18 +259,17 @@ class ClasspathRootsResolver(
report(ERROR, "Module $moduleName cannot be found in the module graph")
}
else {
- result.add(JavaRoot(
- module.moduleRoot,
- if (module.isBinary) JavaRoot.RootType.BINARY else JavaRoot.RootType.SOURCE
- ))
+ for ((root, isBinary) in module.moduleRoots) {
+ result.add(JavaRoot(root, if (isBinary) JavaRoot.RootType.BINARY else JavaRoot.RootType.SOURCE))
+ }
}
}
- if (requireStdlibModule && sourceModule != null && "kotlin.stdlib" !in allDependencies) {
+ if (requireStdlibModule && sourceModule != null && KOTLIN_STDLIB_MODULE_NAME !in allDependencies) {
report(
ERROR,
"The Kotlin standard library is not found in the module graph. " +
- "Please ensure you have the 'requires kotlin.stdlib' clause in your module definition",
+ "Please ensure you have the 'requires $KOTLIN_STDLIB_MODULE_NAME' clause in your module definition",
sourceModule.moduleInfoFile
)
}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt
index 6347f6a22f9..5630aac8486 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt
@@ -204,13 +204,19 @@ class KotlinCoreEnvironment private constructor(
val javaModuleFinder = CliJavaModuleFinder(jdkHome?.path?.let { path ->
jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR)
})
+
+ val outputDirectory =
+ configuration.get(JVMConfigurationKeys.MODULES)?.singleOrNull()?.getOutputDirectory()
+ ?: configuration.get(JVMConfigurationKeys.OUTPUT_DIRECTORY)?.absolutePath
+
classpathRootsResolver = ClasspathRootsResolver(
PsiManager.getInstance(project),
messageCollector,
configuration.getList(JVMConfigurationKeys.ADDITIONAL_JAVA_MODULES),
this::contentRootToVirtualFile,
javaModuleFinder,
- !configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE)
+ !configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE),
+ outputDirectory?.let(this::findLocalFile)
)
val (initialRoots, javaModules) =
@@ -331,7 +337,8 @@ class KotlinCoreEnvironment private constructor(
}
}
- internal fun findLocalFile(path: String) = applicationEnvironment.localFileSystem.findFileByPath(path)
+ internal fun findLocalFile(path: String): VirtualFile? =
+ applicationEnvironment.localFileSystem.findFileByPath(path)
private fun findLocalFile(root: JvmContentRoot): VirtualFile? {
return findLocalFile(root.file.absolutePath).also {
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleFinder.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleFinder.kt
index 87e9eda494e..5abe6b073c1 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleFinder.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleFinder.kt
@@ -42,6 +42,6 @@ class CliJavaModuleFinder(jrtFileSystemRoot: VirtualFile?) : JavaModuleFinder {
private fun findSystemModule(moduleRoot: VirtualFile): JavaModule.Explicit? {
val file = moduleRoot.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE) ?: return null
val moduleInfo = JavaModuleInfo.read(file) ?: return null
- return JavaModule.Explicit(moduleInfo, moduleRoot, file, isBinary = true)
+ return JavaModule.Explicit(moduleInfo, listOf(JavaModule.Root(moduleRoot, isBinary = true)), file)
}
}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleResolver.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleResolver.kt
index a7e15343179..24fab9f872e 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleResolver.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleResolver.kt
@@ -32,12 +32,12 @@ class CliJavaModuleResolver(
private val systemModules: List
) : JavaModuleResolver {
init {
- assert(userModules.count { !it.isBinary } <= 1) {
+ assert(userModules.count(JavaModule::isSourceModule) <= 1) {
"Modules computed by ClasspathRootsResolver cannot have more than one source module: $userModules"
}
}
- private val sourceModule: JavaModule? = userModules.firstOrNull { !it.isBinary }
+ private val sourceModule: JavaModule? = userModules.firstOrNull(JavaModule::isSourceModule)
private fun findJavaModule(file: VirtualFile): JavaModule? {
if (file.fileSystem.protocol == StandardFileSystems.JRT_PROTOCOL) {
@@ -46,13 +46,13 @@ class CliJavaModuleResolver(
return when (file.fileType) {
KotlinFileType.INSTANCE, JavaFileType.INSTANCE -> sourceModule
- JavaClassFileType.INSTANCE -> userModules.firstOrNull { module -> module.isBinary && file in module }
+ JavaClassFileType.INSTANCE -> userModules.firstOrNull { module -> file in module }
else -> null
}
}
private operator fun JavaModule.contains(file: VirtualFile): Boolean =
- VfsUtilCore.isAncestor(moduleRoot, file, false)
+ moduleRoots.any { (root, isBinary) -> isBinary && VfsUtilCore.isAncestor(root, file, false) }
override fun checkAccessibility(
fileFromOurModule: VirtualFile?, referencedFile: VirtualFile, referencedPackage: FqName?
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt
index a32b50bb5e6..623a52937a3 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt
@@ -41,4 +41,6 @@ open class DelegatePackageMemberDeclarationProvider(var delegate: PackageMemberD
override fun getClassOrObjectDeclarations(name: Name) = delegate.getClassOrObjectDeclarations(name)
override fun getTypeAliasDeclarations(name: Name) = delegate.getTypeAliasDeclarations(name)
+
+ override fun getDeclarationNames() = delegate.getDeclarationNames()
}
diff --git a/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompilationOptions.kt b/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompilationOptions.kt
index 3ebd25bc0b5..373cb9569dd 100644
--- a/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompilationOptions.kt
+++ b/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompilationOptions.kt
@@ -48,7 +48,9 @@ class IncrementalCompilationOptions(
/** @See [ReportSeverity] */
reportSeverity: Int,
/** @See [CompilationResultCategory]] */
- requestedCompilationResults: Array
+ requestedCompilationResults: Array,
+ val resultDifferenceFile: File? = null,
+ val friendDifferenceFile: File? = null
) : CompilationOptions(compilerMode, targetPlatform, reportCategories, reportSeverity, requestedCompilationResults) {
companion object {
const val serialVersionUID: Long = 0
diff --git a/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt b/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt
index f95b8bf708d..578f6fc84e3 100644
--- a/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt
+++ b/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt
@@ -507,9 +507,12 @@ class CompileServiceImpl(
workingDir,
enabled = true)
- return IncrementalJvmCompilerRunner(workingDir, javaSourceRoots, versions, reporter, annotationFileUpdater,
- artifactChanges, changesRegistry)
- .compile(allKotlinFiles, k2jvmArgs, compilerMessageCollector, { changedFiles })
+ val compiler = IncrementalJvmCompilerRunner(workingDir, javaSourceRoots, versions,
+ reporter, annotationFileUpdater,
+ artifactChanges, changesRegistry,
+ buildHistoryFile = incrementalCompilationOptions.resultDifferenceFile,
+ friendBuildHistoryFile = incrementalCompilationOptions.friendDifferenceFile)
+ return compiler.compile(allKotlinFiles, k2jvmArgs, compilerMessageCollector, { changedFiles })
}
override fun leaseReplSession(
diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt
index 10e21f38a3f..e35f34d070c 100644
--- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt
+++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt
@@ -22,9 +22,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
-import org.jetbrains.org.objectweb.asm.AnnotationVisitor
-import org.jetbrains.org.objectweb.asm.MethodVisitor
-import org.jetbrains.org.objectweb.asm.Type
+import org.jetbrains.org.objectweb.asm.*
import java.lang.reflect.Array
internal class AnnotationsCollectorMethodVisitor(
@@ -55,6 +53,27 @@ internal class AnnotationsCollectorMethodVisitor(
return BinaryJavaAnnotation.addAnnotation(annotations, desc, context, signatureParser)
}
+
+ override fun visitTypeAnnotation(typeRef: Int, typePath: TypePath?, desc: String, visible: Boolean): AnnotationVisitor? {
+ // TODO: support annotations on type arguments
+ if (typePath != null) return null
+
+ val typeReference = TypeReference(typeRef)
+
+ return when (typeReference.sort) {
+ TypeReference.METHOD_RETURN -> member.safeAs()?.returnType?.let {
+ BinaryJavaAnnotation.addTypeAnnotation(it, desc, context, signatureParser)
+ }
+
+ TypeReference.METHOD_FORMAL_PARAMETER ->
+ BinaryJavaAnnotation.addTypeAnnotation(
+ member.valueParameters[typeReference.formalParameterIndex].type,
+ desc, context, signatureParser
+ )
+
+ else -> null
+ }
+ }
}
class BinaryJavaAnnotation private constructor(
@@ -87,6 +106,20 @@ class BinaryJavaAnnotation private constructor(
return annotationVisitor
}
+
+ fun addTypeAnnotation(
+ type: JavaType,
+ desc: String,
+ context: ClassifierResolutionContext,
+ signatureParser: BinaryClassSignatureParser
+ ): AnnotationVisitor? {
+ type as? PlainJavaClassifierType ?: return null
+
+ val (javaAnnotation, annotationVisitor) = createAnnotationAndVisitor(desc, context, signatureParser)
+ type.addAnnotation(javaAnnotation)
+
+ return annotationVisitor
+ }
}
private val classifierResolutionResult by lazy(LazyThreadSafetyMode.NONE) {
diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/BinaryJavaClass.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/BinaryJavaClass.kt
index e5335c657f9..2dbcc1bb1bd 100644
--- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/BinaryJavaClass.kt
+++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/BinaryJavaClass.kt
@@ -162,6 +162,12 @@ class BinaryJavaClass(
object : FieldVisitor(ASM_API_VERSION_FOR_CLASS_READING) {
override fun visitAnnotation(desc: String, visible: Boolean) =
BinaryJavaAnnotation.addAnnotation(this@run.annotations, desc, context, signatureParser)
+
+ override fun visitTypeAnnotation(typeRef: Int, typePath: TypePath?, desc: String, visible: Boolean) =
+ if (typePath == null)
+ BinaryJavaAnnotation.addTypeAnnotation(type, desc, context, signatureParser)
+ else
+ null
}
}
}
diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Types.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Types.kt
index 609011c2b17..47542d57c07 100644
--- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Types.kt
+++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Types.kt
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.load.java.structure.impl.classFiles
+import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.FqName
@@ -39,9 +40,18 @@ internal class PlainJavaClassifierType(
get() = typeArguments.isEmpty() &&
classifierResolverResult.classifier?.safeAs()?.typeParameters?.isNotEmpty() == true
- // TODO: support type annotations
- override val annotations get() = emptyList()
- override fun findAnnotation(fqName: FqName) = null
+ private var _annotations = emptyList()
+ override val annotations get() = _annotations
+
+ override fun findAnnotation(fqName: FqName) = annotations.find { it.classId?.asSingleFqName() == fqName }
+
+ internal fun addAnnotation(annotation: JavaAnnotation) {
+ if (_annotations.isEmpty()) {
+ _annotations = ContainerUtil.newSmartList()
+ }
+
+ (_annotations as MutableList).add(annotation)
+ }
override val isDeprecatedInJavaDoc get() = false
diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/modules/JavaModule.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/modules/JavaModule.kt
index 3d183abb2aa..50b6a23efa8 100644
--- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/modules/JavaModule.kt
+++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/modules/JavaModule.kt
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.resolve.jvm.modules
+import com.intellij.ide.highlighter.JavaFileType
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.name.FqName
@@ -28,11 +29,11 @@ interface JavaModule {
val name: String
/**
- * A directory or the root of a .jar file on the module path. Can also be the path to the `module-info.java` file if that path
- * was passed as an explicit argument to the compiler.
- * In case of an explicit module, module-info.class file can be found in its children.
+ * A non-empty list of directories or roots of .jar files on the module path. Can also contain the path to the `module-info.java` file
+ * if that path was passed as an explicit argument to the compiler.
+ * In case of an explicit module, module-info.class or module-info.java file must exist in at least one of these roots (the first wins).
*/
- val moduleRoot: VirtualFile
+ val moduleRoots: List
/**
* A module-info.class or module-info.java file where this module was loaded from.
@@ -40,10 +41,11 @@ interface JavaModule {
val moduleInfoFile: VirtualFile?
/**
- * `true` if this module is either an automatic module on the module path, or an explicit module loaded from module-info.class.
- * `false` if this module is an explicit module loaded from module-info.java.
+ * `true` if this module is an explicit module loaded from module-info.java, `false` otherwise. This usually corresponds to the module
+ * currently being compiled.
+ * Note that in case of partial/incremental compilation, the source module may contain both binary roots and non-binary roots.
*/
- val isBinary: Boolean
+ val isSourceModule: Boolean
/**
* `true` if this module exports the package with the given FQ name to all dependent modules.
@@ -64,10 +66,12 @@ interface JavaModule {
*/
fun exportsTo(packageFqName: FqName, moduleName: String): Boolean
- class Automatic(override val name: String, override val moduleRoot: VirtualFile) : JavaModule {
+ data class Root(val file: VirtualFile, val isBinary: Boolean)
+
+ class Automatic(override val name: String, override val moduleRoots: List) : JavaModule {
override val moduleInfoFile: VirtualFile? get() = null
- override val isBinary: Boolean get() = true
+ override val isSourceModule: Boolean get() = false
override fun exports(packageFqName: FqName): Boolean = true
@@ -78,13 +82,15 @@ interface JavaModule {
class Explicit(
val moduleInfo: JavaModuleInfo,
- override val moduleRoot: VirtualFile,
- override val moduleInfoFile: VirtualFile,
- override val isBinary: Boolean
+ override val moduleRoots: List,
+ override val moduleInfoFile: VirtualFile
) : JavaModule {
override val name: String
get() = moduleInfo.moduleName
+ override val isSourceModule: Boolean
+ get() = moduleInfoFile.fileType == JavaFileType.INSTANCE
+
override fun exports(packageFqName: FqName): Boolean {
return moduleInfo.exports.any { (fqName, toModules) ->
fqName == packageFqName && toModules.isEmpty()
@@ -100,3 +106,5 @@ interface JavaModule {
override fun toString(): String = name
}
}
+
+const val KOTLIN_STDLIB_MODULE_NAME = "kotlin.stdlib"
\ No newline at end of file
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt
index c3c58e723a9..59de04c2c84 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt
@@ -118,7 +118,6 @@ class ResolverForProjectImpl(
moduleDescriptor.setDependencies(LazyModuleDependencies(
projectContext.storageManager,
module,
- modulePlatforms,
firstDependency,
this))
@@ -270,7 +269,6 @@ abstract class AnalyzerFacade {
class LazyModuleDependencies(
storageManager: StorageManager,
private val module: M,
- modulePlatforms: (M) -> MultiTargetPlatform?,
firstDependency: M? = null,
private val resolverForProject: ResolverForProjectImpl
) : ModuleDependencies {
@@ -292,14 +290,6 @@ class LazyModuleDependencies(
}.toList()
}
- private val implementingModules = storageManager.createLazyValue {
- if (modulePlatforms(module) != MultiTargetPlatform.Common) emptySet()
- else resolverForProject.modules
- .filterTo(mutableSetOf()) {
- modulePlatforms(it) != MultiTargetPlatform.Common && module in it.dependencies()
- }
- }
-
override val allDependencies: List get() = dependencies()
override val modulesWhoseInternalsAreVisible: Set
@@ -308,8 +298,6 @@ class LazyModuleDependencies(
resolverForProject.descriptorForModule(it as M)
}
- override val allImplementingModules: Set
- get() = implementingModules().mapTo(mutableSetOf()) { resolverForProject.descriptorForModule(it) }
}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInfo.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInfo.kt
index b894cf2dfb8..7e129c3e3a4 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInfo.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInfo.kt
@@ -22,10 +22,10 @@ import org.jetbrains.kotlin.descriptors.VariableDescriptor
typealias ImmutableMap = javaslang.collection.Map
typealias ImmutableHashMap = javaslang.collection.HashMap
-abstract class ControlFlowInfo, D>
+abstract class ControlFlowInfo, D : Any>
internal constructor(
protected val map: ImmutableMap = ImmutableHashMap.empty()
-) : ImmutableMap by map {
+) : ImmutableMap by map, ReadOnlyControlFlowInfo {
abstract protected fun copy(newMap: ImmutableMap): S
override fun put(key: VariableDescriptor, value: D): S = put(key, value, this[key].getOrElse(null as D?))
@@ -41,6 +41,9 @@ internal constructor(
return copy(map.put(key, value))
}
+ override fun getOrNull(variableDescriptor: VariableDescriptor): D? = this[variableDescriptor].getOrElse(null as D?)
+ override fun asMap() = this
+
fun retainAll(predicate: (VariableDescriptor) -> Boolean): S = copy(map.removeAll(map.keySet().filterNot(predicate)))
override fun equals(other: Any?) = map == (other as? ControlFlowInfo<*, *>)?.map
@@ -53,16 +56,26 @@ internal constructor(
operator fun Tuple2.component1(): T = _1()
operator fun Tuple2<*, T>.component2(): T = _2()
-fun ImmutableMap.getOrNull(k: K): V? = this[k].getOrElse(null as V?)
+interface ReadOnlyControlFlowInfo {
+ fun getOrNull(variableDescriptor: VariableDescriptor): D?
+ // Only used in tests
+ fun asMap(): ImmutableMap
+}
+
+interface ReadOnlyInitControlFlowInfo : ReadOnlyControlFlowInfo {
+ fun checkDefiniteInitializationInWhen(merge: ReadOnlyInitControlFlowInfo): Boolean
+}
+
+typealias ReadOnlyUseControlFlowInfo = ReadOnlyControlFlowInfo
class InitControlFlowInfo(map: ImmutableMap = ImmutableHashMap.empty()) :
- ControlFlowInfo(map) {
+ ControlFlowInfo(map), ReadOnlyInitControlFlowInfo {
override fun copy(newMap: ImmutableMap) = InitControlFlowInfo(newMap)
// this = output of EXHAUSTIVE_WHEN_ELSE instruction
// merge = input of MergeInstruction
// returns true if definite initialization in when happens here
- fun checkDefiniteInitializationInWhen(merge: InitControlFlowInfo): Boolean {
+ override fun checkDefiniteInitializationInWhen(merge: ReadOnlyInitControlFlowInfo): Boolean {
for ((key, value) in iterator()) {
if (value.initState == InitState.INITIALIZED_EXHAUSTIVELY &&
merge.getOrNull(key)?.initState == InitState.INITIALIZED) {
@@ -74,7 +87,7 @@ class InitControlFlowInfo(map: ImmutableMap = ImmutableHashMap.empty()) :
- ControlFlowInfo(map) {
+ ControlFlowInfo(map), ReadOnlyUseControlFlowInfo {
override fun copy(newMap: ImmutableMap) = UseControlFlowInfo(newMap)
}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt
index 43c0516c842..94af80a4eb0 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt
@@ -274,8 +274,8 @@ class ControlFlowInformationProvider private constructor(
pseudocode.traverse(TraversalOrder.FORWARD, initializers) {
instruction: Instruction,
- enterData: ImmutableMap,
- exitData: ImmutableMap ->
+ enterData: ReadOnlyInitControlFlowInfo,
+ exitData: ReadOnlyInitControlFlowInfo ->
val ctxt = VariableInitContext(instruction, reportedDiagnosticMap, enterData, exitData, blockScopeVariableInfo)
if (ctxt.variableDescriptor == null) return@traverse
@@ -486,18 +486,21 @@ class ControlFlowInformationProvider private constructor(
}
private fun checkAssignmentBeforeDeclaration(ctxt: VariableInitContext, expression: KtExpression) =
- if (ctxt.enterInitState?.isDeclared == true
- || ctxt.exitInitState?.isDeclared == true
- || ctxt.enterInitState?.mayBeInitialized() == true
- || ctxt.exitInitState?.mayBeInitialized() != true) {
- false
- }
- else {
+ if (ctxt.isInitializationBeforeDeclaration()) {
if (ctxt.variableDescriptor != null) {
report(Errors.INITIALIZATION_BEFORE_DECLARATION.on(expression, ctxt.variableDescriptor), ctxt)
}
true
}
+ else {
+ false
+ }
+
+ private fun VariableInitContext.isInitializationBeforeDeclaration(): Boolean =
+ // is not declared
+ enterInitState?.isDeclared != true && exitInitState?.isDeclared != true &&
+ // wasn't initialized before current instruction
+ enterInitState?.mayBeInitialized() != true
private fun checkInitializationForCustomSetter(ctxt: VariableInitContext, expression: KtExpression): Boolean {
val variableDescriptor = ctxt.variableDescriptor
@@ -532,7 +535,7 @@ class ControlFlowInformationProvider private constructor(
private fun recordInitializedVariables(
pseudocode: Pseudocode,
- initializersMap: Map>
+ initializersMap: Map>
) {
val initializers = initializersMap[pseudocode.exitInstruction] ?: return
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, false)
@@ -554,8 +557,8 @@ class ControlFlowInformationProvider private constructor(
val usedValueExpressions = hashSetOf()
pseudocode.traverse(TraversalOrder.BACKWARD, variableStatusData) {
instruction: Instruction,
- enterData: ImmutableMap,
- _: ImmutableMap ->
+ enterData: ReadOnlyUseControlFlowInfo,
+ _: ReadOnlyUseControlFlowInfo ->
val ctxt = VariableUseContext(instruction, reportedDiagnosticMap)
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.owner, false)
@@ -1030,8 +1033,8 @@ class ControlFlowInformationProvider private constructor(
private inner class VariableInitContext(
instruction: Instruction,
map: MutableMap>,
- `in`: ImmutableMap,
- out: ImmutableMap,
+ `in`: ReadOnlyInitControlFlowInfo,
+ out: ReadOnlyInitControlFlowInfo,
blockScopeVariableInfo: BlockScopeVariableInfo
) : VariableContext(instruction, map) {
internal val enterInitState = initialize(variableDescriptor, blockScopeVariableInfo, `in`)
@@ -1040,7 +1043,7 @@ class ControlFlowInformationProvider private constructor(
private fun initialize(
variableDescriptor: VariableDescriptor?,
blockScopeVariableInfo: BlockScopeVariableInfo,
- map: ImmutableMap
+ map: ReadOnlyInitControlFlowInfo
): VariableControlFlowState? {
val state = map.getOrNull(variableDescriptor ?: return null)
if (state != null) return state
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/PseudocodeVariablesData.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/PseudocodeVariablesData.kt
index 03765764cfa..50c804c5f09 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/PseudocodeVariablesData.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/PseudocodeVariablesData.kt
@@ -26,67 +26,128 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.WriteValueInstructi
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.VariableDeclarationInstruction
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.Edges
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder
+import org.jetbrains.kotlin.cfg.pseudocodeTraverser.traverse
+import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
-import org.jetbrains.kotlin.psi.KtProperty
+import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContextUtils.variableDescriptorForDeclaration
-import java.util.*
+import org.jetbrains.kotlin.utils.addToStdlib.safeAs
+
+private typealias ImmutableSet = javaslang.collection.Set
+private typealias ImmutableHashSet = javaslang.collection.HashSet
class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingContext: BindingContext) {
+ private val containsDoWhile = pseudocode.rootPseudocode.containsDoWhile
private val pseudocodeVariableDataCollector = PseudocodeVariableDataCollector(bindingContext, pseudocode)
- private val declaredVariablesForDeclaration = hashMapOf>()
+ private class VariablesForDeclaration(
+ val valsWithTrivialInitializer: Set,
+ val nonTrivialVariables: Set
+ ) {
+ val allVars =
+ if (nonTrivialVariables.isEmpty())
+ valsWithTrivialInitializer
+ else
+ LinkedHashSet(valsWithTrivialInitializer).also { it.addAll(nonTrivialVariables) }
+ }
- val variableInitializers: Map> by lazy {
+ private val declaredVariablesForDeclaration = hashMapOf()
+ private val rootVariables by lazy(LazyThreadSafetyMode.NONE) {
+ getAllDeclaredVariables(pseudocode, includeInsideLocalDeclarations = true)
+ }
+
+ val variableInitializers: Map> by lazy {
computeVariableInitializers()
}
val blockScopeVariableInfo: BlockScopeVariableInfo
get() = pseudocodeVariableDataCollector.blockScopeVariableInfo
- fun getDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): Set {
+ fun getDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): Set =
+ getAllDeclaredVariables(pseudocode, includeInsideLocalDeclarations).allVars
+
+ fun isVariableWithTrivialInitializer(variableDescriptor: VariableDescriptor) =
+ variableDescriptor in rootVariables.valsWithTrivialInitializer
+
+ private fun getAllDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): VariablesForDeclaration {
if (!includeInsideLocalDeclarations) {
return getUpperLevelDeclaredVariables(pseudocode)
}
- val declaredVariables = linkedSetOf()
- declaredVariables.addAll(getUpperLevelDeclaredVariables(pseudocode))
+ val nonTrivialVariables = linkedSetOf()
+ val valsWithTrivialInitializer = linkedSetOf()
+ addVariablesFromPseudocode(pseudocode, nonTrivialVariables, valsWithTrivialInitializer)
for (localFunctionDeclarationInstruction in pseudocode.localDeclarations) {
val localPseudocode = localFunctionDeclarationInstruction.body
- declaredVariables.addAll(getUpperLevelDeclaredVariables(localPseudocode))
+ addVariablesFromPseudocode(localPseudocode, nonTrivialVariables, valsWithTrivialInitializer)
}
- return declaredVariables
+ return VariablesForDeclaration(valsWithTrivialInitializer, nonTrivialVariables)
}
- private fun getUpperLevelDeclaredVariables(pseudocode: Pseudocode): Set {
- var declaredVariables = declaredVariablesForDeclaration[pseudocode]
- if (declaredVariables == null) {
- declaredVariables = computeDeclaredVariablesForPseudocode(pseudocode)
- declaredVariablesForDeclaration.put(pseudocode, declaredVariables)
+ private fun addVariablesFromPseudocode(
+ pseudocode: Pseudocode,
+ nonTrivialVariables: MutableSet,
+ valsWithTrivialInitializer: MutableSet
+ ) {
+ getUpperLevelDeclaredVariables(pseudocode).let {
+ nonTrivialVariables.addAll(it.nonTrivialVariables)
+ valsWithTrivialInitializer.addAll(it.valsWithTrivialInitializer)
}
- return declaredVariables
}
- private fun computeDeclaredVariablesForPseudocode(pseudocode: Pseudocode): Set {
- val declaredVariables = linkedSetOf()
+ private fun getUpperLevelDeclaredVariables(pseudocode: Pseudocode) = declaredVariablesForDeclaration.getOrPut(pseudocode) {
+ computeDeclaredVariablesForPseudocode(pseudocode)
+ }
+
+ private fun computeDeclaredVariablesForPseudocode(pseudocode: Pseudocode): VariablesForDeclaration {
+ val valsWithTrivialInitializer = linkedSetOf()
+ val nonTrivialVariables = linkedSetOf()
for (instruction in pseudocode.instructions) {
if (instruction is VariableDeclarationInstruction) {
val variableDeclarationElement = instruction.variableDeclarationElement
- val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement)
- variableDescriptorForDeclaration(descriptor)?.let {
- declaredVariables.add(it)
+ val descriptor =
+ variableDescriptorForDeclaration(
+ bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement)
+ ) ?: continue
+
+ if (!containsDoWhile && isValWithTrivialInitializer(variableDeclarationElement, descriptor)) {
+ valsWithTrivialInitializer.add(descriptor)
+ }
+ else {
+ nonTrivialVariables.add(descriptor)
}
}
}
- return Collections.unmodifiableSet(declaredVariables)
+
+ return VariablesForDeclaration(valsWithTrivialInitializer, nonTrivialVariables)
+ }
+
+ private fun isValWithTrivialInitializer(variableDeclarationElement: KtDeclaration, descriptor: VariableDescriptor) =
+ variableDeclarationElement is KtParameter || variableDeclarationElement is KtObjectDeclaration ||
+ variableDeclarationElement.safeAs()?.isVariableWithTrivialInitializer(descriptor) == true
+
+ private fun KtVariableDeclaration.isVariableWithTrivialInitializer(descriptor: VariableDescriptor): Boolean {
+ if (descriptor.isPropertyWithoutBackingField()) return true
+ if (isVar) return false
+ return initializer != null || safeAs()?.delegate != null || this is KtDestructuringDeclarationEntry
+ }
+
+ private fun VariableDescriptor.isPropertyWithoutBackingField(): Boolean {
+ if (this !is PropertyDescriptor) return false
+ return bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, this) != true
}
// variable initializers
- private fun computeVariableInitializers(): Map> {
+ private fun computeVariableInitializers(): Map> {
val blockScopeVariableInfo = pseudocodeVariableDataCollector.blockScopeVariableInfo
+ val resultForValsWithTrivialInitializer = computeInitInfoForTrivialVals()
+
+ if (rootVariables.nonTrivialVariables.isEmpty()) return resultForValsWithTrivialInitializer
+
return pseudocodeVariableDataCollector.collectData(TraversalOrder.FORWARD, InitControlFlowInfo()) {
instruction: Instruction, incomingEdgesData: Collection ->
@@ -94,6 +155,88 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
val exitInstructionData = addVariableInitStateFromCurrentInstructionIfAny(
instruction, enterInstructionData, blockScopeVariableInfo)
Edges(enterInstructionData, exitInstructionData)
+ }.mapValues {
+ (instruction, edges) ->
+ val trivialEdges = resultForValsWithTrivialInitializer[instruction]!!
+ Edges(trivialEdges.incoming.replaceDelegate(edges.incoming), trivialEdges.outgoing.replaceDelegate(edges.outgoing))
+ }
+ }
+
+ private fun computeInitInfoForTrivialVals(): Map> {
+ val result = hashMapOf>()
+ var declaredSet = ImmutableHashSet.empty()
+ var initSet = ImmutableHashSet.empty()
+ pseudocode.traverse(TraversalOrder.FORWARD) { instruction ->
+ val enterState = ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, null)
+ when (instruction) {
+ is VariableDeclarationInstruction ->
+ extractValWithTrivialInitializer(instruction)?.let {
+ variableDescriptor ->
+ declaredSet = declaredSet.add(variableDescriptor)
+ }
+ is WriteValueInstruction -> {
+ val variableDescriptor = extractValWithTrivialInitializer(instruction)
+ if (variableDescriptor != null && instruction.isTrivialInitializer()) {
+ initSet = initSet.add(variableDescriptor)
+ }
+ }
+ }
+
+ val afterState = ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, null)
+
+ result[instruction] = Edges(enterState, afterState)
+ }
+ return result
+ }
+
+ private fun WriteValueInstruction.isTrivialInitializer() =
+ element is KtVariableDeclaration || element is KtParameter
+
+ private inner class ReadOnlyInitControlFlowInfoImpl(
+ val declaredSet: ImmutableSet,
+ val initSet: ImmutableSet,
+ private val delegate: ReadOnlyInitControlFlowInfo?
+ ) : ReadOnlyInitControlFlowInfo {
+ override fun getOrNull(variableDescriptor: VariableDescriptor): VariableControlFlowState? {
+ if (variableDescriptor in declaredSet) {
+ return VariableControlFlowState.create(isInitialized = variableDescriptor in initSet, isDeclared = true)
+ }
+ return delegate?.getOrNull(variableDescriptor)
+ }
+
+ override fun checkDefiniteInitializationInWhen(merge: ReadOnlyInitControlFlowInfo): Boolean =
+ delegate?.checkDefiniteInitializationInWhen(merge) ?: false
+
+ fun replaceDelegate(newDelegate: ReadOnlyInitControlFlowInfo): ReadOnlyInitControlFlowInfo =
+ ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, newDelegate)
+
+ override fun asMap(): ImmutableMap {
+ val initial = delegate?.asMap() ?: ImmutableHashMap.empty()
+
+ return declaredSet.fold(initial) {
+ acc, variableDescriptor ->
+ acc.put(variableDescriptor, getOrNull(variableDescriptor)!!)
+ }
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as ReadOnlyInitControlFlowInfoImpl
+
+ if (declaredSet != other.declaredSet) return false
+ if (initSet != other.initSet) return false
+ if (delegate != other.delegate) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = declaredSet.hashCode()
+ result = 31 * result + initSet.hashCode()
+ result = 31 * result + (delegate?.hashCode() ?: 0)
+ return result
}
}
@@ -115,7 +258,10 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
if (instruction !is WriteValueInstruction && instruction !is VariableDeclarationInstruction) {
return enterInstructionData
}
- val variable = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext) ?: return enterInstructionData
+ val variable =
+ PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext)
+ ?.takeIf { it in rootVariables.nonTrivialVariables }
+ ?: return enterInstructionData
var exitInstructionData = enterInstructionData
if (instruction is WriteValueInstruction) {
// if writing to already initialized object
@@ -129,10 +275,10 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
}
else {
// instruction instanceof VariableDeclarationInstruction
- var enterInitState: VariableControlFlowState? = enterInstructionData.getOrNull(variable)
- if (enterInitState == null) {
- enterInitState = getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo)
- }
+ val enterInitState =
+ enterInstructionData.getOrNull(variable)
+ ?: getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo)
+
if (!enterInitState.mayBeInitialized() || !enterInitState.isDeclared) {
val variableDeclarationInfo = VariableControlFlowState.create(enterInitState.initState, isDeclared = true)
exitInstructionData = exitInstructionData.put(variable, variableDeclarationInfo, enterInitState)
@@ -143,46 +289,128 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
// variable use
- val variableUseStatusData: Map>
- get() = pseudocodeVariableDataCollector.collectData(TraversalOrder.BACKWARD, UseControlFlowInfo()) {
- instruction: Instruction, incomingEdgesData: Collection ->
+ val variableUseStatusData: Map>
+ get() {
+ val resultForTrivialVals = computeUseInfoForTrivialVals()
+ if (rootVariables.nonTrivialVariables.isEmpty()) return resultForTrivialVals
- val enterResult: UseControlFlowInfo = if (incomingEdgesData.size == 1) {
- incomingEdgesData.single()
- }
- else {
- incomingEdgesData.fold(UseControlFlowInfo()) { result, edgeData ->
- edgeData.iterator().fold(result) { subResult, (variableDescriptor, variableUseState) ->
- subResult.put(variableDescriptor, variableUseState.merge(subResult.getOrNull(variableDescriptor)))
+ return pseudocodeVariableDataCollector.collectData(TraversalOrder.BACKWARD, UseControlFlowInfo()) { instruction: Instruction, incomingEdgesData: Collection ->
+
+ val enterResult: UseControlFlowInfo = if (incomingEdgesData.size == 1) {
+ incomingEdgesData.single()
+ }
+ else {
+ incomingEdgesData.fold(UseControlFlowInfo()) { result, edgeData ->
+ edgeData.iterator().fold(result) { subResult, (variableDescriptor, variableUseState) ->
+ subResult.put(variableDescriptor, variableUseState.merge(subResult.getOrNull(variableDescriptor)))
+ }
}
}
- }
- val variableDescriptor = PseudocodeUtil.extractVariableDescriptorFromReference(instruction, bindingContext)
- if (variableDescriptor == null || instruction !is ReadValueInstruction && instruction !is WriteValueInstruction) {
- Edges(enterResult, enterResult)
- }
- else {
- val exitResult =
- if (instruction is ReadValueInstruction) {
- enterResult.put(variableDescriptor, VariableUseState.READ)
- }
- else {
- var variableUseState: VariableUseState? = enterResult.getOrNull(variableDescriptor)
- if (variableUseState == null) {
- variableUseState = VariableUseState.UNUSED
- }
- when (variableUseState) {
- VariableUseState.UNUSED, VariableUseState.ONLY_WRITTEN_NEVER_READ ->
- enterResult.put(variableDescriptor, VariableUseState.ONLY_WRITTEN_NEVER_READ)
- VariableUseState.WRITTEN_AFTER_READ, VariableUseState.READ ->
- enterResult.put(variableDescriptor, VariableUseState.WRITTEN_AFTER_READ)
- }
- }
- Edges(enterResult, exitResult)
+ val variableDescriptor =
+ PseudocodeUtil.extractVariableDescriptorFromReference(instruction, bindingContext)
+ ?.takeIf { it in rootVariables.nonTrivialVariables }
+ if (variableDescriptor == null || instruction !is ReadValueInstruction && instruction !is WriteValueInstruction) {
+ Edges(enterResult, enterResult)
+ }
+ else {
+ val exitResult =
+ if (instruction is ReadValueInstruction) {
+ enterResult.put(variableDescriptor, VariableUseState.READ)
+ }
+ else {
+ var variableUseState: VariableUseState? = enterResult.getOrNull(variableDescriptor)
+ if (variableUseState == null) {
+ variableUseState = VariableUseState.UNUSED
+ }
+ when (variableUseState) {
+ VariableUseState.UNUSED, VariableUseState.ONLY_WRITTEN_NEVER_READ ->
+ enterResult.put(variableDescriptor, VariableUseState.ONLY_WRITTEN_NEVER_READ)
+ VariableUseState.WRITTEN_AFTER_READ, VariableUseState.READ ->
+ enterResult.put(variableDescriptor, VariableUseState.WRITTEN_AFTER_READ)
+ }
+ }
+ Edges(enterResult, exitResult)
+ }
+ }.mapValues {
+ (instruction, edges) ->
+ val edgeForTrivialVals = resultForTrivialVals[instruction]!!
+
+ Edges(
+ edgeForTrivialVals.incoming.replaceDelegate(edges.incoming),
+ edgeForTrivialVals.outgoing.replaceDelegate(edges.outgoing)
+ )
}
}
+ private fun computeUseInfoForTrivialVals(): Map> {
+ val used = hashSetOf()
+
+ pseudocode.traverse(TraversalOrder.FORWARD) { instruction ->
+ if (instruction is ReadValueInstruction) {
+ extractValWithTrivialInitializer(instruction)?.let {
+ used.add(it)
+ }
+ }
+ }
+
+ val constantUseInfo = ReadOnlyUseControlFlowInfoImpl(used, null)
+ val constantEdges = Edges(constantUseInfo, constantUseInfo)
+ val result = hashMapOf>()
+
+ pseudocode.traverse(TraversalOrder.FORWARD) { instruction ->
+ result[instruction] = constantEdges
+ }
+ return result
+ }
+
+ private fun extractValWithTrivialInitializer(instruction: Instruction): VariableDescriptor? {
+ return PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext)?.takeIf {
+ it in rootVariables.valsWithTrivialInitializer
+ }
+ }
+
+ private inner class ReadOnlyUseControlFlowInfoImpl(
+ val used: Set,
+ val delegate: ReadOnlyUseControlFlowInfo?
+ ) : ReadOnlyUseControlFlowInfo {
+ override fun getOrNull(variableDescriptor: VariableDescriptor): VariableUseState? {
+ if (variableDescriptor in used) return VariableUseState.READ
+ return delegate?.getOrNull(variableDescriptor)
+ }
+
+ fun replaceDelegate(newDelegate: ReadOnlyUseControlFlowInfo): ReadOnlyUseControlFlowInfo =
+ ReadOnlyUseControlFlowInfoImpl(used, newDelegate)
+
+ override fun asMap(): ImmutableMap {
+ val initial = delegate?.asMap() ?: ImmutableHashMap.empty()
+
+ return used.fold(initial) {
+ acc, variableDescriptor ->
+ acc.put(variableDescriptor, getOrNull(variableDescriptor)!!)
+ }
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as ReadOnlyUseControlFlowInfoImpl
+
+ if (used != other.used) return false
+ if (delegate != other.delegate) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = used.hashCode()
+ result = 31 * result + (delegate?.hashCode() ?: 0)
+ return result
+ }
+
+ }
+
companion object {
@JvmStatic
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/ControlFlowInstructionsGenerator.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/ControlFlowInstructionsGenerator.kt
index e86c81cc3a8..487edc5d865 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/ControlFlowInstructionsGenerator.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/ControlFlowInstructionsGenerator.kt
@@ -19,8 +19,8 @@ package org.jetbrains.kotlin.cfg.pseudocode
import com.intellij.util.containers.Stack
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.cfg.*
-import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.BlockScope
+import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.*
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
-
import java.util.*
class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
@@ -113,6 +112,10 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
override fun createUnboundLabel(name: String): Label = pseudocode.createLabel("L" + labelCount++, name)
override fun enterLoop(expression: KtLoopExpression): LoopInfo {
+ if (expression is KtDoWhileExpression) {
+ (pseudocode.rootPseudocode as PseudocodeImpl).containsDoWhile = true
+ }
+
val info = LoopInfo(
expression,
createUnboundLabel("loop entry point"),
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/Pseudocode.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/Pseudocode.kt
index b387e2360d6..7ab4903baf6 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/Pseudocode.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/Pseudocode.kt
@@ -45,6 +45,9 @@ interface Pseudocode {
val enterInstruction: SubroutineEnterInstruction
+ val containsDoWhile: Boolean
+ val rootPseudocode: Pseudocode
+
fun getElementValue(element: KtElement?): PseudoValue?
fun getValueElements(value: PseudoValue?): List
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeImpl.kt
index f3b53f2fde1..cb7972476cf 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeImpl.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeImpl.kt
@@ -77,6 +77,9 @@ class PseudocodeImpl(override val correspondingElement: KtElement) : Pseudocode
private var postPrecessed = false
+ override var containsDoWhile: Boolean = false
+ internal set
+
private fun getLocalDeclarations(pseudocode: Pseudocode): Set {
val localDeclarations = linkedSetOf()
for (instruction in (pseudocode as PseudocodeImpl).mutableInstructionList) {
@@ -88,7 +91,7 @@ class PseudocodeImpl(override val correspondingElement: KtElement) : Pseudocode
return localDeclarations
}
- val rootPseudocode: Pseudocode
+ override val rootPseudocode: Pseudocode
get() {
var parent = parent
while (parent != null) {
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java
index a00a3080871..93fdebaa290 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java
@@ -562,6 +562,9 @@ public interface Errors {
DiagnosticFactory0> EXPECTED_ENUM_CONSTRUCTOR = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0 EXPECTED_ENUM_ENTRY_WITH_BODY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0 EXPECTED_PROPERTY_INITIALIZER = DiagnosticFactory0.create(ERROR);
+ DiagnosticFactory0 EXPECTED_DELEGATED_PROPERTY = DiagnosticFactory0.create(ERROR);
+ DiagnosticFactory0 EXPECTED_LATEINIT_PROPERTY = DiagnosticFactory0.create(ERROR);
+ DiagnosticFactory0 SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0 ACTUAL_TYPE_ALIAS_NOT_TO_CLASS = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0
@@ -622,7 +625,8 @@ public interface Errors {
DiagnosticFactory1 MISSING_RECEIVER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0 NO_RECEIVER_ALLOWED = DiagnosticFactory0.create(ERROR);
- DiagnosticFactory0 ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM = DiagnosticFactory0.create(WARNING);
+ DiagnosticFactory1 ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION = DiagnosticFactory1.create(WARNING);
+ DiagnosticFactory0 ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION = DiagnosticFactory0.create(WARNING);
// Call resolution
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java
index 8895bd3b90b..3b82f8970ca 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java
@@ -270,13 +270,16 @@ public class DefaultErrorMessages {
MAP.put(EXPECTED_ENUM_CONSTRUCTOR, "Expected enum class cannot have a constructor");
MAP.put(EXPECTED_ENUM_ENTRY_WITH_BODY, "Expected enum entry cannot have a body");
MAP.put(EXPECTED_PROPERTY_INITIALIZER, "Expected property cannot have an initializer");
+ MAP.put(EXPECTED_DELEGATED_PROPERTY, "Expected property cannot be delegated");
+ MAP.put(EXPECTED_LATEINIT_PROPERTY, "Expected property cannot be lateinit");
+ MAP.put(SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS, "Expected classes cannot initialize supertypes");
MAP.put(ACTUAL_TYPE_ALIAS_NOT_TO_CLASS, "Right-hand side of actual type alias should be a class, not another type alias");
MAP.put(ACTUAL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE, "Aliased class should not have type parameters with declaration-site variance");
MAP.put(ACTUAL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE, "Right-hand side of actual type alias cannot contain use-site variance or star projections");
MAP.put(ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION, "Type arguments in the right-hand side of actual type alias should be its type parameters in the same order, e.g. 'actual typealias Foo = Bar'");
- MAP.put(NO_ACTUAL_FOR_EXPECT, "Expected {0} has no actual in module{1}{2}", DECLARATION_NAME_WITH_KIND,
+ MAP.put(NO_ACTUAL_FOR_EXPECT, "Expected {0} has no actual declaration in module{1}{2}", DECLARATION_NAME_WITH_KIND,
PLATFORM, PlatformIncompatibilityDiagnosticRenderer.TEXT);
MAP.put(ACTUAL_WITHOUT_EXPECT, "Actual {0} has no corresponding expected declaration{1}", DECLARATION_NAME_WITH_KIND,
PlatformIncompatibilityDiagnosticRenderer.TEXT);
@@ -553,8 +556,8 @@ public class DefaultErrorMessages {
MAP.put(MANY_CLASSES_IN_SUPERTYPE_LIST, "Only one class may appear in a supertype list");
MAP.put(SUPERTYPE_NOT_A_CLASS_OR_INTERFACE, "Only classes and interfaces may serve as supertypes");
MAP.put(SUPERTYPE_IS_EXTENSION_FUNCTION_TYPE, "Extension function type is not allowed as supertypes");
- MAP.put(SUPERTYPE_IS_SUSPEND_FUNCTION_TYPE, "Suspend function type is not allowed as supertypes");
MAP.put(SUPERTYPE_INITIALIZED_IN_INTERFACE, "Interfaces cannot initialize supertypes");
+ MAP.put(SUPERTYPE_IS_SUSPEND_FUNCTION_TYPE, "Suspend function type is not allowed as supertypes");
MAP.put(CLASS_IN_SUPERTYPE_FOR_ENUM, "Enum class cannot inherit from classes");
MAP.put(CONSTRUCTOR_IN_INTERFACE, "An interface may not have a constructor");
MAP.put(METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE, "An interface may not implement a method of 'Any'");
@@ -757,7 +760,8 @@ public class DefaultErrorMessages {
MAP.put(NO_VALUE_FOR_PARAMETER, "No value passed for parameter ''{0}''", NAME);
MAP.put(MISSING_RECEIVER, "A receiver of type {0} is required", RENDER_TYPE);
MAP.put(NO_RECEIVER_ALLOWED, "No receiver can be passed to this function or property");
- MAP.put(ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM, "Assigning single elements to varargs in named form is deprecated");
+ MAP.put(ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION, "Assigning single elements to varargs in named form is deprecated", TO_STRING);
+ MAP.put(ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION, "Assigning single elements to varargs in named form is deprecated");
MAP.put(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, "Cannot create an instance of an abstract class");
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/PlatformIncompatibilityDiagnosticRenderer.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/PlatformIncompatibilityDiagnosticRenderer.kt
index 3cf85f8c352..76f4f9fa43a 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/PlatformIncompatibilityDiagnosticRenderer.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/PlatformIncompatibilityDiagnosticRenderer.kt
@@ -101,7 +101,7 @@ private fun StringBuilder.renderIncompatibilityInformation(
if (incompatibility is Incompatible.ClassScopes) {
append(indent)
- append("No actuals are found for expected members listed below:")
+ append("No actual members are found for expected members listed below:")
mode.newLine(this)
renderIncompatibleClassScopes(incompatibility.unfulfilled, indent, context, mode)
}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtFile.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtFile.kt
index bada78df856..d8c6271c43d 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtFile.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtFile.kt
@@ -76,8 +76,18 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) :
return if (ast != null) ast.psi as KtPackageDirective else null
}
- val packageFqName: FqName
+ var packageFqName: FqName
get() = stub?.getPackageFqName() ?: packageFqNameByTree
+ set(value) {
+ val packageDirective = packageDirective
+ if (packageDirective != null) {
+ packageDirective.fqName = value
+ }
+ else {
+ val newPackageDirective = KtPsiFactory(this).createPackageDirectiveIfNeeded(value) ?: return
+ addAfter(newPackageDirective, null)
+ }
+ }
val packageFqNameByTree: FqName
get() = packageDirectiveByTree?.fqName ?: FqName.ROOT
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtNamedDeclarationNotStubbed.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtNamedDeclarationNotStubbed.java
index eeec6006d0e..78653833884 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtNamedDeclarationNotStubbed.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtNamedDeclarationNotStubbed.java
@@ -64,7 +64,10 @@ abstract class KtNamedDeclarationNotStubbed extends KtDeclarationImpl implements
@Override
public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
- return getNameIdentifier().replace(KtPsiFactory(this).createNameIdentifier(name));
+ PsiElement identifier = getNameIdentifier();
+ if (identifier == null) throw new IncorrectOperationException();
+
+ return identifier.replace(KtPsiFactory(this).createNameIdentifier(name));
}
@Override
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java
index 3409f30fc41..d04a00447b5 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java
@@ -530,11 +530,19 @@ public class KtPsiUtil {
return false;
}
- // '(x operator y)' case
- if (innerExpression instanceof KtBinaryExpression &&
- innerOperation != KtTokens.ELVIS &&
- isKeepBinaryExpressionParenthesized((KtBinaryExpression) innerExpression)) {
- return true;
+ if (innerExpression instanceof KtBinaryExpression) {
+ // '(x operator return [...]) operator ...' case
+ if (parentElement instanceof KtBinaryExpression) {
+ KtBinaryExpression innerBinary = (KtBinaryExpression) innerExpression;
+ if (innerBinary.getRight() instanceof KtReturnExpression) {
+ return true;
+ }
+ }
+ // '(x operator y)' case
+ if (innerOperation != KtTokens.ELVIS &&
+ isKeepBinaryExpressionParenthesized((KtBinaryExpression) innerExpression)) {
+ return true;
+ }
}
int innerPriority = getPriority(innerExpression);
@@ -846,7 +854,7 @@ public class KtPsiUtil {
return (KtElement) current;
}
}
- if (current instanceof KtDelegatedSuperTypeEntry) {
+ if (current instanceof KtDelegatedSuperTypeEntry || current instanceof KtSuperTypeCallEntry) {
PsiElement grandParent = current.getParent().getParent();
if (grandParent instanceof KtClassOrObject && !(grandParent.getParent() instanceof KtObjectLiteralExpression)) {
return (KtElement) grandParent;
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt
index ed8ac919e10..104e8a5e9a2 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt
@@ -460,7 +460,7 @@ fun KtExpression.getOutermostParenthesizerOrThis(): KtExpression {
fun PsiElement.isFunctionalExpression(): Boolean = this is KtNamedFunction && nameIdentifier == null
-private val BAD_NEIGHBOUR_FOR_SIMPLE_TEMPLATE_ENTRY_PATTERN = Regex("[a-zA-Z0-9_].*")
+private val BAD_NEIGHBOUR_FOR_SIMPLE_TEMPLATE_ENTRY_PATTERN = Regex("([a-zA-Z0-9_]|[^\\p{ASCII}]).*")
fun canPlaceAfterSimpleNameEntry(element: PsiElement?): Boolean {
val entryText = element?.text ?: return true
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/synthetics/SyntheticClassOrObjectDescriptor.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/synthetics/SyntheticClassOrObjectDescriptor.kt
index a567600436d..b1383c458dd 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/psi/synthetics/SyntheticClassOrObjectDescriptor.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/synthetics/SyntheticClassOrObjectDescriptor.kt
@@ -131,6 +131,7 @@ class SyntheticClassOrObjectDescriptor(
override fun getDestructuringDeclarationsEntries(name: Name): Collection = emptyList()
override fun getClassOrObjectDeclarations(name: Name): Collection = emptyList()
override fun getTypeAliasDeclarations(name: Name): Collection = emptyList()
+ override fun getDeclarationNames() = emptySet()
}
internal inner class SyntheticDeclaration(
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportScope.kt
index 8caf263706a..35aa948ec9c 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportScope.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportScope.kt
@@ -22,15 +22,17 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.BaseImportingScope
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
-import org.jetbrains.kotlin.resolve.scopes.ResolutionScope
+import org.jetbrains.kotlin.resolve.scopes.MemberScope
+import org.jetbrains.kotlin.resolve.scopes.computeAllNames
import org.jetbrains.kotlin.utils.Printer
+import org.jetbrains.kotlin.utils.addToStdlib.flatMapToNullable
class AllUnderImportScope(
descriptor: DeclarationDescriptor,
excludedImportNames: Collection
) : BaseImportingScope(null) {
- private val scopes: List = if (descriptor is ClassDescriptor) {
+ private val scopes: List = if (descriptor is ClassDescriptor) {
listOf(descriptor.staticScope, descriptor.unsubstitutedInnerClassesScope)
}
else {
@@ -49,6 +51,8 @@ class AllUnderImportScope(
excludedImportNames.mapNotNull { if (it.parent() == fqName) it.shortName() else null }.toSet()
}
+ override fun computeImportedNames(): Set? = scopes.flatMapToNullable(hashSetOf(), MemberScope::computeAllNames)
+
override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
@@ -82,6 +86,10 @@ class AllUnderImportScope(
return scopes.flatMap { it.getContributedFunctions(name, location) }
}
+ override fun recordLookup(name: Name, location: LookupLocation) {
+ scopes.forEach { it.recordLookup(name, location) }
+ }
+
override fun printStructure(p: Printer) {
p.println(this::class.java.simpleName)
}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java
index 302c2e8c239..93696ab7927 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java
@@ -316,6 +316,9 @@ public class BodyResolver {
if (descriptor.getKind() == ClassKind.INTERFACE) {
trace.report(SUPERTYPE_INITIALIZED_IN_INTERFACE.on(elementToMark));
}
+ if (descriptor.isExpect()) {
+ trace.report(SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS.on(elementToMark));
+ }
KtTypeReference typeReference = call.getTypeReference();
if (typeReference == null) return;
if (primaryConstructor == null) {
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt
index afd2ee357c1..a4319ae886b 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt
@@ -646,6 +646,9 @@ class DeclarationsChecker(
if (inInterface) {
trace.report(DELEGATED_PROPERTY_IN_INTERFACE.on(delegate))
}
+ else if (isExpect) {
+ trace.report(EXPECTED_DELEGATED_PROPERTY.on(delegate))
+ }
}
else {
val isUninitialized = trace.bindingContext.get(BindingContext.IS_UNINITIALIZED, propertyDescriptor) ?: false
@@ -667,9 +670,14 @@ class DeclarationsChecker(
else if (noExplicitTypeOrGetterType(property)) {
trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property))
}
- if (backingFieldRequired && !inInterface && propertyDescriptor.isLateInit && !isUninitialized &&
- trace[MUST_BE_LATEINIT, propertyDescriptor] != true) {
- trace.report(UNNECESSARY_LATEINIT.on(property))
+
+ if (propertyDescriptor.isLateInit) {
+ if (propertyDescriptor.isExpect) {
+ trace.report(EXPECTED_LATEINIT_PROPERTY.on(property.modifierList?.getModifier(KtTokens.LATEINIT_KEYWORD) ?: property))
+ }
+ if (backingFieldRequired && !inInterface && !isUninitialized && trace[MUST_BE_LATEINIT, propertyDescriptor] != true) {
+ trace.report(UNNECESSARY_LATEINIT.on(property))
+ }
}
}
}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyExplicitImportScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyExplicitImportScope.kt
index 49cc59a5544..e2f62db0519 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyExplicitImportScope.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyExplicitImportScope.kt
@@ -101,6 +101,8 @@ class LazyExplicitImportScope(
return descriptors
}
+ override fun computeImportedNames() = setOf(aliasName)
+
override fun printStructure(p: Printer) {
p.println(this::class.java.simpleName, ": ", aliasName)
}
@@ -148,4 +150,4 @@ class LazyExplicitImportScope(
private fun Collection.choseOnlyVisibleOrAll() =
filter { isVisible(it, packageFragmentForVisibilityCheck, position = QualifierPosition.IMPORT) }.
takeIf { it.isNotEmpty() } ?: this
-}
\ No newline at end of file
+}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt
index 639d0f03018..da56c794b89 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt
@@ -86,9 +86,9 @@ object ModifierCheckerCore {
CONST_KEYWORD to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY),
OPERATOR_KEYWORD to EnumSet.of(FUNCTION),
INFIX_KEYWORD to EnumSet.of(FUNCTION),
- HEADER_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY_WITHOUT_FIELD_OR_DELEGATE, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
+ HEADER_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
IMPL_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, MEMBER_FUNCTION, TOP_LEVEL_PROPERTY, MEMBER_PROPERTY, CONSTRUCTOR, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS, TYPEALIAS),
- EXPECT_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY_WITHOUT_FIELD_OR_DELEGATE, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
+ EXPECT_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
ACTUAL_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, MEMBER_FUNCTION, TOP_LEVEL_PROPERTY, MEMBER_PROPERTY, CONSTRUCTOR, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS, TYPEALIAS)
)
@@ -191,9 +191,6 @@ object ModifierCheckerCore {
// (see the KEEP https://github.com/Kotlin/KEEP/blob/master/proposals/sealed-class-inheritance.md)
result += incompatibilityRegister(SEALED_KEYWORD, INNER_KEYWORD)
- // lateinit is incompatible with header / expect
- result += incompatibilityRegister(LATEINIT_KEYWORD, HEADER_KEYWORD, EXPECT_KEYWORD)
-
// header / expect / impl / actual are all incompatible
result += incompatibilityRegister(HEADER_KEYWORD, EXPECT_KEYWORD, IMPL_KEYWORD, ACTUAL_KEYWORD)
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AssigningNamedArgumentToVarargChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AssigningNamedArgumentToVarargChecker.kt
index a42dfdcd479..5c71ff19f1f 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AssigningNamedArgumentToVarargChecker.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AssigningNamedArgumentToVarargChecker.kt
@@ -53,7 +53,7 @@ class AssigningNamedArgumentToVarargChecker : CallChecker {
checkAssignmentOfSingleElementInAnnotation(argument, argumentExpression, context)
}
else {
- checkAssignmentOfSingleElementInFunction(argument, argumentExpression, context)
+ checkAssignmentOfSingleElementInFunction(argument, argumentExpression, context, parameterDescriptor)
}
}
@@ -64,21 +64,22 @@ class AssigningNamedArgumentToVarargChecker : CallChecker {
) {
if (isArrayOrArrayLiteral(argument, context)) {
if (argument.hasSpread()) {
- context.trace.report(Errors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM.on(argumentExpression))
+ context.trace.report(Errors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION.on(argumentExpression))
}
}
else {
- context.trace.report(Errors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM.on(argumentExpression))
+ context.trace.report(Errors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION.on(argumentExpression))
}
}
private fun checkAssignmentOfSingleElementInFunction(
argument: ValueArgument,
argumentExpression: KtExpression,
- context: ResolutionContext<*>
+ context: ResolutionContext<*>,
+ parameterDescriptor: ValueParameterDescriptor
) {
if (!argument.hasSpread()) {
- context.trace.report(Errors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM.on(argumentExpression))
+ context.trace.report(Errors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION.on(argumentExpression, parameterDescriptor.type))
}
}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt
index 70e096bcf32..7a5f1174eba 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt
@@ -168,10 +168,10 @@ class NewResolutionOldInference(
val processor = kind.createTowerProcessor(this, nameToResolve, tracing, scopeTower, detailedReceiver, context)
if (context.collectAllCandidates) {
- return allCandidatesResult(towerResolver.collectAllCandidates(scopeTower, processor))
+ return allCandidatesResult(towerResolver.collectAllCandidates(scopeTower, processor, nameToResolve))
}
- var candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kind != ResolutionKind.CallableReference)
+ var candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kind != ResolutionKind.CallableReference, name = nameToResolve)
// Temporary hack to resolve 'rem' as 'mod' if the first is do not present
val emptyOrInapplicableCandidates = candidates.isEmpty() ||
@@ -179,7 +179,7 @@ class NewResolutionOldInference(
if (isBinaryRemOperator && shouldUseOperatorRem && emptyOrInapplicableCandidates) {
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name]
val processorForDeprecatedName = kind.createTowerProcessor(this, deprecatedName!!, tracing, scopeTower, detailedReceiver, context)
- candidates = towerResolver.runResolve(scopeTower, processorForDeprecatedName, useOrder = kind != ResolutionKind.CallableReference)
+ candidates = towerResolver.runResolve(scopeTower, processorForDeprecatedName, useOrder = kind != ResolutionKind.CallableReference, name = deprecatedName)
}
if (candidates.isEmpty()) {
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt
index 94c7c958e2e..35d78e8147a 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2016 JetBrains s.r.o.
+ * 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.
@@ -131,7 +131,9 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
if (!hasExpectedModifier) {
if (Compatible !in compatibility) return
- if (checkExpected) {
+ // we suppress error, because annotation classes can only have one constructor and it's a 100% boilerplate
+ // to require every annotation constructor with additional parameters with default values be marked with the `actual` modifier
+ if (checkExpected && !descriptor.isAnnotationConstructor()) {
diagnosticHolder.report(Errors.ACTUAL_MISSING.on(reportOn))
}
}
@@ -362,7 +364,9 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
val aParams = a.valueParameters
val bParams = b.valueParameters
- if (aParams.size != bParams.size) return Incompatible.ParameterCount
+ if (!valueParametersCountCompatible(a, b, aParams, bParams)) {
+ return Incompatible.ParameterCount
+ }
val aTypeParams = a.typeParameters
val bTypeParams = b.typeParameters
@@ -401,6 +405,23 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
return Compatible
}
+ private fun valueParametersCountCompatible(
+ a: CallableMemberDescriptor,
+ b: CallableMemberDescriptor,
+ aParams: List,
+ bParams: List
+ ): Boolean {
+ if (aParams.size == bParams.size) return true
+
+ return if (a.isAnnotationConstructor() && b.isAnnotationConstructor())
+ aParams.isEmpty() && bParams.all { it.declaresDefaultValue() }
+ else
+ false
+ }
+
+ private fun MemberDescriptor.isAnnotationConstructor(): Boolean =
+ this is ConstructorDescriptor && DescriptorUtils.isAnnotationClass(this.constructedClass)
+
private fun areCompatibleTypes(a: KotlinType?, b: KotlinType?, platformModule: ModuleDescriptor): Boolean {
if (a == null) return b == null
if (b == null) return false
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt
index 52ded343428..8900f6c419e 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt
@@ -27,10 +27,7 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtImportsFactory
import org.jetbrains.kotlin.resolve.*
-import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
-import org.jetbrains.kotlin.resolve.scopes.ImportingScope
-import org.jetbrains.kotlin.resolve.scopes.LexicalScope
-import org.jetbrains.kotlin.resolve.scopes.SubpackagesImportingScope
+import org.jetbrains.kotlin.resolve.scopes.*
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.kotlin.script.getScriptExternalDependencies
import org.jetbrains.kotlin.storage.StorageManager
@@ -68,6 +65,41 @@ class FileScopeFactory(
return FilesScopesBuilder(file, existingImports, packageFragment, packageView).result
}
+ private fun createDefaultImportResolvers(extraImports: Collection, aliasImportNames: Collection): Pair {
+ val tempTrace = TemporaryBindingTrace.create(bindingTrace, "Transient trace for default imports lazy resolve", false)
+ val allImplicitImports = defaultImports concat extraImports
+
+ val defaultImportsFiltered = if (aliasImportNames.isEmpty()) { // optimization
+ allImplicitImports
+ }
+ else {
+ allImplicitImports.filter { it.isAllUnder || it.importedFqName !in aliasImportNames }
+ }
+
+ val defaultExplicitImportResolver = createImportResolver(ExplicitImportsIndexed(defaultImportsFiltered), tempTrace, packageFragment = null, aliasImportNames = aliasImportNames)
+ val defaultAllUnderImportResolver =
+ createImportResolver(AllUnderImportsIndexed(defaultImportsFiltered), tempTrace, packageFragment = null, aliasImportNames = aliasImportNames, excludedImports = defaultImportProvider.excludedImports)
+
+ return defaultExplicitImportResolver to defaultAllUnderImportResolver
+ }
+
+ private val defaultImportResolvers by storageManager.createLazyValue {
+ createDefaultImportResolvers(emptyList(), emptyList())
+ }
+
+ private fun createImportResolver(
+ indexedImports: IndexedImports,
+ trace: BindingTrace,
+ aliasImportNames: Collection,
+ packageFragment: PackageFragmentDescriptor?,
+ excludedImports: List? = null
+ ) = LazyImportResolver(
+ storageManager, qualifiedExpressionResolver, moduleDescriptor, platformToKotlinClassMap, languageVersionSettings,
+ indexedImports, aliasImportNames concat excludedImports, trace, packageFragment,
+ deprecationResolver
+ )
+
+
private inner class FilesScopesBuilder(
private val file: KtFile,
private val existingImports: ImportingScope?,
@@ -77,8 +109,8 @@ class FileScopeFactory(
val imports = file.importDirectives
val aliasImportNames = imports.mapNotNull { if (it.aliasName != null) it.importedFqName else null }
- val explicitImportResolver = createImportResolver(ExplicitImportsIndexed(imports), bindingTrace)
- val allUnderImportResolver = createImportResolver(AllUnderImportsIndexed(imports), bindingTrace) // TODO: should we count excludedImports here also?
+ val explicitImportResolver = createImportResolver(ExplicitImportsIndexed(imports), bindingTrace, aliasImportNames, packageFragment)
+ val allUnderImportResolver = createImportResolver(AllUnderImportsIndexed(imports), bindingTrace, aliasImportNames, packageFragment) // TODO: should we count excludedImports here also?
val lazyImportingScope = object : ImportingScope by ImportingScope.Empty {
// avoid constructing the scope before we query it
@@ -107,33 +139,21 @@ class FileScopeFactory(
val result = FileScopes(lexicalScope, lazyImportingScope, importResolver)
- fun createImportResolver(indexedImports: IndexedImports, trace: BindingTrace, excludedImports: List? = null) =
- LazyImportResolver(
- storageManager, qualifiedExpressionResolver, moduleDescriptor, platformToKotlinClassMap, languageVersionSettings,
- indexedImports, aliasImportNames concat excludedImports, trace, packageFragment,
- deprecationResolver
- )
-
-
- fun createImportingScope(): LazyImportScope {
- val tempTrace = TemporaryBindingTrace.create(bindingTrace, "Transient trace for default imports lazy resolve", false)
-
+ private fun createDefaultImportResolversForFile(): Pair {
val extraImports = file.originalFile.virtualFile?.let { vFile ->
val scriptExternalDependencies = getScriptExternalDependencies(vFile, file.project)
ktImportsFactory.createImportDirectives(scriptExternalDependencies?.imports?.map { ImportPath.fromString(it) }.orEmpty())
+ }.orEmpty()
+
+ if (extraImports.isEmpty() && aliasImportNames.isEmpty()) {
+ return defaultImportResolvers
}
- val allImplicitImports = defaultImports concat extraImports
+ return createDefaultImportResolvers(extraImports, aliasImportNames)
+ }
- val defaultImportsFiltered = if (aliasImportNames.isEmpty()) { // optimization
- allImplicitImports
- }
- else {
- allImplicitImports.filter { it.isAllUnder || it.importedFqName !in aliasImportNames }
- }
-
- val defaultExplicitImportResolver = createImportResolver(ExplicitImportsIndexed(defaultImportsFiltered), tempTrace)
- val defaultAllUnderImportResolver = createImportResolver(AllUnderImportsIndexed(defaultImportsFiltered), tempTrace, defaultImportProvider.excludedImports)
+ fun createImportingScope(): LazyImportScope {
+ val (defaultExplicitImportResolver, defaultAllUnderImportResolver) = createDefaultImportResolversForFile()
val dummyContainerDescriptor = DummyContainerDescriptor(file, packageFragment)
@@ -164,8 +184,6 @@ class FileScopeFactory(
return LazyImportScope(scope, explicitImportResolver, LazyImportScope.FilteringKind.ALL, "Explicit imports in $debugName")
}
- private infix fun Collection.concat(other: Collection?) =
- if (other == null || other.isEmpty()) this else this + other
}
private enum class FilteringKind {
@@ -180,6 +198,7 @@ class FileScopeFactory(
parentScope: ImportingScope
): ImportingScope {
val scope = packageView.memberScope
+ val names by lazy(LazyThreadSafetyMode.PUBLICATION) { scope.computeAllNames () }
val packageName = packageView.fqName
val excludedNames = aliasImportNames.mapNotNull { if (it.parent() == packageName) it.shortName() else null }
@@ -220,6 +239,10 @@ class FileScopeFactory(
).filter { it !is PackageViewDescriptor } // subpackages of the current package not accessible by the short name
}
+ override fun computeImportedNames() = packageView.memberScope.computeAllNames()
+
+ override fun definitelyDoesNotContainName(name: Name) = names?.let { name !in it } == true
+
override fun toString() = "Scope for current package (${filteringKind.name})"
override fun printStructure(p: Printer) {
@@ -252,3 +275,6 @@ class FileScopeFactory(
}
}
}
+
+private infix fun Collection.concat(other: Collection?) =
+ if (other == null || other.isEmpty()) this else this + other
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyDeclarationResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyDeclarationResolver.java
deleted file mode 100644
index e8a0951552a..00000000000
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyDeclarationResolver.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * 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.resolve.lazy;
-
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.util.PsiTreeUtil;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.kotlin.context.GlobalContext;
-import org.jetbrains.kotlin.descriptors.*;
-import org.jetbrains.kotlin.incremental.KotlinLookupLocation;
-import org.jetbrains.kotlin.incremental.components.LookupLocation;
-import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
-import org.jetbrains.kotlin.name.FqName;
-import org.jetbrains.kotlin.name.Name;
-import org.jetbrains.kotlin.psi.*;
-import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
-import org.jetbrains.kotlin.renderer.DescriptorRenderer;
-import org.jetbrains.kotlin.resolve.BindingContext;
-import org.jetbrains.kotlin.resolve.BindingTrace;
-import org.jetbrains.kotlin.resolve.lazy.descriptors.AbstractLazyMemberScope;
-import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyPackageDescriptor;
-import org.jetbrains.kotlin.resolve.scopes.MemberScope;
-import org.jetbrains.kotlin.storage.LockBasedLazyResolveStorageManager;
-
-import javax.inject.Inject;
-import java.util.List;
-
-public class LazyDeclarationResolver {
-
- @NotNull private final TopLevelDescriptorProvider topLevelDescriptorProvider;
- @NotNull private final AbsentDescriptorHandler absentDescriptorHandler;
- @NotNull private final BindingTrace trace;
-
- protected DeclarationScopeProvider scopeProvider;
-
- // component dependency cycle
- @Inject
- public void setDeclarationScopeProvider(@NotNull DeclarationScopeProviderImpl scopeProvider) {
- this.scopeProvider = scopeProvider;
- }
-
- @Deprecated
- public LazyDeclarationResolver(
- @NotNull GlobalContext globalContext,
- @NotNull BindingTrace delegationTrace,
- @NotNull TopLevelDescriptorProvider topLevelDescriptorProvider,
- @NotNull AbsentDescriptorHandler absentDescriptorHandler
- ) {
- this.topLevelDescriptorProvider = topLevelDescriptorProvider;
- this.absentDescriptorHandler = absentDescriptorHandler;
- LockBasedLazyResolveStorageManager lockBasedLazyResolveStorageManager =
- new LockBasedLazyResolveStorageManager(globalContext.getStorageManager());
-
- this.trace = lockBasedLazyResolveStorageManager.createSafeTrace(delegationTrace);
- }
-
- @NotNull
- public ClassDescriptor getClassDescriptor(@NotNull KtClassOrObject classOrObject, @NotNull LookupLocation location) {
- return findClassDescriptor(classOrObject, location);
- }
-
- @NotNull
- public ScriptDescriptor getScriptDescriptor(@NotNull KtScript script, @NotNull LookupLocation location) {
- return (ScriptDescriptor) findClassDescriptor(script, location);
- }
-
- @NotNull
- private ClassDescriptor findClassDescriptor(
- @NotNull KtNamedDeclaration classObjectOrScript,
- @NotNull LookupLocation location
- ) {
- MemberScope scope = getMemberScopeDeclaredIn(classObjectOrScript, location);
-
- // Why not use the result here. Because it may be that there is a redeclaration:
- // class A {} class A { fun foo(): A}
- // and if we find the class by name only, we may b-not get the right one.
- // This call is only needed to make sure the classes are written to trace
- ClassifierDescriptor scopeDescriptor = scope.getContributedClassifier(classObjectOrScript.getNameAsSafeName(), location);
- DeclarationDescriptor descriptor = getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, classObjectOrScript);
-
- if (descriptor == null) {
- String providerInfoString = null;
- if (scope instanceof AbstractLazyMemberScope) {
- AbstractLazyMemberScope lazyMemberScope = (AbstractLazyMemberScope) scope;
- providerInfoString = lazyMemberScope.toProviderString();
- }
- throw new IllegalArgumentException(
- String.format(
- "Could not find a classifier for %s.\n" +
- "Found descriptor: %s (%s).\n" +
- "Scope: %s.\n" +
- "Provider: %s.",
- PsiUtilsKt.getElementTextWithContext(classObjectOrScript),
- scopeDescriptor != null ? DescriptorRenderer.DEBUG_TEXT.render(scopeDescriptor) : "null",
- scopeDescriptor != null ? (scopeDescriptor.getContainingDeclaration().getClass()) : null,
- scope,
- providerInfoString != null ? providerInfoString : "null"
- )
- );
- }
-
- return (ClassDescriptor) descriptor;
- }
-
- @NotNull
- private BindingContext getBindingContext() {
- return trace.getBindingContext();
- }
-
- @NotNull
- public DeclarationDescriptor resolveToDescriptor(@NotNull KtDeclaration declaration) {
- return resolveToDescriptor(declaration, /*track =*/true);
- }
-
- @NotNull
- private DeclarationDescriptor resolveToDescriptor(@NotNull KtDeclaration declaration, boolean track) {
- DeclarationDescriptor result = declaration.accept(new KtVisitor() {
- @NotNull
- private LookupLocation lookupLocationFor(@NotNull KtDeclaration declaration, boolean isTopLevel) {
- return isTopLevel && track ? new KotlinLookupLocation(declaration) : NoLookupLocation.WHEN_RESOLVE_DECLARATION;
- }
-
- @Override
- public DeclarationDescriptor visitClass(@NotNull KtClass klass, Void data) {
- return getClassDescriptor(klass, lookupLocationFor(klass, klass.isTopLevel()));
- }
-
- @Override
- public DeclarationDescriptor visitObjectDeclaration(@NotNull KtObjectDeclaration declaration, Void data) {
- return getClassDescriptor(declaration, lookupLocationFor(declaration, declaration.isTopLevel()));
- }
-
- @Override
- public DeclarationDescriptor visitTypeParameter(@NotNull KtTypeParameter parameter, Void data) {
- KtTypeParameterListOwner ownerElement = PsiTreeUtil.getParentOfType(parameter, KtTypeParameterListOwner.class);
- assert ownerElement != null : "Owner not found for type parameter: " + parameter.getText();
- DeclarationDescriptor ownerDescriptor = resolveToDescriptor(ownerElement, /*track =*/false);
-
- List typeParameters;
- if (ownerDescriptor instanceof CallableDescriptor) {
- CallableDescriptor callableDescriptor = (CallableDescriptor) ownerDescriptor;
- typeParameters = callableDescriptor.getTypeParameters();
- }
- else if (ownerDescriptor instanceof ClassifierDescriptorWithTypeParameters) {
- ClassifierDescriptorWithTypeParameters classifierDescriptor = (ClassifierDescriptorWithTypeParameters) ownerDescriptor;
- typeParameters = classifierDescriptor.getTypeConstructor().getParameters();
- }
- else {
- throw new IllegalStateException("Unknown owner kind for a type parameter: " + ownerDescriptor);
- }
-
- Name name = parameter.getNameAsSafeName();
- for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
- if (typeParameterDescriptor.getName().equals(name)) {
- return typeParameterDescriptor;
- }
- }
-
- throw new IllegalStateException("Type parameter " + name + " not found for " + ownerDescriptor);
- }
-
- @Override
- public DeclarationDescriptor visitNamedFunction(@NotNull KtNamedFunction function, Void data) {
- LookupLocation location = lookupLocationFor(function, function.isTopLevel());
- MemberScope scopeForDeclaration = getMemberScopeDeclaredIn(function, location);
- scopeForDeclaration.getContributedFunctions(function.getNameAsSafeName(), location);
- return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
- }
-
- @Override
- public DeclarationDescriptor visitParameter(@NotNull KtParameter parameter, Void data) {
- PsiElement grandFather = parameter.getParent().getParent();
- if (grandFather instanceof KtPrimaryConstructor) {
- KtClassOrObject jetClass = ((KtPrimaryConstructor) grandFather).getContainingClassOrObject();
- // This is a primary constructor parameter
- ClassDescriptor classDescriptor = getClassDescriptor(jetClass, lookupLocationFor(jetClass, false));
- if (parameter.hasValOrVar()) {
- classDescriptor.getDefaultType().getMemberScope().getContributedVariables(parameter.getNameAsSafeName(), lookupLocationFor(parameter, false));
- return getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
- }
- else {
- ConstructorDescriptor constructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
- assert constructor != null: "There are constructor parameters found, so a constructor should also exist";
- constructor.getValueParameters();
- return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
- }
- }
- else if (grandFather instanceof KtNamedFunction) {
- FunctionDescriptor function = (FunctionDescriptor) visitNamedFunction((KtNamedFunction) grandFather, data);
- function.getValueParameters();
- return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
- }
- else if (grandFather instanceof KtSecondaryConstructor) {
- ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) visitSecondaryConstructor(
- (KtSecondaryConstructor) grandFather, data
- );
- constructorDescriptor.getValueParameters();
- return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
- }
- else {
- //TODO: support parameters in accessors and other places(?)
- return super.visitParameter(parameter, data);
- }
- }
-
- @Override
- public DeclarationDescriptor visitSecondaryConstructor(@NotNull KtSecondaryConstructor constructor, Void data) {
- getClassDescriptor((KtClassOrObject) constructor.getParent().getParent(), lookupLocationFor(constructor, false)).getConstructors();
- return getBindingContext().get(BindingContext.CONSTRUCTOR, constructor);
- }
-
- @Override
- public DeclarationDescriptor visitPrimaryConstructor(@NotNull KtPrimaryConstructor constructor, Void data) {
- getClassDescriptor(constructor.getContainingClassOrObject(), lookupLocationFor(constructor, false)).getConstructors();
- return getBindingContext().get(BindingContext.CONSTRUCTOR, constructor);
- }
-
- @Override
- public DeclarationDescriptor visitProperty(@NotNull KtProperty property, Void data) {
- LookupLocation location = lookupLocationFor(property, property.isTopLevel());
- MemberScope scopeForDeclaration = getMemberScopeDeclaredIn(property, location);
- scopeForDeclaration.getContributedVariables(property.getNameAsSafeName(), location);
- return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, property);
- }
-
- @Override
- public DeclarationDescriptor visitDestructuringDeclarationEntry(
- @NotNull KtDestructuringDeclarationEntry destructuringDeclarationEntry, Void data
- ) {
- LookupLocation location = lookupLocationFor(destructuringDeclarationEntry, false);
- KtDestructuringDeclaration destructuringDeclaration = ((KtDestructuringDeclaration) destructuringDeclarationEntry.getParent());
- MemberScope scopeForDeclaration = getMemberScopeDeclaredIn(destructuringDeclaration, location);
- scopeForDeclaration.getContributedVariables(destructuringDeclarationEntry.getNameAsSafeName(), location);
- return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, destructuringDeclarationEntry);
- }
-
- @Override
- public DeclarationDescriptor visitTypeAlias(@NotNull KtTypeAlias typeAlias, Void data) {
- LookupLocation location = lookupLocationFor(typeAlias, typeAlias.isTopLevel());
- MemberScope scopeForDeclaration = getMemberScopeDeclaredIn(typeAlias, location);
- scopeForDeclaration.getContributedClassifier(typeAlias.getNameAsSafeName(), location);
- return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, typeAlias);
- }
-
- @Override
- public DeclarationDescriptor visitScript(@NotNull KtScript script, Void data) {
- return getScriptDescriptor(script, lookupLocationFor(script, true));
- }
-
- @Override
- public DeclarationDescriptor visitKtElement(@NotNull KtElement element, Void data) {
- throw new IllegalArgumentException("Unsupported declaration type: " + element + " " +
- PsiUtilsKt.getElementTextWithContext(element));
- }
- }, null);
- if (result == null) {
- return absentDescriptorHandler.diagnoseDescriptorNotFound(declaration);
- }
- return result;
- }
-
- @NotNull
- /*package*/ MemberScope getMemberScopeDeclaredIn(@NotNull KtDeclaration declaration, @NotNull LookupLocation location) {
- KtDeclaration parentDeclaration = KtStubbedPsiUtil.getContainingDeclaration(declaration);
- boolean isTopLevel = parentDeclaration == null;
- if (isTopLevel) { // for top level declarations we search directly in package because of possible conflicts with imports
- KtFile ktFile = (KtFile) declaration.getContainingFile();
- FqName fqName = ktFile.getPackageFqName();
- topLevelDescriptorProvider.assertValid();
- LazyPackageDescriptor packageDescriptor = topLevelDescriptorProvider.getPackageFragment(fqName);
- if (packageDescriptor == null) {
- if (topLevelDescriptorProvider instanceof LazyClassContext) {
- ((LazyClassContext) topLevelDescriptorProvider).getDeclarationProviderFactory().diagnoseMissingPackageFragment(ktFile);
- }
- else {
- throw new IllegalStateException("Cannot find package fragment for file " + ktFile.getName() + " with package " + fqName);
- }
- }
- return packageDescriptor.getMemberScope();
- }
- else {
- if (parentDeclaration instanceof KtClassOrObject) {
- return getClassDescriptor((KtClassOrObject) parentDeclaration, location).getUnsubstitutedMemberScope();
- }
- else if (parentDeclaration instanceof KtScript) {
- return getScriptDescriptor((KtScript) parentDeclaration, location).getUnsubstitutedMemberScope();
- }
- else {
- throw new IllegalStateException("Don't call this method for local declarations: " + declaration + "\n" +
- PsiUtilsKt.getElementTextWithContext(declaration));
- }
- }
- }
-}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyDeclarationResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyDeclarationResolver.kt
new file mode 100644
index 00000000000..7e0669dcebd
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyDeclarationResolver.kt
@@ -0,0 +1,239 @@
+/*
+ * 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.resolve.lazy
+
+import com.intellij.psi.util.PsiTreeUtil
+import org.jetbrains.kotlin.context.GlobalContext
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.incremental.KotlinLookupLocation
+import org.jetbrains.kotlin.incremental.components.LookupLocation
+import org.jetbrains.kotlin.incremental.components.NoLookupLocation
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.BindingTrace
+import org.jetbrains.kotlin.resolve.scopes.MemberScope
+import org.jetbrains.kotlin.storage.LockBasedLazyResolveStorageManager
+import javax.inject.Inject
+
+open class LazyDeclarationResolver @Deprecated("") constructor(
+ globalContext: GlobalContext,
+ delegationTrace: BindingTrace,
+ private val topLevelDescriptorProvider: TopLevelDescriptorProvider,
+ private val absentDescriptorHandler: AbsentDescriptorHandler
+) {
+ private val trace: BindingTrace
+
+ protected lateinit var scopeProvider: DeclarationScopeProvider
+
+ private val bindingContext: BindingContext
+ get() = trace.bindingContext
+
+ // component dependency cycle
+ @Inject
+ fun setDeclarationScopeProvider(scopeProvider: DeclarationScopeProviderImpl) {
+ this.scopeProvider = scopeProvider
+ }
+
+ init {
+ val lockBasedLazyResolveStorageManager = LockBasedLazyResolveStorageManager(globalContext.storageManager)
+
+ this.trace = lockBasedLazyResolveStorageManager.createSafeTrace(delegationTrace)
+ }
+
+ open fun getClassDescriptorIfAny(classOrObject: KtClassOrObject, location: LookupLocation): ClassDescriptor? =
+ findClassDescriptorIfAny(classOrObject, location)
+
+ open fun getClassDescriptor(classOrObject: KtClassOrObject, location: LookupLocation): ClassDescriptor =
+ findClassDescriptor(classOrObject, location)
+
+ fun getScriptDescriptor(script: KtScript, location: LookupLocation): ScriptDescriptor =
+ findClassDescriptor(script, location) as ScriptDescriptor
+
+ private fun findClassDescriptorIfAny(
+ classObjectOrScript: KtNamedDeclaration,
+ location: LookupLocation
+ ): ClassDescriptor? {
+ val scope = getMemberScopeDeclaredIn(classObjectOrScript, location)
+
+ // Why not use the result here. Because it may be that there is a redeclaration:
+ // class A {} class A { fun foo(): A}
+ // and if we find the class by name only, we may b-not get the right one.
+ // This call is only needed to make sure the classes are written to trace
+ scope.getContributedClassifier(classObjectOrScript.nameAsSafeName, location)
+ val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, classObjectOrScript)
+
+ return descriptor as? ClassDescriptor
+ }
+
+ private fun findClassDescriptor(
+ classObjectOrScript: KtNamedDeclaration,
+ location: LookupLocation
+ ): ClassDescriptor =
+ findClassDescriptorIfAny(classObjectOrScript, location)
+ ?: (absentDescriptorHandler.diagnoseDescriptorNotFound(classObjectOrScript) as ClassDescriptor)
+
+ fun resolveToDescriptor(declaration: KtDeclaration): DeclarationDescriptor =
+ resolveToDescriptor(declaration, /*track =*/true) ?: absentDescriptorHandler.diagnoseDescriptorNotFound(declaration)
+
+ private fun resolveToDescriptor(declaration: KtDeclaration, track: Boolean): DeclarationDescriptor? {
+ return declaration.accept(object : KtVisitor() {
+ private fun lookupLocationFor(declaration: KtDeclaration, isTopLevel: Boolean): LookupLocation =
+ if (isTopLevel && track) KotlinLookupLocation(declaration)
+ else NoLookupLocation.WHEN_RESOLVE_DECLARATION
+
+ override fun visitClass(klass: KtClass, data: Nothing?): DeclarationDescriptor? =
+ getClassDescriptorIfAny(klass, lookupLocationFor(klass, klass.isTopLevel()))
+
+ override fun visitObjectDeclaration(declaration: KtObjectDeclaration, data: Nothing?): DeclarationDescriptor? =
+ getClassDescriptorIfAny(declaration, lookupLocationFor(declaration, declaration.isTopLevel()))
+
+ override fun visitTypeParameter(parameter: KtTypeParameter, data: Nothing?): DeclarationDescriptor? {
+ val ownerElement = PsiTreeUtil.getParentOfType(parameter, KtTypeParameterListOwner::class.java) ?: error("Owner not found for type parameter: " + parameter.text)
+ val ownerDescriptor = resolveToDescriptor(ownerElement, /*track =*/false) ?: return null
+
+ val typeParameters: List
+ typeParameters = when (ownerDescriptor) {
+ is CallableDescriptor -> ownerDescriptor.typeParameters
+ is ClassifierDescriptorWithTypeParameters -> ownerDescriptor.typeConstructor.parameters
+ else -> throw IllegalStateException("Unknown owner kind for a type parameter: " + ownerDescriptor)
+ }
+
+ val name = parameter.nameAsSafeName
+ return typeParameters.firstOrNull { it.name == name }
+ ?: throw IllegalStateException("Type parameter $name not found for $ownerDescriptor")
+ }
+
+ override fun visitNamedFunction(function: KtNamedFunction, data: Nothing?): DeclarationDescriptor? {
+ val location = lookupLocationFor(function, function.isTopLevel)
+ val scopeForDeclaration = getMemberScopeDeclaredIn(function, location)
+ scopeForDeclaration.getContributedFunctions(function.nameAsSafeName, location)
+ return bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function)
+ }
+
+ override fun visitParameter(parameter: KtParameter, data: Nothing?): DeclarationDescriptor? {
+ val grandFather = parameter.parent.parent
+ when (grandFather) {
+ is KtPrimaryConstructor -> {
+ val jetClass = grandFather.getContainingClassOrObject()
+ // This is a primary constructor parameter
+ val classDescriptor = getClassDescriptorIfAny(jetClass, lookupLocationFor(jetClass, false))
+ return when {
+ classDescriptor == null -> null
+ parameter.hasValOrVar() -> {
+ classDescriptor.defaultType.memberScope.getContributedVariables(
+ parameter.nameAsSafeName, lookupLocationFor(parameter, false))
+ bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter)
+ }
+ else -> {
+ val constructor = classDescriptor.unsubstitutedPrimaryConstructor
+ ?: error("There are constructor parameters found, so a constructor should also exist")
+ constructor.valueParameters
+ bindingContext.get(BindingContext.VALUE_PARAMETER, parameter)
+ }
+ }
+ }
+ is KtNamedFunction -> {
+ val function = visitNamedFunction(grandFather, data) as? FunctionDescriptor
+ function?.valueParameters
+ return bindingContext.get(BindingContext.VALUE_PARAMETER, parameter)
+ }
+ is KtSecondaryConstructor -> {
+ val constructorDescriptor = visitSecondaryConstructor(
+ grandFather, data
+ ) as? ConstructorDescriptor
+ constructorDescriptor?.valueParameters
+ return bindingContext.get(BindingContext.VALUE_PARAMETER, parameter)
+ }
+ else -> //TODO: support parameters in accessors and other places(?)
+ return super.visitParameter(parameter, data)
+ }
+ }
+
+ override fun visitSecondaryConstructor(constructor: KtSecondaryConstructor, data: Nothing?): DeclarationDescriptor? {
+ getClassDescriptorIfAny(constructor.parent.parent as KtClassOrObject, lookupLocationFor(constructor, false))?.constructors
+ return bindingContext.get(BindingContext.CONSTRUCTOR, constructor)
+ }
+
+ override fun visitPrimaryConstructor(constructor: KtPrimaryConstructor, data: Nothing?): DeclarationDescriptor? {
+ getClassDescriptorIfAny(constructor.getContainingClassOrObject(), lookupLocationFor(constructor, false))?.constructors
+ return bindingContext.get(BindingContext.CONSTRUCTOR, constructor)
+ }
+
+ override fun visitProperty(property: KtProperty, data: Nothing?): DeclarationDescriptor? {
+ val location = lookupLocationFor(property, property.isTopLevel)
+ val scopeForDeclaration = getMemberScopeDeclaredIn(property, location)
+ scopeForDeclaration.getContributedVariables(property.nameAsSafeName, location)
+ return bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, property)
+ }
+
+ override fun visitDestructuringDeclarationEntry(
+ destructuringDeclarationEntry: KtDestructuringDeclarationEntry, data: Nothing?
+ ): DeclarationDescriptor? {
+ val location = lookupLocationFor(destructuringDeclarationEntry, false)
+ val destructuringDeclaration = destructuringDeclarationEntry.parent as? KtDestructuringDeclaration ?: return null
+ val scopeForDeclaration = getMemberScopeDeclaredIn(destructuringDeclaration, location)
+ scopeForDeclaration.getContributedVariables(destructuringDeclarationEntry.nameAsSafeName, location)
+ return bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, destructuringDeclarationEntry)
+ }
+
+ override fun visitTypeAlias(typeAlias: KtTypeAlias, data: Nothing?): DeclarationDescriptor? {
+ val location = lookupLocationFor(typeAlias, typeAlias.isTopLevel())
+ val scopeForDeclaration = getMemberScopeDeclaredIn(typeAlias, location)
+ scopeForDeclaration.getContributedClassifier(typeAlias.nameAsSafeName, location)
+ return bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, typeAlias)
+ }
+
+ override fun visitScript(script: KtScript, data: Nothing?): DeclarationDescriptor =
+ getScriptDescriptor(script, lookupLocationFor(script, true))
+
+ override fun visitKtElement(element: KtElement, data: Nothing?): DeclarationDescriptor? {
+ throw IllegalArgumentException("Unsupported declaration type: " + element + " " +
+ element.getElementTextWithContext())
+ }
+ }, null)
+ }
+
+ internal fun getMemberScopeDeclaredIn(declaration: KtDeclaration, location: LookupLocation):
+ /*package*/ MemberScope {
+ val parentDeclaration = KtStubbedPsiUtil.getContainingDeclaration(declaration)
+ val isTopLevel = parentDeclaration == null
+ if (isTopLevel) { // for top level declarations we search directly in package because of possible conflicts with imports
+ val ktFile = declaration.containingFile as KtFile
+ val fqName = ktFile.packageFqName
+ topLevelDescriptorProvider.assertValid()
+ val packageDescriptor = topLevelDescriptorProvider.getPackageFragment(fqName)
+ if (packageDescriptor == null) {
+ if (topLevelDescriptorProvider is LazyClassContext) {
+ topLevelDescriptorProvider.declarationProviderFactory.diagnoseMissingPackageFragment(ktFile)
+ }
+ else {
+ throw IllegalStateException("Cannot find package fragment for file " + ktFile.name + " with package " + fqName)
+ }
+ }
+ return packageDescriptor!!.getMemberScope()
+ }
+ else {
+ return when (parentDeclaration) {
+ is KtClassOrObject -> getClassDescriptor(parentDeclaration, location).unsubstitutedMemberScope
+ is KtScript -> getScriptDescriptor(parentDeclaration, location).unsubstitutedMemberScope
+ else -> throw IllegalStateException("Don't call this method for local declarations: " + declaration + "\n" +
+ declaration.getElementTextWithContext())
+ }
+ }
+ }
+}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt
index 5ea473866b9..fc6a4b3804b 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.util.collectionUtils.concat
import org.jetbrains.kotlin.utils.Printer
+import org.jetbrains.kotlin.utils.addToStdlib.flatMapToNullable
import java.util.*
interface IndexedImports {
@@ -81,7 +82,7 @@ class LazyImportResolver(
val indexedImports: IndexedImports,
excludedImportNames: Collection,
private val traceForImportResolve: BindingTrace,
- private val packageFragment: PackageFragmentDescriptor,
+ private val packageFragment: PackageFragmentDescriptor?,
val deprecationResolver: DeprecationResolver
) : ImportResolver {
private val importedScopesProvider = storageManager.createMemoizedFunctionWithNullableValues {
@@ -191,6 +192,19 @@ class LazyImportResolver(
fun getImportScope(directive: KtImportDirective): ImportingScope {
return importedScopesProvider(directive) ?: ImportingScope.Empty
}
+
+ val allNames: Set? by lazy(LazyThreadSafetyMode.PUBLICATION) {
+ indexedImports.imports.flatMapToNullable(hashSetOf()) { getImportScope(it).computeImportedNames() }
+ }
+
+ fun definitelyDoesNotContainName(name: Name) = allNames?.let { name !in it } == true
+
+ fun recordLookup(name: Name, location: LookupLocation) {
+ if (allNames == null) return
+ indexedImports.importsForName(name).forEach {
+ getImportScope(it).recordLookup(name, location)
+ }
+ }
}
class LazyImportScope(
@@ -269,4 +283,12 @@ class LazyImportScope(
p.popIndent()
p.println("}")
}
+
+ override fun definitelyDoesNotContainName(name: Name) = importResolver.definitelyDoesNotContainName(name)
+
+ override fun recordLookup(name: Name, location: LookupLocation) {
+ importResolver.recordLookup(name, location)
+ }
+
+ override fun computeImportedNames() = importResolver.allNames
}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt
index e68a698bd30..4d0e1c5c7c0 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.resolve.lazy.declarations
import com.google.common.collect.ArrayListMultimap
+import com.google.common.collect.Sets
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.lazy.ResolveSessionUtils.safeNameForLazyResolve
@@ -37,6 +38,7 @@ abstract class AbstractPsiBasedDeclarationProvider(storageManager: StorageManage
val classesAndObjects = ArrayListMultimap.create() // order matters here
val typeAliases = ArrayListMultimap.create()
val destructuringDeclarationsEntries = ArrayListMultimap.create()
+ val names = Sets.newHashSet()
fun putToIndex(declaration: KtDeclaration) {
if (declaration is KtAnonymousInitializer || declaration is KtSecondaryConstructor) return
@@ -57,7 +59,9 @@ abstract class AbstractPsiBasedDeclarationProvider(storageManager: StorageManage
}
is KtDestructuringDeclaration -> {
for (entry in declaration.entries) {
- destructuringDeclarationsEntries.put(safeNameForLazyResolve(entry.nameAsName), entry)
+ val name = safeNameForLazyResolve(entry.nameAsName)
+ destructuringDeclarationsEntries.put(name, entry)
+ names.add(name)
}
}
is KtParameter -> {
@@ -65,11 +69,17 @@ abstract class AbstractPsiBasedDeclarationProvider(storageManager: StorageManage
}
else -> throw IllegalArgumentException("Unknown declaration: " + declaration)
}
+
+ when (declaration) {
+ is KtNamedDeclaration -> names.add(safeNameForLazyResolve(declaration))
+ }
}
override fun toString() = "allDeclarations: " + allDeclarations.mapNotNull { it.name }
}
+ override fun getDeclarationNames() = index().names
+
private val index = storageManager.createLazyValue {
val index = Index()
doCreateIndex(index)
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/CombinedPackageMemberDeclarationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/CombinedPackageMemberDeclarationProvider.kt
index c457578d570..f3851057a73 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/CombinedPackageMemberDeclarationProvider.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/CombinedPackageMemberDeclarationProvider.kt
@@ -41,4 +41,6 @@ class CombinedPackageMemberDeclarationProvider(
override fun getClassOrObjectDeclarations(name: Name) = providers.flatMap { it.getClassOrObjectDeclarations(name) }
override fun getTypeAliasDeclarations(name: Name) = providers.flatMap { it.getTypeAliasDeclarations(name) }
+
+ override fun getDeclarationNames(): Set = providers.flatMapTo(HashSet()) { it.getDeclarationNames() }
}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/DeclarationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/DeclarationProvider.kt
index 4957527f3ed..cf484b2588e 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/DeclarationProvider.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/DeclarationProvider.kt
@@ -33,4 +33,6 @@ interface DeclarationProvider {
fun getClassOrObjectDeclarations(name: Name): Collection
fun getTypeAliasDeclarations(name: Name): Collection
+
+ fun getDeclarationNames(): Set
}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt
index 9d1ac9d11fe..3951107526d 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt
@@ -219,8 +219,6 @@ protected constructor(
return result.toList()
}
- abstract fun recordLookup(name: Name, from: LookupLocation)
-
// Do not change this, override in concrete subclasses:
// it is very easy to compromise laziness of this class, and fail all the debugging
// a generic implementation can't do this properly
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyPackageMemberScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyPackageMemberScope.kt
index 98932bdde9c..5ecd085013f 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyPackageMemberScope.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyPackageMemberScope.kt
@@ -58,6 +58,10 @@ class LazyPackageMemberScope(
c.lookupTracker.record(from, thisDescriptor, name)
}
+ override fun getClassifierNames(): Set? = declarationProvider.getDeclarationNames()
+ override fun getFunctionNames() = declarationProvider.getDeclarationNames()
+ override fun getVariableNames() = declarationProvider.getDeclarationNames()
+
// Do not add details here, they may compromise the laziness during debugging
override fun toString() = "lazy scope for package " + thisDescriptor.name
}
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/LocalClassifierAnalyzer.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/LocalClassifierAnalyzer.kt
index 38aa306cfb0..28389553ef9 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/LocalClassifierAnalyzer.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/LocalClassifierAnalyzer.kt
@@ -18,10 +18,8 @@ package org.jetbrains.kotlin.types.expressions
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
-import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.TargetPlatformVersion
-import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.context.GlobalContext
import org.jetbrains.kotlin.context.withModule
@@ -200,6 +198,13 @@ class LocalLazyDeclarationResolver(
}
return super.getClassDescriptor(classOrObject, location)
}
+
+ override fun getClassDescriptorIfAny(classOrObject: KtClassOrObject, location: LookupLocation): ClassDescriptor? {
+ if (localClassDescriptorManager.isMyClass(classOrObject)) {
+ return localClassDescriptorManager.getClassDescriptor(classOrObject, scopeProvider)
+ }
+ return super.getClassDescriptorIfAny(classOrObject, location)
+ }
}
diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/BuildDiffsStorage.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/BuildDiffsStorage.kt
new file mode 100644
index 00000000000..1ba8074d4b1
--- /dev/null
+++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/BuildDiffsStorage.kt
@@ -0,0 +1,132 @@
+/*
+ * 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.incremental
+
+import org.jetbrains.annotations.TestOnly
+import org.jetbrains.kotlin.name.FqName
+import java.io.File
+import java.io.IOException
+import java.io.ObjectInputStream
+import java.io.ObjectOutputStream
+
+data class BuildDifference(val ts: Long, val isIncremental: Boolean, val dirtyData: DirtyData)
+
+// todo: storage format can be optimized by compressing fq-names
+data class BuildDiffsStorage(val buildDiffs: List) {
+ companion object {
+ fun readFromFile(file: File, reporter: ICReporter?): BuildDiffsStorage? {
+ fun reportFail(reason: String) {
+ reporter?.report { "Could not read diff from file $file: $reason" }
+ }
+
+ if (!file.exists()) return null
+
+ try {
+ ObjectInputStream(file.inputStream().buffered()).use { input ->
+ val version = input.readInt()
+ if (version != CURRENT_VERSION) {
+ reportFail("incompatible version $version, actual version is $CURRENT_VERSION")
+ return null
+ }
+
+ val size = input.readInt()
+ val result = ArrayList(size)
+ repeat(size) {
+ result.add(input.readBuildDifference())
+ }
+ return BuildDiffsStorage(result)
+ }
+ }
+ catch (e: IOException) {
+ reportFail(e.toString())
+ }
+
+ return null
+ }
+
+ fun writeToFile(file: File, storage: BuildDiffsStorage, reporter: ICReporter?) {
+ file.parentFile.mkdirs()
+
+ try {
+ ObjectOutputStream(file.outputStream().buffered()).use { output ->
+ output.writeInt(CURRENT_VERSION)
+
+ val diffsToWrite = storage.buildDiffs.sortedBy { it.ts }.takeLast(MAX_DIFFS_ENTRIES)
+ output.writeInt(diffsToWrite.size)
+ for (diff in diffsToWrite) {
+ output.writeBuildDifference(diff)
+ }
+ }
+ }
+ catch (e: IOException) {
+ reporter?.report { "Could not write diff to file $file: $e" }
+ }
+ }
+
+ private fun ObjectInputStream.readBuildDifference(): BuildDifference {
+ val ts = readLong()
+ val isIncremental = readBoolean()
+ val dirtyData = readDirtyData()
+ return BuildDifference(ts, isIncremental, dirtyData)
+ }
+
+ private fun ObjectOutputStream.writeBuildDifference(diff: BuildDifference) {
+ writeLong(diff.ts)
+ writeBoolean(diff.isIncremental)
+ writeDirtyData(diff.dirtyData)
+ }
+
+ private fun ObjectInputStream.readDirtyData(): DirtyData {
+ val lookupSymbolSize = readInt()
+ val lookupSymbols = ArrayList(lookupSymbolSize)
+ repeat(lookupSymbolSize) {
+ val name = readUTF()
+ val scope = readUTF()
+ lookupSymbols.add(LookupSymbol(name = name, scope = scope))
+ }
+
+ val dirtyClassesSize = readInt()
+ val dirtyClassesFqNames = ArrayList(dirtyClassesSize)
+ repeat(dirtyClassesSize) {
+ val fqNameString = readUTF()
+ dirtyClassesFqNames.add(FqName(fqNameString))
+ }
+
+ return DirtyData(lookupSymbols, dirtyClassesFqNames)
+ }
+
+ private fun ObjectOutputStream.writeDirtyData(dirtyData: DirtyData) {
+ val lookupSymbols = dirtyData.dirtyLookupSymbols
+ writeInt(lookupSymbols.size)
+ for ((name, scope) in lookupSymbols) {
+ writeUTF(name)
+ writeUTF(scope)
+ }
+
+ val dirtyClassesFqNames = dirtyData.dirtyClassesFqNames
+ writeInt(dirtyClassesFqNames.size)
+ for (fqName in dirtyClassesFqNames) {
+ writeUTF(fqName.asString())
+ }
+ }
+
+ internal val MAX_DIFFS_ENTRIES: Int = 10
+
+ @set:TestOnly
+ var CURRENT_VERSION: Int = 0
+ }
+}
\ No newline at end of file
diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/BuildInfo.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/BuildInfo.kt
index d5cfc2ded94..d5149dfadb9 100644
--- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/BuildInfo.kt
+++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/BuildInfo.kt
@@ -18,7 +18,7 @@ package org.jetbrains.kotlin.incremental
import java.io.*
-internal data class BuildInfo(val startTS: Long) : Serializable {
+data class BuildInfo(val startTS: Long) : Serializable {
companion object {
fun read(file: File): BuildInfo? =
try {
diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt
index fcd9688ea0b..dfa187249b7 100644
--- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt
+++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalCompilerRunner.kt
@@ -255,16 +255,9 @@ abstract class IncrementalCompilerRunner<
if (exitCode == ExitCode.OK && compilationMode is CompilationMode.Incremental) {
buildDirtyLookupSymbols.addAll(additionalDirtyLookupSymbols())
}
- if (changesRegistry != null) {
- if (compilationMode is CompilationMode.Incremental) {
- val dirtyData = DirtyData(buildDirtyLookupSymbols, buildDirtyFqNames)
- changesRegistry.registerChanges(currentBuildInfo.startTS, dirtyData)
- }
- else {
- assert(compilationMode is CompilationMode.Rebuild) { "Unexpected compilation mode: ${compilationMode::class.java}" }
- changesRegistry.unknownChanges(currentBuildInfo.startTS)
- }
- }
+
+ val dirtyData = DirtyData(buildDirtyLookupSymbols, buildDirtyFqNames)
+ processChangesAfterBuild(compilationMode, currentBuildInfo, dirtyData)
if (exitCode == ExitCode.OK) {
cacheVersions.forEach { it.saveIfNeeded() }
@@ -273,6 +266,18 @@ abstract class IncrementalCompilerRunner<
return exitCode
}
+ protected open fun processChangesAfterBuild(compilationMode: CompilationMode, currentBuildInfo: BuildInfo, dirtyData: DirtyData) {
+ if (changesRegistry == null) return
+
+ if (compilationMode is CompilationMode.Incremental) {
+ changesRegistry.registerChanges(currentBuildInfo.startTS, dirtyData)
+ }
+ else {
+ assert(compilationMode is CompilationMode.Rebuild) { "Unexpected compilation mode: ${compilationMode::class.java}" }
+ changesRegistry.unknownChanges(currentBuildInfo.startTS)
+ }
+ }
+
companion object {
const val DIRTY_SOURCES_FILE_NAME = "dirty-sources.txt"
const val LAST_BUILD_INFO_FILE_NAME = "last-build.bin"
diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt
index 881e14df20c..45ab3f6d3f8 100644
--- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt
+++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt
@@ -16,10 +16,10 @@
package org.jetbrains.kotlin.incremental
+import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.annotation.AnnotationFileUpdater
import org.jetbrains.kotlin.build.GeneratedFile
import org.jetbrains.kotlin.build.GeneratedJvmClass
-import org.jetbrains.kotlin.build.isModuleMappingFile
import org.jetbrains.kotlin.build.JvmSourceRoot
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import java.io.File
import java.util.*
+import kotlin.collections.HashSet
fun makeIncrementally(
cachesDir: File,
@@ -89,7 +90,9 @@ class IncrementalJvmCompilerRunner(
reporter: ICReporter,
private var kaptAnnotationsFileUpdater: AnnotationFileUpdater? = null,
artifactChangesProvider: ArtifactChangesProvider? = null,
- changesRegistry: ChangesRegistry? = null
+ changesRegistry: ChangesRegistry? = null,
+ private val buildHistoryFile: File? = null,
+ private val friendBuildHistoryFile: File? = null
) : IncrementalCompilerRunner(
workingDir,
"caches-jvm",
@@ -110,16 +113,58 @@ class IncrementalJvmCompilerRunner(
private var javaFilesProcessor = ChangedJavaFilesProcessor(reporter)
override fun calculateSourcesToCompile(caches: IncrementalJvmCachesManager, changedFiles: ChangedFiles.Known, args: K2JVMCompilerArguments): CompilationMode {
- val removedClassFiles = changedFiles.removed.filter(File::isClassFile)
- if (removedClassFiles.any()) return CompilationMode.Rebuild { "Removed class files: ${reporter.pathsAsString(removedClassFiles)}" }
+ val dirtyFiles = getDirtyFiles(changedFiles)
- val modifiedClassFiles = changedFiles.modified.filter(File::isClassFile)
- if (modifiedClassFiles.any()) return CompilationMode.Rebuild { "Modified class files: ${reporter.pathsAsString(modifiedClassFiles)}" }
+ fun markDirtyBy(lookupSymbols: Collection) {
+ if (lookupSymbols.isEmpty()) return
+
+ val dirtyFilesFromLookups = mapLookupSymbolsToFiles(caches.lookupCache, lookupSymbols, reporter)
+ dirtyFiles.addAll(dirtyFilesFromLookups)
+ }
+
+ fun markDirtyBy(dirtyClassesFqNames: Collection) {
+ if (dirtyClassesFqNames.isEmpty()) return
+
+ val fqNamesWithSubtypes = dirtyClassesFqNames.flatMap { withSubtypes(it, listOf(caches.platformCache)) }
+ val dirtyFilesFromFqNames = mapClassesFqNamesToFiles(listOf(caches.platformCache), fqNamesWithSubtypes, reporter)
+ dirtyFiles.addAll(dirtyFilesFromFqNames)
+ }
+
+ val lastBuildInfo = BuildInfo.read(lastBuildInfoFile)
+ reporter.report { "Last Kotlin Build info -- $lastBuildInfo" }
+
+ val changesFromFriend by lazy {
+ val myLastTS = lastBuildInfo?.startTS ?: return@lazy ChangesEither.Unknown()
+ val storage = friendBuildHistoryFile?.let { BuildDiffsStorage.readFromFile(it, reporter) } ?: return@lazy ChangesEither.Unknown()
+
+ val (prevDiffs, newDiffs) = storage.buildDiffs.partition { it.ts < myLastTS }
+ if (prevDiffs.isEmpty()) return@lazy ChangesEither.Unknown()
+
+ val dirtyLookupSymbols = HashSet()
+ val dirtyClassesFqNames = HashSet()
+ for ((_, isIncremental, dirtyData) in newDiffs) {
+ if (!isIncremental) return@lazy ChangesEither.Unknown()
+
+ dirtyLookupSymbols.addAll(dirtyData.dirtyLookupSymbols)
+ dirtyClassesFqNames.addAll(dirtyData.dirtyClassesFqNames)
+ }
+
+ markDirtyBy(dirtyLookupSymbols)
+ markDirtyBy(dirtyClassesFqNames)
+ ChangesEither.Known(dirtyLookupSymbols, dirtyClassesFqNames)
+ }
+ val friendDirs = args.friendPaths?.map { File(it) } ?: emptyList()
+ for (file in changedFiles.removed.asSequence() + changedFiles.modified.asSequence()) {
+ if (!file.isClassFile()) continue
+
+ val isFriendClassFile = friendDirs.any { FileUtil.isAncestor(it, file, false) }
+ if (isFriendClassFile && changesFromFriend is ChangesEither.Known) continue
+
+ return CompilationMode.Rebuild { "Cannot get changes from modified or removed class file: ${reporter.pathsAsString(file)}" }
+ }
val classpathSet = args.classpathAsList.toHashSet()
val modifiedClasspathEntries = changedFiles.modified.filter { it in classpathSet }
- val lastBuildInfo = BuildInfo.read(lastBuildInfoFile)
- reporter.report { "Last Kotlin Build info -- $lastBuildInfo" }
val classpathChanges = getClasspathChanges(modifiedClasspathEntries, lastBuildInfo)
if (classpathChanges !is ChangesEither.Known) {
return CompilationMode.Rebuild { "could not get changes from modified classpath entries: ${reporter.pathsAsString(modifiedClasspathEntries)}" }
@@ -131,21 +176,9 @@ class IncrementalJvmCompilerRunner(
is ChangesEither.Unknown -> return CompilationMode.Rebuild { "Could not get changes for java files" }
}
- val dirtyFiles = getDirtyFiles(changedFiles)
- val lookupSymbols = HashSet()
- lookupSymbols.addAll(affectedJavaSymbols)
- lookupSymbols.addAll(classpathChanges.lookupSymbols)
-
- if (lookupSymbols.any()) {
- val dirtyFilesFromLookups = mapLookupSymbolsToFiles(caches.lookupCache, lookupSymbols, reporter)
- dirtyFiles.addAll(dirtyFilesFromLookups)
- }
-
- val dirtyClassesFqNames = classpathChanges.fqNames.flatMap { withSubtypes(it, listOf(caches.platformCache)) }
- if (dirtyClassesFqNames.any()) {
- val dirtyFilesFromFqNames = mapClassesFqNamesToFiles(listOf(caches.platformCache), dirtyClassesFqNames, reporter)
- dirtyFiles.addAll(dirtyFilesFromFqNames)
- }
+ markDirtyBy(affectedJavaSymbols)
+ markDirtyBy(classpathChanges.lookupSymbols)
+ markDirtyBy(classpathChanges.fqNames)
return CompilationMode.Incremental(dirtyFiles)
}
@@ -263,6 +296,23 @@ class IncrementalJvmCompilerRunner(
override fun additionalDirtyLookupSymbols(): Iterable