001 /*
002 * Copyright 2010-2014 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.jet.lang.resolve.kotlin;
018
019 import kotlin.Function1;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
023 import org.jetbrains.jet.lang.resolve.constants.*;
024 import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
025 import org.jetbrains.jet.lang.resolve.java.JvmClassName;
026 import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter;
027 import org.jetbrains.jet.lang.resolve.name.Name;
028 import org.jetbrains.jet.lang.types.DependencyClassByQualifiedNameResolver;
029 import org.jetbrains.jet.storage.MemoizedFunctionToNotNull;
030 import org.jetbrains.jet.storage.StorageManager;
031
032 import javax.inject.Inject;
033 import java.io.IOException;
034 import java.util.*;
035
036 public class DescriptorDeserializersStorage {
037 private DependencyClassByQualifiedNameResolver classResolver;
038 private ErrorReporter errorReporter;
039
040 private final MemoizedFunctionToNotNull<KotlinJvmBinaryClass, Storage> storage;
041
042 public DescriptorDeserializersStorage(@NotNull StorageManager storageManager) {
043 this.storage = storageManager.createMemoizedFunction(
044 new Function1<KotlinJvmBinaryClass, Storage>() {
045 @NotNull
046 @Override
047 public Storage invoke(@NotNull KotlinJvmBinaryClass kotlinClass) {
048 try {
049 return loadAnnotationsAndInitializers(kotlinClass);
050 }
051 catch (IOException e) {
052 errorReporter.reportLoadingError("Error loading member information from Kotlin class: " + kotlinClass, e);
053 return Storage.EMPTY;
054 }
055 }
056 });
057 }
058
059 @Inject
060 public void setClassResolver(DependencyClassByQualifiedNameResolver classResolver) {
061 this.classResolver = classResolver;
062 }
063
064 @Inject
065 public void setErrorReporter(ErrorReporter errorReporter) {
066 this.errorReporter = errorReporter;
067 }
068
069 @NotNull
070 protected MemoizedFunctionToNotNull<KotlinJvmBinaryClass, Storage> getStorage() {
071 return storage;
072 }
073
074 @NotNull
075 private Storage loadAnnotationsAndInitializers(@NotNull KotlinJvmBinaryClass kotlinClass) throws IOException {
076 final Map<MemberSignature, List<AnnotationDescriptor>> memberAnnotations = new HashMap<MemberSignature, List<AnnotationDescriptor>>();
077 final Map<MemberSignature, CompileTimeConstant<?>> propertyConstants = new HashMap<MemberSignature, CompileTimeConstant<?>>();
078
079 kotlinClass.visitMembers(new KotlinJvmBinaryClass.MemberVisitor() {
080 @Nullable
081 @Override
082 public KotlinJvmBinaryClass.MethodAnnotationVisitor visitMethod(@NotNull Name name, @NotNull String desc) {
083 return new AnnotationVisitorForMethod(MemberSignature.fromMethodNameAndDesc(name, desc));
084 }
085
086 @Nullable
087 @Override
088 public KotlinJvmBinaryClass.AnnotationVisitor visitField(@NotNull Name name, @NotNull String desc, @Nullable Object initializer) {
089 MemberSignature signature = MemberSignature.fromFieldNameAndDesc(name, desc);
090 if (initializer != null) {
091 propertyConstants.put(signature, ConstantsPackage.createCompileTimeConstant(
092 initializer, /* canBeUsedInAnnotation */ true, /* isPureIntConstant */ true, /* expectedType */ null));
093 }
094 return new MemberAnnotationVisitor(signature);
095 }
096
097 class AnnotationVisitorForMethod extends MemberAnnotationVisitor implements KotlinJvmBinaryClass.MethodAnnotationVisitor {
098 public AnnotationVisitorForMethod(@NotNull MemberSignature signature) {
099 super(signature);
100 }
101
102 @Nullable
103 @Override
104 public KotlinJvmBinaryClass.AnnotationArgumentVisitor visitParameterAnnotation(int index, @NotNull JvmClassName className) {
105 MemberSignature paramSignature = MemberSignature.fromMethodSignatureAndParameterIndex(signature, index);
106 List<AnnotationDescriptor> result = memberAnnotations.get(paramSignature);
107 if (result == null) {
108 result = new ArrayList<AnnotationDescriptor>();
109 memberAnnotations.put(paramSignature, result);
110 }
111 return AnnotationDescriptorDeserializer.resolveAnnotation(className, result, classResolver);
112 }
113 }
114
115 class MemberAnnotationVisitor implements KotlinJvmBinaryClass.AnnotationVisitor {
116 private final List<AnnotationDescriptor> result = new ArrayList<AnnotationDescriptor>();
117 protected final MemberSignature signature;
118
119 public MemberAnnotationVisitor(@NotNull MemberSignature signature) {
120 this.signature = signature;
121 }
122
123 @Nullable
124 @Override
125 public KotlinJvmBinaryClass.AnnotationArgumentVisitor visitAnnotation(@NotNull JvmClassName className) {
126 return AnnotationDescriptorDeserializer.resolveAnnotation(className, result, classResolver);
127 }
128
129 @Override
130 public void visitEnd() {
131 if (!result.isEmpty()) {
132 memberAnnotations.put(signature, result);
133 }
134 }
135 }
136 });
137
138 return new Storage(memberAnnotations, propertyConstants);
139 }
140
141 // The purpose of this class is to hold a unique signature of either a method or a field, so that annotations on a member can be put
142 // into a map indexed by these signatures
143 protected static final class MemberSignature {
144 private final String signature;
145
146 private MemberSignature(@NotNull String signature) {
147 this.signature = signature;
148 }
149
150 @NotNull
151 public static MemberSignature fromMethodNameAndDesc(@NotNull Name name, @NotNull String desc) {
152 return new MemberSignature(name.asString() + desc);
153 }
154
155 @NotNull
156 public static MemberSignature fromFieldNameAndDesc(@NotNull Name name, @NotNull String desc) {
157 return new MemberSignature(name.asString() + "#" + desc);
158 }
159
160 @NotNull
161 public static MemberSignature fromMethodSignatureAndParameterIndex(@NotNull MemberSignature signature, int index) {
162 return new MemberSignature(signature.signature + "@" + index);
163 }
164
165 @Override
166 public int hashCode() {
167 return signature.hashCode();
168 }
169
170 @Override
171 public boolean equals(Object o) {
172 return o instanceof MemberSignature && signature.equals(((MemberSignature) o).signature);
173 }
174
175 @Override
176 public String toString() {
177 return signature;
178 }
179 }
180
181 protected static class Storage {
182 private final Map<MemberSignature, List<AnnotationDescriptor>> memberAnnotations;
183 private final Map<MemberSignature, CompileTimeConstant<?>> propertyConstants;
184
185 public static final Storage EMPTY = new Storage(
186 Collections.<MemberSignature, List<AnnotationDescriptor>>emptyMap(),
187 Collections.<MemberSignature, CompileTimeConstant<?>>emptyMap()
188 );
189
190 public Storage(
191 @NotNull Map<MemberSignature, List<AnnotationDescriptor>> annotations,
192 @NotNull Map<MemberSignature, CompileTimeConstant<?>> constants
193 ) {
194 this.memberAnnotations = annotations;
195 this.propertyConstants = constants;
196 }
197
198 public Map<MemberSignature, List<AnnotationDescriptor>> getMemberAnnotations() {
199 return memberAnnotations;
200 }
201
202 public Map<MemberSignature, CompileTimeConstant<?>> getPropertyConstants() {
203 return propertyConstants;
204 }
205 }
206 }