diff --git a/build-common/test/org/jetbrains/kotlin/metadata/jvm/DebugJvmModuleProtoBuf.java b/build-common/test/org/jetbrains/kotlin/metadata/jvm/DebugJvmModuleProtoBuf.java index 25f5cfc3965..29ab02863d0 100644 --- a/build-common/test/org/jetbrains/kotlin/metadata/jvm/DebugJvmModuleProtoBuf.java +++ b/build-common/test/org/jetbrains/kotlin/metadata/jvm/DebugJvmModuleProtoBuf.java @@ -208,6 +208,65 @@ public final class DebugJvmModuleProtoBuf { */ org.jetbrains.kotlin.metadata.DebugProtoBuf.AnnotationOrBuilder getAnnotationOrBuilder( int index); + + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + java.util.List + getOptionalAnnotationClassList(); + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + org.jetbrains.kotlin.metadata.DebugProtoBuf.Class getOptionalAnnotationClass(int index); + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + int getOptionalAnnotationClassCount(); + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + java.util.List + getOptionalAnnotationClassOrBuilderList(); + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + org.jetbrains.kotlin.metadata.DebugProtoBuf.ClassOrBuilder getOptionalAnnotationClassOrBuilder( + int index); } /** * 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)); break; } + case 130: { + if (!((mutable_bitField0_ & 0x00000040) == 0x00000040)) { + optionalAnnotationClass_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000040; + } + optionalAnnotationClass_.add(input.readMessage(org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.PARSER, extensionRegistry)); + break; + } } } } catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) { @@ -340,6 +407,9 @@ public final class DebugJvmModuleProtoBuf { if (((mutable_bitField0_ & 0x00000020) == 0x00000020)) { annotation_ = java.util.Collections.unmodifiableList(annotation_); } + if (((mutable_bitField0_ & 0x00000040) == 0x00000040)) { + optionalAnnotationClass_ = java.util.Collections.unmodifiableList(optionalAnnotationClass_); + } this.unknownFields = unknownFields.build(); makeExtensionsImmutable(); } @@ -628,6 +698,76 @@ public final class DebugJvmModuleProtoBuf { return annotation_.get(index); } + public static final int OPTIONAL_ANNOTATION_CLASS_FIELD_NUMBER = 16; + private java.util.List optionalAnnotationClass_; + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + public java.util.List getOptionalAnnotationClassList() { + return optionalAnnotationClass_; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + public java.util.List + getOptionalAnnotationClassOrBuilderList() { + return optionalAnnotationClass_; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + public int getOptionalAnnotationClassCount() { + return optionalAnnotationClass_.size(); + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + public org.jetbrains.kotlin.metadata.DebugProtoBuf.Class getOptionalAnnotationClass(int index) { + return optionalAnnotationClass_.get(index); + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + public org.jetbrains.kotlin.metadata.DebugProtoBuf.ClassOrBuilder getOptionalAnnotationClassOrBuilder( + int index) { + return optionalAnnotationClass_.get(index); + } + private void initFields() { packageParts_ = 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(); qualifiedNameTable_ = org.jetbrains.kotlin.metadata.DebugProtoBuf.QualifiedNameTable.getDefaultInstance(); annotation_ = java.util.Collections.emptyList(); + optionalAnnotationClass_ = java.util.Collections.emptyList(); } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -666,6 +807,12 @@ public final class DebugJvmModuleProtoBuf { return false; } } + for (int i = 0; i < getOptionalAnnotationClassCount(); i++) { + if (!getOptionalAnnotationClass(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } memoizedIsInitialized = 1; return true; } @@ -691,6 +838,9 @@ public final class DebugJvmModuleProtoBuf { for (int i = 0; i < annotation_.size(); i++) { output.writeMessage(6, annotation_.get(i)); } + for (int i = 0; i < optionalAnnotationClass_.size(); i++) { + output.writeMessage(16, optionalAnnotationClass_.get(i)); + } getUnknownFields().writeTo(output); } @@ -729,6 +879,10 @@ public final class DebugJvmModuleProtoBuf { size += org.jetbrains.kotlin.protobuf.CodedOutputStream .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(); memoizedSerializedSize = size; return size; @@ -843,6 +997,7 @@ public final class DebugJvmModuleProtoBuf { getStringTableFieldBuilder(); getQualifiedNameTableFieldBuilder(); getAnnotationFieldBuilder(); + getOptionalAnnotationClassFieldBuilder(); } } private static Builder create() { @@ -883,6 +1038,12 @@ public final class DebugJvmModuleProtoBuf { } else { annotationBuilder_.clear(); } + if (optionalAnnotationClassBuilder_ == null) { + optionalAnnotationClass_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000040); + } else { + optionalAnnotationClassBuilder_.clear(); + } return this; } @@ -959,6 +1120,15 @@ public final class DebugJvmModuleProtoBuf { } else { 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_; onBuilt(); 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()); return this; } @@ -1098,6 +1294,12 @@ public final class DebugJvmModuleProtoBuf { return false; } } + for (int i = 0; i < getOptionalAnnotationClassCount(); i++) { + if (!getOptionalAnnotationClass(i).isInitialized()) { + + return false; + } + } return true; } @@ -2426,6 +2628,372 @@ public final class DebugJvmModuleProtoBuf { return annotationBuilder_; } + private java.util.List optionalAnnotationClass_ = + java.util.Collections.emptyList(); + private void ensureOptionalAnnotationClassIsMutable() { + if (!((bitField0_ & 0x00000040) == 0x00000040)) { + optionalAnnotationClass_ = new java.util.ArrayList(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_; + + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public java.util.List getOptionalAnnotationClassList() { + if (optionalAnnotationClassBuilder_ == null) { + return java.util.Collections.unmodifiableList(optionalAnnotationClass_); + } else { + return optionalAnnotationClassBuilder_.getMessageList(); + } + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public int getOptionalAnnotationClassCount() { + if (optionalAnnotationClassBuilder_ == null) { + return optionalAnnotationClass_.size(); + } else { + return optionalAnnotationClassBuilder_.getCount(); + } + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public org.jetbrains.kotlin.metadata.DebugProtoBuf.Class getOptionalAnnotationClass(int index) { + if (optionalAnnotationClassBuilder_ == null) { + return optionalAnnotationClass_.get(index); + } else { + return optionalAnnotationClassBuilder_.getMessage(index); + } + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + 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; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + 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; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + 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; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + 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; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + 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; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + 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; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public Builder addAllOptionalAnnotationClass( + java.lang.Iterable values) { + if (optionalAnnotationClassBuilder_ == null) { + ensureOptionalAnnotationClassIsMutable(); + org.jetbrains.kotlin.protobuf.AbstractMessageLite.Builder.addAll( + values, optionalAnnotationClass_); + onChanged(); + } else { + optionalAnnotationClassBuilder_.addAllMessages(values); + } + return this; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public Builder clearOptionalAnnotationClass() { + if (optionalAnnotationClassBuilder_ == null) { + optionalAnnotationClass_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000040); + onChanged(); + } else { + optionalAnnotationClassBuilder_.clear(); + } + return this; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public Builder removeOptionalAnnotationClass(int index) { + if (optionalAnnotationClassBuilder_ == null) { + ensureOptionalAnnotationClassIsMutable(); + optionalAnnotationClass_.remove(index); + onChanged(); + } else { + optionalAnnotationClassBuilder_.remove(index); + } + return this; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.Builder getOptionalAnnotationClassBuilder( + int index) { + return getOptionalAnnotationClassFieldBuilder().getBuilder(index); + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public org.jetbrains.kotlin.metadata.DebugProtoBuf.ClassOrBuilder getOptionalAnnotationClassOrBuilder( + int index) { + if (optionalAnnotationClassBuilder_ == null) { + return optionalAnnotationClass_.get(index); } else { + return optionalAnnotationClassBuilder_.getMessageOrBuilder(index); + } + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public java.util.List + getOptionalAnnotationClassOrBuilderList() { + if (optionalAnnotationClassBuilder_ != null) { + return optionalAnnotationClassBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(optionalAnnotationClass_); + } + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.Builder addOptionalAnnotationClassBuilder() { + return getOptionalAnnotationClassFieldBuilder().addBuilder( + org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.getDefaultInstance()); + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.Builder addOptionalAnnotationClassBuilder( + int index) { + return getOptionalAnnotationClassFieldBuilder().addBuilder( + index, org.jetbrains.kotlin.metadata.DebugProtoBuf.Class.getDefaultInstance()); + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public java.util.List + 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) } @@ -4644,7 +5212,7 @@ public final class DebugJvmModuleProtoBuf { "\n,core/metadata.jvm/src/jvm_module.debug" + ".proto\022!org.jetbrains.kotlin.metadata.jv" + "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" + "arts\022G\n\016metadata_parts\030\002 \003(\0132/.org.jetbr" + "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", "1.org.jetbrains.kotlin.metadata.Qualifie" + "dNameTable\022=\n\nannotation\030\006 \003(\0132).org.jet" + - "brains.kotlin.metadata.Annotation\"\276\002\n\014Pa" + - "ckageParts\022\027\n\017package_fq_name\030\001 \002(\t\022\030\n\020s" + - "hort_class_name\030\002 \003(\t\022*\n\036multifile_facad" + - "e_short_name_id\030\003 \003(\005B\002\020\001\022#\n\033multifile_f" + - "acade_short_name\030\004 \003(\t\022.\n&class_with_jvm" + - "_package_name_short_name\030\005 \003(\t\022F\n:class_" + - "with_jvm_package_name_multifile_facade_s" + - "hort_name_id\030\007 \003(\005B\002\020\001\0222\n&class_with_jvm", - "_package_name_package_id\030\006 \003(\005B\002\020\001B\030B\026De" + - "bugJvmModuleProtoBuf" + "brains.kotlin.metadata.Annotation\022G\n\031opt" + + "ional_annotation_class\030\020 \003(\0132$.org.jetbr" + + "ains.kotlin.metadata.Class\"\276\002\n\014PackagePa" + + "rts\022\027\n\017package_fq_name\030\001 \002(\t\022\030\n\020short_cl" + + "ass_name\030\002 \003(\t\022*\n\036multifile_facade_short" + + "_name_id\030\003 \003(\005B\002\020\001\022#\n\033multifile_facade_s" + + "hort_name\030\004 \003(\t\022.\n&class_with_jvm_packag" + + "e_name_short_name\030\005 \003(\t\022F\n:class_with_jv", + "m_package_name_multifile_facade_short_na" + + "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 = 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 org.jetbrains.kotlin.protobuf.GeneratedMessage.FieldAccessorTable( 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 = getDescriptor().getMessageTypes().get(1); internal_static_org_jetbrains_kotlin_metadata_jvm_PackageParts_fieldAccessorTable = new diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index 09efebcd8d1..31d971ff096 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -39,7 +39,6 @@ import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver; 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.inline.InlineUtil; import org.jetbrains.kotlin.resolve.jvm.*; @@ -433,9 +432,6 @@ public class AsmUtil { if (descriptor instanceof SyntheticClassDescriptorForLambda) { return getVisibilityAccessFlagForAnonymous(descriptor); } - if (ExpectedActualDeclarationChecker.isOptionalAnnotationClass(descriptor)) { - return NO_FLAG_PACKAGE_PRIVATE; - } if (descriptor.getKind() == ClassKind.ENUM_ENTRY) { return NO_FLAG_PACKAGE_PRIVATE; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java index 9090acb75f2..87620c140b1 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java @@ -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.ModuleMappingKt; 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.FqName; import org.jetbrains.kotlin.psi.KtFile; @@ -129,15 +130,18 @@ public class ClassFileFactory implements OutputFileCollection { JvmModuleProtoBuf.Module.Builder builder = JvmModuleProtoBuf.Module.newBuilder(); String outputFilePath = getMappingFileName(state.getModuleName()); - for (PackageParts part : ClassFileUtilsKt.addCompiledPartsAndSort(packagePartRegistry.getParts().values(), state)) { - part.addTo(builder); - } + StringTableImpl stringTable = new StringTableImpl(); + ClassFileUtilsKt.addDataFromCompiledModule(builder, packagePartRegistry, stringTable, state); List experimental = state.getLanguageVersionSettings().getFlag(AnalysisFlags.getExperimental()); if (!experimental.isEmpty()) { - writeExperimentalMarkers(state.getModule(), builder, experimental); + writeExperimentalMarkers(state.getModule(), builder, experimental, stringTable); } + Pair tables = stringTable.buildProto(); + builder.setStringTable(tables.getFirst()); + builder.setQualifiedNameTable(tables.getSecond()); + JvmModuleProtoBuf.Module moduleProto = builder.build(); generators.put(outputFilePath, new OutAndSourceFileList(CollectionsKt.toList(sourceFiles)) { @@ -160,9 +164,9 @@ public class ClassFileFactory implements OutputFileCollection { private static void writeExperimentalMarkers( @NotNull ModuleDescriptor module, @NotNull JvmModuleProtoBuf.Module.Builder builder, - @NotNull List experimental + @NotNull List experimental, + @NotNull StringTable stringTable ) { - StringTableImpl stringTable = new StringTableImpl(); for (String fqName : experimental) { ClassDescriptor descriptor = DescriptorUtilKt.resolveClassByFqName(module, new FqName(fqName), NoLookupLocation.FOR_ALREADY_TRACKED); @@ -175,9 +179,6 @@ public class ClassFileFactory implements OutputFileCollection { } } } - Pair tables = stringTable.buildProto(); - builder.setStringTable(tables.getFirst()); - builder.setQualifiedNameTable(tables.getSecond()); } @NotNull diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java index 4f63e424beb..e0d2b6466ef 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java @@ -90,8 +90,12 @@ public class PackageCodegenImpl implements PackageCodegen { for (KtDeclaration declaration : file.getDeclarations()) { if (declaration instanceof KtClassOrObject) { ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, declaration); - if (PsiUtilsKt.hasExpectModifier(declaration) && - (descriptor == null || !ExpectedActualDeclarationChecker.shouldGenerateExpectClass(descriptor))) { + if (PsiUtilsKt.hasExpectModifier(declaration)) { + 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; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartRegistry.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartRegistry.kt index 1f35fd45266..29a526e91a6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartRegistry.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartRegistry.kt @@ -16,11 +16,13 @@ package org.jetbrains.kotlin.codegen +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.metadata.jvm.deserialization.PackageParts import org.jetbrains.kotlin.name.FqName class PackagePartRegistry { val parts = mutableMapOf() + val optionalAnnotations = mutableListOf() fun addPart(packageFqName: FqName, partInternalName: String, facadeInternalName: String?) { parts.computeIfAbsent(packageFqName) { PackageParts(it.asString()) }.addPart(partInternalName, facadeInternalName) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/classFileUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/classFileUtils.kt index ead6ba6a55a..8d1b64ca375 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/classFileUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/classFileUtils.kt @@ -18,10 +18,19 @@ package org.jetbrains.kotlin.codegen import org.jetbrains.kotlin.backend.common.output.OutputFile import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies 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.PackageParts +import org.jetbrains.kotlin.name.ClassId 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 { return asList().filterClassFiles() @@ -31,27 +40,64 @@ fun List.filterClassFiles(): List { return filter { it.relativePath.endsWith(".class") } } -fun Iterable.addCompiledPartsAndSort(state: GenerationState): List = - addCompiledParts(state).sortedBy { it.packageFqName } - -private fun Iterable.addCompiledParts(state: GenerationState): List { - val incrementalCache = state.incrementalCacheForThisTarget ?: return this.toList() - val moduleMappingData = incrementalCache.getModuleMappingData() ?: return this.toList() - - val mapping = ModuleMapping.loadModuleMapping(moduleMappingData, "", state.deserializationConfiguration) { version -> - throw IllegalStateException("Version of the generated module cannot be incompatible: $version") +fun JvmModuleProtoBuf.Module.Builder.addDataFromCompiledModule( + registry: PackagePartRegistry, stringTable: StringTableImpl, state: GenerationState +) { + for (part in registry.parts.values.addCompiledPartsAndSort(state)) { + part.addTo(this) } - 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.addCompiledPartsAndSort(state: GenerationState): List = + addCompiledParts(state).sortedBy { it.packageFqName } + +private fun Iterable.addCompiledParts(state: GenerationState): List { + val mapping = state.loadCompiledModule() ?: return this.toList() + + state.incrementalCacheForThisTarget?.getObsoletePackageParts()?.forEach { internalName -> val qualifier = JvmClassName.byInternalName(internalName).packageFqName.asString() mapping.findPackageParts(qualifier)?.removePart(internalName) } return (this + mapping.packageFqName2Parts.values) - .groupBy { it.packageFqName } - .map { (packageFqName, allOldPackageParts) -> - PackageParts(packageFqName).apply { - allOldPackageParts.forEach { packageParts -> this += packageParts } - } + .groupBy { it.packageFqName } + .map { (packageFqName, allOldPackageParts) -> + PackageParts(packageFqName).apply { + allOldPackageParts.forEach { packageParts -> this += packageParts } } + } +} + +private fun GenerationState.loadCompiledModule(): ModuleMapping? { + val moduleMappingData = incrementalCacheForThisTarget?.getModuleMappingData() ?: return null + return ModuleMapping.loadModuleMapping(moduleMappingData, "", deserializationConfiguration) { version -> + throw IllegalStateException("Version of the generated module cannot be incompatible: $version") + } } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt index 6e04c6da1d1..70e1a890e26 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt @@ -51,6 +51,7 @@ import org.jetbrains.kotlin.konan.properties.propertyList import org.jetbrains.kotlin.konan.util.KlibMetadataFactories import org.jetbrains.kotlin.library.KLIB_PROPERTY_DEPENDS 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.lazy.ModuleClassResolver 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.extensions.AnalysisHandlerExtension 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.declarations.DeclarationProviderFactory 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.StorageManager import java.util.* @@ -195,7 +196,8 @@ object TopDownAnalyzerFacadeForJVM { CompositePackageFragmentProvider( listOf( moduleClassResolver.compiledCodeResolver.packageFragmentProvider, - dependenciesContainer.get() + dependenciesContainer.get(), + dependenciesContainer.get() ) ) ) @@ -252,7 +254,10 @@ object TopDownAnalyzerFacadeForJVM { ) module.initialize( CompositePackageFragmentProvider( - listOf(container.get().packageFragmentProvider) + additionalProviders + listOf( + container.get().packageFragmentProvider, + container.get() + ) + additionalProviders ) ) diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt index 4a1956b8e01..bef3b2dcd29 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt @@ -44,6 +44,7 @@ import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver 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.lazy.KotlinCodeAnalyzer import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory @@ -121,6 +122,7 @@ fun StorageComponentContainer.configureJavaSpecificComponents( useInstance((moduleContext.module.builtIns as JvmBuiltIns).settings) useImpl() } + useImpl() useInstance(javaClassTracker ?: JavaClassesTracker.Default) useInstance( diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/IncrementalPackagePartProvider.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/IncrementalPackagePartProvider.kt index 6eb6ba6675f..4e439270dd0 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/IncrementalPackagePartProvider.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/IncrementalPackagePartProvider.kt @@ -16,18 +16,20 @@ 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.incremental.components.IncrementalCache import org.jetbrains.kotlin.load.kotlin.loadModuleMapping import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.serialization.deserialization.ClassData import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration import org.jetbrains.kotlin.storage.StorageManager class IncrementalPackagePartProvider( - private val parent: PackagePartProvider, - incrementalCaches: List, - storageManager: StorageManager + private val parent: PackagePartProvider, + incrementalCaches: List, + storageManager: StorageManager ) : PackagePartProvider { lateinit var deserializationConfiguration: DeserializationConfiguration @@ -48,4 +50,8 @@ class IncrementalPackagePartProvider( override fun getAnnotationsOnBinaryModule(moduleName: String): List { return parent.getAnnotationsOnBinaryModule(moduleName) } + + override fun getAllOptionalAnnotationClasses(): List = + moduleMappings().flatMap((JvmPackagePartProviderBase)::getAllOptionalAnnotationClasses) + + parent.getAllOptionalAnnotationClasses() } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/multiplatform/OptionalAnnotationPackageFragmentProvider.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/multiplatform/OptionalAnnotationPackageFragmentProvider.kt new file mode 100644 index 00000000000..788bfbdca58 --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/multiplatform/OptionalAnnotationPackageFragmentProvider.kt @@ -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 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().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 = + packages[fqName]?.let(::listOf).orEmpty() + + override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection = + emptyList() +} + +private class OptionalAnnotationClassDataFinder(classes: List) : 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, + classDescriptors: NotNullLazyValue>, +) : 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 = + if (kindFilter.acceptsKinds(DescriptorKindFilter.CLASSIFIERS_MASK)) classDescriptors().values else emptyList() + + override fun getClassifierNames(): Set = classNames + + override fun printScopeStructure(p: Printer) { + p.print("PackageFragmentForOptionalAnnotations{${classNames.joinToString(transform = Name::asString)}}") + } + } + + override fun getMemberScope(): MemberScope = scope +} diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ExpectDeclarationsRemoveLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ExpectDeclarationsRemoveLowering.kt index d1b01cf546b..1fc65bc339c 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ExpectDeclarationsRemoveLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ExpectDeclarationsRemoveLowering.kt @@ -7,19 +7,14 @@ package org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.backend.common.DeclarationTransformer -import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.util.ExpectDeclarationRemover /** * This pass removes all declarations with `isExpect == true`. */ -class ExpectDeclarationsRemoveLowering(context: BackendContext, keepOptionalAnnotations: Boolean = false) : DeclarationTransformer { - - private val remover = ExpectDeclarationRemover( - symbolTable = context.ir.symbols.externalSymbolTable, - doRemove = true, - keepOptionalAnnotations = keepOptionalAnnotations - ) +class ExpectDeclarationsRemoveLowering(context: BackendContext) : DeclarationTransformer { + private val remover = ExpectDeclarationRemover(context.ir.symbols.externalSymbolTable, true) override fun transformFlat(declaration: IrDeclaration): List? { return remover.transformFlat(declaration) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 33e18c44a28..a720c3b1e0a 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -75,8 +75,8 @@ private val arrayConstructorPhase = makeIrFilePhase( description = "Transform `Array(size) { index -> value }` into a loop" ) -private val expectDeclarationsRemovingPhase = makeIrModulePhase( - { context -> ExpectDeclarationsRemoveLowering(context, keepOptionalAnnotations = true) }, +private val expectDeclarationsRemovingPhase = makeIrModulePhase( + ::ExpectDeclarationsRemoveLowering, name = "ExpectDeclarationsRemoving", description = "Remove expect declaration from module fragment" ) @@ -375,6 +375,7 @@ val jvmPhases = namedIrModulePhase( name = "IrLowering", description = "IR lowering", lower = validateIrBeforeLowering then + processOptionalAnnotationsPhase then expectDeclarationsRemovingPhase then fileClassPhase then performByIrFile(lower = jvmFilePhases) then diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt index 4bff18116d6..0181460ce46 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt @@ -372,9 +372,6 @@ internal fun getSignature( */ fun IrClass.getVisibilityAccessFlagForClass(): Int { /* 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) { return AsmUtil.NO_FLAG_PACKAGE_PRIVATE } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ProcessOptionalAnnotations.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ProcessOptionalAnnotations.kt new file mode 100644 index 00000000000..4a7f7edbe68 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ProcessOptionalAnnotations.kt @@ -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 + } + } +} diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ExpectDeclarationRemover.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ExpectDeclarationRemover.kt index 35ff4666e1d..944e1c3299b 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ExpectDeclarationRemover.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ExpectDeclarationRemover.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.ir.util -import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.MemberDescriptor import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* @@ -23,11 +22,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver // `doRemove` means should expect-declaration be removed from IR -class ExpectDeclarationRemover( - val symbolTable: ReferenceSymbolTable, - private val doRemove: Boolean, - private val keepOptionalAnnotations: Boolean -) : IrElementVisitorVoid { +class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private val doRemove: Boolean) : IrElementVisitorVoid { override fun visitElement(element: IrElement) { element.acceptChildrenVoid(this) } @@ -58,10 +53,8 @@ class ExpectDeclarationRemover( } private fun shouldRemoveTopLevelDeclaration(declaration: IrDeclaration): Boolean { - // TODO: rewrite findCompatibleActualForExpected using IR structures instead of descriptors val descriptor = declaration.descriptor - return doRemove && descriptor is MemberDescriptor && descriptor.isExpect && - !(keepOptionalAnnotations && descriptor is ClassDescriptor && ExpectedActualDeclarationChecker.shouldGenerateExpectClass(descriptor)) + return doRemove && descriptor is MemberDescriptor && descriptor.isExpect } private fun tryCopyDefaultArguments(declaration: IrValueParameter) { diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt index e1beb373bfe..daedfb6659a 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt @@ -27,7 +27,10 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl 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.declarations.IrModuleFragment 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.Psi2IrTranslator 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.createGeneratorContext import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContextUtils import org.jetbrains.kotlin.storage.LockBasedStorageManager @@ -162,7 +165,7 @@ fun generateKLib( val moduleName = configuration[CommonConfigurationKeys.MODULE_NAME]!! if (!configuration.expectActualLinker) { - moduleFragment.acceptVoid(ExpectDeclarationRemover(psi2IrContext.symbolTable, doRemove = false, keepOptionalAnnotations = false)) + moduleFragment.acceptVoid(ExpectDeclarationRemover(psi2IrContext.symbolTable, false)) } serializeModuleIntoKlib( diff --git a/compiler/testData/codegen/bytecodeListing/multiplatform/optionalExpectation.txt b/compiler/testData/codegen/bytecodeListing/multiplatform/optionalExpectation.txt index 1f4b3fb78f7..89dba1c107e 100644 --- a/compiler/testData/codegen/bytecodeListing/multiplatform/optionalExpectation.txt +++ b/compiler/testData/codegen/bytecodeListing/multiplatform/optionalExpectation.txt @@ -1,10 +1,3 @@ -@java.lang.annotation.Retention -@kotlin.Metadata -@kotlin.OptionalExpectation -annotation class Anno { - public abstract method s(): java.lang.String -} - @kotlin.Metadata public interface Foo$Nested { inner class Foo$Nested diff --git a/compiler/testData/compileKotlinAgainstKotlin/optionalAnnotation.kt b/compiler/testData/compileKotlinAgainstKotlin/optionalAnnotation.kt index 9c8bebf4988..0af7b987b29 100644 --- a/compiler/testData/compileKotlinAgainstKotlin/optionalAnnotation.kt +++ b/compiler/testData/compileKotlinAgainstKotlin/optionalAnnotation.kt @@ -31,8 +31,10 @@ fun box(): String { val annotations = Test::class.java.declaredMethods.single().annotations.toList() 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" - if (Modifier.isPublic(Class.forName("a.B").modifiers)) return "Fail 2: optional annotation class should not be public in the bytecode" - - return "OK" + try { + Class.forName("a.B") + return "Fail 2: there should be no class file for a.B" + } catch (e: ClassNotFoundException) { + return "OK" + } } diff --git a/compiler/testData/writeFlags/multiplatform/optionalExpectation.kt b/compiler/testData/writeFlags/multiplatform/optionalExpectation.kt deleted file mode 100644 index a9dd4446a1f..00000000000 --- a/compiler/testData/writeFlags/multiplatform/optionalExpectation.kt +++ /dev/null @@ -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 diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/flags/WriteFlagsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/flags/WriteFlagsTestGenerated.java index b425aa44df7..bfeaa809453 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/flags/WriteFlagsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/flags/WriteFlagsTestGenerated.java @@ -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") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrWriteFlagsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrWriteFlagsTestGenerated.java index 0ac9221c8bf..acd0fcf9953 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrWriteFlagsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrWriteFlagsTestGenerated.java @@ -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") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartProviderBase.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartProviderBase.kt index 76ea64ef933..ca97263b9fd 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartProviderBase.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartProviderBase.kt @@ -5,9 +5,11 @@ 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.PackageParts import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.serialization.deserialization.ClassData import org.jetbrains.kotlin.serialization.deserialization.MetadataPartProvider abstract class JvmPackagePartProviderBase : PackagePartProvider, MetadataPartProvider { @@ -51,4 +53,18 @@ abstract class JvmPackagePartProviderBase : PackagePartProvider, Me if (name == moduleName) mapping.moduleData.annotations.map(ClassId::fromString) else null }.flatten() } + + override fun getAllOptionalAnnotationClasses(): List = + loadedModules.flatMap { module -> + getAllOptionalAnnotationClasses(module.mapping) + } + + companion object { + fun getAllOptionalAnnotationClasses(module: ModuleMapping): List { + val data = module.moduleData + return data.optionalAnnotations.map { proto -> + ClassData(data.nameResolver, proto, module.version, SourceElement.NO_SOURCE) + } + } + } } diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/PackagePartProvider.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/PackagePartProvider.kt index c81b19d6542..a6e2647a782 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/PackagePartProvider.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/PackagePartProvider.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.load.kotlin import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.serialization.deserialization.ClassData interface PackagePartProvider { /** @@ -19,9 +20,13 @@ interface PackagePartProvider { fun getAnnotationsOnBinaryModule(moduleName: String): List + fun getAllOptionalAnnotationClasses(): List + object Empty : PackagePartProvider { override fun findPackageParts(packageFqName: String): List = emptyList() override fun getAnnotationsOnBinaryModule(moduleName: String): List = emptyList() + + override fun getAllOptionalAnnotationClasses(): List = emptyList() } } diff --git a/core/metadata.jvm/src/jvm_module.proto b/core/metadata.jvm/src/jvm_module.proto index aae14760aa1..b8443b02a60 100644 --- a/core/metadata.jvm/src/jvm_module.proto +++ b/core/metadata.jvm/src/jvm_module.proto @@ -38,6 +38,12 @@ message Module { // Annotations on the whole module 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 { diff --git a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/JvmModuleProtoBuf.java b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/JvmModuleProtoBuf.java index 29ac15f44d4..270651827bb 100644 --- a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/JvmModuleProtoBuf.java +++ b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/JvmModuleProtoBuf.java @@ -146,6 +146,41 @@ public final class JvmModuleProtoBuf { * */ int getAnnotationCount(); + + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + java.util.List + getOptionalAnnotationClassList(); + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + org.jetbrains.kotlin.metadata.ProtoBuf.Class getOptionalAnnotationClass(int index); + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + int getOptionalAnnotationClassCount(); } /** * 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)); break; } + case 130: { + if (!((mutable_bitField0_ & 0x00000040) == 0x00000040)) { + optionalAnnotationClass_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000040; + } + optionalAnnotationClass_.add(input.readMessage(org.jetbrains.kotlin.metadata.ProtoBuf.Class.PARSER, extensionRegistry)); + break; + } } } } catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) { @@ -276,6 +319,9 @@ public final class JvmModuleProtoBuf { if (((mutable_bitField0_ & 0x00000020) == 0x00000020)) { annotation_ = java.util.Collections.unmodifiableList(annotation_); } + if (((mutable_bitField0_ & 0x00000040) == 0x00000040)) { + optionalAnnotationClass_ = java.util.Collections.unmodifiableList(optionalAnnotationClass_); + } try { unknownFieldsCodedOutput.flush(); } catch (java.io.IOException e) { @@ -546,6 +592,76 @@ public final class JvmModuleProtoBuf { return annotation_.get(index); } + public static final int OPTIONAL_ANNOTATION_CLASS_FIELD_NUMBER = 16; + private java.util.List optionalAnnotationClass_; + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + public java.util.List getOptionalAnnotationClassList() { + return optionalAnnotationClass_; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + public java.util.List + getOptionalAnnotationClassOrBuilderList() { + return optionalAnnotationClass_; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + public int getOptionalAnnotationClassCount() { + return optionalAnnotationClass_.size(); + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + public org.jetbrains.kotlin.metadata.ProtoBuf.Class getOptionalAnnotationClass(int index) { + return optionalAnnotationClass_.get(index); + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+     * @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.
+     * 
+ */ + public org.jetbrains.kotlin.metadata.ProtoBuf.ClassOrBuilder getOptionalAnnotationClassOrBuilder( + int index) { + return optionalAnnotationClass_.get(index); + } + private void initFields() { packageParts_ = 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(); qualifiedNameTable_ = org.jetbrains.kotlin.metadata.ProtoBuf.QualifiedNameTable.getDefaultInstance(); annotation_ = java.util.Collections.emptyList(); + optionalAnnotationClass_ = java.util.Collections.emptyList(); } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -584,6 +701,12 @@ public final class JvmModuleProtoBuf { return false; } } + for (int i = 0; i < getOptionalAnnotationClassCount(); i++) { + if (!getOptionalAnnotationClass(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } memoizedIsInitialized = 1; return true; } @@ -609,6 +732,9 @@ public final class JvmModuleProtoBuf { for (int i = 0; i < annotation_.size(); i++) { output.writeMessage(6, annotation_.get(i)); } + for (int i = 0; i < optionalAnnotationClass_.size(); i++) { + output.writeMessage(16, optionalAnnotationClass_.get(i)); + } output.writeRawBytes(unknownFields); } @@ -647,6 +773,10 @@ public final class JvmModuleProtoBuf { size += org.jetbrains.kotlin.protobuf.CodedOutputStream .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(); memoizedSerializedSize = size; return size; @@ -753,6 +883,8 @@ public final class JvmModuleProtoBuf { bitField0_ = (bitField0_ & ~0x00000010); annotation_ = java.util.Collections.emptyList(); bitField0_ = (bitField0_ & ~0x00000020); + optionalAnnotationClass_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000040); return this; } @@ -804,6 +936,11 @@ public final class JvmModuleProtoBuf { bitField0_ = (bitField0_ & ~0x00000020); } result.annotation_ = annotation_; + if (((bitField0_ & 0x00000040) == 0x00000040)) { + optionalAnnotationClass_ = java.util.Collections.unmodifiableList(optionalAnnotationClass_); + bitField0_ = (bitField0_ & ~0x00000040); + } + result.optionalAnnotationClass_ = optionalAnnotationClass_; result.bitField0_ = to_bitField0_; return result; } @@ -855,6 +992,16 @@ public final class JvmModuleProtoBuf { annotation_.addAll(other.annotation_); } + } + if (!other.optionalAnnotationClass_.isEmpty()) { + if (optionalAnnotationClass_.isEmpty()) { + optionalAnnotationClass_ = other.optionalAnnotationClass_; + bitField0_ = (bitField0_ & ~0x00000040); + } else { + ensureOptionalAnnotationClassIsMutable(); + optionalAnnotationClass_.addAll(other.optionalAnnotationClass_); + } + } setUnknownFields( getUnknownFields().concat(other.unknownFields)); @@ -886,6 +1033,12 @@ public final class JvmModuleProtoBuf { return false; } } + for (int i = 0; i < getOptionalAnnotationClassCount(); i++) { + if (!getOptionalAnnotationClass(i).isInitialized()) { + + return false; + } + } return true; } @@ -1685,6 +1838,215 @@ public final class JvmModuleProtoBuf { return this; } + private java.util.List optionalAnnotationClass_ = + java.util.Collections.emptyList(); + private void ensureOptionalAnnotationClassIsMutable() { + if (!((bitField0_ & 0x00000040) == 0x00000040)) { + optionalAnnotationClass_ = new java.util.ArrayList(optionalAnnotationClass_); + bitField0_ |= 0x00000040; + } + } + + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public java.util.List getOptionalAnnotationClassList() { + return java.util.Collections.unmodifiableList(optionalAnnotationClass_); + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public int getOptionalAnnotationClassCount() { + return optionalAnnotationClass_.size(); + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public org.jetbrains.kotlin.metadata.ProtoBuf.Class getOptionalAnnotationClass(int index) { + return optionalAnnotationClass_.get(index); + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + 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; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public Builder setOptionalAnnotationClass( + int index, org.jetbrains.kotlin.metadata.ProtoBuf.Class.Builder builderForValue) { + ensureOptionalAnnotationClassIsMutable(); + optionalAnnotationClass_.set(index, builderForValue.build()); + + return this; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public Builder addOptionalAnnotationClass(org.jetbrains.kotlin.metadata.ProtoBuf.Class value) { + if (value == null) { + throw new NullPointerException(); + } + ensureOptionalAnnotationClassIsMutable(); + optionalAnnotationClass_.add(value); + + return this; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + 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; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public Builder addOptionalAnnotationClass( + org.jetbrains.kotlin.metadata.ProtoBuf.Class.Builder builderForValue) { + ensureOptionalAnnotationClassIsMutable(); + optionalAnnotationClass_.add(builderForValue.build()); + + return this; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public Builder addOptionalAnnotationClass( + int index, org.jetbrains.kotlin.metadata.ProtoBuf.Class.Builder builderForValue) { + ensureOptionalAnnotationClassIsMutable(); + optionalAnnotationClass_.add(index, builderForValue.build()); + + return this; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public Builder addAllOptionalAnnotationClass( + java.lang.Iterable values) { + ensureOptionalAnnotationClassIsMutable(); + org.jetbrains.kotlin.protobuf.AbstractMessageLite.Builder.addAll( + values, optionalAnnotationClass_); + + return this; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public Builder clearOptionalAnnotationClass() { + optionalAnnotationClass_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000040); + + return this; + } + /** + * repeated .org.jetbrains.kotlin.metadata.Class optional_annotation_class = 16; + * + *
+       * @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.
+       * 
+ */ + public Builder removeOptionalAnnotationClass(int index) { + ensureOptionalAnnotationClassIsMutable(); + optionalAnnotationClass_.remove(index); + + return this; + } + // @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.metadata.jvm.Module) } diff --git a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/BinaryModuleData.kt b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/BinaryModuleData.kt index a6be035d470..89b5d57cf08 100644 --- a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/BinaryModuleData.kt +++ b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/BinaryModuleData.kt @@ -5,7 +5,16 @@ 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 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) +class BinaryModuleData( + val annotations: List, + val optionalAnnotations: List, + val nameResolver: NameResolver, +) diff --git a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/ModuleMapping.kt b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/ModuleMapping.kt index 69b12a2f79d..f1301776c08 100644 --- a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/ModuleMapping.kt +++ b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/ModuleMapping.kt @@ -5,13 +5,17 @@ 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.NameResolverImpl import org.jetbrains.kotlin.metadata.deserialization.isKotlin1Dot4OrLater import org.jetbrains.kotlin.metadata.jvm.JvmModuleProtoBuf +import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite import java.io.* class ModuleMapping private constructor( + val version: JvmMetadataVersion, val packageFqName2Parts: Map, val moduleData: BinaryModuleData, private val debugName: String @@ -26,10 +30,10 @@ class ModuleMapping private constructor( const val MAPPING_FILE_EXT: String = "kotlin_module" @JvmField - val EMPTY: ModuleMapping = ModuleMapping(emptyMap(), BinaryModuleData(emptyList()), "EMPTY") + val EMPTY: ModuleMapping = ModuleMapping(JvmMetadataVersion.INSTANCE, emptyMap(), emptyBinaryData(), "EMPTY") @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 @@ -69,7 +73,9 @@ class ModuleMapping private constructor( 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() for (proto in moduleProto.packagePartsList) { @@ -114,7 +120,12 @@ class ModuleMapping private constructor( val nameResolver = NameResolverImpl(moduleProto.stringTable, moduleProto.qualifiedNameTable) 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( @@ -127,6 +138,13 @@ class ModuleMapping private constructor( val facadeShortName = multifileFacadeId?.let(multifileFacadeShortNames::getOrNull) return facadeShortName?.let { internalNameOf(packageFqName, it) } } + + private fun emptyBinaryData(): BinaryModuleData = + BinaryModuleData( + emptyList(), + emptyList(), + NameResolverImpl(ProtoBuf.StringTable.getDefaultInstance(), ProtoBuf.QualifiedNameTable.getDefaultInstance()) + ) } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEPackagePartProvider.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEPackagePartProvider.kt index eb3787d713d..24866a3d816 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEPackagePartProvider.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEPackagePartProvider.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.idea.vfilefinder.KotlinModuleMappingIndex import org.jetbrains.kotlin.load.kotlin.PackagePartProvider import org.jetbrains.kotlin.metadata.jvm.deserialization.PackageParts import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.serialization.deserialization.ClassData import org.jetbrains.kotlin.serialization.deserialization.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 override fun getAnnotationsOnBinaryModule(moduleName: String): List = 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 = + emptyList() } diff --git a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/IncrementalJvmJpsTestGenerated.java b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/IncrementalJvmJpsTestGenerated.java index fa0ed3f2b4d..8f6dc896138 100644 --- a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/IncrementalJvmJpsTestGenerated.java +++ b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/IncrementalJvmJpsTestGenerated.java @@ -598,6 +598,11 @@ public class IncrementalJvmJpsTestGenerated extends AbstractIncrementalJvmJpsTes 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") public void testNotSameCompiler() throws Exception { 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") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/jps-plugin/testData/incremental/multiModule/multiplatform/custom/complementaryFiles/build.log b/jps-plugin/testData/incremental/multiModule/multiplatform/custom/complementaryFiles/build.log index d50092a5710..3a90f366b38 100644 --- a/jps-plugin/testData/incremental/multiModule/multiplatform/custom/complementaryFiles/build.log +++ b/jps-plugin/testData/incremental/multiModule/multiplatform/custom/complementaryFiles/build.log @@ -8,7 +8,6 @@ Cleaning output files: End of files Cleaning output files: out/production/pJvm/FKt.class - out/production/pJvm/SharedImmutable.class End of files Compiling files: c/src/f.kt diff --git a/jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/_dependencies.txt b/jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/_dependencies.txt new file mode 100644 index 00000000000..94161f8d01d --- /dev/null +++ b/jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/_dependencies.txt @@ -0,0 +1,7 @@ +c [sourceSetHolder] + +pJvm [compilationAndSourceSetHolder, jvm] +pJvm -> c [include] + +pJs [compilationAndSourceSetHolder, js] +pJs -> c [include] diff --git a/jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/build.log b/jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/build.log new file mode 100644 index 00000000000..85eb646b8c3 --- /dev/null +++ b/jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/build.log @@ -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 +------------------------------------------ \ No newline at end of file diff --git a/jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/c_declaration.kt b/jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/c_declaration.kt new file mode 100644 index 00000000000..84c59ee8284 --- /dev/null +++ b/jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/c_declaration.kt @@ -0,0 +1,3 @@ +@OptIn(ExperimentalMultiplatform::class) +@OptionalExpectation +expect annotation class Optional(val value: String) diff --git a/jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/c_usage.kt b/jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/c_usage.kt new file mode 100644 index 00000000000..a76180ac767 --- /dev/null +++ b/jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/c_usage.kt @@ -0,0 +1,2 @@ +@Optional("1") +class Usage diff --git a/jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/c_usage.kt.new.1 b/jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/c_usage.kt.new.1 new file mode 100644 index 00000000000..834e6ff534d --- /dev/null +++ b/jps-plugin/testData/incremental/multiModule/multiplatform/custom/modifyOptionalAnnotationUsage/c_usage.kt.new.1 @@ -0,0 +1,2 @@ +@Optional("2") +class Usage diff --git a/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/KotlinModuleMetadata.kt b/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/KotlinModuleMetadata.kt index 7b6d73bab8d..e7c33c0bfa8 100644 --- a/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/KotlinModuleMetadata.kt +++ b/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/KotlinModuleMetadata.kt @@ -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. */ +@file:Suppress("MemberVisibilityCanBePrivate") + package kotlinx.metadata.jvm import kotlinx.metadata.InconsistentKotlinMetadataException 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.deserialization.JvmMetadataVersion 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. * @@ -80,13 +96,19 @@ class KotlinModuleMetadata(@Suppress("CanBeParameter", "MemberVisibilityCanBePri fun accept(v: KmModuleVisitor) { for ((fqName, parts) in data.packageFqName2Parts) { 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) { v.visitAnnotation(KmAnnotation(annotation, emptyMap())) } + for (classProto in data.moduleData.optionalAnnotations) { + v.visitOptionalAnnotationClass()?.let { + classProto.accept(it, data.moduleData.nameResolver) + } + } + v.visitEnd() } @@ -147,6 +169,17 @@ abstract class KmModuleVisitor(private val delegate: KmModuleVisitor? = null) { 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. */ @@ -171,6 +204,16 @@ class KmModule : KmModuleVisitor() { */ val annotations: MutableList = 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 = ArrayList(0) + override fun visitPackageParts(fqName: String, fileFacades: List, multiFileClassParts: Map) { packageParts[fqName] = KmPackageParts(fileFacades.toMutableList(), multiFileClassParts.toMutableMap()) } @@ -179,6 +222,9 @@ class KmModule : KmModuleVisitor() { annotations.add(annotation) } + override fun visitOptionalAnnotationClass(): KmClass = + KmClass().also(optionalAnnotationClasses::add) + /** * Populates the given visitor with data in this module. * @@ -189,6 +235,7 @@ class KmModule : KmModuleVisitor() { visitor.visitPackageParts(fqName, parts.fileFacades, parts.multiFileClassParts) } annotations.forEach(visitor::visitAnnotation) + optionalAnnotationClasses.forEach { visitor.visitOptionalAnnotationClass()?.let(it::accept) } } } diff --git a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/Kotlinp.kt b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/Kotlinp.kt index 2f7ba4d333e..4a863f116ec 100644 --- a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/Kotlinp.kt +++ b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/Kotlinp.kt @@ -10,7 +10,7 @@ import kotlinx.metadata.jvm.KotlinClassMetadata import kotlinx.metadata.jvm.KotlinModuleMetadata import java.io.File -class Kotlinp(val settings: KotlinpSettings) { +class Kotlinp(private val settings: KotlinpSettings) { internal fun renderClassFile(classFile: KotlinClassMetadata?): String = when (classFile) { is KotlinClassMetadata.Class -> ClassPrinter(settings).print(classFile) @@ -35,7 +35,7 @@ class Kotlinp(val settings: KotlinpSettings) { } internal fun renderModuleFile(metadata: KotlinModuleMetadata?): String = - if (metadata != null) ModuleFilePrinter().print(metadata) + if (metadata != null) ModuleFilePrinter(settings).print(metadata) else buildString { appendln("unsupported file") } internal fun readModuleFile(file: File): KotlinModuleMetadata? = diff --git a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt index 9714475d648..bdbf6098f31 100644 --- a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt +++ b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt @@ -689,7 +689,7 @@ interface AbstractPrinter { class ClassPrinter(private val settings: KotlinpSettings) : KmClassVisitor(), AbstractPrinter { private val sb = StringBuilder() - private val result = StringBuilder() + internal val result = StringBuilder() private var flags: Flags? = null private var name: ClassName? = null @@ -880,7 +880,9 @@ class MultiFileClassFacadePrinter : AbstractPrinter() + private val sb = StringBuilder().apply { appendln("module {") } @@ -901,7 +903,18 @@ class ModuleFilePrinter : KmModuleVisitor() { // TODO } + override fun visitOptionalAnnotationClass(): KmClassVisitor = + ClassPrinter(settings).also(optionalAnnotations::add) + 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("}") } diff --git a/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestGenerated.java b/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestGenerated.java index b02ac639298..bb66ad857d6 100644 --- a/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestGenerated.java +++ b/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestGenerated.java @@ -63,6 +63,11 @@ public class KotlinpTestGenerated extends AbstractKotlinpTest { 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") public void testPlatformType() throws Exception { runTest("libraries/tools/kotlinp/testData/PlatformType.kt"); diff --git a/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestUtils.kt b/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestUtils.kt index 02a65d43d4d..dd4fb7bb9ce 100644 --- a/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestUtils.kt +++ b/libraries/tools/kotlinp/test/org/jetbrains/kotlin/kotlinp/test/KotlinpTestUtils.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.jvm.compiler.AbstractLoadJavaTest import org.jetbrains.kotlin.kotlinp.Kotlinp import org.jetbrains.kotlin.kotlinp.KotlinpSettings import org.jetbrains.kotlin.test.ConfigurationKind +import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.TestJdkKind 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()) } - 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 nodes.", main.toString(), afterNodes.toString()) } diff --git a/libraries/tools/kotlinp/testData/OptionalAnnotation.kt b/libraries/tools/kotlinp/testData/OptionalAnnotation.kt new file mode 100644 index 00000000000..2381c2ef110 --- /dev/null +++ b/libraries/tools/kotlinp/testData/OptionalAnnotation.kt @@ -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) + +@OptionalExpectation +expect annotation class C() + +@Suppress("OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE") +@A(42) +@B(["OK", ""]) +@C +fun ok() {} diff --git a/libraries/tools/kotlinp/testData/OptionalAnnotation.txt b/libraries/tools/kotlinp/testData/OptionalAnnotation.txt new file mode 100644 index 00000000000..fa3ba05afa0 --- /dev/null +++ b/libraries/tools/kotlinp/testData/OptionalAnnotation.txt @@ -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: (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: (Lkotlin/Array;)V + public /* primary */ constructor(a: kotlin/Array) + + public final expect val a: kotlin/Array + public final get + + // module name: main + } + public final expect annotation class test/C : kotlin/Annotation { + + // signature: ()V + public /* primary */ constructor() + + // module name: main + } +}