mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-13 00:21:27 +00:00
Compare commits
316 Commits
rrni/rever
...
update-nat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a35ba7e58 | ||
|
|
d0fb059d58 | ||
|
|
27d3a1e534 | ||
|
|
2027d58ef3 | ||
|
|
8f5ca82b26 | ||
|
|
0d9c30a311 | ||
|
|
76b8319fbe | ||
|
|
069857c12c | ||
|
|
5ab6472a4d | ||
|
|
5306e3f88a | ||
|
|
97a8739182 | ||
|
|
1623ed027d | ||
|
|
e0226ce5dd | ||
|
|
e1734fbbda | ||
|
|
d2a0a2a0de | ||
|
|
59c5ab7d8e | ||
|
|
8ed766e628 | ||
|
|
ad12184e14 | ||
|
|
4f6971339d | ||
|
|
9ee4cab849 | ||
|
|
e2de2fc059 | ||
|
|
eae3cf9f32 | ||
|
|
825dd7abe9 | ||
|
|
ffc235b730 | ||
|
|
9ff115514e | ||
|
|
dc1e44813c | ||
|
|
016e103755 | ||
|
|
12e03c34c6 | ||
|
|
65c6dd9e1a | ||
|
|
6c7cbfc09c | ||
|
|
74d06c63e6 | ||
|
|
01a3accd53 | ||
|
|
da23ed15af | ||
|
|
5cd7d6414d | ||
|
|
0544745a5c | ||
|
|
1651e94bb8 | ||
|
|
2c359a61ff | ||
|
|
a5ef558355 | ||
|
|
e9bfd0b3c2 | ||
|
|
669d7ae9c3 | ||
|
|
60d8f6eabd | ||
|
|
8791ce1685 | ||
|
|
f42336950f | ||
|
|
726901291e | ||
|
|
f7712fc351 | ||
|
|
4fa215eb47 | ||
|
|
84f173e75a | ||
|
|
1a885cf1f4 | ||
|
|
898cbf974a | ||
|
|
386a3ee83e | ||
|
|
392ab05f5f | ||
|
|
547c6ab897 | ||
|
|
231e5679b1 | ||
|
|
03389cd249 | ||
|
|
42c53b5d76 | ||
|
|
d303ae5c28 | ||
|
|
b47636ba9d | ||
|
|
911748fde2 | ||
|
|
682f15f248 | ||
|
|
91b08d374b | ||
|
|
0cc417c97b | ||
|
|
169155d854 | ||
|
|
3f8f53cb8c | ||
|
|
6fc756c4c0 | ||
|
|
6a8ef4ac1a | ||
|
|
4aaf36131f | ||
|
|
f2e1b0bc22 | ||
|
|
ec6b1dc1e5 | ||
|
|
aa2315f378 | ||
|
|
28b91ce848 | ||
|
|
3c7e57d9c4 | ||
|
|
dfd163af34 | ||
|
|
8b24dd98f6 | ||
|
|
4b4a709e86 | ||
|
|
0c4c6860be | ||
|
|
d6fcc35f17 | ||
|
|
0602baa38e | ||
|
|
c9ac71dd8d | ||
|
|
e04959a939 | ||
|
|
a399539094 | ||
|
|
d71e0fc7c3 | ||
|
|
ac870129df | ||
|
|
7f485172a8 | ||
|
|
df4cbd50d6 | ||
|
|
066ecd5308 | ||
|
|
30c7b3cc1d | ||
|
|
38bc99d792 | ||
|
|
88ed2e268f | ||
|
|
720a35bc26 | ||
|
|
e141441bf5 | ||
|
|
f50f9d069f | ||
|
|
c4f99b850b | ||
|
|
8e3eb04271 | ||
|
|
75987697db | ||
|
|
1c93018db4 | ||
|
|
6fa26c5356 | ||
|
|
e97009bd49 | ||
|
|
6ae156c8a4 | ||
|
|
595d55707c | ||
|
|
9fbc71475b | ||
|
|
a13c744533 | ||
|
|
f2f1e923ee | ||
|
|
0905c6ba27 | ||
|
|
0ebe31af73 | ||
|
|
846fb60c91 | ||
|
|
ce36fc594f | ||
|
|
9e6db690d5 | ||
|
|
1702c8df25 | ||
|
|
88fcbdd079 | ||
|
|
8015483db6 | ||
|
|
e644c05b31 | ||
|
|
1220ef51b5 | ||
|
|
624a4802b4 | ||
|
|
7aef1a9073 | ||
|
|
774b5408b6 | ||
|
|
ac867bb063 | ||
|
|
9583b05160 | ||
|
|
a0e3340a03 | ||
|
|
7b68e5b74e | ||
|
|
debc248a78 | ||
|
|
297f5eefb2 | ||
|
|
1751e7ca78 | ||
|
|
30b5535dc1 | ||
|
|
973622bc60 | ||
|
|
cfa3422644 | ||
|
|
00a4365752 | ||
|
|
cfd030ac8d | ||
|
|
6230af0f3b | ||
|
|
0fa22c3327 | ||
|
|
9ba0202d59 | ||
|
|
a967c47d1c | ||
|
|
e8fea9d4ef | ||
|
|
cc5cf643a8 | ||
|
|
20a631a838 | ||
|
|
c6e5a5d72a | ||
|
|
a6bad98241 | ||
|
|
7cf16d9af6 | ||
|
|
59eeb287c9 | ||
|
|
2e14313bc8 | ||
|
|
1872b3dd1d | ||
|
|
4c3ac350c9 | ||
|
|
44f8e92c6f | ||
|
|
f279ae5576 | ||
|
|
e4f4619f37 | ||
|
|
bff63fe902 | ||
|
|
7b6cd7305a | ||
|
|
7640718805 | ||
|
|
8830387118 | ||
|
|
908b8a4b4e | ||
|
|
3430aa24ec | ||
|
|
f3b206227a | ||
|
|
a1d2a5ac82 | ||
|
|
fc33aa9552 | ||
|
|
2c0ecedb5a | ||
|
|
3ba7339a46 | ||
|
|
e449f18fc0 | ||
|
|
7def3c19dc | ||
|
|
fc46a7704c | ||
|
|
4d06db6852 | ||
|
|
883dbfe138 | ||
|
|
d6f388845d | ||
|
|
2e9a596b53 | ||
|
|
da86804719 | ||
|
|
2bbbf9677f | ||
|
|
543671227d | ||
|
|
5b5262eedf | ||
|
|
42ad282dee | ||
|
|
23b0143688 | ||
|
|
1e782311e5 | ||
|
|
7eae8ccc09 | ||
|
|
375e46b91f | ||
|
|
cfdfdcb954 | ||
|
|
819c6e5a51 | ||
|
|
2b1d2ea2fe | ||
|
|
e20444e441 | ||
|
|
c71c2fba05 | ||
|
|
fb5095f94e | ||
|
|
ac77446657 | ||
|
|
7c66d0e3a6 | ||
|
|
c7634fb41a | ||
|
|
d634db2d82 | ||
|
|
43482f60ae | ||
|
|
b940b64d06 | ||
|
|
72e42ba2cb | ||
|
|
20766dce65 | ||
|
|
34199c5d92 | ||
|
|
816976035b | ||
|
|
8df408122f | ||
|
|
f349b92896 | ||
|
|
f221a6794b | ||
|
|
037b7a5f5e | ||
|
|
39af8f3994 | ||
|
|
fd192f811e | ||
|
|
d83e2afcdf | ||
|
|
45e5013097 | ||
|
|
24aa636283 | ||
|
|
2884cfc9e4 | ||
|
|
2cc7bab0ff | ||
|
|
f3bef7e48b | ||
|
|
7717921574 | ||
|
|
08180d95e9 | ||
|
|
318f8e2891 | ||
|
|
724fa51fb4 | ||
|
|
68aa525877 | ||
|
|
51c4a10276 | ||
|
|
75572882a3 | ||
|
|
b731b02eda | ||
|
|
f5d28808c8 | ||
|
|
5b206eeee6 | ||
|
|
f29926006b | ||
|
|
9dc11b2dd7 | ||
|
|
4422fd220a | ||
|
|
0731ad4bf0 | ||
|
|
7dc3797e85 | ||
|
|
4c81b4d4a7 | ||
|
|
2c907e800a | ||
|
|
fe16ac8628 | ||
|
|
a11dd0a7b5 | ||
|
|
3bd19503b0 | ||
|
|
c52204359b | ||
|
|
51fc596aa9 | ||
|
|
0cfbd1a27f | ||
|
|
5da0d8f060 | ||
|
|
d0969e77dd | ||
|
|
b4101ef2ae | ||
|
|
edd4f283c6 | ||
|
|
7d07329292 | ||
|
|
1eadec5432 | ||
|
|
0a33859eb2 | ||
|
|
9a0f3f9e57 | ||
|
|
2a7bb8d13e | ||
|
|
fc9b41a05c | ||
|
|
ac16907f1c | ||
|
|
c24bbff948 | ||
|
|
410123d0f7 | ||
|
|
04cb2265d8 | ||
|
|
d5e1fc24e0 | ||
|
|
7725f0d1d7 | ||
|
|
6e3494d83c | ||
|
|
3cfee99ac6 | ||
|
|
68cd113d83 | ||
|
|
8de34046a8 | ||
|
|
a2be50a223 | ||
|
|
700a7c68eb | ||
|
|
d7d066d081 | ||
|
|
a30b4af7a4 | ||
|
|
55097c09a0 | ||
|
|
09c97d7a18 | ||
|
|
9ac928aa1b | ||
|
|
5322dbe3fe | ||
|
|
3927e7615a | ||
|
|
3a3bd4826f | ||
|
|
148ac0471d | ||
|
|
2eba1714bc | ||
|
|
758db84e53 | ||
|
|
75f8025d6a | ||
|
|
e41d8ca122 | ||
|
|
d0b71643b7 | ||
|
|
80d1c9a7de | ||
|
|
4b060b68fe | ||
|
|
2d10730233 | ||
|
|
53a2fb7302 | ||
|
|
09d0cba192 | ||
|
|
a5b19826e7 | ||
|
|
863be9369a | ||
|
|
92e125413d | ||
|
|
6aebc695ec | ||
|
|
1bb75ac2ec | ||
|
|
1e2115ba83 | ||
|
|
34dd6062fd | ||
|
|
e7cea0239a | ||
|
|
962a52ef0d | ||
|
|
6a50cd8a11 | ||
|
|
b96d77db63 | ||
|
|
fe9287a20e | ||
|
|
d30eb186fd | ||
|
|
b8c0d0f589 | ||
|
|
e6b1e1df3a | ||
|
|
f7d4aae815 | ||
|
|
da5bfd6bea | ||
|
|
d0c59dc73f | ||
|
|
79b9f2fdf2 | ||
|
|
1207568c60 | ||
|
|
0bcec43b9a | ||
|
|
0c5ccbe6eb | ||
|
|
d3d027bc2d | ||
|
|
278afe0691 | ||
|
|
6854ed319b | ||
|
|
07d3842de8 | ||
|
|
c66ce278e2 | ||
|
|
9a76ea227d | ||
|
|
ecbe37085b | ||
|
|
5dc88796d9 | ||
|
|
bf3debdfb2 | ||
|
|
9bb9bdd0a5 | ||
|
|
5bf88069db | ||
|
|
f874b8aebd | ||
|
|
2873aaf4e2 | ||
|
|
daab8d4e14 | ||
|
|
df648dbb06 | ||
|
|
c4d52e0a80 | ||
|
|
6988ab0a4f | ||
|
|
630502e17d | ||
|
|
0cc6ece8dc | ||
|
|
b6dcebb08e | ||
|
|
196193c238 | ||
|
|
e04c080e89 | ||
|
|
b8f92714ac | ||
|
|
ac052ce52a | ||
|
|
83934bfd14 | ||
|
|
7214d36a49 | ||
|
|
43eb3e4042 | ||
|
|
6b6c3e7ff3 | ||
|
|
3ab2da1226 | ||
|
|
d51be4cd77 | ||
|
|
68889d839d |
1
.idea/inspectionProfiles/idea_default.xml
generated
1
.idea/inspectionProfiles/idea_default.xml
generated
@@ -115,6 +115,7 @@
|
||||
<Problem reference="com.intellij.util.AstLoadingFilter" reason="Absent in 181. Almost all methods were renamed in 183. Use org.jetbrains.kotlin.util.AstLoadingFilter instead." />
|
||||
<Problem reference="com.intellij.testFramework.codeInsight.hierarchy.HierarchyViewTestFixture" reason="Absent in <= 181. Use org.jetbrains.kotlin.test.HierarchyViewTestFixture instead." />
|
||||
<Problem reference="org.jetbrains.kotlin.test.HierarchyViewTestFixtureCompat" reason="Do not use the wrapper for 181 directly. Use org.jetbrains.kotlin.test.HierarchyViewTestFixture instead." />
|
||||
<Problem reference="com.intellij.psi.codeStyle.CodeStyleSettingsProvider" reason="Additional method is introduced in 183 instead of deprecated one. Use CodeStyleSettingsProviderCompat instead." />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
|
||||
7264
ChangeLog.md
7264
ChangeLog.md
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@ sourceSets {
|
||||
|
||||
runtimeJar {
|
||||
from("$projectDir/src") { include("**/*.xml") }
|
||||
manifest.attributes.put("Class-Path", "kotlin-stdlib.jar kotlin-reflect.jar kotlin-script-runtime.jar kotlin-preloader.jar")
|
||||
manifest.attributes.put("Class-Path", "$compilerManifestClassPath kotlin-preloader.jar")
|
||||
}
|
||||
|
||||
dist()
|
||||
|
||||
@@ -169,6 +169,7 @@ extra["versions.robolectric"] = "3.1"
|
||||
extra["versions.org.springframework"] = "4.2.0.RELEASE"
|
||||
extra["versions.jflex"] = "1.7.0"
|
||||
extra["versions.markdown"] = "0.1.25"
|
||||
extra["versions.trove4j"] = "1.0.20181211"
|
||||
|
||||
val isTeamcityBuild = project.hasProperty("teamcity") || System.getenv("TEAMCITY_VERSION") != null
|
||||
val intellijUltimateEnabled = project.getBooleanProperty("intellijUltimateEnabled") ?: isTeamcityBuild
|
||||
@@ -479,6 +480,7 @@ tasks {
|
||||
":compiler:container:test",
|
||||
":compiler:tests-java8:test",
|
||||
":compiler:tests-spec:remoteRunTests")
|
||||
dependsOn(":plugins:jvm-abi-gen:test")
|
||||
}
|
||||
|
||||
create("jsCompilerTest") {
|
||||
|
||||
@@ -15,6 +15,7 @@ fun Project.smartJavaExec(configure: JavaExec.() -> Unit) = task<JavaExec> javaE
|
||||
val classpath = classpath
|
||||
val main = main
|
||||
dependsOn(classpath)
|
||||
inputs.files(classpath)
|
||||
inputs.property("main", main)
|
||||
doFirst {
|
||||
val classPathString = classpath.joinToString(" ") { project.file(it).toURI().toString() }
|
||||
|
||||
@@ -104,6 +104,9 @@ fun Project.firstFromJavaHomeThatExists(vararg paths: String, jdkHome: File = Fi
|
||||
fun Project.toolsJar(jdkHome: File = File(this.property("JDK_18") as String)): File? =
|
||||
firstFromJavaHomeThatExists("lib/tools.jar", jdkHome = jdkHome)
|
||||
|
||||
val compilerManifestClassPath
|
||||
get() = "kotlin-stdlib.jar kotlin-reflect.jar kotlin-script-runtime.jar trove4j.jar"
|
||||
|
||||
object EmbeddedComponents {
|
||||
val CONFIGURATION_NAME = "embeddedComponents"
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ val packagesToRelocate =
|
||||
"org.jdom",
|
||||
"org.picocontainer",
|
||||
"org.jline",
|
||||
"gnu",
|
||||
"org.fusesource",
|
||||
"kotlinx.coroutines")
|
||||
|
||||
|
||||
@@ -1217,8 +1217,16 @@ public class AsmUtil {
|
||||
return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName();
|
||||
}
|
||||
|
||||
public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) {
|
||||
if (isPrimitive(type)) {
|
||||
public static void putJavaLangClassInstance(
|
||||
@NotNull InstructionAdapter v,
|
||||
@NotNull Type type,
|
||||
@Nullable KotlinType kotlinType,
|
||||
@NotNull GenerationState state
|
||||
) {
|
||||
if (kotlinType != null && InlineClassesUtilsKt.isInlineClassType(kotlinType)) {
|
||||
v.aconst(boxType(type, kotlinType, state));
|
||||
}
|
||||
else if (isPrimitive(type)) {
|
||||
v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;");
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -40,7 +40,16 @@ public class ClassBuilderMode {
|
||||
* Full function bodies
|
||||
*/
|
||||
public final static ClassBuilderMode FULL = new ClassBuilderMode(
|
||||
/* bodies = */ true,
|
||||
/* bodies = */ true,
|
||||
/* metadata = */ true,
|
||||
/* sourceRetention = */ false,
|
||||
/* generateMultiFileFacadePartClasses = */ true);
|
||||
|
||||
/**
|
||||
* ABI for compilation (non-private signatures + inline function bodies)
|
||||
*/
|
||||
public final static ClassBuilderMode ABI = new ClassBuilderMode(
|
||||
/* bodies = */ true,
|
||||
/* metadata = */ true,
|
||||
/* sourceRetention = */ false,
|
||||
/* generateMultiFileFacadePartClasses = */ true);
|
||||
|
||||
@@ -245,7 +245,9 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
DescriptorSerializer serializer =
|
||||
DescriptorSerializer.createForLambda(new JvmSerializerExtension(v.getSerializationBindings(), state));
|
||||
|
||||
ProtoBuf.Function functionProto = serializer.functionProto(freeLambdaDescriptor).build();
|
||||
ProtoBuf.Function.Builder builder = serializer.functionProto(freeLambdaDescriptor);
|
||||
if (builder == null) return;
|
||||
ProtoBuf.Function functionProto = builder.build();
|
||||
|
||||
WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, 0, av -> {
|
||||
writeAnnotationData(av, serializer, functionProto);
|
||||
@@ -400,7 +402,9 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
|
||||
if (container instanceof ClassDescriptor) {
|
||||
// TODO: would it work for arrays?
|
||||
putJavaLangClassInstance(iv, state.getTypeMapper().mapClass((ClassDescriptor) container));
|
||||
SimpleType containerKotlinType = ((ClassDescriptor) container).getDefaultType();
|
||||
Type containerType = state.getTypeMapper().mapClass((ClassDescriptor) container);
|
||||
putJavaLangClassInstance(iv, containerType, containerKotlinType, state);
|
||||
}
|
||||
else if (container instanceof PackageFragmentDescriptor) {
|
||||
iv.aconst(state.getTypeMapper().mapOwner(descriptor));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@@ -89,6 +89,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isInt;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
@@ -97,8 +98,7 @@ import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
|
||||
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.*;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.*;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
|
||||
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionExpression;
|
||||
@@ -454,6 +454,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
return typeMapper.mapType(type);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Type mapTypeAsDeclaration(@NotNull KotlinType type) {
|
||||
return typeMapper.mapTypeAsDeclaration(type);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Type expressionType(@Nullable KtExpression expression) {
|
||||
return CodegenUtilKt.asmType(expression, typeMapper, bindingContext);
|
||||
@@ -1430,12 +1435,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isShouldMarkLineNumbers() {
|
||||
return shouldMarkLineNumbers;
|
||||
}
|
||||
|
||||
public void setShouldMarkLineNumbers(boolean shouldMarkLineNumbers) {
|
||||
this.shouldMarkLineNumbers = shouldMarkLineNumbers;
|
||||
public <T> T runWithShouldMarkLineNumbers(boolean enable, Supplier<T> operation) {
|
||||
boolean originalStatus = shouldMarkLineNumbers;
|
||||
this.shouldMarkLineNumbers = enable;
|
||||
try {
|
||||
return operation.get();
|
||||
} finally {
|
||||
this.shouldMarkLineNumbers = originalStatus;
|
||||
}
|
||||
}
|
||||
|
||||
public void markStartLineNumber(@NotNull KtElement element) {
|
||||
@@ -1881,7 +1888,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ClassDescriptor getSuperCallTarget(@NotNull Call call) {
|
||||
public ClassDescriptor getSuperCallTarget(@NotNull Call call) {
|
||||
KtSuperExpression superExpression = CallResolverUtilKt.getSuperCallExpression(call);
|
||||
return superExpression == null ? null : getSuperCallLabelTarget(context, superExpression);
|
||||
}
|
||||
@@ -2051,7 +2058,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
isDefaultAccessor(propertyDescriptor.getGetter()) && isDefaultAccessor(propertyDescriptor.getSetter())))) {
|
||||
fieldAccessorKind = JvmCodegenUtil.isDebuggerContext(context) ? AccessorKind.NORMAL : AccessorKind.IN_CLASS_COMPANION;
|
||||
}
|
||||
else if ((syntheticBackingField &&
|
||||
else //noinspection ConstantConditions
|
||||
if ((syntheticBackingField &&
|
||||
context.getFirstCrossInlineOrNonInlineContext().getParentContext().getContextDescriptor() != containingDeclaration)) {
|
||||
fieldAccessorKind = AccessorKind.FIELD_FROM_LOCAL;
|
||||
}
|
||||
@@ -2077,17 +2085,25 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
boolean skipPropertyAccessors;
|
||||
|
||||
PropertyDescriptor originalPropertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor);
|
||||
boolean directAccessToGetter = couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context,
|
||||
state.getShouldInlineConstVals());
|
||||
boolean directAccessToSetter = couldUseDirectAccessToProperty(propertyDescriptor, false, isDelegatedProperty, context,
|
||||
state.getShouldInlineConstVals());
|
||||
boolean directAccessToGetter =
|
||||
couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context, state.getShouldInlineConstVals());
|
||||
boolean directAccessToSetter =
|
||||
couldUseDirectAccessToProperty(propertyDescriptor, false, isDelegatedProperty, context, state.getShouldInlineConstVals());
|
||||
|
||||
if (fieldAccessorKind == AccessorKind.LATEINIT_INTRINSIC) {
|
||||
skipPropertyAccessors = !isPrivateProperty || context.getClassOrPackageParentContext() == backingFieldContext;
|
||||
skipPropertyAccessors =
|
||||
(!isPrivateProperty || context.getClassOrPackageParentContext() == backingFieldContext) &&
|
||||
!isBackingFieldMovedFromCompanion;
|
||||
|
||||
if (!skipPropertyAccessors) {
|
||||
propertyDescriptor = (AccessorForPropertyBackingField)
|
||||
backingFieldContext.getAccessor(propertyDescriptor, fieldAccessorKind, delegateType, superCallTarget);
|
||||
if (isBackingFieldMovedFromCompanion && context.getContextDescriptor() instanceof AccessorForPropertyBackingField) {
|
||||
propertyDescriptor = (PropertyDescriptor) backingFieldContext.getParentContext()
|
||||
.getAccessor(propertyDescriptor, AccessorKind.IN_CLASS_COMPANION, delegateType, superCallTarget);
|
||||
}
|
||||
else {
|
||||
propertyDescriptor =
|
||||
backingFieldContext.getAccessor(propertyDescriptor, fieldAccessorKind, delegateType, superCallTarget);
|
||||
}
|
||||
}
|
||||
ownerDescriptor = propertyDescriptor;
|
||||
}
|
||||
@@ -2097,10 +2113,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
(directAccessToGetter && (!propertyDescriptor.isVar() || directAccessToSetter));
|
||||
|
||||
if (!skipPropertyAccessors) {
|
||||
//noinspection ConstantConditions
|
||||
propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(
|
||||
propertyDescriptor, fieldAccessorKind, delegateType, superCallTarget
|
||||
);
|
||||
propertyDescriptor = backingFieldContext.getAccessor(propertyDescriptor, fieldAccessorKind, delegateType, superCallTarget);
|
||||
assert propertyDescriptor instanceof AccessorForPropertyBackingField :
|
||||
"Unexpected accessor descriptor: " + propertyDescriptor;
|
||||
ownerDescriptor = propertyDescriptor;
|
||||
@@ -3021,7 +3034,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
public int indexOfLocalNotDelegated(KtReferenceExpression lhs) {
|
||||
DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, lhs);
|
||||
if (isVarCapturedInClosure(bindingContext, declarationDescriptor)) {
|
||||
if (isBoxedLocalCapturedInClosure(bindingContext, declarationDescriptor)) {
|
||||
return -1;
|
||||
}
|
||||
if (declarationDescriptor instanceof LocalVariableDescriptor && ((LocalVariableDescriptor) declarationDescriptor).isDelegated()) {
|
||||
@@ -3117,7 +3130,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.JAVA_CLASS);
|
||||
}
|
||||
|
||||
putJavaLangClassInstance(v, typeMapper.mapType(type));
|
||||
putJavaLangClassInstance(v, typeMapper.mapType(type), type, state);
|
||||
}
|
||||
|
||||
if (wrapIntoKClass) {
|
||||
@@ -4030,6 +4043,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
else if (property.hasModifier(KtTokens.LATEINIT_KEYWORD)) {
|
||||
initializeLocalVariable(property, null);
|
||||
}
|
||||
else {
|
||||
initializeLocalVariableWithFakeDefaultValue(property);
|
||||
}
|
||||
|
||||
return StackValue.none();
|
||||
}
|
||||
@@ -4173,6 +4189,50 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
storeTo.storeSelector(resultType, resultKotlinType, v);
|
||||
}
|
||||
|
||||
// This is a workaround to avoid bugs with incorrect range of uninitialized variable:
|
||||
// 1) JDI error 305
|
||||
// 2) Expected R, got . in code with contracts
|
||||
// 3) D8 dropping the whole LVT
|
||||
private void initializeLocalVariableWithFakeDefaultValue(@NotNull KtProperty variableDeclaration) {
|
||||
LocalVariableDescriptor variableDescriptor = (LocalVariableDescriptor) getVariableDescriptorNotNull(variableDeclaration);
|
||||
|
||||
// Boxed variables already have a value
|
||||
if (isBoxedLocalCapturedInClosure(bindingContext, variableDescriptor)) return;
|
||||
|
||||
assert !variableDeclaration.hasDelegateExpressionOrInitializer() &&
|
||||
!variableDescriptor.isLateInit() : variableDeclaration.getText() + " in not variable declaration without initializer";
|
||||
|
||||
KotlinType kotlinType = variableDescriptor.getType();
|
||||
Type type = typeMapper.mapType(kotlinType);
|
||||
|
||||
if (type == Type.VOID_TYPE) return;
|
||||
|
||||
int index = lookupLocalIndex(variableDescriptor);
|
||||
assert index >= 0: variableDescriptor + " is not in frame map";
|
||||
|
||||
switch (type.getSort()) {
|
||||
case Type.BOOLEAN:
|
||||
case Type.CHAR:
|
||||
case Type.BYTE:
|
||||
case Type.SHORT:
|
||||
case Type.INT:
|
||||
v.iconst(0);
|
||||
break;
|
||||
case Type.FLOAT:
|
||||
v.fconst(0.0f);
|
||||
break;
|
||||
case Type.LONG:
|
||||
v.lconst(0L);
|
||||
break;
|
||||
case Type.DOUBLE:
|
||||
v.dconst(0.0);
|
||||
break;
|
||||
default:
|
||||
v.aconst(null);
|
||||
}
|
||||
v.store(index, type);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue generateProvideDelegateCallForLocalVariable(
|
||||
@NotNull StackValue initializer,
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import kotlin.text.StringsKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
||||
@@ -619,6 +620,7 @@ public class FunctionCodegen {
|
||||
isReleaseCoroutines);
|
||||
}
|
||||
|
||||
Label methodEntry = null;
|
||||
Label methodEnd;
|
||||
|
||||
int functionFakeIndex = -1;
|
||||
@@ -647,15 +649,21 @@ public class FunctionCodegen {
|
||||
parentCodegen.state, signature, functionDescriptor.getExtensionReceiverParameter(),
|
||||
functionDescriptor.getValueParameters(), isStaticMethod(context.getContextKind(), functionDescriptor)
|
||||
);
|
||||
// Manually add `continuation` parameter to frame map, thus it will not overlap with fake indices
|
||||
if (functionDescriptor.isSuspend() && CoroutineCodegenUtilKt.isSuspendFunctionNotSuspensionView(functionDescriptor)) {
|
||||
FunctionDescriptor view = CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(functionDescriptor, parentCodegen.state);
|
||||
ValueParameterDescriptor continuationValueDescriptor = view.getValueParameters().get(view.getValueParameters().size() - 1);
|
||||
frameMap.enter(continuationValueDescriptor, typeMapper.mapType(continuationValueDescriptor));
|
||||
}
|
||||
if (context.isInlineMethodContext()) {
|
||||
functionFakeIndex = frameMap.enterTemp(Type.INT_TYPE);
|
||||
functionFakeIndex = newFakeTempIndex(mv, frameMap);
|
||||
}
|
||||
|
||||
if (context instanceof InlineLambdaContext) {
|
||||
lambdaFakeIndex = frameMap.enterTemp(Type.INT_TYPE);
|
||||
lambdaFakeIndex = newFakeTempIndex(mv, frameMap);
|
||||
}
|
||||
|
||||
Label methodEntry = new Label();
|
||||
methodEntry = new Label();
|
||||
mv.visitLabel(methodEntry);
|
||||
context.setMethodStartLabel(methodEntry);
|
||||
|
||||
@@ -707,37 +715,43 @@ public class FunctionCodegen {
|
||||
|
||||
//TODO: it's best to move all below logic to 'generateLocalVariableTable' method
|
||||
if (context.isInlineMethodContext() && functionFakeIndex != -1) {
|
||||
assert methodEntry != null : "methodEntry is not initialized";
|
||||
mv.visitLocalVariable(
|
||||
JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION + typeMapper.mapAsmMethod(functionDescriptor).getName(),
|
||||
Type.INT_TYPE.getDescriptor(), null,
|
||||
methodBegin, methodEnd,
|
||||
methodEntry, methodEnd,
|
||||
functionFakeIndex);
|
||||
}
|
||||
|
||||
if (context instanceof InlineLambdaContext && thisType != null && lambdaFakeIndex != -1) {
|
||||
String name = thisType.getClassName();
|
||||
int indexOfLambdaOrdinal = name.lastIndexOf("$");
|
||||
if (indexOfLambdaOrdinal > 0) {
|
||||
int lambdaOrdinal = Integer.parseInt(name.substring(indexOfLambdaOrdinal + 1));
|
||||
String internalName = thisType.getInternalName();
|
||||
String lambdaLocalName = StringsKt.substringAfterLast(internalName, '/', internalName);
|
||||
|
||||
KtPureElement functionArgument = parentCodegen.element;
|
||||
String functionName = "unknown";
|
||||
if (functionArgument instanceof KtFunction) {
|
||||
ValueParameterDescriptor inlineArgumentDescriptor =
|
||||
InlineUtil.getInlineArgumentDescriptor((KtFunction) functionArgument, parentCodegen.bindingContext);
|
||||
if (inlineArgumentDescriptor != null) {
|
||||
functionName = inlineArgumentDescriptor.getContainingDeclaration().getName().asString();
|
||||
}
|
||||
KtPureElement functionArgument = parentCodegen.element;
|
||||
String functionName = "unknown";
|
||||
if (functionArgument instanceof KtFunction) {
|
||||
ValueParameterDescriptor inlineArgumentDescriptor =
|
||||
InlineUtil.getInlineArgumentDescriptor((KtFunction) functionArgument, parentCodegen.bindingContext);
|
||||
if (inlineArgumentDescriptor != null) {
|
||||
functionName = inlineArgumentDescriptor.getContainingDeclaration().getName().asString();
|
||||
}
|
||||
mv.visitLocalVariable(
|
||||
JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT + lambdaOrdinal + "$" + functionName,
|
||||
Type.INT_TYPE.getDescriptor(), null,
|
||||
methodBegin, methodEnd,
|
||||
lambdaFakeIndex);
|
||||
}
|
||||
assert methodEntry != null : "methodEntry is not initialized";
|
||||
mv.visitLocalVariable(
|
||||
JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT + "-" + functionName + "-" + lambdaLocalName,
|
||||
Type.INT_TYPE.getDescriptor(), null,
|
||||
methodEntry, methodEnd,
|
||||
lambdaFakeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private static int newFakeTempIndex(@NotNull MethodVisitor mv, FrameMap frameMap) {
|
||||
int fakeIndex = frameMap.enterTemp(Type.INT_TYPE);
|
||||
mv.visitLdcInsn(0);
|
||||
mv.visitVarInsn(ISTORE, fakeIndex);
|
||||
return fakeIndex;
|
||||
}
|
||||
|
||||
private static boolean isCompatibilityStubInDefaultImpls(
|
||||
@NotNull FunctionDescriptor functionDescriptor,
|
||||
@NotNull MethodContext context,
|
||||
@@ -1299,8 +1313,14 @@ public class FunctionCodegen {
|
||||
Label loadArg = new Label();
|
||||
iv.ifeq(loadArg);
|
||||
|
||||
StackValue.local(parameterIndex, type, parameterDescriptor.getType())
|
||||
.store(loadStrategy.genValue(parameterDescriptor, codegen), iv);
|
||||
CallableDescriptor containingDeclaration = parameterDescriptor.getContainingDeclaration();
|
||||
codegen.runWithShouldMarkLineNumbers(
|
||||
!(containingDeclaration instanceof MemberDescriptor) || !((MemberDescriptor) containingDeclaration).isExpect(),
|
||||
() -> {
|
||||
StackValue.local(parameterIndex, type, parameterDescriptor.getType())
|
||||
.store(loadStrategy.genValue(parameterDescriptor, codegen), iv);
|
||||
return null;
|
||||
});
|
||||
|
||||
iv.mark(loadArg);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
@@ -107,21 +108,22 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
|
||||
|
||||
JvmKotlinType type = genOrLoadOnStack(iv, context, propertyDescriptor, 0);
|
||||
Type asmType = type.getType();
|
||||
KotlinType kotlinType = type.getKotlinType();
|
||||
|
||||
if (asmType.getSort() == Type.ARRAY) {
|
||||
Type elementType = correctElementType(asmType);
|
||||
if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
|
||||
iv.invokestatic("java/util/Arrays", "toString", "([Ljava/lang/Object;)Ljava/lang/String;", false);
|
||||
asmType = JAVA_STRING_TYPE;
|
||||
kotlinType = DescriptorUtilsKt.getBuiltIns(function).getStringType();
|
||||
}
|
||||
else {
|
||||
if (elementType.getSort() != Type.CHAR) {
|
||||
iv.invokestatic("java/util/Arrays", "toString", "(" + asmType.getDescriptor() + ")Ljava/lang/String;", false);
|
||||
asmType = JAVA_STRING_TYPE;
|
||||
}
|
||||
else if (elementType.getSort() != Type.CHAR) {
|
||||
iv.invokestatic("java/util/Arrays", "toString", "(" + asmType.getDescriptor() + ")Ljava/lang/String;", false);
|
||||
asmType = JAVA_STRING_TYPE;
|
||||
kotlinType = DescriptorUtilsKt.getBuiltIns(function).getStringType();
|
||||
}
|
||||
}
|
||||
genInvokeAppendMethod(iv, asmType, type.getKotlinType(), typeMapper);
|
||||
genInvokeAppendMethod(iv, asmType, kotlinType, typeMapper);
|
||||
}
|
||||
|
||||
iv.aconst(")");
|
||||
|
||||
@@ -170,10 +170,10 @@ class ScriptCodegen private constructor(
|
||||
genFieldFromParam(typeMapper.mapClass(receiver), receiversParamIndex, name)
|
||||
}
|
||||
|
||||
scriptDescriptor.scriptEnvironmentProperties.forEachIndexed { envVarIndex, envVar ->
|
||||
scriptDescriptor.scriptProvidedProperties.forEachIndexed { envVarIndex, envVar ->
|
||||
val fieldClassType = typeMapper.mapType(envVar)
|
||||
val envVarParamIndex = frameMap.enterTemp(fieldClassType)
|
||||
val name = scriptContext.getEnvironmentVarName(envVarIndex)
|
||||
val name = scriptContext.getProvidedPropertyName(envVarIndex)
|
||||
genFieldFromParam(fieldClassType, envVarParamIndex, name)
|
||||
}
|
||||
|
||||
@@ -209,12 +209,12 @@ class ScriptCodegen private constructor(
|
||||
null
|
||||
)
|
||||
}
|
||||
for (envVarIndex in scriptDescriptor.scriptEnvironmentProperties.indices) {
|
||||
for (envVarIndex in scriptDescriptor.scriptProvidedProperties.indices) {
|
||||
classBuilder.newField(
|
||||
NO_ORIGIN,
|
||||
ACC_PUBLIC or ACC_FINAL,
|
||||
scriptContext.getEnvironmentVarName(envVarIndex),
|
||||
scriptContext.getEnvironmentVarType(envVarIndex).descriptor,
|
||||
scriptContext.getProvidedPropertyName(envVarIndex),
|
||||
scriptContext.getProvidedPropertyType(envVarIndex).descriptor,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
@@ -728,15 +728,20 @@ public abstract class StackValue {
|
||||
@NotNull Field refWrapper,
|
||||
@NotNull VariableDescriptor variableDescriptor
|
||||
) {
|
||||
return new FieldForSharedVar(localType, classType, fieldName, refWrapper,
|
||||
variableDescriptor.isLateInit(), variableDescriptor.getName());
|
||||
return new FieldForSharedVar(
|
||||
localType, variableDescriptor.getType(), classType, fieldName, refWrapper,
|
||||
variableDescriptor.isLateInit(), variableDescriptor.getName()
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FieldForSharedVar fieldForSharedVar(@NotNull FieldForSharedVar field, @NotNull StackValue newReceiver) {
|
||||
Field oldReceiver = (Field) field.receiver;
|
||||
Field newSharedVarReceiver = field(oldReceiver, newReceiver);
|
||||
return new FieldForSharedVar(field.type, field.owner, field.name, newSharedVarReceiver, field.isLateinit, field.variableName);
|
||||
return new FieldForSharedVar(
|
||||
field.type, field.kotlinType,
|
||||
field.owner, field.name, newSharedVarReceiver, field.isLateinit, field.variableName
|
||||
);
|
||||
}
|
||||
|
||||
public static StackValue coercion(@NotNull StackValue value, @NotNull Type castType, @Nullable KotlinType castKotlinType) {
|
||||
@@ -880,6 +885,7 @@ public abstract class StackValue {
|
||||
// 2) call using callable reference: in this case it is not local, but rather captured value
|
||||
// 3) recursive call: we are in the middle of defining it, but, thankfully, we can simply call `this.invoke` to
|
||||
// create new coroutine
|
||||
// 4) Normal call, but the value is captured
|
||||
|
||||
// First, check whether this is a normal call
|
||||
int index = codegen.lookupLocalIndex(callee);
|
||||
@@ -893,24 +899,27 @@ public abstract class StackValue {
|
||||
Type calleeType = CodegenBinding.asmTypeForAnonymousClass(bindingContext, callee);
|
||||
if (codegen.context.hasThisDescriptor()) {
|
||||
ClassDescriptor thisDescriptor = codegen.context.getThisDescriptor();
|
||||
ClassDescriptor classDescriptor = bindingContext.get(CLASS_FOR_CALLABLE, callee);
|
||||
if (thisDescriptor instanceof SyntheticClassDescriptorForLambda &&
|
||||
((SyntheticClassDescriptorForLambda) thisDescriptor).isCallableReference()) {
|
||||
// Call is inside a callable reference
|
||||
// if it is call to recursive local, just return this$0
|
||||
Boolean isRecursive = bindingContext.get(RECURSIVE_SUSPEND_CALLABLE_REFERENCE, thisDescriptor);
|
||||
if (isRecursive != null && isRecursive) {
|
||||
ClassDescriptor classDescriptor =
|
||||
bindingContext.get(CLASS_FOR_CALLABLE, callee);
|
||||
assert classDescriptor != null : "No CLASS_FOR_CALLABLE" + callee;
|
||||
return thisOrOuter(codegen, classDescriptor, false, false);
|
||||
}
|
||||
// Otherwise, just call constructor of the closure
|
||||
return codegen.findCapturedValue(callee);
|
||||
}
|
||||
if (classDescriptor == thisDescriptor) {
|
||||
// Recursive suspend local function, just call invoke on this, it will create new coroutine automatically
|
||||
codegen.v.visitVarInsn(ALOAD, 0);
|
||||
return onStack(calleeType);
|
||||
}
|
||||
}
|
||||
// Recursive suspend local function, just call invoke on this, it will create new coroutine automatically
|
||||
codegen.v.visitVarInsn(ALOAD, 0);
|
||||
return onStack(calleeType);
|
||||
// Otherwise, this is captured value
|
||||
return codegen.findCapturedValue(callee);
|
||||
}
|
||||
|
||||
private static StackValue platformStaticCallIfPresent(@NotNull StackValue resultReceiver, @NotNull CallableDescriptor descriptor) {
|
||||
@@ -1655,8 +1664,14 @@ public abstract class StackValue {
|
||||
|
||||
v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD,
|
||||
backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
|
||||
if (!skipLateinitAssertion) {
|
||||
genNotNullAssertionForLateInitIfNeeded(v);
|
||||
if (!skipLateinitAssertion && descriptor.isLateInit()) {
|
||||
CallableMemberDescriptor contextDescriptor = codegen.context.getContextDescriptor();
|
||||
boolean isCompanionAccessor =
|
||||
contextDescriptor instanceof AccessorForPropertyBackingField &&
|
||||
((AccessorForPropertyBackingField) contextDescriptor).getAccessorKind() == AccessorKind.IN_CLASS_COMPANION;
|
||||
if (!isCompanionAccessor) {
|
||||
genNonNullAssertForLateinit(v, this.descriptor.getName().asString());
|
||||
}
|
||||
}
|
||||
coerceTo(type, kotlinType, v);
|
||||
}
|
||||
@@ -1689,6 +1704,19 @@ public abstract class StackValue {
|
||||
|
||||
coerce(typeOfValueOnStack, kotlinTypeOfValueOnStack, type, kotlinType, v);
|
||||
|
||||
// For non-private lateinit properties in companion object, the assertion is generated in the public getFoo method
|
||||
// in the companion and _not_ in the synthetic accessor access$getFoo$cp in the outer class. The reason is that this way,
|
||||
// the synthetic accessor can be reused for isInitialized checks, which require there to be no assertion.
|
||||
// For lateinit properties that are accessed via the backing field directly (or via the synthetic accessor, if the access
|
||||
// is from a different context), the assertion will be generated on each access, see KT-28331.
|
||||
if (descriptor instanceof AccessorForPropertyBackingField) {
|
||||
PropertyDescriptor property = ((AccessorForPropertyBackingField) descriptor).getCalleeDescriptor();
|
||||
if (!skipLateinitAssertion && property.isLateInit() && JvmAbi.isPropertyWithBackingFieldInOuterClass(property) &&
|
||||
!JvmCodegenUtil.couldUseDirectAccessToProperty(property, true, false, codegen.context, false)) {
|
||||
genNonNullAssertForLateinit(v, property.getName().asString());
|
||||
}
|
||||
}
|
||||
|
||||
KotlinType returnType = descriptor.getReturnType();
|
||||
if (returnType != null && KotlinBuiltIns.isNothing(returnType)) {
|
||||
v.aconst(null);
|
||||
@@ -1727,12 +1755,6 @@ public abstract class StackValue {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void genNotNullAssertionForLateInitIfNeeded(@NotNull InstructionAdapter v) {
|
||||
if (!descriptor.isLateInit()) return;
|
||||
|
||||
StackValue.genNonNullAssertForLateinit(v, descriptor.getName().asString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(@NotNull StackValue rightSide, @NotNull InstructionAdapter v, boolean skipReceiver) {
|
||||
PropertySetterDescriptor setterDescriptor = descriptor.getSetter();
|
||||
@@ -1900,10 +1922,11 @@ public abstract class StackValue {
|
||||
final Name variableName;
|
||||
|
||||
public FieldForSharedVar(
|
||||
Type type, Type owner, String name, StackValue.Field receiver,
|
||||
Type type, KotlinType kotlinType,
|
||||
Type owner, String name, StackValue.Field receiver,
|
||||
boolean isLateinit, Name variableName
|
||||
) {
|
||||
super(type, null, false, false, receiver, receiver.canHaveSideEffects());
|
||||
super(type, kotlinType, false, false, receiver, receiver.canHaveSideEffects());
|
||||
|
||||
if (isLateinit && variableName == null) {
|
||||
throw new IllegalArgumentException("variableName should be non-null for captured lateinit variable " + name);
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
import org.jetbrains.org.objectweb.asm.tree.LocalVariableNode;
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
|
||||
import org.jetbrains.org.objectweb.asm.util.Textifier;
|
||||
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.getNodeText;
|
||||
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.wrapWithMaxLocalCalc;
|
||||
|
||||
public abstract class TransformationMethodVisitor extends MethodVisitor {
|
||||
|
||||
private final MethodNode methodNode;
|
||||
private final MethodVisitor delegate;
|
||||
|
||||
public TransformationMethodVisitor(
|
||||
@NotNull MethodVisitor delegate,
|
||||
int access,
|
||||
@NotNull String name,
|
||||
@NotNull String desc,
|
||||
@Nullable String signature,
|
||||
@Nullable String[] exceptions
|
||||
) {
|
||||
super(Opcodes.ASM5);
|
||||
this.delegate = delegate;
|
||||
this.methodNode = new MethodNode(access, name, desc, signature, exceptions);
|
||||
this.methodNode.localVariables = new ArrayList<>(5);
|
||||
this.mv = wrapWithMaxLocalCalc(methodNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
// force mv to calculate maxStack/maxLocals in case it didn't yet done
|
||||
if (methodNode.maxLocals <= 0 || methodNode.maxStack <= 0) {
|
||||
mv.visitMaxs(-1, -1);
|
||||
}
|
||||
|
||||
super.visitEnd();
|
||||
|
||||
try {
|
||||
if (shouldBeTransformed(methodNode)) {
|
||||
performTransformations(methodNode);
|
||||
}
|
||||
|
||||
methodNode.accept(new EndIgnoringMethodVisitorDecorator(Opcodes.ASM5, delegate));
|
||||
|
||||
|
||||
// In case of empty instructions list MethodNode.accept doesn't call visitLocalVariables of delegate
|
||||
// So we just do it here
|
||||
if (methodNode.instructions.size() == 0
|
||||
// MethodNode does not create a list of variables for abstract methods, so we would get NPE in accept() instead
|
||||
&& (!(delegate instanceof MethodNode) || methodNode.localVariables != null)
|
||||
) {
|
||||
List<LocalVariableNode> localVariables = methodNode.localVariables;
|
||||
// visits local variables
|
||||
int n = localVariables == null ? 0 : localVariables.size();
|
||||
for (int i = 0; i < n; ++i) {
|
||||
localVariables.get(i).accept(delegate);
|
||||
}
|
||||
}
|
||||
|
||||
delegate.visitEnd();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new CompilationException("Couldn't transform method node:\n" + getNodeText(methodNode), t, null);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void performTransformations(@NotNull MethodNode methodNode);
|
||||
|
||||
/**
|
||||
* You can use it when you need to ignore visit end
|
||||
*/
|
||||
private static class EndIgnoringMethodVisitorDecorator extends MethodVisitor {
|
||||
public EndIgnoringMethodVisitorDecorator(int api, @NotNull MethodVisitor mv) {
|
||||
super(api, mv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TraceMethodVisitor getTraceMethodVisitorIfPossible() {
|
||||
TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(new Textifier());
|
||||
try {
|
||||
methodNode.accept(traceMethodVisitor);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return traceMethodVisitor;
|
||||
}
|
||||
|
||||
private static boolean shouldBeTransformed(@NotNull MethodNode node) {
|
||||
return node.instructions.size() > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.org.objectweb.asm.util.Textifier
|
||||
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
import org.jetbrains.kotlin.codegen.inline.nodeText
|
||||
import org.jetbrains.kotlin.codegen.inline.wrapWithMaxLocalCalc
|
||||
|
||||
abstract class TransformationMethodVisitor(
|
||||
private val delegate: MethodVisitor,
|
||||
access: Int,
|
||||
name: String,
|
||||
desc: String,
|
||||
signature: String?,
|
||||
exceptions: Array<out String>?,
|
||||
api: Int = Opcodes.ASM5
|
||||
) : MethodVisitor(api) {
|
||||
|
||||
private val methodNode = MethodNode(access, name, desc, signature, exceptions).apply {
|
||||
localVariables = ArrayList(5)
|
||||
}
|
||||
|
||||
val traceMethodVisitorIfPossible: TraceMethodVisitor?
|
||||
get() {
|
||||
val traceMethodVisitor = TraceMethodVisitor(Textifier())
|
||||
try {
|
||||
methodNode.accept(traceMethodVisitor)
|
||||
} catch (e: Throwable) {
|
||||
return null
|
||||
}
|
||||
|
||||
return traceMethodVisitor
|
||||
}
|
||||
|
||||
init {
|
||||
mv = wrapWithMaxLocalCalc(methodNode)
|
||||
}
|
||||
|
||||
override fun visitEnd() {
|
||||
// force mv to calculate maxStack/maxLocals in case it didn't yet done
|
||||
if (methodNode.maxLocals <= 0 || methodNode.maxStack <= 0) {
|
||||
mv.visitMaxs(-1, -1)
|
||||
}
|
||||
|
||||
super.visitEnd()
|
||||
|
||||
try {
|
||||
if (shouldBeTransformed(methodNode)) {
|
||||
performTransformations(methodNode)
|
||||
}
|
||||
|
||||
methodNode.accept(EndIgnoringMethodVisitorDecorator(Opcodes.ASM5, delegate))
|
||||
|
||||
|
||||
// In case of empty instructions list MethodNode.accept doesn't call visitLocalVariables of delegate
|
||||
// So we just do it here
|
||||
if (methodNode.instructions.size() == 0
|
||||
// MethodNode does not create a list of variables for abstract methods, so we would get NPE in accept() instead
|
||||
&& (delegate !is MethodNode || methodNode.localVariables != null)
|
||||
) {
|
||||
val localVariables = methodNode.localVariables
|
||||
// visits local variables
|
||||
val n = localVariables?.size ?: 0
|
||||
for (i in 0 until n) {
|
||||
localVariables!![i].accept(delegate)
|
||||
}
|
||||
}
|
||||
|
||||
delegate.visitEnd()
|
||||
} catch (t: Throwable) {
|
||||
throw CompilationException("Couldn't transform method node:\n" + methodNode.nodeText, t, null)
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun performTransformations(methodNode: MethodNode)
|
||||
|
||||
/**
|
||||
* You can use it when you need to ignore visit end
|
||||
*/
|
||||
private class EndIgnoringMethodVisitorDecorator(api: Int, mv: MethodVisitor) : MethodVisitor(api, mv) {
|
||||
|
||||
override fun visitEnd() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldBeTransformed(node: MethodNode): Boolean {
|
||||
return node.instructions.size() > 0
|
||||
}
|
||||
}
|
||||
@@ -323,30 +323,27 @@ fun FqName.topLevelClassInternalName() = JvmClassName.byClassId(ClassId(parent()
|
||||
fun FqName.topLevelClassAsmType(): Type = Type.getObjectType(topLevelClassInternalName())
|
||||
|
||||
fun initializeVariablesForDestructuredLambdaParameters(codegen: ExpressionCodegen, valueParameters: List<ValueParameterDescriptor>) {
|
||||
val savedIsShouldMarkLineNumbers = codegen.isShouldMarkLineNumbers
|
||||
// Do not write line numbers until destructuring happens
|
||||
// (otherwise destructuring variables will be uninitialized in the beginning of lambda)
|
||||
codegen.isShouldMarkLineNumbers = false
|
||||
codegen.runWithShouldMarkLineNumbers(false) {
|
||||
for (parameterDescriptor in valueParameters) {
|
||||
if (parameterDescriptor !is ValueParameterDescriptorImpl.WithDestructuringDeclaration) continue
|
||||
|
||||
for (parameterDescriptor in valueParameters) {
|
||||
if (parameterDescriptor !is ValueParameterDescriptorImpl.WithDestructuringDeclaration) continue
|
||||
for (entry in parameterDescriptor.destructuringVariables.filterOutDescriptorsWithSpecialNames()) {
|
||||
codegen.myFrameMap.enter(entry, codegen.typeMapper.mapType(entry.type))
|
||||
}
|
||||
|
||||
for (entry in parameterDescriptor.destructuringVariables.filterOutDescriptorsWithSpecialNames()) {
|
||||
codegen.myFrameMap.enter(entry, codegen.typeMapper.mapType(entry.type))
|
||||
val destructuringDeclaration =
|
||||
(DescriptorToSourceUtils.descriptorToDeclaration(parameterDescriptor) as? KtParameter)?.destructuringDeclaration
|
||||
?: error("Destructuring declaration for descriptor $parameterDescriptor not found")
|
||||
|
||||
codegen.initializeDestructuringDeclarationVariables(
|
||||
destructuringDeclaration,
|
||||
TransientReceiver(parameterDescriptor.type),
|
||||
codegen.findLocalOrCapturedValue(parameterDescriptor) ?: error("Local var not found for parameter $parameterDescriptor")
|
||||
)
|
||||
}
|
||||
|
||||
val destructuringDeclaration =
|
||||
(DescriptorToSourceUtils.descriptorToDeclaration(parameterDescriptor) as? KtParameter)?.destructuringDeclaration
|
||||
?: error("Destructuring declaration for descriptor $parameterDescriptor not found")
|
||||
|
||||
codegen.initializeDestructuringDeclarationVariables(
|
||||
destructuringDeclaration,
|
||||
TransientReceiver(parameterDescriptor.type),
|
||||
codegen.findLocalOrCapturedValue(parameterDescriptor) ?: error("Local var not found for parameter $parameterDescriptor")
|
||||
)
|
||||
}
|
||||
|
||||
codegen.isShouldMarkLineNumbers = savedIsShouldMarkLineNumbers
|
||||
}
|
||||
|
||||
fun <D : CallableDescriptor> D.unwrapFrontendVersion() = unwrapInitialDescriptorForSuspendFunction()
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.context
|
||||
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.FieldInfo
|
||||
import org.jetbrains.kotlin.codegen.OwnerKind
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
@@ -33,9 +32,8 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.script.ScriptEnvironmentDescriptor
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.script.ScriptProvidedPropertiesDescriptor
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class ScriptContext(
|
||||
val typeMapper: KotlinTypeMapper,
|
||||
@@ -76,25 +74,24 @@ class ScriptContext(
|
||||
private val ctorImplicitReceiversParametersStart =
|
||||
ctorValueParametersStart + (scriptDescriptor.getSuperClassNotAny()?.unsubstitutedPrimaryConstructor?.valueParameters?.size ?: 0)
|
||||
|
||||
private val ctorEnvironmentVarsParametersStart =
|
||||
private val ctorProvidedPropertiesParametersStart =
|
||||
ctorImplicitReceiversParametersStart + scriptDescriptor.implicitReceivers.size
|
||||
|
||||
fun getImplicitReceiverName(index: Int): String =
|
||||
scriptDescriptor.unsubstitutedPrimaryConstructor.valueParameters[ctorImplicitReceiversParametersStart + index].name.identifier
|
||||
|
||||
fun getImplicitReceiverType(index: Int): Type? {
|
||||
val receivers = script.kotlinScriptDefinition.implicitReceivers
|
||||
val kClass = receivers.getOrNull(index)?.classifier as? KClass<*>
|
||||
return kClass?.java?.classId?.let(AsmUtil::asmTypeByClassId)
|
||||
val receiverParam = scriptDescriptor.unsubstitutedPrimaryConstructor.valueParameters[ctorImplicitReceiversParametersStart + index]
|
||||
return state.typeMapper.mapType(receiverParam.type)
|
||||
}
|
||||
|
||||
fun getEnvironmentVarName(index: Int): String =
|
||||
scriptDescriptor.unsubstitutedPrimaryConstructor.valueParameters[ctorEnvironmentVarsParametersStart + index].name.identifier
|
||||
fun getProvidedPropertyName(index: Int): String =
|
||||
scriptDescriptor.unsubstitutedPrimaryConstructor.valueParameters[ctorProvidedPropertiesParametersStart + index].name.identifier
|
||||
|
||||
fun getEnvironmentVarType(index: Int): Type = typeMapper.mapType(scriptDescriptor.scriptEnvironmentProperties[index].type)
|
||||
fun getProvidedPropertyType(index: Int): Type = typeMapper.mapType(scriptDescriptor.scriptProvidedProperties[index].type)
|
||||
|
||||
fun getOuterReceiverExpression(prefix: StackValue?, thisOrOuterClass: ClassDescriptor): StackValue {
|
||||
if (thisOrOuterClass is ScriptEnvironmentDescriptor) {
|
||||
if (thisOrOuterClass is ScriptProvidedPropertiesDescriptor) {
|
||||
return prefix ?: StackValue.LOCAL_0
|
||||
}
|
||||
receiverDescriptors.forEachIndexed { index, outerReceiver ->
|
||||
@@ -113,10 +110,8 @@ class ScriptContext(
|
||||
|
||||
fun getScriptFieldName(scriptDescriptor: ScriptDescriptor): String {
|
||||
val index = earlierScripts.indexOf(scriptDescriptor)
|
||||
if (index < 0) {
|
||||
throw IllegalStateException("Unregistered script: $scriptDescriptor")
|
||||
}
|
||||
return "script$" + (index + 1)
|
||||
return if (index >= 0) "script$" + (index + 1)
|
||||
else "\$\$importedScript${scriptDescriptor.name.identifier}"
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
|
||||
@@ -652,7 +652,8 @@ class CoroutineCodegenForNamedFunction private constructor(
|
||||
override fun generateKotlinMetadataAnnotation() {
|
||||
writeKotlinMetadata(v, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, 0) { av ->
|
||||
val serializer = DescriptorSerializer.createForLambda(JvmSerializerExtension(v.serializationBindings, state))
|
||||
val functionProto = serializer.functionProto(createFreeFakeLambdaDescriptor(suspendFunctionJvmView)).build()
|
||||
val functionProto =
|
||||
serializer.functionProto(createFreeFakeLambdaDescriptor(suspendFunctionJvmView))?.build() ?: return@writeKotlinMetadata
|
||||
AsmUtil.writeAnnotationData(av, serializer, functionProto)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
@@ -538,7 +539,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
// k + 2 - exception
|
||||
val variablesToSpill =
|
||||
(0 until localsCount)
|
||||
.filter { it !in setOf(continuationIndex, dataIndex, exceptionIndex) }
|
||||
.filterNot { it in setOf(continuationIndex, dataIndex, exceptionIndex) }
|
||||
.map { Pair(it, frame.getLocal(it)) }
|
||||
.filter { (index, value) ->
|
||||
(index == 0 && needDispatchReceiver && isForNamedFunction) ||
|
||||
@@ -944,7 +945,13 @@ private fun allSuspensionPointsAreTailCalls(
|
||||
}
|
||||
if (insideTryBlock) return@all false
|
||||
|
||||
safelyReachableReturns[endIndex + 1] != null
|
||||
safelyReachableReturns[endIndex + 1]?.all { returnIndex ->
|
||||
sourceFrames[returnIndex].top().sure {
|
||||
"There must be some value on stack to return"
|
||||
}.insns.all { sourceInsn ->
|
||||
sourceInsn?.let(instructions::indexOf) in beginIndex..endIndex
|
||||
}
|
||||
} ?: false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ import com.google.common.collect.LinkedListMultimap
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import java.util.*
|
||||
import kotlin.collections.HashSet
|
||||
import kotlin.collections.LinkedHashSet
|
||||
|
||||
abstract class CoveringTryCatchNodeProcessor(parameterSize: Int) {
|
||||
val tryBlocksMetaInfo: IntervalMetaInfo<TryCatchBlockNodeInfo> = IntervalMetaInfo(this)
|
||||
@@ -114,7 +116,7 @@ class IntervalMetaInfo<T : SplittableInterval<T>>(private val processor: Coverin
|
||||
}
|
||||
|
||||
fun splitAndRemoveCurrentIntervals(by: Interval, keepStart: Boolean) {
|
||||
currentIntervals.map { splitAndRemoveInterval(it, by, keepStart) }
|
||||
currentIntervals.toList().forEach { splitAndRemoveIntervalFromCurrents(it, by, keepStart) }
|
||||
}
|
||||
|
||||
fun processCurrent(curIns: LabelNode, directOrder: Boolean) {
|
||||
@@ -141,7 +143,7 @@ class IntervalMetaInfo<T : SplittableInterval<T>>(private val processor: Coverin
|
||||
return split
|
||||
}
|
||||
|
||||
fun splitAndRemoveInterval(interval: T, by: Interval, keepStart: Boolean): SplitPair<T> {
|
||||
fun splitAndRemoveIntervalFromCurrents(interval: T, by: Interval, keepStart: Boolean): SplitPair<T> {
|
||||
val splitPair = split(interval, by, keepStart)
|
||||
val removed = currentIntervals.remove(splitPair.patchedPart)
|
||||
assert(removed) { "Wrong interval structure: $splitPair" }
|
||||
|
||||
@@ -381,7 +381,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
||||
// so we should split original interval by inserted finally one
|
||||
for (TryCatchBlockNodeInfo block : updatingClusterBlocks) {
|
||||
//update exception mapping
|
||||
SplitPair<TryCatchBlockNodeInfo> split = tryBlocksMetaInfo.splitAndRemoveInterval(block, splitBy, false);
|
||||
SplitPair<TryCatchBlockNodeInfo> split = tryBlocksMetaInfo.splitAndRemoveIntervalFromCurrents(block, splitBy, false);
|
||||
checkFinally(split.getNewPart());
|
||||
checkFinally(split.getPatchedPart());
|
||||
//block patched in split method
|
||||
|
||||
@@ -156,17 +156,18 @@ class DefaultLambda(
|
||||
|
||||
isBoundCallableReference = (isFunctionReference || isPropertyReference) && capturedVars.isNotEmpty()
|
||||
|
||||
invokeMethod = Method(
|
||||
(if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString(),
|
||||
sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod.descriptor
|
||||
)
|
||||
val methodName = (if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString()
|
||||
val signature = sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod.descriptor
|
||||
|
||||
node = getMethodNode(
|
||||
classReader.b,
|
||||
invokeMethod.name,
|
||||
invokeMethod.descriptor,
|
||||
lambdaClassType
|
||||
) ?: error("Can't find method '${invokeMethod.name}${invokeMethod.descriptor}' in '${classReader.className}'")
|
||||
methodName,
|
||||
signature,
|
||||
lambdaClassType,
|
||||
signatureAmbiguity = true
|
||||
) ?: error("Can't find method '$methodName$signature' in '${classReader.className}'")
|
||||
|
||||
invokeMethod = Method(node.node.name, node.node.desc)
|
||||
|
||||
if (needReification) {
|
||||
//nested classes could also require reification
|
||||
|
||||
@@ -418,12 +418,15 @@ class MethodInliner(
|
||||
private val isInliningLambda = nodeRemapper.isInsideInliningLambda
|
||||
|
||||
private fun getNewIndex(`var`: Int): Int {
|
||||
if (inliningContext.isInliningLambda && inliningContext.lambdaInfo is IrExpressionLambda) {
|
||||
val lambdaInfo = inliningContext.lambdaInfo
|
||||
if (inliningContext.isInliningLambda && lambdaInfo is IrExpressionLambda) {
|
||||
if (`var` < parameters.argsSizeOnStack) {
|
||||
if (`var` < capturedParamsSize) {
|
||||
return `var` + realParametersSize
|
||||
}
|
||||
else {
|
||||
val capturedParamsStartIndex =
|
||||
if (lambdaInfo.isExtensionLambda) lambdaInfo.invokeMethod.argumentTypes[0].size else 0 //shift by extension
|
||||
val capturedParamsEndIndex = capturedParamsSize + capturedParamsStartIndex - 1
|
||||
if (`var` in capturedParamsStartIndex..capturedParamsEndIndex) {
|
||||
return `var` + realParametersSize - capturedParamsStartIndex //subtract extension
|
||||
} else if (`var` >= capturedParamsStartIndex) {
|
||||
return `var` - capturedParamsSize
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,8 @@ internal fun getMethodNode(
|
||||
classData: ByteArray,
|
||||
methodName: String,
|
||||
methodDescriptor: String,
|
||||
classType: Type
|
||||
classType: Type,
|
||||
signatureAmbiguity: Boolean = false
|
||||
): SMAPAndMethodNode? {
|
||||
val cr = ClassReader(classData)
|
||||
var node: MethodNode? = null
|
||||
@@ -113,17 +114,28 @@ internal fun getMethodNode(
|
||||
signature: String?,
|
||||
exceptions: Array<String>?
|
||||
): MethodVisitor? {
|
||||
if (methodName == name && methodDescriptor == desc) {
|
||||
node = object : MethodNode(API, access, name, desc, signature, exceptions) {
|
||||
override fun visitLineNumber(line: Int, start: Label) {
|
||||
super.visitLineNumber(line, start)
|
||||
lines[0] = Math.min(lines[0], line)
|
||||
lines[1] = Math.max(lines[1], line)
|
||||
}
|
||||
if (methodName != name || (signatureAmbiguity && access.and(Opcodes.ACC_SYNTHETIC) != 0)) return null
|
||||
|
||||
if (methodDescriptor != desc) {
|
||||
val sameNumberOfParameters = Type.getArgumentTypes(methodDescriptor).size == Type.getArgumentTypes(desc).size
|
||||
if (!signatureAmbiguity || !sameNumberOfParameters) {
|
||||
return null
|
||||
}
|
||||
return node
|
||||
}
|
||||
return null
|
||||
|
||||
node?.let { existing ->
|
||||
throw AssertionError("Can't find proper '$name' method for inline: ambiguity between '${existing.name + existing.desc}' and '${name + desc}'")
|
||||
}
|
||||
|
||||
return object : MethodNode(API, access, name, desc, signature, exceptions) {
|
||||
override fun visitLineNumber(line: Int, start: Label) {
|
||||
super.visitLineNumber(line, start)
|
||||
lines[0] = Math.min(lines[0], line)
|
||||
lines[1] = Math.max(lines[1], line)
|
||||
}
|
||||
}.also {
|
||||
node = it
|
||||
}
|
||||
}
|
||||
}, ClassReader.SKIP_FRAMES or if (GENERATE_SMAP) 0 else ClassReader.SKIP_DEBUG)
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ class KClassJavaObjectTypeProperty : IntrinsicPropertyGetter() {
|
||||
}
|
||||
codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(lhs.type, ReifiedTypeInliner.OperationKind.JAVA_CLASS)
|
||||
}
|
||||
iv.aconst(AsmUtil.boxType(codegen.asmType(lhs.type)))
|
||||
iv.aconst(AsmUtil.boxType(codegen.mapTypeAsDeclaration(lhs.type)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.psi.KtClassLiteralExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.isInlineClassType
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
@@ -32,21 +33,28 @@ class KClassJavaPrimitiveTypeProperty : IntrinsicPropertyGetter() {
|
||||
val receiverType = codegen.bindingContext.getType(receiverExpression) ?: return null
|
||||
if (!KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType(receiverType)) return null
|
||||
}
|
||||
|
||||
val lhsType = codegen.asmType(lhs.type)
|
||||
return StackValue.operation(returnType) { iv ->
|
||||
when {
|
||||
lhs is DoubleColonLHS.Expression && !lhs.isObjectQualifier -> {
|
||||
codegen.gen(receiverExpression).put(lhsType, iv)
|
||||
AsmUtil.pop(iv, lhsType)
|
||||
if (lhs.type.isInlineClassType())
|
||||
iv.aconst(null)
|
||||
else
|
||||
iv.getstatic(AsmUtil.boxType(lhsType).internalName, "TYPE", "Ljava/lang/Class;")
|
||||
}
|
||||
|
||||
!lhs.type.isInlineClassType() && isPrimitiveOrWrapper(lhsType) -> {
|
||||
iv.getstatic(AsmUtil.boxType(lhsType).internalName, "TYPE", "Ljava/lang/Class;")
|
||||
}
|
||||
AsmUtil.isPrimitive(lhsType) ||
|
||||
AsmUtil.unboxPrimitiveTypeOrNull(lhsType) != null ||
|
||||
AsmTypes.VOID_WRAPPER_TYPE == lhsType -> {
|
||||
iv.getstatic(AsmUtil.boxType(lhsType).internalName, "TYPE", "Ljava/lang/Class;")
|
||||
}
|
||||
|
||||
else -> iv.aconst(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isPrimitiveOrWrapper(lhsType: Type) =
|
||||
AsmUtil.isPrimitive(lhsType) || AsmUtil.unboxPrimitiveTypeOrNull(lhsType) != null || AsmTypes.VOID_WRAPPER_TYPE == lhsType
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@ class OptimizationMethodVisitor(
|
||||
optimizationTransformer.transform("fake", methodNode)
|
||||
}
|
||||
|
||||
DeadCodeEliminationMethodTransformer().transform("fake", methodNode)
|
||||
|
||||
methodNode.prepareForEmitting()
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.codegen.optimization.common
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.IincInsnNode
|
||||
@@ -78,11 +79,13 @@ private fun useVar(
|
||||
) {
|
||||
val index = node.instructions.indexOf(insn)
|
||||
node.localVariables.filter {
|
||||
node.instructions.indexOf(it.start) < index && index < node.instructions.indexOf(it.end) &&
|
||||
// Inliner fake variables, despite being present in LVT, are not read, thus are always dead
|
||||
!it.name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT) && !it.name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) &&
|
||||
node.instructions.indexOf(it.start) < index && index < node.instructions.indexOf(it.end) &&
|
||||
Type.getType(it.desc).sort == typeAnnotatedFrame?.getLocal(it.index)?.type?.sort
|
||||
}.forEach {
|
||||
frame.markAlive(it.index)
|
||||
}
|
||||
frame.markAlive(it.index)
|
||||
}
|
||||
|
||||
if (insn is VarInsnNode && insn.isLoadOperation()) {
|
||||
frame.markAlive(insn.`var`)
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.protobuf.GeneratedMessageLite
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPrivateApi
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.nonSourceAnnotations
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmDefaultAnnotation
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer
|
||||
@@ -47,6 +48,21 @@ class JvmSerializerExtension(private val bindings: JvmSerializationBindings, sta
|
||||
override val metadataVersion = state.metadataVersion
|
||||
|
||||
override fun shouldUseTypeTable(): Boolean = useTypeTable
|
||||
override fun shouldSerializeFunction(descriptor: FunctionDescriptor): Boolean {
|
||||
return classBuilderMode != ClassBuilderMode.ABI || descriptor.visibility != Visibilities.PRIVATE
|
||||
}
|
||||
|
||||
override fun shouldSerializeProperty(descriptor: PropertyDescriptor): Boolean {
|
||||
return classBuilderMode != ClassBuilderMode.ABI || descriptor.visibility != Visibilities.PRIVATE
|
||||
}
|
||||
|
||||
override fun shouldSerializeTypeAlias(descriptor: TypeAliasDescriptor): Boolean {
|
||||
return classBuilderMode != ClassBuilderMode.ABI || descriptor.visibility != Visibilities.PRIVATE
|
||||
}
|
||||
|
||||
override fun shouldSerializeNestedClass(descriptor: ClassDescriptor): Boolean {
|
||||
return classBuilderMode != ClassBuilderMode.ABI || !descriptor.isEffectivelyPrivateApi
|
||||
}
|
||||
|
||||
override fun serializeClass(
|
||||
descriptor: ClassDescriptor,
|
||||
@@ -103,7 +119,7 @@ class JvmSerializerExtension(private val bindings: JvmSerializationBindings, sta
|
||||
for (localVariable in localVariables) {
|
||||
val propertyDescriptor = createFreeFakeLocalPropertyDescriptor(localVariable)
|
||||
val serializer = DescriptorSerializer.createForLambda(this)
|
||||
proto.addExtension(extension, serializer.propertyProto(propertyDescriptor).build())
|
||||
proto.addExtension(extension, serializer.propertyProto(propertyDescriptor)?.build() ?: continue)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ import static org.jetbrains.kotlin.codegen.AsmUtil.isStaticMethod;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.isBoxedLocalCapturedInClosure;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.DEFAULT_CONSTRUCTOR_MARKER;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE;
|
||||
@@ -1870,7 +1870,7 @@ public class KotlinTypeMapper {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (descriptor instanceof VariableDescriptor && isVarCapturedInClosure(bindingContext, descriptor)) {
|
||||
if (descriptor instanceof VariableDescriptor && isBoxedLocalCapturedInClosure(bindingContext, descriptor)) {
|
||||
return StackValue.sharedTypeForType(mapType(((VariableDescriptor) descriptor).getType()));
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ abstract class CommonToolArguments : Freezable(), Serializable {
|
||||
var freeArgs: List<String> by FreezableVar(emptyList())
|
||||
|
||||
@Transient
|
||||
var errors: ArgumentParseErrors = ArgumentParseErrors()
|
||||
var errors: ArgumentParseErrors? = null
|
||||
|
||||
@Argument(value = "-help", shortName = "-h", description = "Print a synopsis of standard options")
|
||||
var help: Boolean by FreezableVar(false)
|
||||
|
||||
@@ -38,12 +38,12 @@ private const val ADVANCED_ARGUMENT_PREFIX = "-X"
|
||||
private const val FREE_ARGS_DELIMITER = "--"
|
||||
|
||||
data class ArgumentParseErrors(
|
||||
val unknownArgs: MutableList<String> = SmartList<String>(),
|
||||
val unknownArgs: MutableList<String> = SmartList(),
|
||||
|
||||
val unknownExtraFlags: MutableList<String> = SmartList<String>(),
|
||||
val unknownExtraFlags: MutableList<String> = SmartList(),
|
||||
|
||||
// Names of extra (-X...) arguments which have been passed in an obsolete form ("-Xaaa bbb", instead of "-Xaaa=bbb")
|
||||
val extraArgumentsPassedInObsoleteForm: MutableList<String> = SmartList<String>(),
|
||||
val extraArgumentsPassedInObsoleteForm: MutableList<String> = SmartList(),
|
||||
|
||||
// Non-boolean arguments which have been passed multiple times, possibly with different values.
|
||||
// The key in the map is the name of the argument, the value is the last passed value.
|
||||
@@ -62,11 +62,12 @@ data class ArgumentParseErrors(
|
||||
|
||||
// Parses arguments into the passed [result] object. Errors related to the parsing will be collected into [CommonToolArguments.errors].
|
||||
fun <A : CommonToolArguments> parseCommandLineArguments(args: List<String>, result: A) {
|
||||
val preprocessed = preprocessCommandLineArguments(args, result.errors)
|
||||
parsePreprocessedCommandLineArguments(preprocessed, result)
|
||||
val errors = result.errors ?: ArgumentParseErrors().also { result.errors = it }
|
||||
val preprocessed = preprocessCommandLineArguments(args, errors)
|
||||
parsePreprocessedCommandLineArguments(preprocessed, result, errors)
|
||||
}
|
||||
|
||||
private fun <A : CommonToolArguments> parsePreprocessedCommandLineArguments(args: List<String>, result: A) {
|
||||
private fun <A : CommonToolArguments> parsePreprocessedCommandLineArguments(args: List<String>, result: A, errors: ArgumentParseErrors) {
|
||||
data class ArgumentField(val property: KMutableProperty1<A, Any?>, val argument: Argument)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@@ -76,7 +77,6 @@ private fun <A : CommonToolArguments> parsePreprocessedCommandLineArguments(args
|
||||
ArgumentField(property as KMutableProperty1<A, Any?>, argument)
|
||||
}
|
||||
|
||||
val errors = result.errors
|
||||
val visitedArgs = mutableSetOf<String>()
|
||||
var freeArgsStarted = false
|
||||
|
||||
@@ -198,7 +198,8 @@ private fun <A : CommonToolArguments> updateField(property: KMutableProperty1<A,
|
||||
/**
|
||||
* @return error message if arguments are parsed incorrectly, null otherwise
|
||||
*/
|
||||
fun validateArguments(errors: ArgumentParseErrors): String? {
|
||||
fun validateArguments(errors: ArgumentParseErrors?): String? {
|
||||
if (errors == null) return null
|
||||
if (errors.argumentWithoutValue != null) {
|
||||
return "No value passed for argument ${errors.argumentWithoutValue}"
|
||||
}
|
||||
|
||||
@@ -118,7 +118,10 @@ abstract class CLITool<A : CommonToolArguments> {
|
||||
}
|
||||
|
||||
private fun reportArgumentParseProblems(collector: MessageCollector, arguments: A) {
|
||||
val errors = arguments.errors
|
||||
reportUnsafeInternalArgumentsIfAny(arguments, collector)
|
||||
|
||||
val errors = arguments.errors ?: return
|
||||
|
||||
for (flag in errors.unknownExtraFlags) {
|
||||
collector.report(STRONG_WARNING, "Flag is not supported by this version of the compiler: $flag")
|
||||
}
|
||||
@@ -139,7 +142,6 @@ abstract class CLITool<A : CommonToolArguments> {
|
||||
collector.report(STRONG_WARNING, argfileError)
|
||||
}
|
||||
|
||||
reportUnsafeInternalArgumentsIfAny(arguments, collector)
|
||||
for (internalArgumentsError in errors.internalArgumentsParsingProblems) {
|
||||
collector.report(STRONG_WARNING, internalArgumentsError)
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import gnu.trove.THashSet
|
||||
import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
|
||||
import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndex
|
||||
import org.jetbrains.kotlin.cli.jvm.index.SingleJavaFileRootsIndex
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinder
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryClassSignatureParser
|
||||
@@ -81,7 +82,10 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
|
||||
private val binaryCache: MutableMap<ClassId, JavaClass?> = THashMap()
|
||||
private val signatureParsingComponent = BinaryClassSignatureParser()
|
||||
|
||||
override fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? {
|
||||
fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? = findClass(JavaClassFinder.Request(classId), searchScope)
|
||||
|
||||
override fun findClass(request: JavaClassFinder.Request, searchScope: GlobalSearchScope): JavaClass? {
|
||||
val (classId, classFileContentFromRequest, outerClassFromRequest) = request
|
||||
val virtualFile = findVirtualFileForTopLevelClass(classId, searchScope) ?: return null
|
||||
|
||||
if (useFastClassFilesReading && virtualFile.extension == "class") {
|
||||
@@ -92,13 +96,20 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
|
||||
// This is a true assumption by now since there are two search scopes in compiler: one for sources and another one for binary
|
||||
// When it become wrong because we introduce the modules into CLI, it's worth to consider
|
||||
// having different KotlinCliJavaFileManagerImpl's for different modules
|
||||
val classContent = virtualFile.contentsToByteArray()
|
||||
if (virtualFile.nameWithoutExtension.contains("$") && isNotTopLevelClass(classContent)) return@getOrPut null
|
||||
|
||||
classId.outerClassId?.let { outerClassId ->
|
||||
val outerClass = findClass(outerClassId, searchScope)
|
||||
return@getOrPut outerClass?.findInnerClass(classId.shortClassName)
|
||||
val outerClass = outerClassFromRequest ?: findClass(outerClassId, searchScope)
|
||||
|
||||
return if (outerClass is BinaryJavaClass)
|
||||
outerClass.findInnerClass(classId.shortClassName, classFileContentFromRequest)
|
||||
else
|
||||
outerClass?.findInnerClass(classId.shortClassName)
|
||||
}
|
||||
|
||||
// Here, we assume the class is top-level
|
||||
val classContent = classFileContentFromRequest ?: virtualFile.contentsToByteArray()
|
||||
if (virtualFile.nameWithoutExtension.contains("$") && isNotTopLevelClass(classContent)) return@getOrPut null
|
||||
|
||||
val resolver = ClassifierResolutionContext { findClass(it, allScope) }
|
||||
|
||||
BinaryJavaClass(
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.intellij.codeInsight.InferredAnnotationsManager
|
||||
import com.intellij.codeInsight.runner.JavaMainMethodProvider
|
||||
import com.intellij.core.*
|
||||
import com.intellij.ide.highlighter.JavaFileType
|
||||
import com.intellij.ide.plugins.PluginManagerCore
|
||||
import com.intellij.lang.MetaLanguage
|
||||
import com.intellij.lang.java.JavaParserDefinition
|
||||
import com.intellij.openapi.Disposable
|
||||
@@ -69,6 +68,7 @@ import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PRO
|
||||
import org.jetbrains.kotlin.cli.common.config.ContentRoot
|
||||
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
|
||||
import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.STRONG_WARNING
|
||||
@@ -241,16 +241,13 @@ class KotlinCoreEnvironment private constructor(
|
||||
}
|
||||
|
||||
sourceFiles += createKtFiles(project)
|
||||
sourceFiles.sortBy { it.virtualFile.path }
|
||||
|
||||
if (scriptDefinitionProvider != null) {
|
||||
ScriptDependenciesProvider.getInstance(project).let { importsProvider ->
|
||||
configuration.addJvmClasspathRoots(
|
||||
sourceFiles.mapNotNull(importsProvider::getScriptDependencies)
|
||||
.flatMap { it.classpath }
|
||||
.distinctBy { it.absolutePath })
|
||||
}
|
||||
val (classpath, newSources, _) = collectScriptsCompilationDependencies(configuration, project, sourceFiles)
|
||||
configuration.addJvmClasspathRoots(classpath)
|
||||
sourceFiles += newSources
|
||||
}
|
||||
sourceFiles.sortBy { it.virtualFile.path }
|
||||
|
||||
val jdkHome = configuration.get(JVMConfigurationKeys.JDK_HOME)
|
||||
val jrtFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL)
|
||||
@@ -427,58 +424,10 @@ class KotlinCoreEnvironment private constructor(
|
||||
|
||||
fun getSourceFiles(): List<KtFile> = sourceFiles
|
||||
|
||||
private fun createKtFiles(project: Project): List<KtFile> {
|
||||
val sourceRoots = getSourceRootsCheckingForDuplicates()
|
||||
private fun createKtFiles(project: Project): List<KtFile> =
|
||||
createSourceFilesFromSourceRoots(configuration, project, getSourceRootsCheckingForDuplicates())
|
||||
|
||||
val localFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
|
||||
val psiManager = PsiManager.getInstance(project)
|
||||
|
||||
val processedFiles = hashSetOf<VirtualFile>()
|
||||
val result = mutableListOf<KtFile>()
|
||||
|
||||
val virtualFileCreator = PreprocessedFileCreator(project)
|
||||
|
||||
for ((sourceRootPath, isCommon) in sourceRoots) {
|
||||
val vFile = localFileSystem.findFileByPath(sourceRootPath)
|
||||
if (vFile == null) {
|
||||
val message = "Source file or directory not found: $sourceRootPath"
|
||||
|
||||
val buildFilePath = configuration.get(JVMConfigurationKeys.MODULE_XML_FILE)
|
||||
if (buildFilePath != null && Logger.isInitialized()) {
|
||||
LOG.warn("$message\n\nbuild file path: $buildFilePath\ncontent:\n${buildFilePath.readText()}")
|
||||
}
|
||||
|
||||
report(ERROR, message)
|
||||
continue
|
||||
}
|
||||
|
||||
if (!vFile.isDirectory && vFile.fileType != KotlinFileType.INSTANCE) {
|
||||
report(ERROR, "Source entry is not a Kotlin file: $sourceRootPath")
|
||||
continue
|
||||
}
|
||||
|
||||
for (file in File(sourceRootPath).walkTopDown()) {
|
||||
if (!file.isFile) continue
|
||||
|
||||
val virtualFile = localFileSystem.findFileByPath(file.absolutePath)?.let(virtualFileCreator::create)
|
||||
if (virtualFile != null && processedFiles.add(virtualFile)) {
|
||||
val psiFile = psiManager.findFile(virtualFile)
|
||||
if (psiFile is KtFile) {
|
||||
result.add(psiFile)
|
||||
if (isCommon) {
|
||||
psiFile.isCommonSource = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun report(severity: CompilerMessageSeverity, message: String) {
|
||||
configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(severity, message)
|
||||
}
|
||||
internal fun report(severity: CompilerMessageSeverity, message: String) = report(configuration, severity, message)
|
||||
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(KotlinCoreEnvironment::class.java)
|
||||
@@ -531,6 +480,67 @@ class KotlinCoreEnvironment private constructor(
|
||||
// used in the daemon for jar cache cleanup
|
||||
val applicationEnvironment: JavaCoreApplicationEnvironment? get() = ourApplicationEnvironment
|
||||
|
||||
internal fun report(
|
||||
configuration: CompilerConfiguration,
|
||||
severity: CompilerMessageSeverity,
|
||||
message: String,
|
||||
location: CompilerMessageLocation? = null
|
||||
) {
|
||||
configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(severity, message, location)
|
||||
}
|
||||
|
||||
internal fun createSourceFilesFromSourceRoots(
|
||||
configuration: CompilerConfiguration,
|
||||
project: Project,
|
||||
sourceRoots: List<KotlinSourceRoot>,
|
||||
reportLocation: CompilerMessageLocation? = null
|
||||
): MutableList<KtFile> {
|
||||
val localFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
|
||||
val psiManager = PsiManager.getInstance(project)
|
||||
|
||||
val processedFiles = hashSetOf<VirtualFile>()
|
||||
val result = mutableListOf<KtFile>()
|
||||
|
||||
val virtualFileCreator = PreprocessedFileCreator(project)
|
||||
|
||||
for ((sourceRootPath, isCommon) in sourceRoots) {
|
||||
val vFile = localFileSystem.findFileByPath(sourceRootPath)
|
||||
if (vFile == null) {
|
||||
val message = "Source file or directory not found: $sourceRootPath"
|
||||
|
||||
val buildFilePath = configuration.get(JVMConfigurationKeys.MODULE_XML_FILE)
|
||||
if (buildFilePath != null && Logger.isInitialized()) {
|
||||
KotlinCoreEnvironment.LOG.warn("$message\n\nbuild file path: $buildFilePath\ncontent:\n${buildFilePath.readText()}")
|
||||
}
|
||||
|
||||
report(configuration, ERROR, message, reportLocation)
|
||||
continue
|
||||
}
|
||||
|
||||
if (!vFile.isDirectory && vFile.fileType != KotlinFileType.INSTANCE) {
|
||||
report(configuration, ERROR, "Source entry is not a Kotlin file: $sourceRootPath", reportLocation)
|
||||
continue
|
||||
}
|
||||
|
||||
for (file in File(sourceRootPath).walkTopDown()) {
|
||||
if (!file.isFile) continue
|
||||
|
||||
val virtualFile = localFileSystem.findFileByPath(file.absolutePath)?.let(virtualFileCreator::create)
|
||||
if (virtualFile != null && processedFiles.add(virtualFile)) {
|
||||
val psiFile = psiManager.findFile(virtualFile)
|
||||
if (psiFile is KtFile) {
|
||||
result.add(psiFile)
|
||||
if (isCommon) {
|
||||
psiFile.isCommonSource = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun getOrCreateApplicationEnvironmentForProduction(configuration: CompilerConfiguration): JavaCoreApplicationEnvironment {
|
||||
synchronized(APPLICATION_LOCK) {
|
||||
if (ourApplicationEnvironment != null)
|
||||
@@ -701,3 +711,4 @@ class KotlinCoreEnvironment private constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ object KotlinToJVMBytecodeCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun compileAndExecuteScript(environment: KotlinCoreEnvironment, scriptArgs: List<String>): ExitCode {
|
||||
fun compileAndExecuteScript(environment: KotlinCoreEnvironment, scriptArgs: List<String>): ExitCode {
|
||||
val scriptClass = compileScript(environment) ?: return ExitCode.COMPILATION_ERROR
|
||||
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.cli.jvm.compiler
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.script.ScriptDependenciesProvider
|
||||
import java.io.File
|
||||
|
||||
data class ScriptsCompilationDependencies(
|
||||
val classpath: List<File>,
|
||||
val sources: List<KtFile>,
|
||||
val sourceDependencies: List<SourceDependencies>
|
||||
) {
|
||||
data class SourceDependencies(
|
||||
val scriptFile: KtFile,
|
||||
val sourceDependencies: List<KtFile>
|
||||
)
|
||||
}
|
||||
|
||||
// recursively collect dependencies from initial and imported scripts
|
||||
fun collectScriptsCompilationDependencies(
|
||||
configuration: CompilerConfiguration,
|
||||
project: Project,
|
||||
initialSources: Iterable<KtFile>
|
||||
): ScriptsCompilationDependencies {
|
||||
val collectedClassPath = ArrayList<File>()
|
||||
val collectedSources = ArrayList<KtFile>()
|
||||
val collectedSourceDependencies = ArrayList<ScriptsCompilationDependencies.SourceDependencies>()
|
||||
var remainingSources = initialSources
|
||||
val knownSourcePaths = initialSources.mapNotNullTo(HashSet()) { it.virtualFile?.path }
|
||||
val importsProvider = ScriptDependenciesProvider.getInstance(project)
|
||||
while (true) {
|
||||
val newRemainingSources = ArrayList<KtFile>()
|
||||
for (source in remainingSources) {
|
||||
val dependencies = importsProvider.getScriptDependencies(source)
|
||||
if (dependencies != null) {
|
||||
collectedClassPath.addAll(dependencies.classpath)
|
||||
|
||||
val sourceDependenciesRoots = dependencies.scripts.map {
|
||||
KotlinSourceRoot(it.path, false)
|
||||
}
|
||||
val sourceDependencies =
|
||||
KotlinCoreEnvironment.createSourceFilesFromSourceRoots(
|
||||
configuration, project, sourceDependenciesRoots,
|
||||
// TODO: consider receiving and using precise location from the resolver in the future
|
||||
source.virtualFile?.path?.let { CompilerMessageLocation.create(it) }
|
||||
)
|
||||
if (sourceDependencies.isNotEmpty()) {
|
||||
collectedSourceDependencies.add(ScriptsCompilationDependencies.SourceDependencies(source, sourceDependencies))
|
||||
|
||||
val newSources = sourceDependencies.filterNot { knownSourcePaths.contains(it.virtualFile.path) }
|
||||
for (newSource in newSources) {
|
||||
collectedSources.add(newSource)
|
||||
newRemainingSources.add(newSource)
|
||||
knownSourcePaths.add(newSource.virtualFile.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newRemainingSources.isEmpty()) break
|
||||
else {
|
||||
remainingSources = newRemainingSources
|
||||
}
|
||||
}
|
||||
return ScriptsCompilationDependencies(
|
||||
collectedClassPath.distinctBy { it.absolutePath },
|
||||
collectedSources,
|
||||
collectedSourceDependencies
|
||||
)
|
||||
}
|
||||
@@ -91,6 +91,7 @@ object TopDownAnalyzerFacadeForJVM {
|
||||
val analysisHandlerExtensions = AnalysisHandlerExtension.getInstances(project)
|
||||
|
||||
fun invokeExtensionsOnAnalysisComplete(): AnalysisResult? {
|
||||
container.get<JavaClassesTracker>().onCompletedAnalysis(module)
|
||||
for (extension in analysisHandlerExtensions) {
|
||||
val result = extension.analysisCompleted(project, module, trace, files)
|
||||
if (result != null) return result
|
||||
@@ -108,7 +109,6 @@ object TopDownAnalyzerFacadeForJVM {
|
||||
}
|
||||
|
||||
container.get<LazyTopDownAnalyzer>().analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, files)
|
||||
container.get<JavaClassesTracker>().onCompletedAnalysis(module)
|
||||
|
||||
invokeExtensionsOnAnalysisComplete()?.let { return it }
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ object PluginCliParser {
|
||||
private fun processPluginOptions(
|
||||
pluginOptions: Iterable<String>?,
|
||||
configuration: CompilerConfiguration,
|
||||
classLoader: ClassLoader
|
||||
classLoader: URLClassLoader
|
||||
) {
|
||||
val optionValuesByPlugin = pluginOptions?.map(::parsePluginOption)?.groupBy {
|
||||
if (it == null) throw CliOptionProcessingException("Wrong plugin option format: $it, should be ${CommonCompilerArguments.PLUGIN_OPTION_FORMAT}")
|
||||
@@ -84,7 +84,7 @@ object PluginCliParser {
|
||||
} ?: mapOf()
|
||||
|
||||
// TODO issue a warning on using deprecated command line processors when all official plugin migrate to the newer convention
|
||||
val commandLineProcessors = ServiceLoader.load(CommandLineProcessor::class.java, classLoader)
|
||||
val commandLineProcessors = ServiceLoaderLite.loadImplementations(CommandLineProcessor::class.java, classLoader)
|
||||
|
||||
for (processor in commandLineProcessors) {
|
||||
val declaredOptions = processor.pluginOptions.associateBy { it.optionName }
|
||||
|
||||
@@ -11,7 +11,10 @@ import java.lang.Character.isJavaIdentifierPart
|
||||
import java.lang.Character.isJavaIdentifierStart
|
||||
import java.lang.IllegalArgumentException
|
||||
import java.lang.RuntimeException
|
||||
import java.lang.UnsupportedOperationException
|
||||
import java.net.URLClassLoader
|
||||
import java.nio.file.FileSystemNotFoundException
|
||||
import java.nio.file.Paths
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
/**
|
||||
@@ -32,9 +35,13 @@ object ServiceLoaderLite {
|
||||
*/
|
||||
fun <Service> loadImplementations(service: Class<out Service>, classLoader: URLClassLoader): List<Service> {
|
||||
val files = classLoader.urLs.map { url ->
|
||||
if (url.protocol.toLowerCase() != "file") throw IllegalArgumentException("Only local files are supported, got $url")
|
||||
val path = url.path.takeIf { it.isNotEmpty() } ?: throw IllegalArgumentException("Path is empty for $url")
|
||||
File(path)
|
||||
try {
|
||||
Paths.get(url.toURI()).toFile()
|
||||
} catch (e: FileSystemNotFoundException) {
|
||||
throw IllegalArgumentException("Only local URLs are supported, got ${url.protocol}")
|
||||
} catch (e: UnsupportedOperationException) {
|
||||
throw IllegalArgumentException("Only local URLs are supported, got ${url.protocol}")
|
||||
}
|
||||
}
|
||||
|
||||
val implementations = mutableListOf<Service>()
|
||||
|
||||
@@ -200,6 +200,7 @@ messages/**)
|
||||
-keep class org.jetbrains.org.objectweb.asm.tree.FieldNode { *; }
|
||||
-keep class org.jetbrains.org.objectweb.asm.tree.ParameterNode { *; }
|
||||
-keep class org.jetbrains.org.objectweb.asm.tree.TypeAnnotationNode { *; }
|
||||
-keep class org.jetbrains.org.objectweb.asm.tree.InsnList { *; }
|
||||
|
||||
-keep class org.jetbrains.org.objectweb.asm.signature.SignatureReader { *; }
|
||||
-keep class org.jetbrains.org.objectweb.asm.signature.SignatureVisitor { *; }
|
||||
@@ -236,6 +237,9 @@ messages/**)
|
||||
|
||||
# for kapt
|
||||
-keep class com.intellij.openapi.project.Project { *; }
|
||||
-keepclassmembers class com.intellij.util.PathUtil {
|
||||
public static java.lang.String getJarPathForClass(java.lang.Class);
|
||||
}
|
||||
|
||||
-keepclassmembers class com.intellij.util.PathUtil {
|
||||
public static java.lang.String getJarPathForClass(java.lang.Class);
|
||||
@@ -245,3 +249,6 @@ messages/**)
|
||||
-keep class org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt { *; }
|
||||
|
||||
-keep class net.jpountz.lz4.* { *; }
|
||||
|
||||
# used in LazyScriptDescriptor
|
||||
-keep class org.jetbrains.kotlin.utils.addToStdlib.AddToStdlibKt { *; }
|
||||
|
||||
@@ -219,6 +219,9 @@ messages/**)
|
||||
|
||||
# for kapt
|
||||
-keep class com.intellij.openapi.project.Project { *; }
|
||||
-keepclassmembers class com.intellij.util.PathUtil {
|
||||
public static java.lang.String getJarPathForClass(java.lang.Class);
|
||||
}
|
||||
|
||||
-keepclassmembers class com.intellij.util.PathUtil {
|
||||
public static java.lang.String getJarPathForClass(java.lang.Class);
|
||||
@@ -228,3 +231,6 @@ messages/**)
|
||||
-keep class org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt { *; }
|
||||
|
||||
-keep class net.jpountz.lz4.* { *; }
|
||||
|
||||
# used in LazyScriptDescriptor
|
||||
-keep class org.jetbrains.kotlin.utils.addToStdlib.AddToStdlibKt { *; }
|
||||
|
||||
@@ -237,6 +237,9 @@ messages/**)
|
||||
|
||||
# for kapt
|
||||
-keep class com.intellij.openapi.project.Project { *; }
|
||||
-keepclassmembers class com.intellij.util.PathUtil {
|
||||
public static java.lang.String getJarPathForClass(java.lang.Class);
|
||||
}
|
||||
|
||||
-keepclassmembers class com.intellij.util.PathUtil {
|
||||
public static java.lang.String getJarPathForClass(java.lang.Class);
|
||||
@@ -246,3 +249,6 @@ messages/**)
|
||||
-keep class org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt { *; }
|
||||
|
||||
-keep class net.jpountz.lz4.* { *; }
|
||||
|
||||
# used in LazyScriptDescriptor
|
||||
-keep class org.jetbrains.kotlin.utils.addToStdlib.AddToStdlibKt { *; }
|
||||
|
||||
@@ -220,6 +220,9 @@ messages/**)
|
||||
|
||||
# for kapt
|
||||
-keep class com.intellij.openapi.project.Project { *; }
|
||||
-keepclassmembers class com.intellij.util.PathUtil {
|
||||
public static java.lang.String getJarPathForClass(java.lang.Class);
|
||||
}
|
||||
|
||||
-keepclassmembers class com.intellij.util.PathUtil {
|
||||
public static java.lang.String getJarPathForClass(java.lang.Class);
|
||||
@@ -227,3 +230,6 @@ messages/**)
|
||||
|
||||
# remove when KT-18563 would be fixed
|
||||
-keep class org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt { *; }
|
||||
|
||||
# used in LazyScriptDescriptor
|
||||
-keep class org.jetbrains.kotlin.utils.addToStdlib.AddToStdlibKt { *; }
|
||||
|
||||
@@ -237,6 +237,9 @@ messages/**)
|
||||
|
||||
# for kapt
|
||||
-keep class com.intellij.openapi.project.Project { *; }
|
||||
-keepclassmembers class com.intellij.util.PathUtil {
|
||||
public static java.lang.String getJarPathForClass(java.lang.Class);
|
||||
}
|
||||
|
||||
-keepclassmembers class com.intellij.util.PathUtil {
|
||||
public static java.lang.String getJarPathForClass(java.lang.Class);
|
||||
@@ -246,3 +249,6 @@ messages/**)
|
||||
-keep class org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt { *; }
|
||||
|
||||
-keep class net.jpountz.lz4.* { *; }
|
||||
|
||||
# used in LazyScriptDescriptor
|
||||
-keep class org.jetbrains.kotlin.utils.addToStdlib.AddToStdlibKt { *; }
|
||||
|
||||
@@ -102,7 +102,7 @@ class StorageComponentContainer(private val id: String, parent: StorageComponent
|
||||
override fun <T> create(request: Class<T>): T {
|
||||
val constructorBinding = request.bindToConstructor(unknownContext)
|
||||
val args = constructorBinding.argumentDescriptors.map { it.getValue() }.toTypedArray()
|
||||
return constructorBinding.constructor.newInstance(*args) as T
|
||||
return runWithUnwrappingInvocationException { constructorBinding.constructor.newInstance(*args) as T }
|
||||
}
|
||||
|
||||
override fun toString() = "Container $id"
|
||||
|
||||
@@ -20,7 +20,7 @@ import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Member
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Type
|
||||
import java.util.ArrayList
|
||||
import java.util.*
|
||||
|
||||
interface ValueResolver {
|
||||
fun resolve(request: Type, context: ValueResolveContext): ValueDescriptor?
|
||||
@@ -45,7 +45,7 @@ class ConstructorBinding(val constructor: Constructor<*>, val argumentDescriptor
|
||||
class MethodBinding(val method: Method, private val argumentDescriptors: List<ValueDescriptor>) {
|
||||
fun invoke(instance: Any) {
|
||||
val arguments = computeArguments(argumentDescriptors).toTypedArray()
|
||||
method.invoke(instance, *arguments)
|
||||
runWithUnwrappingInvocationException { method.invoke(instance, *arguments) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ package org.jetbrains.kotlin.container
|
||||
|
||||
import java.io.Closeable
|
||||
import java.lang.reflect.Type
|
||||
import java.util.ArrayList
|
||||
import java.util.*
|
||||
|
||||
enum class ComponentState {
|
||||
Null,
|
||||
@@ -131,7 +131,7 @@ open class SingletonTypeComponentDescriptor(container: ComponentContainer, val k
|
||||
val constructor = binding.constructor
|
||||
val arguments = computeArguments(binding.argumentDescriptors)
|
||||
|
||||
val instance = constructor.newInstance(*arguments.toTypedArray())!!
|
||||
val instance = runWithUnwrappingInvocationException { constructor.newInstance(*arguments.toTypedArray())!! }
|
||||
state = ComponentState.Initialized
|
||||
return instance
|
||||
}
|
||||
@@ -154,4 +154,4 @@ class DefaultSingletonTypeComponentDescriptor(container: ComponentContainer, kla
|
||||
override fun toString(): String {
|
||||
return "Default: ${klass.simpleName}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.container
|
||||
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
|
||||
inline fun <T> runWithUnwrappingInvocationException(block: () -> T) =
|
||||
try {
|
||||
block()
|
||||
} catch (e: InvocationTargetException) {
|
||||
throw e.targetException ?: e
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.fir.java.symbols.JavaClassSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinder
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
|
||||
@@ -38,7 +39,7 @@ class JavaSymbolProvider(val project: Project) : FirSymbolProvider {
|
||||
override fun getSymbolByFqName(classId: ClassId): ConeSymbol? {
|
||||
return classCache.lookupCacheOrCalculate(classId) {
|
||||
val facade = KotlinJavaPsiFacade.getInstance(project)
|
||||
val foundClass = facade.findClass(classId, allScope)
|
||||
val foundClass = facade.findClass(JavaClassFinder.Request(classId), allScope)
|
||||
foundClass?.let { javaClass -> JavaClassSymbol(javaClass) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
package org.jetbrains.kotlin.fir.visitors
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
package org.jetbrains.kotlin.fir.visitors
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
package org.jetbrains.kotlin.fir.visitors
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.load.java
|
||||
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaPackageImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
|
||||
@@ -33,10 +32,10 @@ class JavaClassFinderImpl : AbstractJavaClassFinder() {
|
||||
super.initialize(trace, codeAnalyzer)
|
||||
}
|
||||
|
||||
override fun findClass(classId: ClassId): JavaClass? = javaFacade.findClass(classId, javaSearchScope)
|
||||
override fun findClass(request: JavaClassFinder.Request): JavaClass? = javaFacade.findClass(request, javaSearchScope)
|
||||
|
||||
override fun findPackage(fqName: FqName) = javaFacade.findPackage(fqName.asString(), javaSearchScope)?.let { JavaPackageImpl(it, javaSearchScope) }
|
||||
|
||||
override fun knownClassNamesInPackage(packageFqName: FqName): Set<String>? = javaFacade.knownClassNamesInPackage(packageFqName)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.load.java.structure.impl;
|
||||
|
||||
import com.intellij.psi.PsiAnnotationMemberValue;
|
||||
import com.intellij.psi.PsiAnnotationMethod;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMethod;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaType;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaValueParameter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.load.java.structure.*;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
|
||||
import java.util.List;
|
||||
@@ -57,9 +56,17 @@ public class JavaMethodImpl extends JavaMemberImpl<PsiMethod> implements JavaMet
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getHasAnnotationParameterDefaultValue() {
|
||||
@Nullable
|
||||
public JavaAnnotationArgument getAnnotationParameterDefaultValue() {
|
||||
PsiMethod psiMethod = getPsi();
|
||||
return psiMethod instanceof PsiAnnotationMethod && ((PsiAnnotationMethod) psiMethod).getDefaultValue() != null;
|
||||
if (psiMethod instanceof PsiAnnotationMethod) {
|
||||
PsiAnnotationMemberValue defaultValue = ((PsiAnnotationMethod) psiMethod).getDefaultValue();
|
||||
if (defaultValue != null) {
|
||||
return JavaAnnotationArgumentImpl.Factory.create(defaultValue, null);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
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.*
|
||||
import java.lang.reflect.Array
|
||||
@@ -37,11 +36,10 @@ internal class AnnotationsAndParameterCollectorMethodVisitor(
|
||||
private var visibleAnnotableParameterCount = parametersCountInMethodDesc
|
||||
private var invisibleAnnotableParameterCount = parametersCountInMethodDesc
|
||||
|
||||
override fun visitAnnotationDefault(): AnnotationVisitor? {
|
||||
member.safeAs<BinaryJavaMethod>()?.hasAnnotationParameterDefaultValue = true
|
||||
// We don't store default value in Java model
|
||||
return null
|
||||
}
|
||||
override fun visitAnnotationDefault(): AnnotationVisitor? =
|
||||
BinaryJavaAnnotationVisitor(context, signatureParser) {
|
||||
member.safeAs<BinaryJavaMethod>()?.annotationParameterDefaultValue = it
|
||||
}
|
||||
|
||||
override fun visitParameter(name: String?, access: Int) {
|
||||
if (name != null) {
|
||||
@@ -165,19 +163,26 @@ class BinaryJavaAnnotation private constructor(
|
||||
}
|
||||
|
||||
class BinaryJavaAnnotationVisitor(
|
||||
private val context: ClassifierResolutionContext,
|
||||
private val signatureParser: BinaryClassSignatureParser,
|
||||
private val arguments: MutableCollection<JavaAnnotationArgument>
|
||||
private val context: ClassifierResolutionContext,
|
||||
private val signatureParser: BinaryClassSignatureParser,
|
||||
private val sink: (JavaAnnotationArgument) -> Unit
|
||||
) : AnnotationVisitor(ASM_API_VERSION_FOR_CLASS_READING) {
|
||||
constructor(
|
||||
context: ClassifierResolutionContext,
|
||||
signatureParser: BinaryClassSignatureParser,
|
||||
arguments: MutableCollection<JavaAnnotationArgument>
|
||||
) : this(context, signatureParser, { arguments.add(it) })
|
||||
|
||||
private fun addArgument(argument: JavaAnnotationArgument?) {
|
||||
arguments.addIfNotNull(argument)
|
||||
if (argument != null) {
|
||||
sink(argument)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitAnnotation(name: String?, desc: String): AnnotationVisitor {
|
||||
val (annotation, visitor) =
|
||||
BinaryJavaAnnotation.createAnnotationAndVisitor(desc, context, signatureParser)
|
||||
val (annotation, visitor) = BinaryJavaAnnotation.createAnnotationAndVisitor(desc, context, signatureParser)
|
||||
|
||||
arguments.add(PlainJavaAnnotationAsAnnotationArgument(name, annotation))
|
||||
sink(PlainJavaAnnotationAsAnnotationArgument(name, annotation))
|
||||
|
||||
return visitor
|
||||
}
|
||||
|
||||
@@ -31,13 +31,13 @@ import java.text.CharacterIterator
|
||||
import java.text.StringCharacterIterator
|
||||
|
||||
class BinaryJavaClass(
|
||||
override val virtualFile: VirtualFile,
|
||||
override val fqName: FqName,
|
||||
internal val context: ClassifierResolutionContext,
|
||||
private val signatureParser: BinaryClassSignatureParser,
|
||||
override var access: Int = 0,
|
||||
override val outerClass: JavaClass?,
|
||||
classContent: ByteArray? = null
|
||||
override val virtualFile: VirtualFile,
|
||||
override val fqName: FqName,
|
||||
internal val context: ClassifierResolutionContext,
|
||||
private val signatureParser: BinaryClassSignatureParser,
|
||||
override var access: Int = 0,
|
||||
override val outerClass: JavaClass?,
|
||||
classContent: ByteArray? = null
|
||||
) : ClassVisitor(ASM_API_VERSION_FOR_CLASS_READING), VirtualFileBoundJavaClass, BinaryJavaModifierListOwner, MapBasedJavaAnnotationOwner {
|
||||
private lateinit var myInternalName: String
|
||||
|
||||
@@ -74,8 +74,8 @@ class BinaryJavaClass(
|
||||
|
||||
init {
|
||||
ClassReader(classContent ?: virtualFile.contentsToByteArray()).accept(
|
||||
this,
|
||||
ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES
|
||||
this,
|
||||
ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES
|
||||
)
|
||||
}
|
||||
|
||||
@@ -115,20 +115,19 @@ class BinaryJavaClass(
|
||||
}
|
||||
|
||||
override fun visit(
|
||||
version: Int,
|
||||
access: Int,
|
||||
name: String,
|
||||
signature: String?,
|
||||
superName: String?,
|
||||
interfaces: Array<out String>?
|
||||
version: Int,
|
||||
access: Int,
|
||||
name: String,
|
||||
signature: String?,
|
||||
superName: String?,
|
||||
interfaces: Array<out String>?
|
||||
) {
|
||||
this.access = this.access or access
|
||||
this.myInternalName = name
|
||||
|
||||
if (signature != null) {
|
||||
parseClassSignature(signature)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.typeParameters = emptyList()
|
||||
this.supertypes = mutableListOf<JavaClassifierType>().apply {
|
||||
addIfNotNull(superName?.convertInternalNameToClassifierType())
|
||||
@@ -142,9 +141,9 @@ class BinaryJavaClass(
|
||||
private fun parseClassSignature(signature: String) {
|
||||
val iterator = StringCharacterIterator(signature)
|
||||
this.typeParameters =
|
||||
signatureParser
|
||||
.parseTypeParametersDeclaration(iterator, context)
|
||||
.also(context::addTypeParameters)
|
||||
signatureParser
|
||||
.parseTypeParametersDeclaration(iterator, context)
|
||||
.also(context::addTypeParameters)
|
||||
|
||||
val supertypes = ContainerUtil.newSmartList<JavaClassifierType>()
|
||||
supertypes.addIfNotNull(signatureParser.parseClassifierRefSignature(iterator, context))
|
||||
@@ -155,7 +154,7 @@ class BinaryJavaClass(
|
||||
}
|
||||
|
||||
private fun String.convertInternalNameToClassifierType(): JavaClassifierType =
|
||||
PlainJavaClassifierType({ context.resolveByInternalName(this) }, emptyList())
|
||||
PlainJavaClassifierType({ context.resolveByInternalName(this) }, emptyList())
|
||||
|
||||
override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor? {
|
||||
if (access.isSet(Opcodes.ACC_SYNTHETIC)) return null
|
||||
@@ -169,13 +168,13 @@ 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)
|
||||
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
|
||||
if (typePath == null)
|
||||
BinaryJavaAnnotation.addTypeAnnotation(type, desc, context, signatureParser)
|
||||
else
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,7 +186,7 @@ class BinaryJavaClass(
|
||||
if (fieldType !is JavaPrimitiveType || fieldType.type == null || value !is Int) return value
|
||||
|
||||
return when (fieldType.type) {
|
||||
PrimitiveType.BOOLEAN -> {
|
||||
PrimitiveType.BOOLEAN -> {
|
||||
when (value) {
|
||||
0 -> false
|
||||
1 -> true
|
||||
@@ -200,13 +199,18 @@ class BinaryJavaClass(
|
||||
}
|
||||
|
||||
override fun visitAnnotation(desc: String, visible: Boolean) =
|
||||
BinaryJavaAnnotation.addAnnotation(annotations, desc, context, signatureParser)
|
||||
BinaryJavaAnnotation.addAnnotation(annotations, desc, context, signatureParser)
|
||||
|
||||
override fun findInnerClass(name: Name): JavaClass? {
|
||||
override fun findInnerClass(name: Name): JavaClass? = findInnerClass(name, classFileContent = null)
|
||||
|
||||
fun findInnerClass(name: Name, classFileContent: ByteArray?): JavaClass? {
|
||||
val access = ownInnerClassNameToAccess[name] ?: return null
|
||||
|
||||
return virtualFile.parent.findChild("${virtualFile.nameWithoutExtension}$$name.class")?.let {
|
||||
BinaryJavaClass(it, fqName.child(name), context.copyForMember(), signatureParser, access, this)
|
||||
BinaryJavaClass(
|
||||
it, fqName.child(name), context.copyForMember(), signatureParser, access, this,
|
||||
classFileContent
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +169,15 @@ class BinaryJavaMethod(
|
||||
) : BinaryJavaMethodBase(
|
||||
flags, containingClass, valueParameters, typeParameters, name
|
||||
), JavaMethod {
|
||||
override var hasAnnotationParameterDefaultValue: Boolean = false
|
||||
override var annotationParameterDefaultValue: JavaAnnotationArgument? = null
|
||||
internal set(value) {
|
||||
if (field != null) {
|
||||
throw AssertionError(
|
||||
"Annotation method cannot have two default values: $this (old=$field, new=$value)"
|
||||
)
|
||||
}
|
||||
field = value
|
||||
}
|
||||
}
|
||||
|
||||
class BinaryJavaConstructor(
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.load.java.structure.JavaModifierListOwner
|
||||
import org.jetbrains.kotlin.load.java.structure.MapBasedJavaAnnotationOwner
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
|
||||
internal val ASM_API_VERSION_FOR_CLASS_READING = Opcodes.ASM5
|
||||
internal const val ASM_API_VERSION_FOR_CLASS_READING = Opcodes.API_VERSION
|
||||
|
||||
internal interface BinaryJavaModifierListOwner : JavaModifierListOwner, MapBasedJavaAnnotationOwner {
|
||||
val access: Int
|
||||
|
||||
@@ -85,7 +85,7 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass {
|
||||
|
||||
// TODO public to be accessible in companion object of subclass, workaround for KT-3974
|
||||
@Nullable
|
||||
public static <T extends FileBasedKotlinClass> T create(
|
||||
public static <T> T create(
|
||||
@NotNull byte[] fileContents,
|
||||
@NotNull Function4<ClassId, Integer, KotlinClassHeader, InnerClassesInfo, T> factory
|
||||
) {
|
||||
|
||||
@@ -28,14 +28,17 @@ class KotlinBinaryClassCache : Disposable {
|
||||
private class RequestCache {
|
||||
internal var virtualFile: VirtualFile? = null
|
||||
internal var modificationStamp: Long = 0
|
||||
internal var virtualFileKotlinClass: VirtualFileKotlinClass? = null
|
||||
internal var result: KotlinClassFinder.Result? = null
|
||||
|
||||
fun cache(file: VirtualFile, aClass: VirtualFileKotlinClass?): VirtualFileKotlinClass? {
|
||||
fun cache(
|
||||
file: VirtualFile,
|
||||
result: KotlinClassFinder.Result?
|
||||
): KotlinClassFinder.Result? {
|
||||
virtualFile = file
|
||||
virtualFileKotlinClass = aClass
|
||||
this.result = result
|
||||
modificationStamp = file.modificationStamp
|
||||
|
||||
return aClass
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +56,9 @@ class KotlinBinaryClassCache : Disposable {
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? {
|
||||
fun getKotlinBinaryClassOrClassFileContent(
|
||||
file: VirtualFile, fileContent: ByteArray? = null
|
||||
): KotlinClassFinder.Result? {
|
||||
if (file.fileType !== JavaClassFileType.INSTANCE) return null
|
||||
|
||||
if (file.name == PsiJavaModule.MODULE_INFO_CLS_FILE) return null
|
||||
@@ -62,7 +67,7 @@ class KotlinBinaryClassCache : Disposable {
|
||||
val requestCache = service.cache.get()
|
||||
|
||||
if (file.modificationStamp == requestCache.modificationStamp && file == requestCache.virtualFile) {
|
||||
return requestCache.virtualFileKotlinClass
|
||||
return requestCache.result
|
||||
}
|
||||
|
||||
val aClass = ApplicationManager.getApplication().runReadAction(Computable {
|
||||
|
||||
@@ -27,14 +27,17 @@ class KotlinBinaryClassCache : Disposable {
|
||||
private class RequestCache {
|
||||
internal var virtualFile: VirtualFile? = null
|
||||
internal var modificationStamp: Long = 0
|
||||
internal var virtualFileKotlinClass: VirtualFileKotlinClass? = null
|
||||
internal var result: KotlinClassFinder.Result? = null
|
||||
|
||||
fun cache(file: VirtualFile, aClass: VirtualFileKotlinClass?): VirtualFileKotlinClass? {
|
||||
fun cache(
|
||||
file: VirtualFile,
|
||||
result: KotlinClassFinder.Result?
|
||||
): KotlinClassFinder.Result? {
|
||||
virtualFile = file
|
||||
virtualFileKotlinClass = aClass
|
||||
this.result = result
|
||||
modificationStamp = file.modificationStamp
|
||||
|
||||
return aClass
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,14 +55,16 @@ class KotlinBinaryClassCache : Disposable {
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? {
|
||||
fun getKotlinBinaryClassOrClassFileContent(
|
||||
file: VirtualFile, fileContent: ByteArray? = null
|
||||
): KotlinClassFinder.Result? {
|
||||
if (file.fileType !== JavaClassFileType.INSTANCE) return null
|
||||
|
||||
val service = ServiceManager.getService(KotlinBinaryClassCache::class.java)
|
||||
val requestCache = service.cache.get()
|
||||
|
||||
if (file.modificationStamp == requestCache.modificationStamp && file == requestCache.virtualFile) {
|
||||
return requestCache.virtualFileKotlinClass
|
||||
return requestCache.result
|
||||
}
|
||||
|
||||
val aClass = ApplicationManager.getApplication().runReadAction(Computable {
|
||||
|
||||
@@ -27,14 +27,17 @@ class KotlinBinaryClassCache : Disposable {
|
||||
private class RequestCache {
|
||||
internal var virtualFile: VirtualFile? = null
|
||||
internal var modificationStamp: Long = 0
|
||||
internal var virtualFileKotlinClass: VirtualFileKotlinClass? = null
|
||||
internal var result: KotlinClassFinder.Result? = null
|
||||
|
||||
fun cache(file: VirtualFile, aClass: VirtualFileKotlinClass?): VirtualFileKotlinClass? {
|
||||
fun cache(
|
||||
file: VirtualFile,
|
||||
result: KotlinClassFinder.Result?
|
||||
): KotlinClassFinder.Result? {
|
||||
virtualFile = file
|
||||
virtualFileKotlinClass = aClass
|
||||
this.result = result
|
||||
modificationStamp = file.modificationStamp
|
||||
|
||||
return aClass
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,14 +55,16 @@ class KotlinBinaryClassCache : Disposable {
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? {
|
||||
fun getKotlinBinaryClassOrClassFileContent(
|
||||
file: VirtualFile, fileContent: ByteArray? = null
|
||||
): KotlinClassFinder.Result? {
|
||||
if (file.fileType !== JavaClassFileType.INSTANCE) return null
|
||||
|
||||
val service = ServiceManager.getService(KotlinBinaryClassCache::class.java)
|
||||
val requestCache = service.cache.get()
|
||||
|
||||
if (file.modificationStamp == requestCache.modificationStamp && file == requestCache.virtualFile) {
|
||||
return requestCache.virtualFileKotlinClass
|
||||
return requestCache.result
|
||||
}
|
||||
|
||||
val aClass = ApplicationManager.getApplication().runReadAction(Computable {
|
||||
|
||||
@@ -27,12 +27,12 @@ import org.jetbrains.kotlin.utils.sure
|
||||
abstract class VirtualFileFinder : KotlinClassFinder {
|
||||
abstract fun findVirtualFileWithHeader(classId: ClassId): VirtualFile?
|
||||
|
||||
override fun findKotlinClass(classId: ClassId): KotlinJvmBinaryClass? {
|
||||
override fun findKotlinClassOrContent(classId: ClassId): KotlinClassFinder.Result? {
|
||||
val file = findVirtualFileWithHeader(classId) ?: return null
|
||||
return KotlinBinaryClassCache.getKotlinBinaryClass(file)
|
||||
return KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file)
|
||||
}
|
||||
|
||||
override fun findKotlinClass(javaClass: JavaClass): KotlinJvmBinaryClass? {
|
||||
override fun findKotlinClassOrContent(javaClass: JavaClass): KotlinClassFinder.Result? {
|
||||
var file = (javaClass as? VirtualFileBoundJavaClass)?.virtualFile ?: return null
|
||||
|
||||
if (javaClass.outerClass != null) {
|
||||
@@ -41,7 +41,7 @@ abstract class VirtualFileFinder : KotlinClassFinder {
|
||||
file = file.parent!!.findChild(classFileName(javaClass) + ".class").sure { "Virtual file not found for $javaClass" }
|
||||
}
|
||||
|
||||
return KotlinBinaryClassCache.getKotlinBinaryClass(file)
|
||||
return KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file)
|
||||
}
|
||||
|
||||
private fun classFileName(jClass: JavaClass): String {
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.load.kotlin
|
||||
import com.intellij.ide.highlighter.JavaClassFileType
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder.Result.KotlinClass
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.util.PerformanceCounter
|
||||
@@ -56,17 +57,19 @@ class VirtualFileKotlinClass private constructor(
|
||||
private val perfCounter = PerformanceCounter.create("Binary class from Kotlin file")
|
||||
|
||||
@Deprecated("Use KotlinBinaryClassCache")
|
||||
fun create(file: VirtualFile, fileContent: ByteArray?): VirtualFileKotlinClass? {
|
||||
fun create(file: VirtualFile, fileContent: ByteArray?): KotlinClassFinder.Result? {
|
||||
return perfCounter.time {
|
||||
assert(file.fileType == JavaClassFileType.INSTANCE) { "Trying to read binary data from a non-class file $file" }
|
||||
|
||||
try {
|
||||
val byteContent = fileContent ?: file.contentsToByteArray(false)
|
||||
if (!byteContent.isEmpty()) {
|
||||
return@time FileBasedKotlinClass.create(byteContent) {
|
||||
name, classVersion, header, innerClasses ->
|
||||
val kotlinJvmBinaryClass = FileBasedKotlinClass.create(byteContent) { name, classVersion, header, innerClasses ->
|
||||
VirtualFileKotlinClass(file, name, classVersion, header, innerClasses)
|
||||
}
|
||||
|
||||
return@time kotlinJvmBinaryClass?.let(::KotlinClass)
|
||||
?: KotlinClassFinder.Result.ClassFileContent(byteContent)
|
||||
}
|
||||
}
|
||||
catch (e: FileNotFoundException) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
|
||||
import org.jetbrains.kotlin.load.kotlin.findKotlinClass
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
|
||||
@@ -87,5 +87,5 @@ fun getSourceElement(descriptor: DeclarationDescriptor): SourceElement =
|
||||
descriptor.toSourceElement
|
||||
}
|
||||
|
||||
private val DeclarationDescriptor.toSourceElement: SourceElement
|
||||
val DeclarationDescriptor.toSourceElement: SourceElement
|
||||
get() = if (this is DeclarationDescriptorWithSource) source else SourceElement.NO_SOURCE
|
||||
|
||||
@@ -18,11 +18,11 @@ package org.jetbrains.kotlin.resolve.jvm
|
||||
|
||||
import com.intellij.psi.impl.file.impl.JavaFileManager
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinder
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
interface KotlinCliJavaFileManager : JavaFileManager {
|
||||
fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass?
|
||||
fun findClass(request: JavaClassFinder.Request, searchScope: GlobalSearchScope): JavaClass?
|
||||
fun knownClassNamesInPackage(packageFqName: FqName): Set<String>?
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.asJava.KtLightClassMarker;
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage;
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinder;
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinderImpl;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass;
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl;
|
||||
@@ -104,9 +105,10 @@ public class KotlinJavaPsiFacade {
|
||||
return emptyModifierList;
|
||||
}
|
||||
|
||||
public JavaClass findClass(@NotNull ClassId classId, @NotNull GlobalSearchScope scope) {
|
||||
public JavaClass findClass(@NotNull JavaClassFinder.Request request, @NotNull GlobalSearchScope scope) {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); // We hope this method is being called often enough to cancel daemon processes smoothly
|
||||
|
||||
ClassId classId = request.getClassId();
|
||||
String qualifiedName = classId.asSingleFqName().asString();
|
||||
|
||||
if (shouldUseSlowResolve()) {
|
||||
@@ -119,7 +121,7 @@ public class KotlinJavaPsiFacade {
|
||||
|
||||
for (KotlinPsiElementFinderWrapper finder : finders()) {
|
||||
if (finder instanceof CliFinder) {
|
||||
JavaClass aClass = ((CliFinder) finder).findClass(classId, scope);
|
||||
JavaClass aClass = ((CliFinder) finder).findClass(request, scope);
|
||||
if (aClass != null) return aClass;
|
||||
}
|
||||
else {
|
||||
@@ -383,8 +385,8 @@ public class KotlinJavaPsiFacade {
|
||||
return javaFileManager.findClass(qualifiedName, scope);
|
||||
}
|
||||
|
||||
public JavaClass findClass(@NotNull ClassId classId, @NotNull GlobalSearchScope scope) {
|
||||
return javaFileManager.findClass(classId, scope);
|
||||
public JavaClass findClass(@NotNull JavaClassFinder.Request request, @NotNull GlobalSearchScope scope) {
|
||||
return javaFileManager.findClass(request, scope);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.jvm.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeUniqueAsSequence
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
/**
|
||||
* This checker detects if call by operator convention to a Java method violates some expected contract:
|
||||
* - "key in map" commonly resolves to an stdlib extension that calls Map.containsKey(),
|
||||
* but there's a member in ConcurrentHashMap with acceptable signature that delegates to `containsValue` instead
|
||||
*/
|
||||
object InconsistentOperatorFromJavaCallChecker : CallChecker {
|
||||
private val CONCURRENT_HASH_MAP_FQ_NAME = FqName("java.util.concurrent.ConcurrentHashMap")
|
||||
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
val candidateDescriptor = resolvedCall.candidateDescriptor
|
||||
if (candidateDescriptor.name != OperatorNameConventions.CONTAINS) return
|
||||
if (candidateDescriptor.valueParameters.singleOrNull()?.type?.isAnyOrNullableAny() != true) return
|
||||
if (resolvedCall.call.callElement !is KtBinaryExpression || !resolvedCall.status.possibleTransformToSuccess()) return
|
||||
|
||||
for (callableDescriptor in candidateDescriptor.overriddenTreeUniqueAsSequence(useOriginal = false)) {
|
||||
val containingClass = callableDescriptor.containingDeclaration as? ClassDescriptor ?: continue
|
||||
if (containingClass.fqNameOrNull() != CONCURRENT_HASH_MAP_FQ_NAME) continue
|
||||
|
||||
val diagnosticFactory =
|
||||
if (context.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitConcurrentHashMapContains))
|
||||
ErrorsJvm.CONCURRENT_HASH_MAP_CONTAINS_OPERATOR_ERROR
|
||||
else
|
||||
ErrorsJvm.CONCURRENT_HASH_MAP_CONTAINS_OPERATOR
|
||||
|
||||
context.trace.report(diagnosticFactory.on(reportOn))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.resolve.annotations.hasJvmStaticAnnotation
|
||||
import org.jetbrains.kotlin.resolve.calls.components.isActualParameterWithCorrespondingExpectedDefault
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotationConstructor
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
import org.jetbrains.kotlin.resolve.isInlineClass
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.VOLATILE_ANNOTATION_FQ_NAME
|
||||
@@ -194,21 +195,34 @@ class OverloadsAnnotationChecker: DeclarationChecker {
|
||||
descriptor.findJvmOverloadsAnnotation()?.let { annotation ->
|
||||
val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(annotation)
|
||||
if (annotationEntry != null) {
|
||||
checkDeclaration(annotationEntry, descriptor, context.trace)
|
||||
checkDeclaration(annotationEntry, descriptor, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkDeclaration(annotationEntry: KtAnnotationEntry, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) {
|
||||
private fun checkDeclaration(
|
||||
annotationEntry: KtAnnotationEntry,
|
||||
descriptor: DeclarationDescriptor,
|
||||
context: DeclarationCheckerContext
|
||||
) {
|
||||
val diagnosticHolder = context.trace
|
||||
|
||||
if (descriptor !is CallableDescriptor) {
|
||||
return
|
||||
}
|
||||
if ((descriptor.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.INTERFACE) {
|
||||
} else if ((descriptor.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.INTERFACE) {
|
||||
diagnosticHolder.report(ErrorsJvm.OVERLOADS_INTERFACE.on(annotationEntry))
|
||||
} else if (descriptor is FunctionDescriptor && descriptor.modality == Modality.ABSTRACT) {
|
||||
diagnosticHolder.report(ErrorsJvm.OVERLOADS_ABSTRACT.on(annotationEntry))
|
||||
} else if (DescriptorUtils.isLocal(descriptor)) {
|
||||
diagnosticHolder.report(ErrorsJvm.OVERLOADS_LOCAL.on(annotationEntry))
|
||||
} else if (descriptor.isAnnotationConstructor()) {
|
||||
val diagnostic =
|
||||
if (context.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses))
|
||||
ErrorsJvm.OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR
|
||||
else
|
||||
ErrorsJvm.OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR_WARNING
|
||||
|
||||
diagnosticHolder.report(diagnostic.on(annotationEntry))
|
||||
} else if (!descriptor.visibility.isPublicAPI && descriptor.visibility != Visibilities.INTERNAL) {
|
||||
diagnosticHolder.report(ErrorsJvm.OVERLOADS_PRIVATE.on(annotationEntry))
|
||||
} else if (descriptor.valueParameters.none { it.declaresDefaultValue() || it.isActualParameterWithCorrespondingExpectedDefault }) {
|
||||
|
||||
@@ -50,6 +50,8 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
|
||||
MAP.put(OVERLOADS_INTERFACE, "'@JvmOverloads' annotation cannot be used on interface methods");
|
||||
MAP.put(OVERLOADS_PRIVATE, "'@JvmOverloads' annotation has no effect on private declarations");
|
||||
MAP.put(OVERLOADS_LOCAL, "'@JvmOverloads' annotation cannot be used on local declarations");
|
||||
MAP.put(OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR_WARNING, "'@JvmOverloads' annotation on constructors of annotation classes is deprecated");
|
||||
MAP.put(OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR, "'@JvmOverloads' annotation cannot be used on constructors of annotation classes");
|
||||
MAP.put(INAPPLICABLE_JVM_NAME, "'@JvmName' annotation is not applicable to this declaration");
|
||||
MAP.put(ILLEGAL_JVM_NAME, "Illegal JVM name");
|
||||
MAP.put(VOLATILE_ON_VALUE, "'@Volatile' annotation cannot be used on immutable properties");
|
||||
@@ -138,6 +140,13 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
|
||||
MAP.put(EXPLICIT_METADATA_IS_DISALLOWED, "Explicit @Metadata is disallowed");
|
||||
MAP.put(SUSPENSION_POINT_INSIDE_MONITOR, "A suspension point at {0} is inside a critical section", STRING);
|
||||
MAP.put(SUSPENSION_POINT_INSIDE_SYNCHRONIZED, "The ''{0}'' suspension point is inside a synchronized block", NAME);
|
||||
|
||||
String MESSAGE_FOR_CONCURRENT_HASH_MAP_CONTAINS =
|
||||
"Method 'contains' from ConcurrentHashMap may have unexpected semantics: it calls 'containsValue' instead of 'containsKey'. " +
|
||||
"Use explicit form of the call to 'containsKey'/'containsValue'/'contains' or cast the value to kotlin.collections.Map instead. " +
|
||||
"See https://youtrack.jetbrains.com/issue/KT-18053 for more details";
|
||||
MAP.put(CONCURRENT_HASH_MAP_CONTAINS_OPERATOR, MESSAGE_FOR_CONCURRENT_HASH_MAP_CONTAINS);
|
||||
MAP.put(CONCURRENT_HASH_MAP_CONTAINS_OPERATOR_ERROR, MESSAGE_FOR_CONCURRENT_HASH_MAP_CONTAINS);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -54,6 +54,9 @@ public interface ErrorsJvm {
|
||||
DiagnosticFactory0<KtAnnotationEntry> OVERLOADS_INTERFACE = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtAnnotationEntry> OVERLOADS_PRIVATE = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<KtAnnotationEntry> OVERLOADS_LOCAL = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtAnnotationEntry> OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR_WARNING = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<KtAnnotationEntry> OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
|
||||
DiagnosticFactory0<KtDeclaration> EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT = DiagnosticFactory0.create(ERROR, ABSTRACT_MODIFIER);
|
||||
DiagnosticFactory0<KtDeclaration> EXTERNAL_DECLARATION_CANNOT_HAVE_BODY = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
@@ -125,6 +128,9 @@ public interface ErrorsJvm {
|
||||
DiagnosticFactory1<PsiElement, String> SUSPENSION_POINT_INSIDE_MONITOR = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, CallableDescriptor> SUSPENSION_POINT_INSIDE_SYNCHRONIZED = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<PsiElement> CONCURRENT_HASH_MAP_CONTAINS_OPERATOR = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> CONCURRENT_HASH_MAP_CONTAINS_OPERATOR_ERROR = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
Object _initializer = new Object() {
|
||||
{
|
||||
|
||||
@@ -5,13 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.jvm.multiplatform
|
||||
|
||||
import com.intellij.psi.PsiAnnotationMethod
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.components.JavaPropertyInitializerEvaluatorImpl
|
||||
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaAnnotationArgumentImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
|
||||
@@ -23,11 +22,10 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
|
||||
class JavaActualAnnotationArgumentExtractor : ExpectedActualDeclarationChecker.ActualAnnotationArgumentExtractor {
|
||||
override fun extractActualValue(argument: PsiElement, expectedType: KotlinType): ConstantValue<*>? =
|
||||
(argument as? PsiAnnotationMethod)
|
||||
?.defaultValue
|
||||
?.let { JavaAnnotationArgumentImpl.create(it, null) }
|
||||
?.convert(expectedType)
|
||||
override fun extractDefaultValue(parameter: ValueParameterDescriptor, expectedType: KotlinType): ConstantValue<*>? {
|
||||
val element = (parameter.source as? JavaSourceElement)?.javaElement
|
||||
return (element as? JavaMethod)?.annotationParameterDefaultValue?.convert(expectedType)
|
||||
}
|
||||
|
||||
// This code is similar to LazyJavaAnnotationDescriptor.resolveAnnotationArgument, but cannot be reused until
|
||||
// KClassValue/AnnotationValue are untied from descriptors/types, because here we do not have an instance of LazyJavaResolverContext.
|
||||
|
||||
@@ -50,7 +50,8 @@ object JvmPlatformConfigurator : PlatformConfigurator(
|
||||
ProtectedSyntheticExtensionCallChecker,
|
||||
ReifiedTypeParameterSubstitutionChecker(),
|
||||
RuntimeAssertionsOnExtensionReceiverCallChecker,
|
||||
ApiVersionIsAtLeastArgumentsChecker
|
||||
ApiVersionIsAtLeastArgumentsChecker,
|
||||
InconsistentOperatorFromJavaCallChecker
|
||||
),
|
||||
|
||||
additionalTypeCheckers = listOf(
|
||||
|
||||
@@ -92,7 +92,7 @@ interface SyntheticJavaPropertyDescriptor : PropertyDescriptor, SyntheticPropert
|
||||
}
|
||||
}
|
||||
|
||||
class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val lookupTracker: LookupTracker) : SyntheticScope {
|
||||
class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val lookupTracker: LookupTracker) : SyntheticScope.Default() {
|
||||
private val syntheticPropertyInClass =
|
||||
storageManager.createMemoizedFunction<Pair<ClassDescriptor, Name>, SyntheticPropertyHolder> { pair ->
|
||||
syntheticPropertyInClassNotCached(pair.first, pair.second)
|
||||
@@ -205,18 +205,6 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSyntheticStaticFunctions(scope: ResolutionScope, name: Name, location: LookupLocation): Collection<FunctionDescriptor> =
|
||||
emptyList()
|
||||
|
||||
override fun getSyntheticConstructors(scope: ResolutionScope, name: Name, location: LookupLocation): Collection<FunctionDescriptor> =
|
||||
emptyList()
|
||||
|
||||
override fun getSyntheticStaticFunctions(scope: ResolutionScope): Collection<FunctionDescriptor> = emptyList()
|
||||
|
||||
override fun getSyntheticConstructors(scope: ResolutionScope): Collection<FunctionDescriptor> = emptyList()
|
||||
|
||||
override fun getSyntheticConstructor(constructor: ConstructorDescriptor): ConstructorDescriptor? = null
|
||||
|
||||
private fun collectSyntheticPropertiesByName(
|
||||
result: SmartList<PropertyDescriptor>?,
|
||||
type: TypeConstructor,
|
||||
@@ -239,7 +227,10 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
|
||||
return result
|
||||
}
|
||||
|
||||
override fun getSyntheticExtensionProperties(receiverTypes: Collection<KotlinType>): Collection<PropertyDescriptor> {
|
||||
override fun getSyntheticExtensionProperties(
|
||||
receiverTypes: Collection<KotlinType>,
|
||||
location: LookupLocation
|
||||
): Collection<PropertyDescriptor> {
|
||||
val result = ArrayList<PropertyDescriptor>()
|
||||
val processedTypes = HashSet<TypeConstructor>()
|
||||
receiverTypes.forEach { result.collectSyntheticProperties(it.constructor, processedTypes) }
|
||||
|
||||
@@ -16,25 +16,46 @@
|
||||
|
||||
package org.jetbrains.kotlin.synthetic
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.load.java.components.SamConversionResolver
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
class JavaSyntheticScopes(
|
||||
private val project: Project,
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
storageManager: StorageManager,
|
||||
lookupTracker: LookupTracker,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
samConventionResolver: SamConversionResolver,
|
||||
deprecationResolver: DeprecationResolver
|
||||
): SyntheticScopes {
|
||||
override val scopes = listOf(
|
||||
JavaSyntheticPropertiesScope(storageManager, lookupTracker),
|
||||
override val scopes = run {
|
||||
val javaSyntheticPropertiesScope = JavaSyntheticPropertiesScope(storageManager, lookupTracker)
|
||||
|
||||
val scopesFromExtensions = SyntheticScopeProviderExtension
|
||||
.getInstances(project)
|
||||
.flatMap { it.getScopes(moduleDescriptor, javaSyntheticPropertiesScope) }
|
||||
|
||||
listOf(
|
||||
javaSyntheticPropertiesScope,
|
||||
SamAdapterFunctionsScope(
|
||||
storageManager, languageVersionSettings, samConventionResolver, deprecationResolver,
|
||||
lookupTracker
|
||||
storageManager, languageVersionSettings, samConventionResolver, deprecationResolver,
|
||||
lookupTracker
|
||||
)
|
||||
)
|
||||
) + scopesFromExtensions
|
||||
}
|
||||
}
|
||||
|
||||
interface SyntheticScopeProviderExtension {
|
||||
companion object : ProjectExtensionDescriptor<SyntheticScopeProviderExtension>(
|
||||
"org.jetbrains.kotlin.syntheticScopeProviderExtension", SyntheticScopeProviderExtension::class.java)
|
||||
|
||||
fun getScopes(moduleDescriptor: ModuleDescriptor, javaSyntheticPropertiesScope: JavaSyntheticPropertiesScope): List<SyntheticScope>
|
||||
}
|
||||
@@ -59,7 +59,7 @@ class SamAdapterFunctionsScope(
|
||||
private val samResolver: SamConversionResolver,
|
||||
private val deprecationResolver: DeprecationResolver,
|
||||
private val lookupTracker: LookupTracker
|
||||
) : SyntheticScope {
|
||||
) : SyntheticScope.Default() {
|
||||
private val samViaSyntheticScopeDisabled = languageVersionSettings.supportsFeature(LanguageFeature.NewInference)
|
||||
|
||||
private val extensionForFunction =
|
||||
@@ -150,10 +150,6 @@ class SamAdapterFunctionsScope(
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSyntheticExtensionProperties(receiverTypes: Collection<KotlinType>, name: Name, location: LookupLocation): Collection<PropertyDescriptor> = emptyList()
|
||||
|
||||
override fun getSyntheticExtensionProperties(receiverTypes: Collection<KotlinType>): Collection<PropertyDescriptor> = emptyList()
|
||||
|
||||
override fun getSyntheticStaticFunctions(scope: ResolutionScope, name: Name, location: LookupLocation): Collection<FunctionDescriptor> {
|
||||
if (samViaSyntheticScopeDisabled) return emptyList()
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.script
|
||||
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
import kotlin.reflect.jvm.jvmErasure
|
||||
@@ -160,18 +159,6 @@ private class StringArgsConverter : ArgsConverter<String> {
|
||||
|
||||
override fun tryConvertVararg(parameter: KParameter, firstArg: NamedArgument<String>, restArgsIt: Iterator<NamedArgument<String>>): ArgsConverter.Result {
|
||||
|
||||
fun convertAnyArray(classifier: KClassifier?, args: Sequence<String?>): Any? =
|
||||
when (classifier) {
|
||||
String::class -> args.toList().toTypedArray()
|
||||
is KClass<*> -> classifier.constructors.firstNotNullResult { ctor ->
|
||||
try {
|
||||
args.map { ctor.call(it) }.toList().toTypedArray()
|
||||
}
|
||||
catch (e: Exception) { null }
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun convertPrimitivesArray(type: KType, args: Sequence<String?>): Any? =
|
||||
when (type.classifier) {
|
||||
IntArray::class -> args.map { it?.toIntOrNull() }
|
||||
@@ -228,9 +215,42 @@ private class AnyArgsConverter : ArgsConverter<Any> {
|
||||
?: ArgsConverter.Result.Failure
|
||||
}
|
||||
|
||||
override fun tryConvertVararg(parameter: KParameter, firstArg: NamedArgument<Any>, restArgsIt: Iterator<NamedArgument<Any>>): ArgsConverter.Result =
|
||||
ArgsConverter.Result.Failure
|
||||
override fun tryConvertVararg(
|
||||
parameter: KParameter, firstArg: NamedArgument<Any>, restArgsIt: Iterator<NamedArgument<Any>>
|
||||
): ArgsConverter.Result {
|
||||
|
||||
val parameterType = parameter.type
|
||||
if (parameterType.jvmErasure.java.isArray) {
|
||||
val argsSequence = sequenceOf(firstArg.value) + restArgsIt.asSequence().map { it.value }
|
||||
val arrayElementType = parameterType.arguments.firstOrNull()?.type
|
||||
val arrayArgCandidate = convertAnyArray(arrayElementType?.classifier, argsSequence)
|
||||
if (arrayArgCandidate != null)
|
||||
return ArgsConverter.Result.Success(arrayArgCandidate)
|
||||
}
|
||||
|
||||
return ArgsConverter.Result.Failure
|
||||
}
|
||||
|
||||
override fun tryConvertTail(parameter: KParameter, firstArg: NamedArgument<Any>, restArgsIt: Iterator<NamedArgument<Any>>): ArgsConverter.Result =
|
||||
tryConvertSingle(parameter, firstArg)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private inline fun <reified T> convertAnyArray(classifier: KClassifier?, args: Sequence<T?>): Any? =
|
||||
if (classifier == T::class) args.toList().toTypedArray() // simple case
|
||||
else convertAnyArrayImpl<T>(classifier, args)
|
||||
|
||||
private fun <T> convertAnyArrayImpl(classifier: KClassifier?, args: Sequence<T?>): Any? {
|
||||
val elementClass = (classifier as? KClass<*>) ?: return null
|
||||
|
||||
val argsList = args.toList()
|
||||
val result = java.lang.reflect.Array.newInstance(elementClass.java, argsList.size)
|
||||
argsList.forEachIndexed { idx, arg ->
|
||||
try {
|
||||
java.lang.reflect.Array.set(result, idx, arg)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
return@convertAnyArrayImpl null
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.cfg.TailRecursionKind.*
|
||||
import org.jetbrains.kotlin.cfg.VariableUseState.*
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeUtil
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.containingDeclarationForPseudocode
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.KtElementInstruction
|
||||
@@ -30,6 +31,7 @@ import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.idea.MainFunctionDetector
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.*
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
|
||||
@@ -118,32 +120,69 @@ class ControlFlowInformationProvider private constructor(
|
||||
markAndCheckTailCalls()
|
||||
}
|
||||
|
||||
private fun collectReturnExpressions(returnedExpressions: MutableCollection<KtElement>) {
|
||||
/**
|
||||
* Collects returned expressions from current pseudocode.
|
||||
*
|
||||
* "Returned expression" here == "last expression" in *control-flow terms*. Intuitively,
|
||||
* it considers all execution paths, takes last expression on each path and returns them.
|
||||
*
|
||||
* More specifically, this function starts from EXIT instruction, and performs DFS-search
|
||||
* on reversed control-flow edges in a following manner:
|
||||
* - if the current instruction is a Return-instruction, then add it's expression to result
|
||||
* - if the current instruction is a Element-instruction, then add it's element to result
|
||||
* - if the current instruction is a Jump-instruction, then process it's predecessors
|
||||
* recursively
|
||||
*
|
||||
* NB. The second case (Element-instruction) means that notion of "returned expression"
|
||||
* here differs from what the language treats as "returned expression" (notably in the
|
||||
* presence of Unit-coercion). Example:
|
||||
*
|
||||
* fun foo() {
|
||||
* val x = 42
|
||||
* x.inc() // This call will be in a [returnedExpressions], even though this expression
|
||||
* // isn't actually returned
|
||||
* }
|
||||
*/
|
||||
private fun collectReturnExpressions(): ReturnedExpressionsInfo {
|
||||
val instructions = pseudocode.instructions.toHashSet()
|
||||
val exitInstruction = pseudocode.exitInstruction
|
||||
|
||||
val returnedExpressions = arrayListOf<KtElement>()
|
||||
var hasReturnsInInlinedLambda = false
|
||||
|
||||
for (previousInstruction in exitInstruction.previousInstructions) {
|
||||
previousInstruction.accept(object : InstructionVisitor() {
|
||||
override fun visitReturnValue(instruction: ReturnValueInstruction) {
|
||||
if (instructions.contains(instruction)) { //exclude non-local return expressions
|
||||
returnedExpressions.add(instruction.element)
|
||||
}
|
||||
|
||||
if (instruction.owner.isInlined) {
|
||||
hasReturnsInInlinedLambda = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitReturnNoValue(instruction: ReturnNoValueInstruction) {
|
||||
if (instructions.contains(instruction)) {
|
||||
returnedExpressions.add(instruction.element)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun visitJump(instruction: AbstractJumpInstruction) {
|
||||
// Nothing
|
||||
if (instruction.owner.isInlined) {
|
||||
hasReturnsInInlinedLambda = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitUnconditionalJump(instruction: UnconditionalJumpInstruction) {
|
||||
redirectToPrevInstructions(instruction)
|
||||
}
|
||||
|
||||
override fun visitConditionalJump(instruction: ConditionalJumpInstruction) {
|
||||
redirectToPrevInstructions(instruction)
|
||||
}
|
||||
|
||||
// Note that there's no need to overload `visitThrowException`, because
|
||||
// it can never be a predecessor of EXIT (throwing always leads to ERROR)
|
||||
|
||||
private fun redirectToPrevInstructions(instruction: Instruction) {
|
||||
for (redirectInstruction in instruction.previousInstructions) {
|
||||
redirectInstruction.accept(this)
|
||||
@@ -160,6 +199,9 @@ class ControlFlowInformationProvider private constructor(
|
||||
|
||||
override fun visitInstruction(instruction: Instruction) {
|
||||
if (instruction is KtElementInstruction) {
|
||||
// Caveats:
|
||||
// - for empty block-bodies, read(Unit) is emitted and will be processed here
|
||||
// - for Unit-coerced blocks, last expression will be processed here
|
||||
returnedExpressions.add(instruction.element)
|
||||
} else {
|
||||
throw IllegalStateException("$instruction precedes the exit point")
|
||||
@@ -167,6 +209,8 @@ class ControlFlowInformationProvider private constructor(
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return ReturnedExpressionsInfo(returnedExpressions, hasReturnsInInlinedLambda)
|
||||
}
|
||||
|
||||
private fun checkLocalFunctions() {
|
||||
@@ -192,8 +236,7 @@ class ControlFlowInformationProvider private constructor(
|
||||
|
||||
if (!function.hasBody()) return
|
||||
|
||||
val returnedExpressions = arrayListOf<KtElement>()
|
||||
collectReturnExpressions(returnedExpressions)
|
||||
val (returnedExpressions, hasReturnsInInlinedLambdas) = collectReturnExpressions()
|
||||
|
||||
val blockBody = function.hasBlockBody()
|
||||
|
||||
@@ -211,17 +254,25 @@ class ControlFlowInformationProvider private constructor(
|
||||
|
||||
if (blockBody && !noExpectedType(expectedReturnType)
|
||||
&& !KotlinBuiltIns.isUnit(expectedReturnType)
|
||||
&& !unreachableCode.elements.contains(element)) {
|
||||
&& !unreachableCode.elements.contains(element)
|
||||
) {
|
||||
noReturnError = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (noReturnError) {
|
||||
trace.report(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY.on(function))
|
||||
if (hasReturnsInInlinedLambdas) {
|
||||
trace.report(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY_MIGRATION.on(function))
|
||||
} else {
|
||||
trace.report(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY.on(function))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class ReturnedExpressionsInfo(val returnedExpressions: Collection<KtElement>, val hasReturnsInInlinedLambda: Boolean)
|
||||
|
||||
private fun reportUnreachableCode(unreachableCode: UnreachableCode) {
|
||||
for (element in unreachableCode.elements) {
|
||||
trace.report(Errors.UNREACHABLE_CODE.on(element, unreachableCode.getUnreachableTextRanges(element)))
|
||||
|
||||
@@ -28,10 +28,14 @@ import org.jetbrains.kotlin.metadata.deserialization.isInstanceType
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ContractDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
import org.jetbrains.kotlin.serialization.deserialization.TypeDeserializer
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
class ContractDeserializerImpl(private val configuration: DeserializationConfiguration) : ContractDeserializer {
|
||||
class ContractDeserializerImpl(
|
||||
private val configuration: DeserializationConfiguration,
|
||||
private val storageManager: StorageManager
|
||||
) : ContractDeserializer {
|
||||
override fun deserializeContractFromFunction(
|
||||
proto: ProtoBuf.Function,
|
||||
ownerFunction: FunctionDescriptor,
|
||||
@@ -42,7 +46,7 @@ class ContractDeserializerImpl(private val configuration: DeserializationConfigu
|
||||
|
||||
if (!configuration.readDeserializedContracts) return null
|
||||
|
||||
val worker = ContractDeserializationWorker(typeTable, typeDeserializer, ownerFunction)
|
||||
val worker = ContractDeserializationWorker(typeTable, typeDeserializer, ownerFunction, storageManager)
|
||||
val contract = worker.deserializeContract(proto.contract)
|
||||
return ContractProviderKey to LazyContractProvider.createInitialized(contract)
|
||||
}
|
||||
@@ -50,12 +54,13 @@ class ContractDeserializerImpl(private val configuration: DeserializationConfigu
|
||||
private class ContractDeserializationWorker(
|
||||
private val typeTable: TypeTable,
|
||||
private val typeDeserializer: TypeDeserializer,
|
||||
private val ownerFunction: FunctionDescriptor
|
||||
private val ownerFunction: FunctionDescriptor,
|
||||
private val storageManager: StorageManager
|
||||
) {
|
||||
|
||||
fun deserializeContract(proto: ProtoBuf.Contract): ContractDescription? {
|
||||
val effects = proto.effectList.map { deserializePossiblyConditionalEffect(it) ?: return null }
|
||||
return ContractDescription(effects, ownerFunction)
|
||||
return ContractDescription(effects, ownerFunction, storageManager)
|
||||
}
|
||||
|
||||
private fun deserializePossiblyConditionalEffect(proto: ProtoBuf.Effect): EffectDeclaration? {
|
||||
@@ -75,7 +80,7 @@ class ContractDeserializerImpl(private val configuration: DeserializationConfigu
|
||||
val argument = proto.effectConstructorArgumentList.getOrNull(0)
|
||||
val returnValue =
|
||||
if (argument == null) ConstantReference.WILDCARD else deserializeExpression(argument) as? ConstantReference
|
||||
?: return null
|
||||
?: return null
|
||||
ReturnsEffectDeclaration(returnValue)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.contracts
|
||||
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.contracts.description.ContractProviderKey
|
||||
import org.jetbrains.kotlin.contracts.interpretation.ContractInterpretationDispatcher
|
||||
import org.jetbrains.kotlin.contracts.model.Computation
|
||||
import org.jetbrains.kotlin.contracts.model.ConditionalEffect
|
||||
@@ -168,11 +169,8 @@ class EffectsExtractingVisitor(
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.getFunctor(): Functor? {
|
||||
trace[BindingContext.FUNCTOR, this]?.let { return it }
|
||||
|
||||
val functor = ContractInterpretationDispatcher().resolveFunctor(this) ?: return null
|
||||
trace.record(BindingContext.FUNCTOR, this, functor)
|
||||
return functor
|
||||
val contractDescription = getUserData(ContractProviderKey)?.getContractDescription() ?: return null
|
||||
return contractDescription.functor
|
||||
}
|
||||
|
||||
private fun ResolvedCall<*>.isCallWithUnsupportedReceiver(): Boolean =
|
||||
|
||||
@@ -32,8 +32,9 @@ import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
class ContractParsingServices(val languageVersionSettings: LanguageVersionSettings) {
|
||||
class ContractParsingServices(val languageVersionSettings: LanguageVersionSettings, private val storageManager: StorageManager) {
|
||||
/**
|
||||
* ! IMPORTANT NOTICE !
|
||||
*
|
||||
@@ -77,7 +78,7 @@ class ContractParsingServices(val languageVersionSettings: LanguageVersionSettin
|
||||
// Small optimization: do not even try to parse contract if we already have errors
|
||||
if (collector.hasErrors()) return null
|
||||
|
||||
val parsedContract = PsiContractParserDispatcher(collector, callContext).parseContract()
|
||||
val parsedContract = PsiContractParserDispatcher(collector, callContext, storageManager).parseContract()
|
||||
|
||||
// Make sure that at least generic error will be reported if we couldn't parse contract
|
||||
// (null returned => at least one error was reported)
|
||||
|
||||
@@ -40,10 +40,12 @@ import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
internal class PsiContractParserDispatcher(
|
||||
private val collector: ContractParsingDiagnosticsCollector,
|
||||
private val callContext: ContractCallContext
|
||||
private val callContext: ContractCallContext,
|
||||
private val storageManager: StorageManager
|
||||
) {
|
||||
private val conditionParser = PsiConditionParser(collector, callContext, this)
|
||||
private val constantParser = PsiConstantParser(callContext)
|
||||
@@ -71,7 +73,7 @@ internal class PsiContractParserDispatcher(
|
||||
|
||||
if (effects.isEmpty()) return null
|
||||
|
||||
return ContractDescription(effects, callContext.functionDescriptor)
|
||||
return ContractDescription(effects, callContext.functionDescriptor, storageManager)
|
||||
}
|
||||
|
||||
fun parseCondition(expression: KtExpression?): BooleanExpression? = expression?.accept(conditionParser, Unit)
|
||||
|
||||
@@ -101,7 +101,9 @@ public interface Errors {
|
||||
DiagnosticFactory1<PsiElement, String> MISSING_SCRIPT_BASE_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> MISSING_SCRIPT_STANDARD_TEMPLATE = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> MISSING_SCRIPT_RECEIVER_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> MISSING_SCRIPT_ENVIRONMENT_PROPERTY_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> MISSING_IMPORTED_SCRIPT_FILE = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> MISSING_IMPORTED_SCRIPT_PSI = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> MISSING_SCRIPT_PROVIDED_PROPERTY_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> PRE_RELEASE_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory2<PsiElement, String, IncompatibleVersionErrorData<?>> INCOMPATIBLE_CLASS = DiagnosticFactory2.create(ERROR);
|
||||
|
||||
@@ -952,6 +954,8 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtTypeReference> LOCAL_EXTENSION_PROPERTY = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtPropertyAccessor> LOCAL_VARIABLE_WITH_GETTER = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtPropertyAccessor> LOCAL_VARIABLE_WITH_SETTER = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtTypeParameterList> LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<KtTypeParameterList> LOCAL_VARIABLE_WITH_TYPE_PARAMETERS = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
DiagnosticFactory3<KtExpression, DeclarationDescriptor, Visibility, DeclarationDescriptor> INVISIBLE_SETTER = DiagnosticFactory3.create(ERROR);
|
||||
|
||||
@@ -1014,6 +1018,8 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtReturnExpression> RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY = DiagnosticFactory0.create(ERROR, PositioningStrategies.RETURN_WITH_LABEL);
|
||||
DiagnosticFactory0<KtDeclarationWithBody>
|
||||
NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY = DiagnosticFactory0.create(ERROR, DECLARATION_WITH_BODY);
|
||||
DiagnosticFactory0<KtDeclarationWithBody>
|
||||
NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY_MIGRATION = DiagnosticFactory0.create(ERROR, DECLARATION_WITH_BODY);
|
||||
|
||||
DiagnosticFactory0<KtAnonymousInitializer> ANONYMOUS_INITIALIZER_IN_INTERFACE = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
|
||||
|
||||
@@ -365,7 +365,9 @@ public class DefaultErrorMessages {
|
||||
MAP.put(MISSING_SCRIPT_BASE_CLASS, "Cannot access script base class ''{0}''. Check your module classpath for missing or conflicting dependencies", TO_STRING);
|
||||
MAP.put(MISSING_SCRIPT_STANDARD_TEMPLATE, "No script runtime was found in the classpath: class ''{0}'' not found. Please add kotlin-script-runtime.jar to the module dependencies.", TO_STRING);
|
||||
MAP.put(MISSING_SCRIPT_RECEIVER_CLASS, "Cannot access implicit script receiver class ''{0}''. Check your module classpath for missing or conflicting dependencies", TO_STRING);
|
||||
MAP.put(MISSING_SCRIPT_ENVIRONMENT_PROPERTY_CLASS, "Cannot access script environment property class ''{0}''. Check your module classpath for missing or conflicting dependencies", TO_STRING);
|
||||
MAP.put(MISSING_IMPORTED_SCRIPT_FILE, "Cannot find imported script file ''{0}''. Check your script imports", TO_STRING);
|
||||
MAP.put(MISSING_IMPORTED_SCRIPT_PSI, "Imported script file ''{0}'' is not loaded. Check your script imports", TO_STRING);
|
||||
MAP.put(MISSING_SCRIPT_PROVIDED_PROPERTY_CLASS, "Cannot access script provided property class ''{0}''. Check your module classpath for missing or conflicting dependencies", TO_STRING);
|
||||
MAP.put(PRE_RELEASE_CLASS, "{0} is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler", TO_STRING);
|
||||
MAP.put(INCOMPATIBLE_CLASS,
|
||||
"{0} was compiled with an incompatible version of Kotlin. {1}",
|
||||
@@ -397,6 +399,8 @@ public class DefaultErrorMessages {
|
||||
MAP.put(LOCAL_EXTENSION_PROPERTY, "Local extension properties are not allowed");
|
||||
MAP.put(LOCAL_VARIABLE_WITH_GETTER, "Local variables are not allowed to have getters");
|
||||
MAP.put(LOCAL_VARIABLE_WITH_SETTER, "Local variables are not allowed to have setters");
|
||||
MAP.put(LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING, "Type parameters for local variables are deprecated");
|
||||
MAP.put(LOCAL_VARIABLE_WITH_TYPE_PARAMETERS, "Local variables are not allowed to have type parameters");
|
||||
MAP.put(VAL_WITH_SETTER, "A 'val'-property cannot have a setter");
|
||||
|
||||
MAP.put(DEPRECATED_IDENTITY_EQUALS, "Identity equality for arguments of types {0} and {1} is deprecated", RENDER_TYPE, RENDER_TYPE);
|
||||
@@ -495,6 +499,9 @@ public class DefaultErrorMessages {
|
||||
MAP.put(RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY,
|
||||
"Returns are not allowed for functions with expression body. Use block body in '{...}'");
|
||||
MAP.put(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY, "A 'return' expression required in a function with a block body ('{...}')");
|
||||
MAP.put(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY_MIGRATION, "A 'return' expression required in a function with a block body ('{...}'). " +
|
||||
"If you got this error after the compiler update, then it's most likely due to a fix of a bug " +
|
||||
"introduced in 1.3.0 (see KT-28061 for details)");
|
||||
MAP.put(RETURN_TYPE_MISMATCH, "This function must return a value of type {0}", RENDER_TYPE);
|
||||
MAP.put(EXPECTED_TYPE_MISMATCH, "Expected a value of type {0}", RENDER_TYPE);
|
||||
MAP.put(ASSIGNMENT_TYPE_MISMATCH,
|
||||
|
||||
@@ -98,7 +98,6 @@ public interface BindingContext {
|
||||
WritableSlice<KtExpression, DataFlowInfo> DATA_FLOW_INFO_BEFORE = new BasicWritableSlice<>(DO_NOTHING);
|
||||
WritableSlice<KtExpression, KotlinType> EXPECTED_EXPRESSION_TYPE = new BasicWritableSlice<>(DO_NOTHING);
|
||||
WritableSlice<KtElement, Computation> EXPRESSION_EFFECTS = Slices.createSimpleSlice();
|
||||
WritableSlice<FunctionDescriptor, Functor> FUNCTOR = Slices.createSimpleSlice();
|
||||
WritableSlice<KtFunction, KotlinType> EXPECTED_RETURN_TYPE = new BasicWritableSlice<>(DO_NOTHING);
|
||||
WritableSlice<KtExpression, DataFlowInfo> DATAFLOW_INFO_AFTER_CONDITION = Slices.createSimpleSlice();
|
||||
WritableSlice<VariableDescriptor, DataFlowValue> BOUND_INITIALIZER_VALUE = Slices.createSimpleSlice();
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve;
|
||||
@@ -33,6 +22,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.TowerLevelsKt;
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.MutableDiagnosticsWithSuppression;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
import org.jetbrains.kotlin.types.expressions.CaptureKind;
|
||||
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo;
|
||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
|
||||
import org.jetbrains.kotlin.util.slicedMap.MutableSlicedMap;
|
||||
@@ -204,8 +194,15 @@ public class BindingContextUtils {
|
||||
return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null;
|
||||
}
|
||||
|
||||
public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) {
|
||||
return isCapturedInClosure(bindingContext, descriptor) && ((VariableDescriptor) descriptor).isVar();
|
||||
public static boolean isCapturedInClosureWithExactlyOnceEffect(BindingContext bindingContext, DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof VariableDescriptor) || descriptor instanceof PropertyDescriptor) return false;
|
||||
VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
|
||||
return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) == CaptureKind.EXACTLY_ONCE_EFFECT;
|
||||
}
|
||||
|
||||
public static boolean isBoxedLocalCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) {
|
||||
return (isCapturedInClosure(bindingContext, descriptor) && ((VariableDescriptor) descriptor).isVar()) ||
|
||||
isCapturedInClosureWithExactlyOnceEffect(bindingContext, descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -122,7 +122,8 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
|
||||
PropertiesWithBackingFieldsInsideInlineClass(),
|
||||
AnnotationClassTargetAndRetentionChecker(),
|
||||
ReservedMembersAndConstructsForInlineClass(),
|
||||
ResultClassInReturnTypeChecker()
|
||||
ResultClassInReturnTypeChecker(),
|
||||
LocalVariableTypeParametersChecker()
|
||||
)
|
||||
|
||||
private val DEFAULT_CALL_CHECKERS = listOf(
|
||||
|
||||
@@ -1,28 +1,24 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.contracts.description.CallsEffectDeclaration
|
||||
import org.jetbrains.kotlin.contracts.description.ContractProviderKey
|
||||
import org.jetbrains.kotlin.contracts.description.InvocationKind
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.CAPTURED_IN_CLOSURE
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentForExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
@@ -43,8 +39,7 @@ class CapturingInClosureChecker : CallChecker {
|
||||
val scopeContainer = scope.ownerDescriptor
|
||||
if (isCapturedVariable(variableParent, scopeContainer)) {
|
||||
if (trace.get(CAPTURED_IN_CLOSURE, variable) != CaptureKind.NOT_INLINE) {
|
||||
val inline = isCapturedInInline(trace.bindingContext, scopeContainer, variableParent)
|
||||
trace.record(CAPTURED_IN_CLOSURE, variable, if (inline) CaptureKind.INLINE_ONLY else CaptureKind.NOT_INLINE)
|
||||
trace.record(CAPTURED_IN_CLOSURE, variable, getCaptureKind(trace.bindingContext, scopeContainer, variableParent))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,17 +56,34 @@ class CapturingInClosureChecker : CallChecker {
|
||||
return true
|
||||
}
|
||||
|
||||
private fun isCapturedInInline(
|
||||
private fun getCaptureKind(
|
||||
context: BindingContext, scopeContainer: DeclarationDescriptor, variableParent: DeclarationDescriptor
|
||||
): Boolean {
|
||||
): CaptureKind {
|
||||
val scopeDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(scopeContainer)
|
||||
if (!InlineUtil.canBeInlineArgument(scopeDeclaration)) return false
|
||||
if (!InlineUtil.canBeInlineArgument(scopeDeclaration)) return CaptureKind.NOT_INLINE
|
||||
|
||||
if (InlineUtil.isInlinedArgument(scopeDeclaration as KtFunction, context, false)) {
|
||||
val exactlyOnceContract = isExactlyOnceContract(context, scopeDeclaration as KtFunction)
|
||||
if (InlineUtil.isInlinedArgument(scopeDeclaration, context, exactlyOnceContract)) {
|
||||
val scopeContainerParent = scopeContainer.containingDeclaration ?: error("parent is null for $scopeContainer")
|
||||
return !isCapturedVariable(variableParent, scopeContainerParent) ||
|
||||
isCapturedInInline(context, scopeContainerParent, variableParent)
|
||||
return if (
|
||||
!isCapturedVariable(variableParent, scopeContainerParent) ||
|
||||
getCaptureKind(context, scopeContainerParent, variableParent) == CaptureKind.INLINE_ONLY
|
||||
) CaptureKind.INLINE_ONLY else CaptureKind.NOT_INLINE
|
||||
}
|
||||
return false
|
||||
if (exactlyOnceContract) return CaptureKind.EXACTLY_ONCE_EFFECT
|
||||
return CaptureKind.NOT_INLINE
|
||||
}
|
||||
|
||||
private fun isExactlyOnceContract(bindingContext: BindingContext, argument: KtFunction): Boolean {
|
||||
val call = KtPsiUtil.getParentCallIfPresent(argument) ?: return false
|
||||
val resolvedCall = call.getResolvedCall(bindingContext) ?: return false
|
||||
val descriptor = resolvedCall.getResultingDescriptor()
|
||||
val valueArgument = resolvedCall.call.getValueArgumentForExpression(argument) ?: return false
|
||||
val mapping = resolvedCall.getArgumentMapping(valueArgument) as? ArgumentMatch ?: return false
|
||||
val parameter = mapping.valueParameter
|
||||
val contractDescription = descriptor.getUserData(ContractProviderKey)?.getContractDescription() ?: return false
|
||||
val effect = contractDescription.effects.filterIsInstance<CallsEffectDeclaration>()
|
||||
.find { it.variableReference.descriptor == parameter } ?: return false
|
||||
return effect.kind == InvocationKind.EXACTLY_ONCE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ import java.io.File
|
||||
|
||||
class ExpectedActualDeclarationChecker(val argumentExtractors: List<ActualAnnotationArgumentExtractor> = emptyList()) : DeclarationChecker {
|
||||
interface ActualAnnotationArgumentExtractor {
|
||||
fun extractActualValue(argument: PsiElement, expectedType: KotlinType): ConstantValue<*>?
|
||||
fun extractDefaultValue(parameter: ValueParameterDescriptor, expectedType: KotlinType): ConstantValue<*>?
|
||||
}
|
||||
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
@@ -233,14 +233,15 @@ class ExpectedActualDeclarationChecker(val argumentExtractors: List<ActualAnnota
|
||||
if (expectedParameterDescriptor.declaresDefaultValue() && actualParameterDescriptor.declaresDefaultValue()) {
|
||||
val expectedParameter =
|
||||
DescriptorToSourceUtils.descriptorToDeclaration(expectedParameterDescriptor) as? KtParameter ?: continue
|
||||
val actualParameter = DescriptorToSourceUtils.descriptorToDeclaration(actualParameterDescriptor)
|
||||
|
||||
val expectedValue = trace.bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expectedParameter.defaultValue)
|
||||
?.toConstantValue(expectedParameterDescriptor.type)
|
||||
|
||||
val actualValue = getActualAnnotationParameterValue(actualParameter, trace.bindingContext, expectedParameterDescriptor.type)
|
||||
val actualValue =
|
||||
getActualAnnotationParameterValue(actualParameterDescriptor, trace.bindingContext, expectedParameterDescriptor.type)
|
||||
if (expectedValue != actualValue) {
|
||||
val target = (actualParameter as? KtParameter)?.defaultValue ?: (reportOn as? KtTypeAlias)?.nameIdentifier ?: reportOn
|
||||
val ktParameter = DescriptorToSourceUtils.descriptorToDeclaration(actualParameterDescriptor)
|
||||
val target = (ktParameter as? KtParameter)?.defaultValue ?: (reportOn as? KtTypeAlias)?.nameIdentifier ?: reportOn
|
||||
trace.report(Errors.ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE.on(target, actualParameterDescriptor))
|
||||
}
|
||||
}
|
||||
@@ -248,16 +249,15 @@ class ExpectedActualDeclarationChecker(val argumentExtractors: List<ActualAnnota
|
||||
}
|
||||
|
||||
private fun getActualAnnotationParameterValue(
|
||||
actualParameter: PsiElement?, bindingContext: BindingContext, expectedType: KotlinType
|
||||
actualParameter: ValueParameterDescriptor, bindingContext: BindingContext, expectedType: KotlinType
|
||||
): ConstantValue<*>? {
|
||||
if (actualParameter is KtParameter) {
|
||||
return bindingContext.get(BindingContext.COMPILE_TIME_VALUE, actualParameter.defaultValue)?.toConstantValue(expectedType)
|
||||
val declaration = DescriptorToSourceUtils.descriptorToDeclaration(actualParameter)
|
||||
if (declaration is KtParameter) {
|
||||
return bindingContext.get(BindingContext.COMPILE_TIME_VALUE, declaration.defaultValue)?.toConstantValue(expectedType)
|
||||
}
|
||||
|
||||
if (actualParameter != null) {
|
||||
for (extractor in argumentExtractors) {
|
||||
extractor.extractActualValue(actualParameter, expectedType)?.let { return it }
|
||||
}
|
||||
for (extractor in argumentExtractors) {
|
||||
extractor.extractDefaultValue(actualParameter, expectedType)?.let { return it }
|
||||
}
|
||||
|
||||
return null
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.checkers
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
|
||||
class LocalVariableTypeParametersChecker : DeclarationChecker {
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
if (declaration !is KtProperty || descriptor !is LocalVariableDescriptor) return
|
||||
|
||||
val typeParameters = declaration.typeParameters
|
||||
val typeParametersList = declaration.typeParameterList
|
||||
if (typeParameters.isEmpty() || typeParametersList == null) return
|
||||
|
||||
val diagnostic =
|
||||
if (context.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitTypeParametersForLocalVariables))
|
||||
Errors.LOCAL_VARIABLE_WITH_TYPE_PARAMETERS
|
||||
else
|
||||
Errors.LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING
|
||||
|
||||
context.trace.report(diagnostic.on(typeParametersList))
|
||||
}
|
||||
}
|
||||
@@ -41,10 +41,13 @@ class LazyScriptClassMemberScope(
|
||||
if (baseConstructorDescriptor != null) {
|
||||
val implicitReceiversParamTypes =
|
||||
scriptDescriptor.implicitReceivers.mapIndexed { idx, receiver ->
|
||||
"$IMPLICIT_RECEIVER_PARAM_NAME_PREFIX$idx" to receiver.defaultType
|
||||
val name =
|
||||
if (receiver is ScriptDescriptor) "$IMPORTED_SCRIPT_PARAM_NAME_PREFIX${receiver.name}"
|
||||
else "$IMPLICIT_RECEIVER_PARAM_NAME_PREFIX$idx"
|
||||
name to receiver.defaultType
|
||||
}
|
||||
val environmentVarsParamTypes =
|
||||
scriptDescriptor.scriptEnvironmentProperties.map {
|
||||
val providedPropertiesParamTypes =
|
||||
scriptDescriptor.scriptProvidedProperties.map {
|
||||
it.name.identifier to it.type
|
||||
}
|
||||
val annotations = baseConstructorDescriptor.annotations
|
||||
@@ -53,7 +56,7 @@ class LazyScriptClassMemberScope(
|
||||
)
|
||||
var paramsIndexBase = baseConstructorDescriptor.valueParameters.lastIndex + 1
|
||||
val syntheticParameters =
|
||||
(implicitReceiversParamTypes + environmentVarsParamTypes).map { param: Pair<String, KotlinType> ->
|
||||
(implicitReceiversParamTypes + providedPropertiesParamTypes).map { param: Pair<String, KotlinType> ->
|
||||
ValueParameterDescriptorImpl(
|
||||
constructorDescriptor,
|
||||
null,
|
||||
@@ -103,6 +106,7 @@ class LazyScriptClassMemberScope(
|
||||
|
||||
companion object {
|
||||
const val IMPLICIT_RECEIVER_PARAM_NAME_PREFIX = "\$\$implicitReceiver"
|
||||
const val IMPORTED_SCRIPT_PARAM_NAME_PREFIX = "\$\$importedScript"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,17 +16,20 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.lazy.descriptors
|
||||
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.openapi.vfs.local.CoreLocalFileSystem
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtBlockExpression
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtScriptInitializer
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getChildOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -37,17 +40,20 @@ import org.jetbrains.kotlin.resolve.lazy.ResolveSession
|
||||
import org.jetbrains.kotlin.resolve.lazy.data.KtScriptInfo
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.script.ReplResultPropertyDescriptor
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.script.ScriptEnvironmentDescriptor
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.script.ScriptProvidedPropertiesDescriptor
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.script.classId
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeImpl
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind
|
||||
import org.jetbrains.kotlin.resolve.source.toSourceElement
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.script.ScriptDependenciesProvider
|
||||
import org.jetbrains.kotlin.script.ScriptPriorities
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import java.io.File
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
|
||||
@@ -143,10 +149,48 @@ class LazyScriptDescriptor(
|
||||
|
||||
override fun computeSupertypes() = listOf(baseClassDescriptor()?.defaultType ?: builtIns.anyType)
|
||||
|
||||
private inner class ImportedScriptDescriptorsFinder {
|
||||
|
||||
val fileManager = VirtualFileManager.getInstance()
|
||||
val localFS = fileManager.getFileSystem(StandardFileSystems.FILE_PROTOCOL)
|
||||
val psiManager = PsiManager.getInstance(scriptInfo.script.project)
|
||||
|
||||
operator fun invoke(importedScriptFile: File): ScriptDescriptor? {
|
||||
|
||||
fun errorDescriptor(errorDiagnostic: DiagnosticFactory1<PsiElement, String>?): ScriptDescriptor? {
|
||||
reportErrorString1(errorDiagnostic, importedScriptFile.path)
|
||||
return null
|
||||
}
|
||||
|
||||
val vfile = localFS.findFileByPath(importedScriptFile.path)
|
||||
?: return errorDescriptor(MISSING_IMPORTED_SCRIPT_FILE)
|
||||
val psiFile = psiManager.findFile(vfile)
|
||||
?: return errorDescriptor(MISSING_IMPORTED_SCRIPT_PSI)
|
||||
// Note: is not an error now - if import references other valid source file, it is simply compiled along with script
|
||||
// TODO: check if this is the behavior we want to have - see #KT-28916
|
||||
val ktScript = (psiFile as? KtFile)?.declarations?.firstIsInstanceOrNull<KtScript>()
|
||||
?: return null
|
||||
return resolveSession.getScriptDescriptor(ktScript)
|
||||
}
|
||||
}
|
||||
|
||||
private val scriptImplicitReceivers: () -> List<ClassDescriptor> = resolveSession.storageManager.createLazyValue {
|
||||
scriptDefinition().implicitReceivers.mapNotNull { receiver ->
|
||||
val res = ArrayList<ClassDescriptor>()
|
||||
|
||||
val importedScriptsFiles = ScriptDependenciesProvider.getInstance(scriptInfo.script.project)
|
||||
.getScriptDependencies(scriptInfo.script.containingKtFile)?.scripts
|
||||
if (importedScriptsFiles != null) {
|
||||
val findImportedScriptDescriptor = ImportedScriptDescriptorsFinder()
|
||||
importedScriptsFiles.mapNotNullTo(res) {
|
||||
findImportedScriptDescriptor(it)
|
||||
}
|
||||
}
|
||||
|
||||
scriptDefinition().implicitReceivers.mapNotNullTo(res) { receiver ->
|
||||
findTypeDescriptor(receiver, Errors.MISSING_SCRIPT_RECEIVER_CLASS)
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
internal fun findTypeDescriptor(kClass: KClass<*>, errorDiagnostic: DiagnosticFactory1<PsiElement, String>?): ClassDescriptor? =
|
||||
@@ -160,33 +204,39 @@ class LazyScriptDescriptor(
|
||||
errorDiagnostic: DiagnosticFactory1<PsiElement, String>?
|
||||
): ClassDescriptor? {
|
||||
val typeDescriptor = classId?.let { module.findClassAcrossModuleDependencies(it) }
|
||||
if (typeDescriptor == null && errorDiagnostic != null) {
|
||||
// TODO: use PositioningStrategies to highlight some specific place in case of error, instead of treating the whole file as invalid
|
||||
resolveSession.trace.report(
|
||||
errorDiagnostic.on(
|
||||
scriptInfo.script,
|
||||
classId?.asSingleFqName()?.toString() ?: typeName
|
||||
)
|
||||
)
|
||||
if (typeDescriptor == null) {
|
||||
reportErrorString1(errorDiagnostic, classId?.asSingleFqName()?.toString() ?: typeName)
|
||||
}
|
||||
return typeDescriptor
|
||||
}
|
||||
|
||||
override fun getImplicitReceivers(): List<ClassDescriptor> = scriptImplicitReceivers()
|
||||
|
||||
private val scriptEnvironment: () -> ScriptEnvironmentDescriptor = resolveSession.storageManager.createLazyValue {
|
||||
ScriptEnvironmentDescriptor(this)
|
||||
private fun reportErrorString1(errorDiagnostic: DiagnosticFactory1<PsiElement, String>?, arg: String) {
|
||||
if (errorDiagnostic != null) {
|
||||
// TODO: use PositioningStrategies to highlight some specific place in case of error, instead of treating the whole file as invalid
|
||||
resolveSession.trace.report(
|
||||
errorDiagnostic.on(
|
||||
scriptInfo.script,
|
||||
arg
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getScriptEnvironmentProperties(): List<PropertyDescriptor> = scriptEnvironment().properties()
|
||||
override fun getImplicitReceivers(): List<ClassDescriptor> = scriptImplicitReceivers()
|
||||
|
||||
private val scriptProvidedProperties: () -> ScriptProvidedPropertiesDescriptor = resolveSession.storageManager.createLazyValue {
|
||||
ScriptProvidedPropertiesDescriptor(this)
|
||||
}
|
||||
|
||||
override fun getScriptProvidedProperties(): List<PropertyDescriptor> = scriptProvidedProperties().properties()
|
||||
|
||||
private val scriptOuterScope: () -> LexicalScope = resolveSession.storageManager.createLazyValue {
|
||||
var outerScope = super.getOuterScope()
|
||||
val outerScopeReceivers = implicitReceivers.let {
|
||||
if (scriptDefinition().environmentVariables.isEmpty()) {
|
||||
if (scriptDefinition().providedProperties.isEmpty()) {
|
||||
it
|
||||
} else {
|
||||
it + ScriptEnvironmentDescriptor(this)
|
||||
it + ScriptProvidedPropertiesDescriptor(this)
|
||||
}
|
||||
}
|
||||
for (receiverClassDescriptor in outerScopeReceivers.asReversed()) {
|
||||
|
||||
@@ -17,11 +17,11 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
|
||||
class ScriptEnvironmentDescriptor(script: LazyScriptDescriptor) :
|
||||
class ScriptProvidedPropertiesDescriptor(script: LazyScriptDescriptor) :
|
||||
MutableClassDescriptor(
|
||||
script,
|
||||
ClassKind.CLASS, false, false,
|
||||
Name.special("<synthetic script environment for ${script.name}>"),
|
||||
Name.special("<synthetic script provided properties for ${script.name}>"),
|
||||
SourceElement.NO_SOURCE,
|
||||
LockBasedStorageManager.NO_LOCKS
|
||||
) {
|
||||
@@ -33,8 +33,8 @@ class ScriptEnvironmentDescriptor(script: LazyScriptDescriptor) :
|
||||
createTypeConstructor()
|
||||
}
|
||||
|
||||
private val memberScope: () -> ScriptEnvironmentMemberScope = script.resolveSession.storageManager.createLazyValue {
|
||||
ScriptEnvironmentMemberScope(
|
||||
private val memberScope: () -> ScriptProvidedPropertiesMemberScope = script.resolveSession.storageManager.createLazyValue {
|
||||
ScriptProvidedPropertiesMemberScope(
|
||||
script.name.identifier,
|
||||
properties()
|
||||
)
|
||||
@@ -42,13 +42,13 @@ class ScriptEnvironmentDescriptor(script: LazyScriptDescriptor) :
|
||||
|
||||
override fun getUnsubstitutedMemberScope(): MemberScope = memberScope()
|
||||
|
||||
val properties: () -> List<ScriptEnvironmentPropertyDescriptor> = script.resolveSession.storageManager.createLazyValue {
|
||||
script.scriptDefinition().environmentVariables.mapNotNull { (name, type) ->
|
||||
script.findTypeDescriptor(type, Errors.MISSING_SCRIPT_ENVIRONMENT_PROPERTY_CLASS)?.let {
|
||||
val properties: () -> List<ScriptProvidedPropertyDescriptor> = script.resolveSession.storageManager.createLazyValue {
|
||||
script.scriptDefinition().providedProperties.mapNotNull { (name, type) ->
|
||||
script.findTypeDescriptor(type, Errors.MISSING_SCRIPT_PROVIDED_PROPERTY_CLASS)?.let {
|
||||
name to it
|
||||
}
|
||||
}.map { (name, classDescriptor) ->
|
||||
ScriptEnvironmentPropertyDescriptor(
|
||||
ScriptProvidedPropertyDescriptor(
|
||||
Name.identifier(name),
|
||||
classDescriptor,
|
||||
thisAsReceiverParameter,
|
||||
@@ -58,21 +58,21 @@ class ScriptEnvironmentDescriptor(script: LazyScriptDescriptor) :
|
||||
}
|
||||
}
|
||||
|
||||
private class ScriptEnvironmentMemberScope(
|
||||
private class ScriptProvidedPropertiesMemberScope(
|
||||
private val scriptId: String,
|
||||
private val environmentProperties: List<PropertyDescriptor>
|
||||
private val providedProperties: List<PropertyDescriptor>
|
||||
) : MemberScopeImpl() {
|
||||
override fun getContributedDescriptors(
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean
|
||||
): Collection<DeclarationDescriptor> =
|
||||
environmentProperties
|
||||
providedProperties
|
||||
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> =
|
||||
environmentProperties.filter { it.name == name }
|
||||
providedProperties.filter { it.name == name }
|
||||
|
||||
override fun printScopeStructure(p: Printer) {
|
||||
p.println("Scope of script environment: $scriptId")
|
||||
p.println("Scope of script provided properties: $scriptId")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor
|
||||
|
||||
class ScriptEnvironmentPropertyDescriptor(
|
||||
class ScriptProvidedPropertyDescriptor(
|
||||
name: Name,
|
||||
typeDescriptor: ClassDescriptor,
|
||||
receiver: ReceiverParameterDescriptor?,
|
||||
@@ -1,22 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.types.expressions;
|
||||
|
||||
public enum CaptureKind {
|
||||
NOT_INLINE,
|
||||
INLINE_ONLY
|
||||
INLINE_ONLY,
|
||||
EXACTLY_ONCE_EFFECT
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user