Support new scheme of compilation of OptionalExpectation annotations

Instead of generating these annotation classes as package-private on
JVM, serialize their metadata to the .kotlin_module file, and load it
when compiling dependent multiplatform modules.

The problem with generating them as package-private was that
kotlin-stdlib for JVM would end up declaring symbols from other
platforms, which would include some annotations from package
kotlin.native. But using that package is discouraged by some tools
because it has a Java keyword in its name. In particular, jlink refused
to work with such artifact altogether (KT-21266).

 #KT-38652 Fixed
This commit is contained in:
Alexander Udalov
2019-12-17 17:43:42 +01:00
committed by Alexander Udalov
parent 63e355d979
commit 012ffa2993
42 changed files with 1469 additions and 145 deletions
@@ -208,6 +208,65 @@ public final class DebugJvmModuleProtoBuf {
*/ */
org.jetbrains.kotlin.metadata.DebugProtoBuf.AnnotationOrBuilder getAnnotationOrBuilder( org.jetbrains.kotlin.metadata.DebugProtoBuf.AnnotationOrBuilder getAnnotationOrBuilder(
int index); int index);
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
java.util.List<org.jetbrains.kotlin.metadata.DebugProtoBuf.Class>
getOptionalAnnotationClassList();
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
org.jetbrains.kotlin.metadata.DebugProtoBuf.Class getOptionalAnnotationClass(int index);
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
int getOptionalAnnotationClassCount();
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
java.util.List<? extends org.jetbrains.kotlin.metadata.DebugProtoBuf.ClassOrBuilder>
getOptionalAnnotationClassOrBuilderList();
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
org.jetbrains.kotlin.metadata.DebugProtoBuf.ClassOrBuilder getOptionalAnnotationClassOrBuilder(
int index);
} }
/** /**
* Protobuf type {@code org.jetbrains.kotlin.metadata.jvm.Module} * Protobuf type {@code org.jetbrains.kotlin.metadata.jvm.Module}
@@ -320,6 +379,14 @@ public final class DebugJvmModuleProtoBuf {
annotation_.add(input.readMessage(org.jetbrains.kotlin.metadata.DebugProtoBuf.Annotation.PARSER, extensionRegistry)); annotation_.add(input.readMessage(org.jetbrains.kotlin.metadata.DebugProtoBuf.Annotation.PARSER, extensionRegistry));
break; break;
} }
case 130: {
if (!((mutable_bitField0_ & 0x00000040) == 0x00000040)) {
optionalAnnotationClass_ = new java.util.ArrayList<org.jetbrains.kotlin.metadata.DebugProtoBuf.Class>();
mutable_bitField0_ |= 0x00000040;
}
optionalAnnotationClass_.add(input.readMessage(org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.PARSER, extensionRegistry));
break;
}
} }
} }
} catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) { } catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) {
@@ -340,6 +407,9 @@ public final class DebugJvmModuleProtoBuf {
if (((mutable_bitField0_ & 0x00000020) == 0x00000020)) { if (((mutable_bitField0_ & 0x00000020) == 0x00000020)) {
annotation_ = java.util.Collections.unmodifiableList(annotation_); annotation_ = java.util.Collections.unmodifiableList(annotation_);
} }
if (((mutable_bitField0_ & 0x00000040) == 0x00000040)) {
optionalAnnotationClass_ = java.util.Collections.unmodifiableList(optionalAnnotationClass_);
}
this.unknownFields = unknownFields.build(); this.unknownFields = unknownFields.build();
makeExtensionsImmutable(); makeExtensionsImmutable();
} }
@@ -628,6 +698,76 @@ public final class DebugJvmModuleProtoBuf {
return annotation_.get(index); return annotation_.get(index);
} }
public static final int OPTIONAL_ANNOTATION_CLASS_FIELD_NUMBER = 16;
private java.util.List<org.jetbrains.kotlin.metadata.DebugProtoBuf.Class> optionalAnnotationClass_;
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public java.util.List<org.jetbrains.kotlin.metadata.DebugProtoBuf.Class> getOptionalAnnotationClassList() {
return optionalAnnotationClass_;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public java.util.List<? extends org.jetbrains.kotlin.metadata.DebugProtoBuf.ClassOrBuilder>
getOptionalAnnotationClassOrBuilderList() {
return optionalAnnotationClass_;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public int getOptionalAnnotationClassCount() {
return optionalAnnotationClass_.size();
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public org.jetbrains.kotlin.metadata.DebugProtoBuf.Class getOptionalAnnotationClass(int index) {
return optionalAnnotationClass_.get(index);
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public org.jetbrains.kotlin.metadata.DebugProtoBuf.ClassOrBuilder getOptionalAnnotationClassOrBuilder(
int index) {
return optionalAnnotationClass_.get(index);
}
private void initFields() { private void initFields() {
packageParts_ = java.util.Collections.emptyList(); packageParts_ = java.util.Collections.emptyList();
metadataParts_ = java.util.Collections.emptyList(); metadataParts_ = java.util.Collections.emptyList();
@@ -635,6 +775,7 @@ public final class DebugJvmModuleProtoBuf {
stringTable_ = org.jetbrains.kotlin.metadata.DebugProtoBuf.StringTable.getDefaultInstance(); stringTable_ = org.jetbrains.kotlin.metadata.DebugProtoBuf.StringTable.getDefaultInstance();
qualifiedNameTable_ = org.jetbrains.kotlin.metadata.DebugProtoBuf.QualifiedNameTable.getDefaultInstance(); qualifiedNameTable_ = org.jetbrains.kotlin.metadata.DebugProtoBuf.QualifiedNameTable.getDefaultInstance();
annotation_ = java.util.Collections.emptyList(); annotation_ = java.util.Collections.emptyList();
optionalAnnotationClass_ = java.util.Collections.emptyList();
} }
private byte memoizedIsInitialized = -1; private byte memoizedIsInitialized = -1;
public final boolean isInitialized() { public final boolean isInitialized() {
@@ -666,6 +807,12 @@ public final class DebugJvmModuleProtoBuf {
return false; return false;
} }
} }
for (int i = 0; i < getOptionalAnnotationClassCount(); i++) {
if (!getOptionalAnnotationClass(i).isInitialized()) {
memoizedIsInitialized = 0;
return false;
}
}
memoizedIsInitialized = 1; memoizedIsInitialized = 1;
return true; return true;
} }
@@ -691,6 +838,9 @@ public final class DebugJvmModuleProtoBuf {
for (int i = 0; i < annotation_.size(); i++) { for (int i = 0; i < annotation_.size(); i++) {
output.writeMessage(6, annotation_.get(i)); output.writeMessage(6, annotation_.get(i));
} }
for (int i = 0; i < optionalAnnotationClass_.size(); i++) {
output.writeMessage(16, optionalAnnotationClass_.get(i));
}
getUnknownFields().writeTo(output); getUnknownFields().writeTo(output);
} }
@@ -729,6 +879,10 @@ public final class DebugJvmModuleProtoBuf {
size += org.jetbrains.kotlin.protobuf.CodedOutputStream size += org.jetbrains.kotlin.protobuf.CodedOutputStream
.computeMessageSize(6, annotation_.get(i)); .computeMessageSize(6, annotation_.get(i));
} }
for (int i = 0; i < optionalAnnotationClass_.size(); i++) {
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
.computeMessageSize(16, optionalAnnotationClass_.get(i));
}
size += getUnknownFields().getSerializedSize(); size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size; memoizedSerializedSize = size;
return size; return size;
@@ -843,6 +997,7 @@ public final class DebugJvmModuleProtoBuf {
getStringTableFieldBuilder(); getStringTableFieldBuilder();
getQualifiedNameTableFieldBuilder(); getQualifiedNameTableFieldBuilder();
getAnnotationFieldBuilder(); getAnnotationFieldBuilder();
getOptionalAnnotationClassFieldBuilder();
} }
} }
private static Builder create() { private static Builder create() {
@@ -883,6 +1038,12 @@ public final class DebugJvmModuleProtoBuf {
} else { } else {
annotationBuilder_.clear(); annotationBuilder_.clear();
} }
if (optionalAnnotationClassBuilder_ == null) {
optionalAnnotationClass_ = java.util.Collections.emptyList();
bitField0_ = (bitField0_ & ~0x00000040);
} else {
optionalAnnotationClassBuilder_.clear();
}
return this; return this;
} }
@@ -959,6 +1120,15 @@ public final class DebugJvmModuleProtoBuf {
} else { } else {
result.annotation_ = annotationBuilder_.build(); result.annotation_ = annotationBuilder_.build();
} }
if (optionalAnnotationClassBuilder_ == null) {
if (((bitField0_ & 0x00000040) == 0x00000040)) {
optionalAnnotationClass_ = java.util.Collections.unmodifiableList(optionalAnnotationClass_);
bitField0_ = (bitField0_ & ~0x00000040);
}
result.optionalAnnotationClass_ = optionalAnnotationClass_;
} else {
result.optionalAnnotationClass_ = optionalAnnotationClassBuilder_.build();
}
result.bitField0_ = to_bitField0_; result.bitField0_ = to_bitField0_;
onBuilt(); onBuilt();
return result; return result;
@@ -1069,6 +1239,32 @@ public final class DebugJvmModuleProtoBuf {
} }
} }
} }
if (optionalAnnotationClassBuilder_ == null) {
if (!other.optionalAnnotationClass_.isEmpty()) {
if (optionalAnnotationClass_.isEmpty()) {
optionalAnnotationClass_ = other.optionalAnnotationClass_;
bitField0_ = (bitField0_ & ~0x00000040);
} else {
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.addAll(other.optionalAnnotationClass_);
}
onChanged();
}
} else {
if (!other.optionalAnnotationClass_.isEmpty()) {
if (optionalAnnotationClassBuilder_.isEmpty()) {
optionalAnnotationClassBuilder_.dispose();
optionalAnnotationClassBuilder_ = null;
optionalAnnotationClass_ = other.optionalAnnotationClass_;
bitField0_ = (bitField0_ & ~0x00000040);
optionalAnnotationClassBuilder_ =
org.jetbrains.kotlin.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
getOptionalAnnotationClassFieldBuilder() : null;
} else {
optionalAnnotationClassBuilder_.addAllMessages(other.optionalAnnotationClass_);
}
}
}
this.mergeUnknownFields(other.getUnknownFields()); this.mergeUnknownFields(other.getUnknownFields());
return this; return this;
} }
@@ -1098,6 +1294,12 @@ public final class DebugJvmModuleProtoBuf {
return false; return false;
} }
} }
for (int i = 0; i < getOptionalAnnotationClassCount(); i++) {
if (!getOptionalAnnotationClass(i).isInitialized()) {
return false;
}
}
return true; return true;
} }
@@ -2426,6 +2628,372 @@ public final class DebugJvmModuleProtoBuf {
return annotationBuilder_; return annotationBuilder_;
} }
private java.util.List<org.jetbrains.kotlin.metadata.DebugProtoBuf.Class> optionalAnnotationClass_ =
java.util.Collections.emptyList();
private void ensureOptionalAnnotationClassIsMutable() {
if (!((bitField0_ & 0x00000040) == 0x00000040)) {
optionalAnnotationClass_ = new java.util.ArrayList<org.jetbrains.kotlin.metadata.DebugProtoBuf.Class>(optionalAnnotationClass_);
bitField0_ |= 0x00000040;
}
}
private org.jetbrains.kotlin.protobuf.RepeatedFieldBuilder<
org.jetbrains.kotlin.metadata.DebugProtoBuf.Class, org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.Builder, org.jetbrains.kotlin.metadata.DebugProtoBuf.ClassOrBuilder> optionalAnnotationClassBuilder_;
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public java.util.List<org.jetbrains.kotlin.metadata.DebugProtoBuf.Class> getOptionalAnnotationClassList() {
if (optionalAnnotationClassBuilder_ == null) {
return java.util.Collections.unmodifiableList(optionalAnnotationClass_);
} else {
return optionalAnnotationClassBuilder_.getMessageList();
}
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public int getOptionalAnnotationClassCount() {
if (optionalAnnotationClassBuilder_ == null) {
return optionalAnnotationClass_.size();
} else {
return optionalAnnotationClassBuilder_.getCount();
}
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public org.jetbrains.kotlin.metadata.DebugProtoBuf.Class getOptionalAnnotationClass(int index) {
if (optionalAnnotationClassBuilder_ == null) {
return optionalAnnotationClass_.get(index);
} else {
return optionalAnnotationClassBuilder_.getMessage(index);
}
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder setOptionalAnnotationClass(
int index, org.jetbrains.kotlin.metadata.DebugProtoBuf.Class value) {
if (optionalAnnotationClassBuilder_ == null) {
if (value == null) {
throw new NullPointerException();
}
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.set(index, value);
onChanged();
} else {
optionalAnnotationClassBuilder_.setMessage(index, value);
}
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder setOptionalAnnotationClass(
int index, org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.Builder builderForValue) {
if (optionalAnnotationClassBuilder_ == null) {
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.set(index, builderForValue.build());
onChanged();
} else {
optionalAnnotationClassBuilder_.setMessage(index, builderForValue.build());
}
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder addOptionalAnnotationClass(org.jetbrains.kotlin.metadata.DebugProtoBuf.Class value) {
if (optionalAnnotationClassBuilder_ == null) {
if (value == null) {
throw new NullPointerException();
}
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.add(value);
onChanged();
} else {
optionalAnnotationClassBuilder_.addMessage(value);
}
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder addOptionalAnnotationClass(
int index, org.jetbrains.kotlin.metadata.DebugProtoBuf.Class value) {
if (optionalAnnotationClassBuilder_ == null) {
if (value == null) {
throw new NullPointerException();
}
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.add(index, value);
onChanged();
} else {
optionalAnnotationClassBuilder_.addMessage(index, value);
}
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder addOptionalAnnotationClass(
org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.Builder builderForValue) {
if (optionalAnnotationClassBuilder_ == null) {
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.add(builderForValue.build());
onChanged();
} else {
optionalAnnotationClassBuilder_.addMessage(builderForValue.build());
}
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder addOptionalAnnotationClass(
int index, org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.Builder builderForValue) {
if (optionalAnnotationClassBuilder_ == null) {
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.add(index, builderForValue.build());
onChanged();
} else {
optionalAnnotationClassBuilder_.addMessage(index, builderForValue.build());
}
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder addAllOptionalAnnotationClass(
java.lang.Iterable<? extends org.jetbrains.kotlin.metadata.DebugProtoBuf.Class> values) {
if (optionalAnnotationClassBuilder_ == null) {
ensureOptionalAnnotationClassIsMutable();
org.jetbrains.kotlin.protobuf.AbstractMessageLite.Builder.addAll(
values, optionalAnnotationClass_);
onChanged();
} else {
optionalAnnotationClassBuilder_.addAllMessages(values);
}
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder clearOptionalAnnotationClass() {
if (optionalAnnotationClassBuilder_ == null) {
optionalAnnotationClass_ = java.util.Collections.emptyList();
bitField0_ = (bitField0_ & ~0x00000040);
onChanged();
} else {
optionalAnnotationClassBuilder_.clear();
}
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder removeOptionalAnnotationClass(int index) {
if (optionalAnnotationClassBuilder_ == null) {
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.remove(index);
onChanged();
} else {
optionalAnnotationClassBuilder_.remove(index);
}
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.Builder getOptionalAnnotationClassBuilder(
int index) {
return getOptionalAnnotationClassFieldBuilder().getBuilder(index);
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public org.jetbrains.kotlin.metadata.DebugProtoBuf.ClassOrBuilder getOptionalAnnotationClassOrBuilder(
int index) {
if (optionalAnnotationClassBuilder_ == null) {
return optionalAnnotationClass_.get(index); } else {
return optionalAnnotationClassBuilder_.getMessageOrBuilder(index);
}
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public java.util.List<? extends org.jetbrains.kotlin.metadata.DebugProtoBuf.ClassOrBuilder>
getOptionalAnnotationClassOrBuilderList() {
if (optionalAnnotationClassBuilder_ != null) {
return optionalAnnotationClassBuilder_.getMessageOrBuilderList();
} else {
return java.util.Collections.unmodifiableList(optionalAnnotationClass_);
}
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.Builder addOptionalAnnotationClassBuilder() {
return getOptionalAnnotationClassFieldBuilder().addBuilder(
org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.getDefaultInstance());
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.Builder addOptionalAnnotationClassBuilder(
int index) {
return getOptionalAnnotationClassFieldBuilder().addBuilder(
index, org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.getDefaultInstance());
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public java.util.List<org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.Builder>
getOptionalAnnotationClassBuilderList() {
return getOptionalAnnotationClassFieldBuilder().getBuilderList();
}
private org.jetbrains.kotlin.protobuf.RepeatedFieldBuilder<
org.jetbrains.kotlin.metadata.DebugProtoBuf.Class, org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.Builder, org.jetbrains.kotlin.metadata.DebugProtoBuf.ClassOrBuilder>
getOptionalAnnotationClassFieldBuilder() {
if (optionalAnnotationClassBuilder_ == null) {
optionalAnnotationClassBuilder_ = new org.jetbrains.kotlin.protobuf.RepeatedFieldBuilder<
org.jetbrains.kotlin.metadata.DebugProtoBuf.Class, org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.Builder, org.jetbrains.kotlin.metadata.DebugProtoBuf.ClassOrBuilder>(
optionalAnnotationClass_,
((bitField0_ & 0x00000040) == 0x00000040),
getParentForChildren(),
isClean());
optionalAnnotationClass_ = null;
}
return optionalAnnotationClassBuilder_;
}
// @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.metadata.jvm.Module) // @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.metadata.jvm.Module)
} }
@@ -4644,7 +5212,7 @@ public final class DebugJvmModuleProtoBuf {
"\n,core/metadata.jvm/src/jvm_module.debug" + "\n,core/metadata.jvm/src/jvm_module.debug" +
".proto\022!org.jetbrains.kotlin.metadata.jv" + ".proto\022!org.jetbrains.kotlin.metadata.jv" +
"m\032&core/metadata/src/metadata.debug.prot" + "m\032&core/metadata/src/metadata.debug.prot" +
"o\"\205\003\n\006Module\022F\n\rpackage_parts\030\001 \003(\0132/.or" + "o\"\316\003\n\006Module\022F\n\rpackage_parts\030\001 \003(\0132/.or" +
"g.jetbrains.kotlin.metadata.jvm.PackageP" + "g.jetbrains.kotlin.metadata.jvm.PackageP" +
"arts\022G\n\016metadata_parts\030\002 \003(\0132/.org.jetbr" + "arts\022G\n\016metadata_parts\030\002 \003(\0132/.org.jetbr" +
"ains.kotlin.metadata.jvm.PackageParts\022\030\n" + "ains.kotlin.metadata.jvm.PackageParts\022\030\n" +
@@ -4653,16 +5221,18 @@ public final class DebugJvmModuleProtoBuf {
"ringTable\022O\n\024qualified_name_table\030\005 \001(\0132", "ringTable\022O\n\024qualified_name_table\030\005 \001(\0132",
"1.org.jetbrains.kotlin.metadata.Qualifie" + "1.org.jetbrains.kotlin.metadata.Qualifie" +
"dNameTable\022=\n\nannotation\030\006 \003(\0132).org.jet" + "dNameTable\022=\n\nannotation\030\006 \003(\0132).org.jet" +
"brains.kotlin.metadata.Annotation\"\276\002\n\014Pa" + "brains.kotlin.metadata.Annotation\022G\n\031opt" +
"ckageParts\022\027\n\017package_fq_name\030\001 \002(\t\022\030\n\020s" + "ional_annotation_class\030\020 \003(\0132$.org.jetbr" +
"hort_class_name\030\002 \003(\t\022*\n\036multifile_facad" + "ains.kotlin.metadata.Class\"\276\002\n\014PackagePa" +
"e_short_name_id\030\003 \003(\005B\002\020\001\022#\n\033multifile_f" + "rts\022\027\n\017package_fq_name\030\001 \002(\t\022\030\n\020short_cl" +
"acade_short_name\030\004 \003(\t\022.\n&class_with_jvm" + "ass_name\030\002 \003(\t\022*\n\036multifile_facade_short" +
"_package_name_short_name\030\005 \003(\t\022F\n:class_" + "_name_id\030\003 \003(\005B\002\020\001\022#\n\033multifile_facade_s" +
"with_jvm_package_name_multifile_facade_s" + "hort_name\030\004 \003(\t\022.\n&class_with_jvm_packag" +
"hort_name_id\030\007 \003(\005B\002\020\001\0222\n&class_with_jvm", "e_name_short_name\030\005 \003(\t\022F\n:class_with_jv",
"_package_name_package_id\030\006 \003(\005B\002\020\001B\030B\026De" + "m_package_name_multifile_facade_short_na" +
"bugJvmModuleProtoBuf" "me_id\030\007 \003(\005B\002\020\001\0222\n&class_with_jvm_packag" +
"e_name_package_id\030\006 \003(\005B\002\020\001B\030B\026DebugJvmM" +
"oduleProtoBuf"
}; };
org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { new org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
@@ -4682,7 +5252,7 @@ public final class DebugJvmModuleProtoBuf {
internal_static_org_jetbrains_kotlin_metadata_jvm_Module_fieldAccessorTable = new internal_static_org_jetbrains_kotlin_metadata_jvm_Module_fieldAccessorTable = new
org.jetbrains.kotlin.protobuf.GeneratedMessage.FieldAccessorTable( org.jetbrains.kotlin.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_org_jetbrains_kotlin_metadata_jvm_Module_descriptor, internal_static_org_jetbrains_kotlin_metadata_jvm_Module_descriptor,
new java.lang.String[] { "PackageParts", "MetadataParts", "JvmPackageName", "StringTable", "QualifiedNameTable", "Annotation", }); new java.lang.String[] { "PackageParts", "MetadataParts", "JvmPackageName", "StringTable", "QualifiedNameTable", "Annotation", "OptionalAnnotationClass", });
internal_static_org_jetbrains_kotlin_metadata_jvm_PackageParts_descriptor = internal_static_org_jetbrains_kotlin_metadata_jvm_PackageParts_descriptor =
getDescriptor().getMessageTypes().get(1); getDescriptor().getMessageTypes().get(1);
internal_static_org_jetbrains_kotlin_metadata_jvm_PackageParts_fieldAccessorTable = new internal_static_org_jetbrains_kotlin_metadata_jvm_PackageParts_fieldAccessorTable = new
@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver; import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver;
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt; import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker;
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver; import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver;
import org.jetbrains.kotlin.resolve.inline.InlineUtil; import org.jetbrains.kotlin.resolve.inline.InlineUtil;
import org.jetbrains.kotlin.resolve.jvm.*; import org.jetbrains.kotlin.resolve.jvm.*;
@@ -433,9 +432,6 @@ public class AsmUtil {
if (descriptor instanceof SyntheticClassDescriptorForLambda) { if (descriptor instanceof SyntheticClassDescriptorForLambda) {
return getVisibilityAccessFlagForAnonymous(descriptor); return getVisibilityAccessFlagForAnonymous(descriptor);
} }
if (ExpectedActualDeclarationChecker.isOptionalAnnotationClass(descriptor)) {
return NO_FLAG_PACKAGE_PRIVATE;
}
if (descriptor.getKind() == ClassKind.ENUM_ENTRY) { if (descriptor.getKind() == ClassKind.ENUM_ENTRY) {
return NO_FLAG_PACKAGE_PRIVATE; return NO_FLAG_PACKAGE_PRIVATE;
} }
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.metadata.jvm.JvmModuleProtoBuf;
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping; import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping;
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMappingKt; import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMappingKt;
import org.jetbrains.kotlin.metadata.jvm.deserialization.PackageParts; import org.jetbrains.kotlin.metadata.jvm.deserialization.PackageParts;
import org.jetbrains.kotlin.metadata.serialization.StringTable;
import org.jetbrains.kotlin.name.ClassId; import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.KtFile; import org.jetbrains.kotlin.psi.KtFile;
@@ -129,15 +130,18 @@ public class ClassFileFactory implements OutputFileCollection {
JvmModuleProtoBuf.Module.Builder builder = JvmModuleProtoBuf.Module.newBuilder(); JvmModuleProtoBuf.Module.Builder builder = JvmModuleProtoBuf.Module.newBuilder();
String outputFilePath = getMappingFileName(state.getModuleName()); String outputFilePath = getMappingFileName(state.getModuleName());
for (PackageParts part : ClassFileUtilsKt.addCompiledPartsAndSort(packagePartRegistry.getParts().values(), state)) { StringTableImpl stringTable = new StringTableImpl();
part.addTo(builder); ClassFileUtilsKt.addDataFromCompiledModule(builder, packagePartRegistry, stringTable, state);
}
List<String> experimental = state.getLanguageVersionSettings().getFlag(AnalysisFlags.getExperimental()); List<String> experimental = state.getLanguageVersionSettings().getFlag(AnalysisFlags.getExperimental());
if (!experimental.isEmpty()) { if (!experimental.isEmpty()) {
writeExperimentalMarkers(state.getModule(), builder, experimental); writeExperimentalMarkers(state.getModule(), builder, experimental, stringTable);
} }
Pair<ProtoBuf.StringTable, ProtoBuf.QualifiedNameTable> tables = stringTable.buildProto();
builder.setStringTable(tables.getFirst());
builder.setQualifiedNameTable(tables.getSecond());
JvmModuleProtoBuf.Module moduleProto = builder.build(); JvmModuleProtoBuf.Module moduleProto = builder.build();
generators.put(outputFilePath, new OutAndSourceFileList(CollectionsKt.toList(sourceFiles)) { generators.put(outputFilePath, new OutAndSourceFileList(CollectionsKt.toList(sourceFiles)) {
@@ -160,9 +164,9 @@ public class ClassFileFactory implements OutputFileCollection {
private static void writeExperimentalMarkers( private static void writeExperimentalMarkers(
@NotNull ModuleDescriptor module, @NotNull ModuleDescriptor module,
@NotNull JvmModuleProtoBuf.Module.Builder builder, @NotNull JvmModuleProtoBuf.Module.Builder builder,
@NotNull List<String> experimental @NotNull List<String> experimental,
@NotNull StringTable stringTable
) { ) {
StringTableImpl stringTable = new StringTableImpl();
for (String fqName : experimental) { for (String fqName : experimental) {
ClassDescriptor descriptor = ClassDescriptor descriptor =
DescriptorUtilKt.resolveClassByFqName(module, new FqName(fqName), NoLookupLocation.FOR_ALREADY_TRACKED); DescriptorUtilKt.resolveClassByFqName(module, new FqName(fqName), NoLookupLocation.FOR_ALREADY_TRACKED);
@@ -175,9 +179,6 @@ public class ClassFileFactory implements OutputFileCollection {
} }
} }
} }
Pair<ProtoBuf.StringTable, ProtoBuf.QualifiedNameTable> tables = stringTable.buildProto();
builder.setStringTable(tables.getFirst());
builder.setQualifiedNameTable(tables.getSecond());
} }
@NotNull @NotNull
@@ -90,8 +90,12 @@ public class PackageCodegenImpl implements PackageCodegen {
for (KtDeclaration declaration : file.getDeclarations()) { for (KtDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof KtClassOrObject) { if (declaration instanceof KtClassOrObject) {
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, declaration); ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, declaration);
if (PsiUtilsKt.hasExpectModifier(declaration) && if (PsiUtilsKt.hasExpectModifier(declaration)) {
(descriptor == null || !ExpectedActualDeclarationChecker.shouldGenerateExpectClass(descriptor))) { if (descriptor != null && ExpectedActualDeclarationChecker.shouldGenerateExpectClass(descriptor)) {
assert ExpectedActualDeclarationChecker.isOptionalAnnotationClass(descriptor) :
"Expect class should be generated only if it's an optional annotation: " + descriptor;
state.getFactory().getPackagePartRegistry().getOptionalAnnotations().add(descriptor);
}
continue; continue;
} }
@@ -16,11 +16,13 @@
package org.jetbrains.kotlin.codegen package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.metadata.jvm.deserialization.PackageParts import org.jetbrains.kotlin.metadata.jvm.deserialization.PackageParts
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
class PackagePartRegistry { class PackagePartRegistry {
val parts = mutableMapOf<FqName, PackageParts>() val parts = mutableMapOf<FqName, PackageParts>()
val optionalAnnotations = mutableListOf<ClassDescriptor>()
fun addPart(packageFqName: FqName, partInternalName: String, facadeInternalName: String?) { fun addPart(packageFqName: FqName, partInternalName: String, facadeInternalName: String?) {
parts.computeIfAbsent(packageFqName) { PackageParts(it.asString()) }.addPart(partInternalName, facadeInternalName) parts.computeIfAbsent(packageFqName) { PackageParts(it.asString()) }.addPart(partInternalName, facadeInternalName)
@@ -18,10 +18,19 @@ package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.backend.common.output.OutputFile import org.jetbrains.kotlin.backend.common.output.OutputFile
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.load.kotlin.loadModuleMapping import org.jetbrains.kotlin.load.kotlin.loadModuleMapping
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.jvm.JvmModuleProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
import org.jetbrains.kotlin.metadata.jvm.deserialization.PackageParts import org.jetbrains.kotlin.metadata.jvm.deserialization.PackageParts
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase
import org.jetbrains.kotlin.serialization.StringTableImpl
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
fun ClassFileFactory.getClassFiles(): Iterable<OutputFile> { fun ClassFileFactory.getClassFiles(): Iterable<OutputFile> {
return asList().filterClassFiles() return asList().filterClassFiles()
@@ -31,27 +40,64 @@ fun List<OutputFile>.filterClassFiles(): List<OutputFile> {
return filter { it.relativePath.endsWith(".class") } return filter { it.relativePath.endsWith(".class") }
} }
fun Iterable<PackageParts>.addCompiledPartsAndSort(state: GenerationState): List<PackageParts> = fun JvmModuleProtoBuf.Module.Builder.addDataFromCompiledModule(
addCompiledParts(state).sortedBy { it.packageFqName } registry: PackagePartRegistry, stringTable: StringTableImpl, state: GenerationState
) {
private fun Iterable<PackageParts>.addCompiledParts(state: GenerationState): List<PackageParts> { for (part in registry.parts.values.addCompiledPartsAndSort(state)) {
val incrementalCache = state.incrementalCacheForThisTarget ?: return this.toList() part.addTo(this)
val moduleMappingData = incrementalCache.getModuleMappingData() ?: return this.toList()
val mapping = ModuleMapping.loadModuleMapping(moduleMappingData, "<incremental>", state.deserializationConfiguration) { version ->
throw IllegalStateException("Version of the generated module cannot be incompatible: $version")
} }
incrementalCache.getObsoletePackageParts().forEach { internalName -> // Take all optional annotation classes from sources, as well as look up all previously compiled optional annotation classes
// by FQ name in the current module. The latter is needed because in incremental compilation scenario, the already compiled
// classes will not be available via sources.
val optionalAnnotationClassDescriptors =
registry.optionalAnnotations.toSet() +
state.loadCompiledModule()?.moduleData?.run {
optionalAnnotations.mapNotNull { proto ->
state.module.findClassAcrossModuleDependencies(
ClassId.fromString(nameResolver.getQualifiedClassName(proto.fqName))
)
}
}.orEmpty()
val serializer = DescriptorSerializer.createTopLevel(JvmOptionalAnnotationSerializerExtension(stringTable))
for (descriptor in optionalAnnotationClassDescriptors) {
addOptionalAnnotationClass(serializer.classProto(descriptor))
}
}
class JvmOptionalAnnotationSerializerExtension(
override val stringTable: StringTableImpl
) : KotlinSerializerExtensionBase(BuiltInSerializerProtocol) {
override val metadataVersion: BinaryVersion
get() = JvmMetadataVersion.INSTANCE
override fun shouldUseTypeTable(): Boolean = true
}
private fun Iterable<PackageParts>.addCompiledPartsAndSort(state: GenerationState): List<PackageParts> =
addCompiledParts(state).sortedBy { it.packageFqName }
private fun Iterable<PackageParts>.addCompiledParts(state: GenerationState): List<PackageParts> {
val mapping = state.loadCompiledModule() ?: return this.toList()
state.incrementalCacheForThisTarget?.getObsoletePackageParts()?.forEach { internalName ->
val qualifier = JvmClassName.byInternalName(internalName).packageFqName.asString() val qualifier = JvmClassName.byInternalName(internalName).packageFqName.asString()
mapping.findPackageParts(qualifier)?.removePart(internalName) mapping.findPackageParts(qualifier)?.removePart(internalName)
} }
return (this + mapping.packageFqName2Parts.values) return (this + mapping.packageFqName2Parts.values)
.groupBy { it.packageFqName } .groupBy { it.packageFqName }
.map { (packageFqName, allOldPackageParts) -> .map { (packageFqName, allOldPackageParts) ->
PackageParts(packageFqName).apply { PackageParts(packageFqName).apply {
allOldPackageParts.forEach { packageParts -> this += packageParts } allOldPackageParts.forEach { packageParts -> this += packageParts }
}
} }
}
}
private fun GenerationState.loadCompiledModule(): ModuleMapping? {
val moduleMappingData = incrementalCacheForThisTarget?.getModuleMappingData() ?: return null
return ModuleMapping.loadModuleMapping(moduleMappingData, "<incremental>", deserializationConfiguration) { version ->
throw IllegalStateException("Version of the generated module cannot be incompatible: $version")
}
} }
@@ -51,6 +51,7 @@ import org.jetbrains.kotlin.konan.properties.propertyList
import org.jetbrains.kotlin.konan.util.KlibMetadataFactories import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
import org.jetbrains.kotlin.library.KLIB_PROPERTY_DEPENDS import org.jetbrains.kotlin.library.KLIB_PROPERTY_DEPENDS
import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.metadata.NullFlexibleTypeDeserializer
import org.jetbrains.kotlin.load.java.JavaClassesTracker import org.jetbrains.kotlin.load.java.JavaClassesTracker
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver
import org.jetbrains.kotlin.load.java.structure.JavaClass import org.jetbrains.kotlin.load.java.structure.JavaClass
@@ -68,10 +69,10 @@ import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension
import org.jetbrains.kotlin.resolve.jvm.multiplatform.OptionalAnnotationPackageFragmentProvider
import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
import org.jetbrains.kotlin.library.metadata.NullFlexibleTypeDeserializer
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
import java.util.* import java.util.*
@@ -195,7 +196,8 @@ object TopDownAnalyzerFacadeForJVM {
CompositePackageFragmentProvider( CompositePackageFragmentProvider(
listOf( listOf(
moduleClassResolver.compiledCodeResolver.packageFragmentProvider, moduleClassResolver.compiledCodeResolver.packageFragmentProvider,
dependenciesContainer.get<JvmBuiltInsPackageFragmentProvider>() dependenciesContainer.get<JvmBuiltInsPackageFragmentProvider>(),
dependenciesContainer.get<OptionalAnnotationPackageFragmentProvider>()
) )
) )
) )
@@ -252,7 +254,10 @@ object TopDownAnalyzerFacadeForJVM {
) )
module.initialize( module.initialize(
CompositePackageFragmentProvider( CompositePackageFragmentProvider(
listOf(container.get<KotlinCodeAnalyzer>().packageFragmentProvider) + additionalProviders listOf(
container.get<KotlinCodeAnalyzer>().packageFragmentProvider,
container.get<OptionalAnnotationPackageFragmentProvider>()
) + additionalProviders
) )
) )
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
import org.jetbrains.kotlin.resolve.jvm.JvmDiagnosticComponents import org.jetbrains.kotlin.resolve.jvm.JvmDiagnosticComponents
import org.jetbrains.kotlin.resolve.jvm.multiplatform.OptionalAnnotationPackageFragmentProvider
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
@@ -121,6 +122,7 @@ fun StorageComponentContainer.configureJavaSpecificComponents(
useInstance((moduleContext.module.builtIns as JvmBuiltIns).settings) useInstance((moduleContext.module.builtIns as JvmBuiltIns).settings)
useImpl<JvmBuiltInsPackageFragmentProvider>() useImpl<JvmBuiltInsPackageFragmentProvider>()
} }
useImpl<OptionalAnnotationPackageFragmentProvider>()
useInstance(javaClassTracker ?: JavaClassesTracker.Default) useInstance(javaClassTracker ?: JavaClassesTracker.Default)
useInstance( useInstance(
@@ -16,18 +16,20 @@
package org.jetbrains.kotlin.load.kotlin.incremental package org.jetbrains.kotlin.load.kotlin.incremental
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartProviderBase
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
import org.jetbrains.kotlin.load.kotlin.loadModuleMapping import org.jetbrains.kotlin.load.kotlin.loadModuleMapping
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.deserialization.ClassData
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
class IncrementalPackagePartProvider( class IncrementalPackagePartProvider(
private val parent: PackagePartProvider, private val parent: PackagePartProvider,
incrementalCaches: List<IncrementalCache>, incrementalCaches: List<IncrementalCache>,
storageManager: StorageManager storageManager: StorageManager
) : PackagePartProvider { ) : PackagePartProvider {
lateinit var deserializationConfiguration: DeserializationConfiguration lateinit var deserializationConfiguration: DeserializationConfiguration
@@ -48,4 +50,8 @@ class IncrementalPackagePartProvider(
override fun getAnnotationsOnBinaryModule(moduleName: String): List<ClassId> { override fun getAnnotationsOnBinaryModule(moduleName: String): List<ClassId> {
return parent.getAnnotationsOnBinaryModule(moduleName) return parent.getAnnotationsOnBinaryModule(moduleName)
} }
override fun getAllOptionalAnnotationClasses(): List<ClassData> =
moduleMappings().flatMap((JvmPackagePartProviderBase)::getAllOptionalAnnotationClasses) +
parent.getAllOptionalAnnotationClasses()
} }
@@ -0,0 +1,118 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.jvm.multiplatform
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
import org.jetbrains.kotlin.resolve.sam.SamConversionResolver
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
import org.jetbrains.kotlin.serialization.deserialization.*
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.storage.NotNullLazyValue
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.storage.getValue
import org.jetbrains.kotlin.utils.Printer
class OptionalAnnotationPackageFragmentProvider(
module: ModuleDescriptor,
storageManager: StorageManager,
notFoundClasses: NotFoundClasses,
languageVersionSettings: LanguageVersionSettings,
packagePartProvider: PackagePartProvider,
) : PackageFragmentProvider {
val packages: Map<FqName, PackageFragmentDescriptor> by storageManager.createLazyValue p@{
// We call getAllOptionalAnnotationClasses under lazy value only because IncrementalPackagePartProvider requires
// deserializationConfiguration to be injected.
val optionalAnnotationClasses = packagePartProvider.getAllOptionalAnnotationClasses()
if (optionalAnnotationClasses.isEmpty()) return@p emptyMap()
mutableMapOf<FqName, PackageFragmentDescriptor>().also { packages ->
// We use BuiltInSerializerProtocol when serializing optional annotation classes (see
// JvmOptionalAnnotationSerializerExtension). Use it in deserialization as well, to be able to load annotations on
// optional annotation classes and their members (in particular, the `@OptionalExpectation` annotation).
val serializerProtocol = BuiltInSerializerProtocol
val classDataFinder = OptionalAnnotationClassDataFinder(optionalAnnotationClasses)
val components = storageManager.createLazyValue {
DeserializationComponents(
storageManager, module, CompilerDeserializationConfiguration(languageVersionSettings),
classDataFinder,
AnnotationAndConstantLoaderImpl(module, notFoundClasses, serializerProtocol),
this,
LocalClassifierTypeSettings.Default,
ErrorReporter.DO_NOTHING,
LookupTracker.DO_NOTHING,
FlexibleTypeDeserializer.ThrowException,
emptyList(),
notFoundClasses,
ContractDeserializer.DEFAULT,
extensionRegistryLite = serializerProtocol.extensionRegistry,
samConversionResolver = SamConversionResolver.Empty
)
}
for ((packageFqName, classes) in classDataFinder.classIdToData.entries.groupBy { it.key.packageFqName }) {
val classNames = classes.mapNotNull { (classId) ->
classId.shortClassName.takeUnless { classId.isNestedClass }
}.toSet()
// TODO: make this lazy value more granular, e.g. a memoized function ClassId -> ClassDescriptor
val classDescriptors = storageManager.createLazyValue {
classes.mapNotNull { (classId, classData) ->
components().classDeserializer.deserializeClass(classId, classData)
}.associateBy(ClassDescriptor::getName)
}
packages[packageFqName] = PackageFragmentForOptionalAnnotations(module, packageFqName, classNames, classDescriptors)
}
}
}
override fun getPackageFragments(fqName: FqName): List<PackageFragmentDescriptor> =
packages[fqName]?.let(::listOf).orEmpty()
override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection<FqName> =
emptyList()
}
private class OptionalAnnotationClassDataFinder(classes: List<ClassData>) : ClassDataFinder {
val classIdToData = classes.associateBy { (nameResolver, klass) -> nameResolver.getClassId(klass.fqName) }
override fun findClassData(classId: ClassId): ClassData? = classIdToData[classId]
}
private class PackageFragmentForOptionalAnnotations(
module: ModuleDescriptor,
fqName: FqName,
classNames: Set<Name>,
classDescriptors: NotNullLazyValue<Map<Name, ClassDescriptor>>,
) : PackageFragmentDescriptorImpl(module, fqName) {
private val scope = object : MemberScopeImpl() {
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = classDescriptors()[name]
override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> =
if (kindFilter.acceptsKinds(DescriptorKindFilter.CLASSIFIERS_MASK)) classDescriptors().values else emptyList()
override fun getClassifierNames(): Set<Name> = classNames
override fun printScopeStructure(p: Printer) {
p.print("PackageFragmentForOptionalAnnotations{${classNames.joinToString(transform = Name::asString)}}")
}
}
override fun getMemberScope(): MemberScope = scope
}
@@ -7,19 +7,14 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.DeclarationTransformer import org.jetbrains.kotlin.backend.common.DeclarationTransformer
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.ExpectDeclarationRemover
/** /**
* This pass removes all declarations with `isExpect == true`. * This pass removes all declarations with `isExpect == true`.
*/ */
class ExpectDeclarationsRemoveLowering(context: BackendContext, keepOptionalAnnotations: Boolean = false) : DeclarationTransformer { class ExpectDeclarationsRemoveLowering(context: BackendContext) : DeclarationTransformer {
private val remover = ExpectDeclarationRemover(context.ir.symbols.externalSymbolTable, true)
private val remover = ExpectDeclarationRemover(
symbolTable = context.ir.symbols.externalSymbolTable,
doRemove = true,
keepOptionalAnnotations = keepOptionalAnnotations
)
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? { override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
return remover.transformFlat(declaration) return remover.transformFlat(declaration)
@@ -75,8 +75,8 @@ private val arrayConstructorPhase = makeIrFilePhase(
description = "Transform `Array(size) { index -> value }` into a loop" description = "Transform `Array(size) { index -> value }` into a loop"
) )
private val expectDeclarationsRemovingPhase = makeIrModulePhase<JvmBackendContext>( private val expectDeclarationsRemovingPhase = makeIrModulePhase(
{ context -> ExpectDeclarationsRemoveLowering(context, keepOptionalAnnotations = true) }, ::ExpectDeclarationsRemoveLowering,
name = "ExpectDeclarationsRemoving", name = "ExpectDeclarationsRemoving",
description = "Remove expect declaration from module fragment" description = "Remove expect declaration from module fragment"
) )
@@ -375,6 +375,7 @@ val jvmPhases = namedIrModulePhase(
name = "IrLowering", name = "IrLowering",
description = "IR lowering", description = "IR lowering",
lower = validateIrBeforeLowering then lower = validateIrBeforeLowering then
processOptionalAnnotationsPhase then
expectDeclarationsRemovingPhase then expectDeclarationsRemovingPhase then
fileClassPhase then fileClassPhase then
performByIrFile(lower = jvmFilePhases) then performByIrFile(lower = jvmFilePhases) then
@@ -372,9 +372,6 @@ internal fun getSignature(
*/ */
fun IrClass.getVisibilityAccessFlagForClass(): Int { fun IrClass.getVisibilityAccessFlagForClass(): Int {
/* Original had a check for SyntheticClassDescriptorForJava, never invoked in th IR backend. */ /* Original had a check for SyntheticClassDescriptorForJava, never invoked in th IR backend. */
if (isOptionalAnnotationClass()) {
return AsmUtil.NO_FLAG_PACKAGE_PRIVATE
}
if (kind == ClassKind.ENUM_ENTRY) { if (kind == ClassKind.ENUM_ENTRY) {
return AsmUtil.NO_FLAG_PACKAGE_PRIVATE return AsmUtil.NO_FLAG_PACKAGE_PRIVATE
} }
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.codegen.isOptionalAnnotationClass
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.MetadataSource
internal val processOptionalAnnotationsPhase = makeIrModulePhase(
::ProcessOptionalAnnotations,
name = "ProcessOptionalAnnotations",
description = "Record metadata of @OptionalExpectation-annotated classes to backend-specific storage, later written to .kotlin_module"
)
class ProcessOptionalAnnotations(private val context: JvmBackendContext) : FileLoweringPass {
override fun lower(irFile: IrFile) {
for (declaration in irFile.declarations) {
if (declaration !is IrClass || !declaration.isOptionalAnnotationClass()) continue
val metadataSource = (declaration.metadata as? MetadataSource.Class)?.descriptor ?: continue
context.state.factory.packagePartRegistry.optionalAnnotations += metadataSource
}
}
}
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.ir.util package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.MemberDescriptor import org.jetbrains.kotlin.descriptors.MemberDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
@@ -23,11 +22,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
// `doRemove` means should expect-declaration be removed from IR // `doRemove` means should expect-declaration be removed from IR
class ExpectDeclarationRemover( class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private val doRemove: Boolean) : IrElementVisitorVoid {
val symbolTable: ReferenceSymbolTable,
private val doRemove: Boolean,
private val keepOptionalAnnotations: Boolean
) : IrElementVisitorVoid {
override fun visitElement(element: IrElement) { override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this) element.acceptChildrenVoid(this)
} }
@@ -58,10 +53,8 @@ class ExpectDeclarationRemover(
} }
private fun shouldRemoveTopLevelDeclaration(declaration: IrDeclaration): Boolean { private fun shouldRemoveTopLevelDeclaration(declaration: IrDeclaration): Boolean {
// TODO: rewrite findCompatibleActualForExpected using IR structures instead of descriptors
val descriptor = declaration.descriptor val descriptor = declaration.descriptor
return doRemove && descriptor is MemberDescriptor && descriptor.isExpect && return doRemove && descriptor is MemberDescriptor && descriptor.isExpect
!(keepOptionalAnnotations && descriptor is ClassDescriptor && ExpectedActualDeclarationChecker.shouldGenerateExpectClass(descriptor))
} }
private fun tryCopyDefaultArguments(declaration: IrValueParameter) { private fun tryCopyDefaultArguments(declaration: IrValueParameter) {
@@ -27,7 +27,10 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.* import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrModuleSerializer
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.KlibMetadataIncrementalSerializer import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.KlibMetadataIncrementalSerializer
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
@@ -51,8 +54,8 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.psi2ir.generators.createGeneratorContext
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
import org.jetbrains.kotlin.psi2ir.generators.createGeneratorContext
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContextUtils import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
@@ -162,7 +165,7 @@ fun generateKLib(
val moduleName = configuration[CommonConfigurationKeys.MODULE_NAME]!! val moduleName = configuration[CommonConfigurationKeys.MODULE_NAME]!!
if (!configuration.expectActualLinker) { if (!configuration.expectActualLinker) {
moduleFragment.acceptVoid(ExpectDeclarationRemover(psi2IrContext.symbolTable, doRemove = false, keepOptionalAnnotations = false)) moduleFragment.acceptVoid(ExpectDeclarationRemover(psi2IrContext.symbolTable, false))
} }
serializeModuleIntoKlib( serializeModuleIntoKlib(
@@ -1,10 +1,3 @@
@java.lang.annotation.Retention
@kotlin.Metadata
@kotlin.OptionalExpectation
annotation class Anno {
public abstract method s(): java.lang.String
}
@kotlin.Metadata @kotlin.Metadata
public interface Foo$Nested { public interface Foo$Nested {
inner class Foo$Nested inner class Foo$Nested
@@ -31,8 +31,10 @@ fun box(): String {
val annotations = Test::class.java.declaredMethods.single().annotations.toList() val annotations = Test::class.java.declaredMethods.single().annotations.toList()
if (annotations.toString() != "[@a.A(x=42)]") return "Fail 1: $annotations" if (annotations.toString() != "[@a.A(x=42)]") return "Fail 1: $annotations"
// Can't use B::class.java because "Declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry" try {
if (Modifier.isPublic(Class.forName("a.B").modifiers)) return "Fail 2: optional annotation class should not be public in the bytecode" Class.forName("a.B")
return "Fail 2: there should be no class file for a.B"
return "OK" } catch (e: ClassNotFoundException) {
return "OK"
}
} }
@@ -1,12 +0,0 @@
// !LANGUAGE: +MultiPlatformProjects
// !USE_EXPERIMENTAL: kotlin.ExperimentalMultiplatform
// WITH_RUNTIME
@file:Suppress("OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE") // TODO: support common sources in the test infrastructure
@OptionalExpectation
expect annotation class Anno(val s: String)
// TESTED_OBJECT_KIND: class
// TESTED_OBJECTS: Anno
// FLAGS: ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
@@ -895,24 +895,6 @@ public class WriteFlagsTestGenerated extends AbstractWriteFlagsTest {
} }
} }
@TestMetadata("compiler/testData/writeFlags/multiplatform")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Multiplatform extends AbstractWriteFlagsTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInMultiplatform() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/writeFlags/multiplatform"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("optionalExpectation.kt")
public void testOptionalExpectation() throws Exception {
runTest("compiler/testData/writeFlags/multiplatform/optionalExpectation.kt");
}
}
@TestMetadata("compiler/testData/writeFlags/property") @TestMetadata("compiler/testData/writeFlags/property")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -895,24 +895,6 @@ public class IrWriteFlagsTestGenerated extends AbstractIrWriteFlagsTest {
} }
} }
@TestMetadata("compiler/testData/writeFlags/multiplatform")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Multiplatform extends AbstractIrWriteFlagsTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
}
public void testAllFilesPresentInMultiplatform() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/writeFlags/multiplatform"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("optionalExpectation.kt")
public void testOptionalExpectation() throws Exception {
runTest("compiler/testData/writeFlags/multiplatform/optionalExpectation.kt");
}
}
@TestMetadata("compiler/testData/writeFlags/property") @TestMetadata("compiler/testData/writeFlags/property")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -5,9 +5,11 @@
package org.jetbrains.kotlin.load.kotlin package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
import org.jetbrains.kotlin.metadata.jvm.deserialization.PackageParts import org.jetbrains.kotlin.metadata.jvm.deserialization.PackageParts
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.deserialization.ClassData
import org.jetbrains.kotlin.serialization.deserialization.MetadataPartProvider import org.jetbrains.kotlin.serialization.deserialization.MetadataPartProvider
abstract class JvmPackagePartProviderBase<MappingsKey> : PackagePartProvider, MetadataPartProvider { abstract class JvmPackagePartProviderBase<MappingsKey> : PackagePartProvider, MetadataPartProvider {
@@ -51,4 +53,18 @@ abstract class JvmPackagePartProviderBase<MappingsKey> : PackagePartProvider, Me
if (name == moduleName) mapping.moduleData.annotations.map(ClassId::fromString) else null if (name == moduleName) mapping.moduleData.annotations.map(ClassId::fromString) else null
}.flatten() }.flatten()
} }
override fun getAllOptionalAnnotationClasses(): List<ClassData> =
loadedModules.flatMap { module ->
getAllOptionalAnnotationClasses(module.mapping)
}
companion object {
fun getAllOptionalAnnotationClasses(module: ModuleMapping): List<ClassData> {
val data = module.moduleData
return data.optionalAnnotations.map { proto ->
ClassData(data.nameResolver, proto, module.version, SourceElement.NO_SOURCE)
}
}
}
} }
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.load.kotlin package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.deserialization.ClassData
interface PackagePartProvider { interface PackagePartProvider {
/** /**
@@ -19,9 +20,13 @@ interface PackagePartProvider {
fun getAnnotationsOnBinaryModule(moduleName: String): List<ClassId> fun getAnnotationsOnBinaryModule(moduleName: String): List<ClassId>
fun getAllOptionalAnnotationClasses(): List<ClassData>
object Empty : PackagePartProvider { object Empty : PackagePartProvider {
override fun findPackageParts(packageFqName: String): List<String> = emptyList() override fun findPackageParts(packageFqName: String): List<String> = emptyList()
override fun getAnnotationsOnBinaryModule(moduleName: String): List<ClassId> = emptyList() override fun getAnnotationsOnBinaryModule(moduleName: String): List<ClassId> = emptyList()
override fun getAllOptionalAnnotationClasses(): List<ClassData> = emptyList()
} }
} }
+6
View File
@@ -38,6 +38,12 @@ message Module {
// Annotations on the whole module // Annotations on the whole module
repeated Annotation annotation = 6; repeated Annotation annotation = 6;
// @OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
// a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
// This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
// it to the corresponding class with the resolution capabilities of common modules.
repeated Class optional_annotation_class = 16;
} }
message PackageParts { message PackageParts {
@@ -146,6 +146,41 @@ public final class JvmModuleProtoBuf {
* </pre> * </pre>
*/ */
int getAnnotationCount(); int getAnnotationCount();
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
java.util.List<org.jetbrains.kotlin.metadata.ProtoBuf.Class>
getOptionalAnnotationClassList();
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
org.jetbrains.kotlin.metadata.ProtoBuf.Class getOptionalAnnotationClass(int index);
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
int getOptionalAnnotationClassCount();
} }
/** /**
* Protobuf type {@code org.jetbrains.kotlin.metadata.jvm.Module} * Protobuf type {@code org.jetbrains.kotlin.metadata.jvm.Module}
@@ -256,6 +291,14 @@ public final class JvmModuleProtoBuf {
annotation_.add(input.readMessage(org.jetbrains.kotlin.metadata.ProtoBuf.Annotation.PARSER, extensionRegistry)); annotation_.add(input.readMessage(org.jetbrains.kotlin.metadata.ProtoBuf.Annotation.PARSER, extensionRegistry));
break; break;
} }
case 130: {
if (!((mutable_bitField0_ & 0x00000040) == 0x00000040)) {
optionalAnnotationClass_ = new java.util.ArrayList<org.jetbrains.kotlin.metadata.ProtoBuf.Class>();
mutable_bitField0_ |= 0x00000040;
}
optionalAnnotationClass_.add(input.readMessage(org.jetbrains.kotlin.metadata.ProtoBuf.Class.PARSER, extensionRegistry));
break;
}
} }
} }
} catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) { } catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) {
@@ -276,6 +319,9 @@ public final class JvmModuleProtoBuf {
if (((mutable_bitField0_ & 0x00000020) == 0x00000020)) { if (((mutable_bitField0_ & 0x00000020) == 0x00000020)) {
annotation_ = java.util.Collections.unmodifiableList(annotation_); annotation_ = java.util.Collections.unmodifiableList(annotation_);
} }
if (((mutable_bitField0_ & 0x00000040) == 0x00000040)) {
optionalAnnotationClass_ = java.util.Collections.unmodifiableList(optionalAnnotationClass_);
}
try { try {
unknownFieldsCodedOutput.flush(); unknownFieldsCodedOutput.flush();
} catch (java.io.IOException e) { } catch (java.io.IOException e) {
@@ -546,6 +592,76 @@ public final class JvmModuleProtoBuf {
return annotation_.get(index); return annotation_.get(index);
} }
public static final int OPTIONAL_ANNOTATION_CLASS_FIELD_NUMBER = 16;
private java.util.List<org.jetbrains.kotlin.metadata.ProtoBuf.Class> optionalAnnotationClass_;
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public java.util.List<org.jetbrains.kotlin.metadata.ProtoBuf.Class> getOptionalAnnotationClassList() {
return optionalAnnotationClass_;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public java.util.List<? extends org.jetbrains.kotlin.metadata.ProtoBuf.ClassOrBuilder>
getOptionalAnnotationClassOrBuilderList() {
return optionalAnnotationClass_;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public int getOptionalAnnotationClassCount() {
return optionalAnnotationClass_.size();
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public org.jetbrains.kotlin.metadata.ProtoBuf.Class getOptionalAnnotationClass(int index) {
return optionalAnnotationClass_.get(index);
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public org.jetbrains.kotlin.metadata.ProtoBuf.ClassOrBuilder getOptionalAnnotationClassOrBuilder(
int index) {
return optionalAnnotationClass_.get(index);
}
private void initFields() { private void initFields() {
packageParts_ = java.util.Collections.emptyList(); packageParts_ = java.util.Collections.emptyList();
metadataParts_ = java.util.Collections.emptyList(); metadataParts_ = java.util.Collections.emptyList();
@@ -553,6 +669,7 @@ public final class JvmModuleProtoBuf {
stringTable_ = org.jetbrains.kotlin.metadata.ProtoBuf.StringTable.getDefaultInstance(); stringTable_ = org.jetbrains.kotlin.metadata.ProtoBuf.StringTable.getDefaultInstance();
qualifiedNameTable_ = org.jetbrains.kotlin.metadata.ProtoBuf.QualifiedNameTable.getDefaultInstance(); qualifiedNameTable_ = org.jetbrains.kotlin.metadata.ProtoBuf.QualifiedNameTable.getDefaultInstance();
annotation_ = java.util.Collections.emptyList(); annotation_ = java.util.Collections.emptyList();
optionalAnnotationClass_ = java.util.Collections.emptyList();
} }
private byte memoizedIsInitialized = -1; private byte memoizedIsInitialized = -1;
public final boolean isInitialized() { public final boolean isInitialized() {
@@ -584,6 +701,12 @@ public final class JvmModuleProtoBuf {
return false; return false;
} }
} }
for (int i = 0; i < getOptionalAnnotationClassCount(); i++) {
if (!getOptionalAnnotationClass(i).isInitialized()) {
memoizedIsInitialized = 0;
return false;
}
}
memoizedIsInitialized = 1; memoizedIsInitialized = 1;
return true; return true;
} }
@@ -609,6 +732,9 @@ public final class JvmModuleProtoBuf {
for (int i = 0; i < annotation_.size(); i++) { for (int i = 0; i < annotation_.size(); i++) {
output.writeMessage(6, annotation_.get(i)); output.writeMessage(6, annotation_.get(i));
} }
for (int i = 0; i < optionalAnnotationClass_.size(); i++) {
output.writeMessage(16, optionalAnnotationClass_.get(i));
}
output.writeRawBytes(unknownFields); output.writeRawBytes(unknownFields);
} }
@@ -647,6 +773,10 @@ public final class JvmModuleProtoBuf {
size += org.jetbrains.kotlin.protobuf.CodedOutputStream size += org.jetbrains.kotlin.protobuf.CodedOutputStream
.computeMessageSize(6, annotation_.get(i)); .computeMessageSize(6, annotation_.get(i));
} }
for (int i = 0; i < optionalAnnotationClass_.size(); i++) {
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
.computeMessageSize(16, optionalAnnotationClass_.get(i));
}
size += unknownFields.size(); size += unknownFields.size();
memoizedSerializedSize = size; memoizedSerializedSize = size;
return size; return size;
@@ -753,6 +883,8 @@ public final class JvmModuleProtoBuf {
bitField0_ = (bitField0_ & ~0x00000010); bitField0_ = (bitField0_ & ~0x00000010);
annotation_ = java.util.Collections.emptyList(); annotation_ = java.util.Collections.emptyList();
bitField0_ = (bitField0_ & ~0x00000020); bitField0_ = (bitField0_ & ~0x00000020);
optionalAnnotationClass_ = java.util.Collections.emptyList();
bitField0_ = (bitField0_ & ~0x00000040);
return this; return this;
} }
@@ -804,6 +936,11 @@ public final class JvmModuleProtoBuf {
bitField0_ = (bitField0_ & ~0x00000020); bitField0_ = (bitField0_ & ~0x00000020);
} }
result.annotation_ = annotation_; result.annotation_ = annotation_;
if (((bitField0_ & 0x00000040) == 0x00000040)) {
optionalAnnotationClass_ = java.util.Collections.unmodifiableList(optionalAnnotationClass_);
bitField0_ = (bitField0_ & ~0x00000040);
}
result.optionalAnnotationClass_ = optionalAnnotationClass_;
result.bitField0_ = to_bitField0_; result.bitField0_ = to_bitField0_;
return result; return result;
} }
@@ -855,6 +992,16 @@ public final class JvmModuleProtoBuf {
annotation_.addAll(other.annotation_); annotation_.addAll(other.annotation_);
} }
}
if (!other.optionalAnnotationClass_.isEmpty()) {
if (optionalAnnotationClass_.isEmpty()) {
optionalAnnotationClass_ = other.optionalAnnotationClass_;
bitField0_ = (bitField0_ & ~0x00000040);
} else {
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.addAll(other.optionalAnnotationClass_);
}
} }
setUnknownFields( setUnknownFields(
getUnknownFields().concat(other.unknownFields)); getUnknownFields().concat(other.unknownFields));
@@ -886,6 +1033,12 @@ public final class JvmModuleProtoBuf {
return false; return false;
} }
} }
for (int i = 0; i < getOptionalAnnotationClassCount(); i++) {
if (!getOptionalAnnotationClass(i).isInitialized()) {
return false;
}
}
return true; return true;
} }
@@ -1685,6 +1838,215 @@ public final class JvmModuleProtoBuf {
return this; return this;
} }
private java.util.List<org.jetbrains.kotlin.metadata.ProtoBuf.Class> optionalAnnotationClass_ =
java.util.Collections.emptyList();
private void ensureOptionalAnnotationClassIsMutable() {
if (!((bitField0_ & 0x00000040) == 0x00000040)) {
optionalAnnotationClass_ = new java.util.ArrayList<org.jetbrains.kotlin.metadata.ProtoBuf.Class>(optionalAnnotationClass_);
bitField0_ |= 0x00000040;
}
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public java.util.List<org.jetbrains.kotlin.metadata.ProtoBuf.Class> getOptionalAnnotationClassList() {
return java.util.Collections.unmodifiableList(optionalAnnotationClass_);
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public int getOptionalAnnotationClassCount() {
return optionalAnnotationClass_.size();
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public org.jetbrains.kotlin.metadata.ProtoBuf.Class getOptionalAnnotationClass(int index) {
return optionalAnnotationClass_.get(index);
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder setOptionalAnnotationClass(
int index, org.jetbrains.kotlin.metadata.ProtoBuf.Class value) {
if (value == null) {
throw new NullPointerException();
}
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.set(index, value);
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder setOptionalAnnotationClass(
int index, org.jetbrains.kotlin.metadata.ProtoBuf.Class.Builder builderForValue) {
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.set(index, builderForValue.build());
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder addOptionalAnnotationClass(org.jetbrains.kotlin.metadata.ProtoBuf.Class value) {
if (value == null) {
throw new NullPointerException();
}
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.add(value);
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder addOptionalAnnotationClass(
int index, org.jetbrains.kotlin.metadata.ProtoBuf.Class value) {
if (value == null) {
throw new NullPointerException();
}
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.add(index, value);
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder addOptionalAnnotationClass(
org.jetbrains.kotlin.metadata.ProtoBuf.Class.Builder builderForValue) {
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.add(builderForValue.build());
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder addOptionalAnnotationClass(
int index, org.jetbrains.kotlin.metadata.ProtoBuf.Class.Builder builderForValue) {
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.add(index, builderForValue.build());
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder addAllOptionalAnnotationClass(
java.lang.Iterable<? extends org.jetbrains.kotlin.metadata.ProtoBuf.Class> values) {
ensureOptionalAnnotationClassIsMutable();
org.jetbrains.kotlin.protobuf.AbstractMessageLite.Builder.addAll(
values, optionalAnnotationClass_);
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder clearOptionalAnnotationClass() {
optionalAnnotationClass_ = java.util.Collections.emptyList();
bitField0_ = (bitField0_ & ~0x00000040);
return this;
}
/**
* <code>repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16;</code>
*
* <pre>
* &#64;OptionalExpectation-annotated annotation classes in this module. This list is only used in the compiler frontend when compiling
* a second-tier multiplatform module against a multiplatform module which uses optional annotations, not actualized on the JVM.
* This is not needed in the IDE because optional annotations can only be used in common modules, where the IDE plugin resolves
* it to the corresponding class with the resolution capabilities of common modules.
* </pre>
*/
public Builder removeOptionalAnnotationClass(int index) {
ensureOptionalAnnotationClassIsMutable();
optionalAnnotationClass_.remove(index);
return this;
}
// @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.metadata.jvm.Module) // @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.metadata.jvm.Module)
} }
@@ -5,7 +5,16 @@
package org.jetbrains.kotlin.metadata.jvm.deserialization package org.jetbrains.kotlin.metadata.jvm.deserialization
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
/** /**
* @param annotations list of module annotations, in the format: "org/foo/bar/Baz.Inner" (see [ClassId.fromString]) * @param annotations list of module annotations, in the format: "org/foo/bar/Baz.Inner" (see [ClassId.fromString])
* @param optionalAnnotations list of @OptionalExpectation-annotated annotation classes in this module.
* @param nameResolver string table to resolve names referenced in classes in [optionalAnnotations].
*/ */
class BinaryModuleData(val annotations: List<String>) class BinaryModuleData(
val annotations: List<String>,
val optionalAnnotations: List<ProtoBuf.Class>,
val nameResolver: NameResolver,
)
@@ -5,13 +5,17 @@
package org.jetbrains.kotlin.metadata.jvm.deserialization package org.jetbrains.kotlin.metadata.jvm.deserialization
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.builtins.BuiltInsProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
import org.jetbrains.kotlin.metadata.deserialization.isKotlin1Dot4OrLater import org.jetbrains.kotlin.metadata.deserialization.isKotlin1Dot4OrLater
import org.jetbrains.kotlin.metadata.jvm.JvmModuleProtoBuf import org.jetbrains.kotlin.metadata.jvm.JvmModuleProtoBuf
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
import java.io.* import java.io.*
class ModuleMapping private constructor( class ModuleMapping private constructor(
val version: JvmMetadataVersion,
val packageFqName2Parts: Map<String, PackageParts>, val packageFqName2Parts: Map<String, PackageParts>,
val moduleData: BinaryModuleData, val moduleData: BinaryModuleData,
private val debugName: String private val debugName: String
@@ -26,10 +30,10 @@ class ModuleMapping private constructor(
const val MAPPING_FILE_EXT: String = "kotlin_module" const val MAPPING_FILE_EXT: String = "kotlin_module"
@JvmField @JvmField
val EMPTY: ModuleMapping = ModuleMapping(emptyMap(), BinaryModuleData(emptyList()), "EMPTY") val EMPTY: ModuleMapping = ModuleMapping(JvmMetadataVersion.INSTANCE, emptyMap(), emptyBinaryData(), "EMPTY")
@JvmField @JvmField
val CORRUPTED: ModuleMapping = ModuleMapping(emptyMap(), BinaryModuleData(emptyList()), "CORRUPTED") val CORRUPTED: ModuleMapping = ModuleMapping(JvmMetadataVersion.INSTANCE, emptyMap(), emptyBinaryData(), "CORRUPTED")
const val STRICT_METADATA_VERSION_SEMANTICS_FLAG = 1 shl 0 const val STRICT_METADATA_VERSION_SEMANTICS_FLAG = 1 shl 0
@@ -69,7 +73,9 @@ class ModuleMapping private constructor(
return EMPTY return EMPTY
} }
val moduleProto = JvmModuleProtoBuf.Module.parseFrom(stream) ?: return EMPTY // "Builtin" extension registry is needed in order to deserialize annotations on optional annotation classes and their members.
val extensions = ExtensionRegistryLite.newInstance().apply(BuiltInsProtoBuf::registerAllExtensions)
val moduleProto = JvmModuleProtoBuf.Module.parseFrom(stream, extensions) ?: return EMPTY
val result = linkedMapOf<String, PackageParts>() val result = linkedMapOf<String, PackageParts>()
for (proto in moduleProto.packagePartsList) { for (proto in moduleProto.packagePartsList) {
@@ -114,7 +120,12 @@ class ModuleMapping private constructor(
val nameResolver = NameResolverImpl(moduleProto.stringTable, moduleProto.qualifiedNameTable) val nameResolver = NameResolverImpl(moduleProto.stringTable, moduleProto.qualifiedNameTable)
val annotations = moduleProto.annotationList.map { proto -> nameResolver.getQualifiedClassName(proto.id) } val annotations = moduleProto.annotationList.map { proto -> nameResolver.getQualifiedClassName(proto.id) }
return ModuleMapping(result, BinaryModuleData(annotations), debugName) return ModuleMapping(
version,
result,
BinaryModuleData(annotations, moduleProto.optionalAnnotationClassList, nameResolver),
debugName
)
} }
private fun loadMultiFileFacadeInternalName( private fun loadMultiFileFacadeInternalName(
@@ -127,6 +138,13 @@ class ModuleMapping private constructor(
val facadeShortName = multifileFacadeId?.let(multifileFacadeShortNames::getOrNull) val facadeShortName = multifileFacadeId?.let(multifileFacadeShortNames::getOrNull)
return facadeShortName?.let { internalNameOf(packageFqName, it) } return facadeShortName?.let { internalNameOf(packageFqName, it) }
} }
private fun emptyBinaryData(): BinaryModuleData =
BinaryModuleData(
emptyList(),
emptyList(),
NameResolverImpl(ProtoBuf.StringTable.getDefaultInstance(), ProtoBuf.QualifiedNameTable.getDefaultInstance())
)
} }
} }
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.idea.vfilefinder.KotlinModuleMappingIndex
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.metadata.jvm.deserialization.PackageParts import org.jetbrains.kotlin.metadata.jvm.deserialization.PackageParts
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.deserialization.ClassData
import org.jetbrains.kotlin.serialization.deserialization.MetadataPartProvider import org.jetbrains.kotlin.serialization.deserialization.MetadataPartProvider
class IDEPackagePartProvider(val scope: GlobalSearchScope) : PackagePartProvider, MetadataPartProvider { class IDEPackagePartProvider(val scope: GlobalSearchScope) : PackagePartProvider, MetadataPartProvider {
@@ -38,4 +39,10 @@ class IDEPackagePartProvider(val scope: GlobalSearchScope) : PackagePartProvider
// Note that in case of several modules with the same name, we return all annotations on all of them, which is probably incorrect // Note that in case of several modules with the same name, we return all annotations on all of them, which is probably incorrect
override fun getAnnotationsOnBinaryModule(moduleName: String): List<ClassId> = override fun getAnnotationsOnBinaryModule(moduleName: String): List<ClassId> =
FileBasedIndex.getInstance().getValues(KotlinJvmModuleAnnotationsIndex.KEY, moduleName, scope).flatten() FileBasedIndex.getInstance().getValues(KotlinJvmModuleAnnotationsIndex.KEY, moduleName, scope).flatten()
// Optional annotations are not needed in IDE because they can only be used in common module sources, and they are loaded via the
// standard common module resolution there. (In the CLI compiler the situation is different because we compile common+platform
// sources together, _without_ common dependencies.)
override fun getAllOptionalAnnotationClasses(): List<ClassData> =
emptyList()
} }
@@ -598,6 +598,11 @@ public class IncrementalJvmJpsTestGenerated extends AbstractIncrementalJvmJpsTes
runTest("jps-plugin/testData/incremental/multiModule/multiplatform/custom/complementaryFiles/"); runTest("jps-plugin/testData/incremental/multiModule/multiplatform/custom/complementaryFiles/");
} }
@TestMetadata("modifyOptionalAnnotationUsage")
public void testModifyOptionalAnnotationUsage() throws Exception {
runTest("jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/");
}
@TestMetadata("notSameCompiler") @TestMetadata("notSameCompiler")
public void testNotSameCompiler() throws Exception { public void testNotSameCompiler() throws Exception {
runTest("jps-plugin/testData/incremental/multiModule/multiplatform/custom/notSameCompiler/"); runTest("jps-plugin/testData/incremental/multiModule/multiplatform/custom/notSameCompiler/");
@@ -655,6 +660,19 @@ public class IncrementalJvmJpsTestGenerated extends AbstractIncrementalJvmJpsTes
} }
} }
@TestMetadata("jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ModifyOptionalAnnotationUsage extends AbstractIncrementalJvmJpsTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInModifyOptionalAnnotationUsage() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage"), Pattern.compile("^([^\\.]+)$"), null, true);
}
}
@TestMetadata("jps-plugin/testData/incremental/multiModule/multiplatform/custom/notSameCompiler") @TestMetadata("jps-plugin/testData/incremental/multiModule/multiplatform/custom/notSameCompiler")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -8,7 +8,6 @@ Cleaning output files:
End of files End of files
Cleaning output files: Cleaning output files:
out/production/pJvm/FKt.class out/production/pJvm/FKt.class
out/production/pJvm/SharedImmutable.class
End of files End of files
Compiling files: Compiling files:
c/src/f.kt c/src/f.kt
@@ -0,0 +1,7 @@
c [sourceSetHolder]
pJvm [compilationAndSourceSetHolder, jvm]
pJvm -> c [include]
pJs [compilationAndSourceSetHolder, js]
pJs -> c [include]
@@ -0,0 +1,24 @@
================ Step #1 =================
Building c
Building pJs
Cleaning output files:
out/production/pJs/pJs.js
out/production/pJs/pJs.meta.js
out/production/pJs/pJs/root-package.kjsm
End of files
Compiling files:
c/src/usage.kt
End of files
Exit code: OK
------------------------------------------
Building pJvm
Cleaning output files:
out/production/pJvm/META-INF/pJvm.kotlin_module
out/production/pJvm/Usage.class
End of files
Compiling files:
c/src/usage.kt
End of files
Exit code: OK
------------------------------------------
@@ -0,0 +1,3 @@
@OptIn(ExperimentalMultiplatform::class)
@OptionalExpectation
expect annotation class Optional(val value: String)
@@ -0,0 +1,2 @@
@Optional("1")
class Usage
@@ -0,0 +1,2 @@
@Optional("2")
class Usage
@@ -3,10 +3,15 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:Suppress("MemberVisibilityCanBePrivate")
package kotlinx.metadata.jvm package kotlinx.metadata.jvm
import kotlinx.metadata.InconsistentKotlinMetadataException import kotlinx.metadata.InconsistentKotlinMetadataException
import kotlinx.metadata.KmAnnotation import kotlinx.metadata.KmAnnotation
import kotlinx.metadata.KmClass
import kotlinx.metadata.KmClassVisitor
import kotlinx.metadata.impl.accept
import org.jetbrains.kotlin.metadata.jvm.JvmModuleProtoBuf import org.jetbrains.kotlin.metadata.jvm.JvmModuleProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
@@ -62,6 +67,17 @@ class KotlinModuleMetadata(@Suppress("CanBeParameter", "MemberVisibilityCanBePri
*/ */
} }
override fun visitOptionalAnnotationClass(): KmClassVisitor? {
/*
return object : ClassWriter(TODO() /* use StringTableImpl here */) {
override fun visitEnd() {
b.addOptionalAnnotationClass(t)
}
}
*/
return null
}
/** /**
* Returns the metadata of the module file that was written with this writer. * Returns the metadata of the module file that was written with this writer.
* *
@@ -80,13 +96,19 @@ class KotlinModuleMetadata(@Suppress("CanBeParameter", "MemberVisibilityCanBePri
fun accept(v: KmModuleVisitor) { fun accept(v: KmModuleVisitor) {
for ((fqName, parts) in data.packageFqName2Parts) { for ((fqName, parts) in data.packageFqName2Parts) {
val (fileFacades, multiFileClassParts) = parts.parts.partition { parts.getMultifileFacadeName(it) == null } val (fileFacades, multiFileClassParts) = parts.parts.partition { parts.getMultifileFacadeName(it) == null }
v.visitPackageParts(fqName, fileFacades, multiFileClassParts.associate { it to parts.getMultifileFacadeName(it)!! }) v.visitPackageParts(fqName, fileFacades, multiFileClassParts.associateWith { parts.getMultifileFacadeName(it)!! })
} }
for (annotation in data.moduleData.annotations) { for (annotation in data.moduleData.annotations) {
v.visitAnnotation(KmAnnotation(annotation, emptyMap())) v.visitAnnotation(KmAnnotation(annotation, emptyMap()))
} }
for (classProto in data.moduleData.optionalAnnotations) {
v.visitOptionalAnnotationClass()?.let {
classProto.accept(it, data.moduleData.nameResolver)
}
}
v.visitEnd() v.visitEnd()
} }
@@ -147,6 +169,17 @@ abstract class KmModuleVisitor(private val delegate: KmModuleVisitor? = null) {
delegate?.visitAnnotation(annotation) delegate?.visitAnnotation(annotation)
} }
/**
* Visits an `@OptionalExpectation`-annotated annotation class declared in this module.
* Such classes are not materialized to bytecode on JVM, but the Kotlin compiler stores their metadata in the module file on JVM,
* and loads it during compilation of dependent modules, in order to avoid reporting "unresolved reference" errors on usages.
*
* Multiplatform projects are an experimental feature of Kotlin, and their behavior and/or binary format
* may change in a subsequent release.
*/
open fun visitOptionalAnnotationClass(): KmClassVisitor? =
delegate?.visitOptionalAnnotationClass()
/** /**
* Visits the end of the module. * Visits the end of the module.
*/ */
@@ -171,6 +204,16 @@ class KmModule : KmModuleVisitor() {
*/ */
val annotations: MutableList<KmAnnotation> = ArrayList(0) val annotations: MutableList<KmAnnotation> = ArrayList(0)
/**
* `@OptionalExpectation`-annotated annotation classes declared in this module.
* Such classes are not materialized to bytecode on JVM, but the Kotlin compiler stores their metadata in the module file on JVM,
* and loads it during compilation of dependent modules, in order to avoid reporting "unresolved reference" errors on usages.
*
* Multiplatform projects are an experimental feature of Kotlin, and their behavior and/or binary format
* may change in a subsequent release.
*/
val optionalAnnotationClasses: MutableList<KmClass> = ArrayList(0)
override fun visitPackageParts(fqName: String, fileFacades: List<String>, multiFileClassParts: Map<String, String>) { override fun visitPackageParts(fqName: String, fileFacades: List<String>, multiFileClassParts: Map<String, String>) {
packageParts[fqName] = KmPackageParts(fileFacades.toMutableList(), multiFileClassParts.toMutableMap()) packageParts[fqName] = KmPackageParts(fileFacades.toMutableList(), multiFileClassParts.toMutableMap())
} }
@@ -179,6 +222,9 @@ class KmModule : KmModuleVisitor() {
annotations.add(annotation) annotations.add(annotation)
} }
override fun visitOptionalAnnotationClass(): KmClass =
KmClass().also(optionalAnnotationClasses::add)
/** /**
* Populates the given visitor with data in this module. * Populates the given visitor with data in this module.
* *
@@ -189,6 +235,7 @@ class KmModule : KmModuleVisitor() {
visitor.visitPackageParts(fqName, parts.fileFacades, parts.multiFileClassParts) visitor.visitPackageParts(fqName, parts.fileFacades, parts.multiFileClassParts)
} }
annotations.forEach(visitor::visitAnnotation) annotations.forEach(visitor::visitAnnotation)
optionalAnnotationClasses.forEach { visitor.visitOptionalAnnotationClass()?.let(it::accept) }
} }
} }
@@ -10,7 +10,7 @@ import kotlinx.metadata.jvm.KotlinClassMetadata
import kotlinx.metadata.jvm.KotlinModuleMetadata import kotlinx.metadata.jvm.KotlinModuleMetadata
import java.io.File import java.io.File
class Kotlinp(val settings: KotlinpSettings) { class Kotlinp(private val settings: KotlinpSettings) {
internal fun renderClassFile(classFile: KotlinClassMetadata?): String = internal fun renderClassFile(classFile: KotlinClassMetadata?): String =
when (classFile) { when (classFile) {
is KotlinClassMetadata.Class -> ClassPrinter(settings).print(classFile) is KotlinClassMetadata.Class -> ClassPrinter(settings).print(classFile)
@@ -35,7 +35,7 @@ class Kotlinp(val settings: KotlinpSettings) {
} }
internal fun renderModuleFile(metadata: KotlinModuleMetadata?): String = internal fun renderModuleFile(metadata: KotlinModuleMetadata?): String =
if (metadata != null) ModuleFilePrinter().print(metadata) if (metadata != null) ModuleFilePrinter(settings).print(metadata)
else buildString { appendln("unsupported file") } else buildString { appendln("unsupported file") }
internal fun readModuleFile(file: File): KotlinModuleMetadata? = internal fun readModuleFile(file: File): KotlinModuleMetadata? =
@@ -689,7 +689,7 @@ interface AbstractPrinter<in T : KotlinClassMetadata> {
class ClassPrinter(private val settings: KotlinpSettings) : KmClassVisitor(), AbstractPrinter<KotlinClassMetadata.Class> { class ClassPrinter(private val settings: KotlinpSettings) : KmClassVisitor(), AbstractPrinter<KotlinClassMetadata.Class> {
private val sb = StringBuilder() private val sb = StringBuilder()
private val result = StringBuilder() internal val result = StringBuilder()
private var flags: Flags? = null private var flags: Flags? = null
private var name: ClassName? = null private var name: ClassName? = null
@@ -880,7 +880,9 @@ class MultiFileClassFacadePrinter : AbstractPrinter<KotlinClassMetadata.MultiFil
} }
} }
class ModuleFilePrinter : KmModuleVisitor() { class ModuleFilePrinter(private val settings: KotlinpSettings) : KmModuleVisitor() {
private val optionalAnnotations = mutableListOf<ClassPrinter>()
private val sb = StringBuilder().apply { private val sb = StringBuilder().apply {
appendln("module {") appendln("module {")
} }
@@ -901,7 +903,18 @@ class ModuleFilePrinter : KmModuleVisitor() {
// TODO // TODO
} }
override fun visitOptionalAnnotationClass(): KmClassVisitor =
ClassPrinter(settings).also(optionalAnnotations::add)
override fun visitEnd() { override fun visitEnd() {
if (optionalAnnotations.isNotEmpty()) {
sb.appendln()
sb.appendln(" // Optional annotations")
sb.appendln()
for (element in optionalAnnotations) {
sb.appendln(" " + element.result.toString().replace("\n", "\n ").trimEnd())
}
}
sb.appendln("}") sb.appendln("}")
} }
@@ -63,6 +63,11 @@ public class KotlinpTestGenerated extends AbstractKotlinpTest {
runTest("libraries/tools/kotlinp/testData/NestedClasses.kt"); runTest("libraries/tools/kotlinp/testData/NestedClasses.kt");
} }
@TestMetadata("OptionalAnnotation.kt")
public void testOptionalAnnotation() throws Exception {
runTest("libraries/tools/kotlinp/testData/OptionalAnnotation.kt");
}
@TestMetadata("PlatformType.kt") @TestMetadata("PlatformType.kt")
public void testPlatformType() throws Exception { public void testPlatformType() throws Exception {
runTest("libraries/tools/kotlinp/testData/PlatformType.kt"); runTest("libraries/tools/kotlinp/testData/PlatformType.kt");
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.jvm.compiler.AbstractLoadJavaTest
import org.jetbrains.kotlin.kotlinp.Kotlinp import org.jetbrains.kotlin.kotlinp.Kotlinp
import org.jetbrains.kotlin.kotlinp.KotlinpSettings import org.jetbrains.kotlin.kotlinp.KotlinpSettings
import org.jetbrains.kotlin.test.ConfigurationKind import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestJdkKind import org.jetbrains.kotlin.test.TestJdkKind
import java.io.File import java.io.File
@@ -63,7 +64,7 @@ fun compileAndPrintAllFiles(file: File, disposable: Disposable, tmpdir: File, co
KotlinTestUtils.assertEqualsToFile(File(file.path.replace(".kt", ".txt")), main.toString()) KotlinTestUtils.assertEqualsToFile(File(file.path.replace(".kt", ".txt")), main.toString())
} }
if (readWriteAndCompare) { if (readWriteAndCompare && InTextDirectivesUtils.findStringWithPrefixes(file.readText(), "// NO_READ_WRITE_COMPARE") == null) {
assertEquals("Metadata is different after transformation with visitors.", main.toString(), afterVisitors.toString()) assertEquals("Metadata is different after transformation with visitors.", main.toString(), afterVisitors.toString())
assertEquals("Metadata is different after transformation with nodes.", main.toString(), afterNodes.toString()) assertEquals("Metadata is different after transformation with nodes.", main.toString(), afterNodes.toString())
} }
+20
View File
@@ -0,0 +1,20 @@
// !LANGUAGE: +MultiPlatformProjects
// !USE_EXPERIMENTAL: kotlin.ExperimentalMultiplatform
// NO_READ_WRITE_COMPARE
package test
@OptionalExpectation
expect annotation class A(val x: Int)
@OptionalExpectation
expect annotation class B(val a: Array<String>)
@OptionalExpectation
expect annotation class C()
@Suppress("OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE")
@A(42)
@B(["OK", ""])
@C
fun ok() {}
+44
View File
@@ -0,0 +1,44 @@
// test/OptionalAnnotationKt.class
// ------------------------------------------
package {
// signature: ok()V
public final fun ok(): kotlin/Unit
}
// META-INF/test-module.kotlin_module
// ------------------------------------------
module {
package test {
test/OptionalAnnotationKt
}
// Optional annotations
public final expect annotation class test/A : kotlin/Annotation {
// signature: <init>(I)V
public /* primary */ constructor(x: kotlin/Int)
public final expect val x: kotlin/Int
public final get
// module name: main
}
public final expect annotation class test/B : kotlin/Annotation {
// signature: <init>(Lkotlin/Array;)V
public /* primary */ constructor(a: kotlin/Array<kotlin/String>)
public final expect val a: kotlin/Array<kotlin/String>
public final get
// module name: main
}
public final expect annotation class test/C : kotlin/Annotation {
// signature: <init>()V
public /* primary */ constructor()
// module name: main
}
}