Deserialize annotations on classes

First version, not all kinds of value arguments of annotations are supported
This commit is contained in:
Alexander Udalov
2013-07-04 21:04:53 +04:00
parent 9a33567287
commit 4aeeafdff0
31 changed files with 804 additions and 152 deletions
@@ -34,6 +34,7 @@ import org.jetbrains.jet.lang.resolve.java.resolver.JavaFunctionResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaValueParameterResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaSignatureResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.DeserializedDescriptorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.AnnotationDescriptorDeserializer;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaNamespaceResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaConstructorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaInnerClassResolver;
@@ -62,6 +63,7 @@ public class InjectorForJavaDescriptorResolver {
private final JavaValueParameterResolver javaValueParameterResolver;
private final JavaSignatureResolver javaSignatureResolver;
private final DeserializedDescriptorResolver deserializedDescriptorResolver;
private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer;
private final JavaNamespaceResolver javaNamespaceResolver;
private final JavaConstructorResolver javaConstructorResolver;
private final JavaInnerClassResolver javaInnerClassResolver;
@@ -90,6 +92,7 @@ public class InjectorForJavaDescriptorResolver {
this.javaValueParameterResolver = new JavaValueParameterResolver();
this.javaSignatureResolver = new JavaSignatureResolver();
this.deserializedDescriptorResolver = new DeserializedDescriptorResolver();
this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer();
this.javaNamespaceResolver = new JavaNamespaceResolver();
this.javaConstructorResolver = new JavaConstructorResolver();
this.javaInnerClassResolver = new JavaInnerClassResolver();
@@ -151,9 +154,13 @@ public class InjectorForJavaDescriptorResolver {
javaSignatureResolver.setJavaSemanticServices(javaSemanticServices);
deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer);
deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver);
deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver);
annotationDescriptorDeserializer.setJavaClassResolver(javaClassResolver);
annotationDescriptorDeserializer.setPsiClassFinder(psiClassFinder);
javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver);
javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices);
javaNamespaceResolver.setPsiClassFinder(psiClassFinder);
@@ -34,6 +34,7 @@ import org.jetbrains.jet.lang.resolve.java.resolver.JavaFunctionResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaValueParameterResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaSignatureResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.DeserializedDescriptorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.AnnotationDescriptorDeserializer;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaNamespaceResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaConstructorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaInnerClassResolver;
@@ -62,6 +63,7 @@ public class InjectorForJavaSemanticServices {
private final JavaValueParameterResolver javaValueParameterResolver;
private final JavaSignatureResolver javaSignatureResolver;
private final DeserializedDescriptorResolver deserializedDescriptorResolver;
private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer;
private final JavaNamespaceResolver javaNamespaceResolver;
private final JavaConstructorResolver javaConstructorResolver;
private final JavaInnerClassResolver javaInnerClassResolver;
@@ -88,6 +90,7 @@ public class InjectorForJavaSemanticServices {
this.javaValueParameterResolver = new JavaValueParameterResolver();
this.javaSignatureResolver = new JavaSignatureResolver();
this.deserializedDescriptorResolver = new DeserializedDescriptorResolver();
this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer();
this.javaNamespaceResolver = new JavaNamespaceResolver();
this.javaConstructorResolver = new JavaConstructorResolver();
this.javaInnerClassResolver = new JavaInnerClassResolver();
@@ -151,9 +154,13 @@ public class InjectorForJavaSemanticServices {
javaSignatureResolver.setJavaSemanticServices(javaSemanticServices);
deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer);
deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver);
deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver);
annotationDescriptorDeserializer.setJavaClassResolver(javaClassResolver);
annotationDescriptorDeserializer.setPsiClassFinder(psiClassFinder);
javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver);
javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices);
javaNamespaceResolver.setPsiClassFinder(psiClassFinder);
@@ -59,6 +59,7 @@ import org.jetbrains.jet.lang.resolve.java.resolver.JavaFunctionResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaValueParameterResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaSignatureResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.DeserializedDescriptorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.AnnotationDescriptorDeserializer;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaNamespaceResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaConstructorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaInnerClassResolver;
@@ -112,6 +113,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
private final JavaValueParameterResolver javaValueParameterResolver;
private final JavaSignatureResolver javaSignatureResolver;
private final DeserializedDescriptorResolver deserializedDescriptorResolver;
private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer;
private final JavaNamespaceResolver javaNamespaceResolver;
private final JavaConstructorResolver javaConstructorResolver;
private final JavaInnerClassResolver javaInnerClassResolver;
@@ -166,6 +168,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
this.javaValueParameterResolver = new JavaValueParameterResolver();
this.javaSignatureResolver = new JavaSignatureResolver();
this.deserializedDescriptorResolver = new DeserializedDescriptorResolver();
this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer();
this.javaNamespaceResolver = new JavaNamespaceResolver();
this.javaConstructorResolver = new JavaConstructorResolver();
this.javaInnerClassResolver = new JavaInnerClassResolver();
@@ -329,9 +332,13 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
javaSignatureResolver.setJavaSemanticServices(javaSemanticServices);
deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer);
deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver);
deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver);
annotationDescriptorDeserializer.setJavaClassResolver(javaClassResolver);
annotationDescriptorDeserializer.setPsiClassFinder(psiClassFinder);
javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver);
javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices);
javaNamespaceResolver.setPsiClassFinder(psiClassFinder);
@@ -0,0 +1,164 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve.java.resolver;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.AnnotationVisitor;
import org.jetbrains.asm4.ClassReader;
import org.jetbrains.asm4.ClassVisitor;
import org.jetbrains.asm4.Opcodes;
import org.jetbrains.jet.descriptors.serialization.ProtoBuf;
import org.jetbrains.jet.descriptors.serialization.descriptors.AnnotationDeserializer;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils;
import org.jetbrains.jet.lang.resolve.java.PsiClassFinder;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.utils.ExceptionUtils;
import javax.inject.Inject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.jetbrains.asm4.ClassReader.*;
import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.ERROR_IF_FOUND_IN_KOTLIN;
import static org.jetbrains.jet.lang.resolve.java.resolver.DeserializedResolverUtils.*;
public class AnnotationDescriptorDeserializer implements AnnotationDeserializer {
private PsiClassFinder psiClassFinder;
private JavaClassResolver javaClassResolver;
@Inject
public void setPsiClassFinder(PsiClassFinder psiClassFinder) {
this.psiClassFinder = psiClassFinder;
}
@Inject
public void setJavaClassResolver(JavaClassResolver javaClassResolver) {
this.javaClassResolver = javaClassResolver;
}
@NotNull
@Override
public List<AnnotationDescriptor> loadClassAnnotations(
@NotNull ClassDescriptor descriptor,
@NotNull ProtoBuf.Class classProto
) {
FqName fqName = kotlinFqNameToJavaFqName(naiveKotlinFqName(descriptor));
PsiClass psiClass = psiClassFinder.findPsiClass(fqName, PsiClassFinder.RuntimeClassesHandleMode.IGNORE /* TODO: ?! */);
if (psiClass == null) {
throw new IllegalStateException("Psi class is not found for class: " + descriptor);
}
VirtualFile virtualFile = getVirtualFile(psiClass, fqName, (ClassOrNamespaceDescriptor) descriptor.getContainingDeclaration());
if (virtualFile == null) {
throw new IllegalStateException("Virtual file is not found for class: " + descriptor) ;
}
try {
return loadClassAnnotationsFromFile(virtualFile);
}
catch (IOException e) {
throw ExceptionUtils.rethrow(e);
}
}
@NotNull
private List<AnnotationDescriptor> loadClassAnnotationsFromFile(@NotNull VirtualFile virtualFile) throws IOException {
final List<AnnotationDescriptor> result = new ArrayList<AnnotationDescriptor>();
new ClassReader(virtualFile.getInputStream()).accept(new ClassVisitor(Opcodes.ASM4) {
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (ignoreAnnotation(desc)) return null;
FqName annotationFqName = convertJvmDescriptorToFqName(desc);
ClassDescriptor annotationClass = javaClassResolver.resolveClass(annotationFqName, ERROR_IF_FOUND_IN_KOTLIN);
assert annotationClass != null : "Annotation class is not found: " + desc;
return resolveAnnotation(annotationClass, result);
}
}, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES);
return result;
}
private static boolean ignoreAnnotation(@NotNull String desc) {
// TODO: JvmAbi.JETBRAINS_NOT_NULL_ANNOTATION ?
return desc.equals(DeserializedDescriptorResolver.KOTLIN_INFO_TYPE) || desc.startsWith("Ljet/runtime/typeinfo/");
}
@NotNull
private static FqName convertJvmDescriptorToFqName(@NotNull String desc) {
assert desc.startsWith("L") && desc.endsWith(";") : "Not a JVM descriptor: " + desc;
String fqName = desc.substring(1, desc.length() - 1).replace('$', '.').replace('/', '.');
return new FqName(fqName);
}
@NotNull
private static AnnotationVisitor resolveAnnotation(
@NotNull final ClassDescriptor annotationClass,
@NotNull final List<AnnotationDescriptor> result
) {
final AnnotationDescriptor annotation = new AnnotationDescriptor();
annotation.setAnnotationType(annotationClass.getDefaultType());
return new AnnotationVisitor(Opcodes.ASM4) {
// TODO: arrays, annotations, enums
@Override
public void visit(String name, Object value) {
ValueParameterDescriptor parameter =
DescriptorResolverUtils.getValueParameterDescriptorForAnnotationParameter(Name.identifier(name), annotationClass);
if (parameter != null) {
CompileTimeConstant<?> argument = JavaCompileTimeConstResolver.resolveCompileTimeConstantValue(value, null);
if (argument != null) {
annotation.setValueArgument(parameter, argument);
}
}
}
@Override
public void visitEnd() {
result.add(annotation);
}
};
}
@NotNull
@Override
public List<AnnotationDescriptor> loadCallableAnnotations(@NotNull ProtoBuf.Callable callableProto) {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public List<AnnotationDescriptor> loadValueParameterAnnotations(@NotNull ProtoBuf.Callable.ValueParameter parameterProto) {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public List<AnnotationDescriptor> loadSetterAnnotations(@NotNull ProtoBuf.Callable callableProto) {
throw new UnsupportedOperationException(); // TODO
}
}
@@ -24,69 +24,36 @@ import org.jetbrains.asm4.AnnotationVisitor;
import org.jetbrains.asm4.ClassReader;
import org.jetbrains.asm4.ClassVisitor;
import org.jetbrains.asm4.Opcodes;
import org.jetbrains.jet.descriptors.serialization.*;
import org.jetbrains.jet.descriptors.serialization.descriptors.AnnotationDeserializer;
import org.jetbrains.jet.descriptors.serialization.ClassData;
import org.jetbrains.jet.descriptors.serialization.ClassId;
import org.jetbrains.jet.descriptors.serialization.DescriptorFinder;
import org.jetbrains.jet.descriptors.serialization.PackageData;
import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedClassDescriptor;
import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedPackageMemberScope;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
import org.jetbrains.jet.lang.resolve.lazy.storage.LockBasedStorageManager;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.utils.ExceptionUtils;
import javax.inject.Inject;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.asm4.ClassReader.*;
import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.INCLUDE_KOTLIN;
import static org.jetbrains.jet.lang.resolve.java.resolver.DeserializedResolverUtils.getVirtualFile;
import static org.jetbrains.jet.lang.resolve.java.resolver.DeserializedResolverUtils.kotlinFqNameToJavaFqName;
public final class DeserializedDescriptorResolver {
public static final String KOTLIN_INFO_TYPE = JvmStdlibNames.KOTLIN_INFO_CLASS.getAsmType().toString();
private static final String KOTLIN_INFO_TYPE = JvmStdlibNames.KOTLIN_INFO_CLASS.getAsmType().toString();
private AnnotationDescriptorDeserializer annotationDeserializer;
public static final AnnotationDeserializer DUMMY_ANNOTATION_DESERIALIZER = new AnnotationDeserializer() {
@NotNull
@Override
public List<AnnotationDescriptor> loadClassAnnotations(@NotNull ProtoBuf.Class classProto) {
// This is a hack for tests: only data annotations are present in test data so far
AnnotationDescriptor annotationDescriptor = new AnnotationDescriptor();
annotationDescriptor.setAnnotationType(KotlinBuiltIns.getInstance().getDataClassAnnotation().getDefaultType());
return Collections.singletonList(annotationDescriptor);
}
@NotNull
@Override
public List<AnnotationDescriptor> loadCallableAnnotations(@NotNull ProtoBuf.Callable callableProto) {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public List<AnnotationDescriptor> loadSetterAnnotations(@NotNull ProtoBuf.Callable callableProto) {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public List<AnnotationDescriptor> loadValueParameterAnnotations(@NotNull ProtoBuf.Callable.ValueParameter parameterProto) {
throw new UnsupportedOperationException(); // TODO
}
};
@NotNull
private final LockBasedStorageManager storageManager = new LockBasedStorageManager();
private JavaNamespaceResolver javaNamespaceResolver;
@@ -102,6 +69,11 @@ public final class DeserializedDescriptorResolver {
}
};
@Inject
public void setAnnotationDeserializer(AnnotationDescriptorDeserializer annotationDeserializer) {
this.annotationDeserializer = annotationDeserializer;
}
@Inject
public void setJavaNamespaceResolver(JavaNamespaceResolver javaNamespaceResolver) {
this.javaNamespaceResolver = javaNamespaceResolver;
@@ -144,32 +116,7 @@ public final class DeserializedDescriptorResolver {
throw new IllegalStateException("No KotlinInfo annotation stored for " + fqName.asString());
}
return DeserializedPackageMemberScope.createScopeFromPackageData(packageDescriptor, packageData, javaDescriptorFinder,
DUMMY_ANNOTATION_DESERIALIZER, storageManager);
}
@Nullable
private static VirtualFile getVirtualFile(
@NotNull PsiClass psiClass,
@NotNull FqName classFqName,
@NotNull ClassOrNamespaceDescriptor containingDeclaration
) {
VirtualFile mostOuterClassVirtualFile = psiClass.getContainingFile().getVirtualFile();
if (mostOuterClassVirtualFile == null) {
throw new IllegalStateException("Could not find virtual file for " + classFqName.asString());
}
String fileExtension = mostOuterClassVirtualFile.getExtension();
if (fileExtension == null || !fileExtension.equals("class")) {
return null;
}
ClassId id = ClassId.fromFqNameAndContainingDeclaration(classFqName, containingDeclaration);
FqNameUnsafe relativeClassName = id.getRelativeClassName();
assert relativeClassName.isSafe() : "Relative class name " + relativeClassName.asString() + " should be safe at this point";
String classNameWithBucks = relativeClassName.asString().replace(".", "$") + ".class";
VirtualFile virtualFile = mostOuterClassVirtualFile.getParent().findChild(classNameWithBucks);
if (virtualFile == null) {
throw new IllegalStateException("No virtual file for " + classFqName.asString());
}
return virtualFile;
annotationDeserializer, storageManager);
}
@Nullable
@@ -187,7 +134,7 @@ public final class DeserializedDescriptorResolver {
assert owner != null : "No owner found for " + classId;
return new DeserializedClassDescriptor(classId, storageManager, owner, classData.getNameResolver(),
DUMMY_ANNOTATION_DESERIALIZER, javaDescriptorFinder, classData.getClassProto(), null);
annotationDeserializer, javaDescriptorFinder, classData.getClassProto(), null);
}
@Nullable
@@ -267,19 +214,4 @@ public final class DeserializedDescriptorResolver {
return data;
}
}
@NotNull
private static FqName kotlinFqNameToJavaFqName(@NotNull FqNameUnsafe kotlinFqName) {
List<String> correctedSegments = new ArrayList<String>();
for (Name segment : kotlinFqName.pathSegments()) {
if (segment.asString().startsWith("<class-object-for")) {
correctedSegments.add(JvmAbi.CLASS_OBJECT_CLASS_NAME);
}
else {
assert !segment.isSpecial();
correctedSegments.add(segment.asString());
}
}
return FqName.fromSegments(correctedSegments);
}
}
@@ -0,0 +1,94 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve.java.resolver;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.descriptors.serialization.ClassId;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
import org.jetbrains.jet.lang.resolve.name.Name;
import java.util.ArrayList;
import java.util.List;
public class DeserializedResolverUtils {
private DeserializedResolverUtils() {
}
@NotNull
public static FqName kotlinFqNameToJavaFqName(@NotNull FqNameUnsafe kotlinFqName) {
List<String> correctedSegments = new ArrayList<String>();
for (Name segment : kotlinFqName.pathSegments()) {
if (segment.asString().startsWith("<class-object-for")) {
correctedSegments.add(JvmAbi.CLASS_OBJECT_CLASS_NAME);
}
else {
assert !segment.isSpecial();
correctedSegments.add(segment.asString());
}
}
return FqName.fromSegments(correctedSegments);
}
@Nullable
public static VirtualFile getVirtualFile(
@NotNull PsiClass psiClass,
@NotNull FqName classFqName,
@NotNull ClassOrNamespaceDescriptor containingDeclaration
) {
VirtualFile mostOuterClassVirtualFile = psiClass.getContainingFile().getVirtualFile();
if (mostOuterClassVirtualFile == null) {
throw new IllegalStateException("Could not find virtual file for " + classFqName.asString());
}
String fileExtension = mostOuterClassVirtualFile.getExtension();
if (fileExtension == null || !fileExtension.equals("class")) {
return null;
}
ClassId id = ClassId.fromFqNameAndContainingDeclaration(classFqName, containingDeclaration);
FqNameUnsafe relativeClassName = id.getRelativeClassName();
assert relativeClassName.isSafe() : "Relative class name " + relativeClassName.asString() + " should be safe at this point";
String classNameWithBucks = relativeClassName.asString().replace(".", "$") + ".class";
VirtualFile virtualFile = mostOuterClassVirtualFile.getParent().findChild(classNameWithBucks);
if (virtualFile == null) {
throw new IllegalStateException("No virtual file for " + classFqName.asString());
}
return virtualFile;
}
@NotNull
public static FqNameUnsafe naiveKotlinFqName(@NotNull ClassDescriptor descriptor) {
DeclarationDescriptor containing = descriptor.getContainingDeclaration();
if (containing instanceof ClassDescriptor) {
return naiveKotlinFqName((ClassDescriptor) containing).child(descriptor.getName());
}
else if (containing instanceof NamespaceDescriptor) {
return DescriptorUtils.getFQName(containing).child(descriptor.getName());
}
else {
throw new IllegalArgumentException("Class doesn't have a FQ name: " + descriptor);
}
}
}
@@ -18,9 +18,11 @@ package org.jetbrains.jet.lang.resolve.java.resolver;
import com.google.common.collect.Lists;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.resolve.constants.*;
import org.jetbrains.jet.lang.resolve.constants.StringValue;
@@ -61,7 +63,7 @@ public final class JavaCompileTimeConstResolver {
PsiAnnotationMemberValue value, PostponedTasks postponedTasks
) {
if (value instanceof PsiLiteralExpression) {
return getCompileTimeConstFromLiteralExpression((PsiLiteralExpression) value);
return resolveCompileTimeConstantValue(((PsiLiteralExpression) value).getValue(), null);
}
// Enum
else if (value instanceof PsiReferenceExpression) {
@@ -165,54 +167,46 @@ public final class JavaCompileTimeConstResolver {
}
@Nullable
private static CompileTimeConstant<?> getCompileTimeConstFromLiteralExpression(PsiLiteralExpression value) {
return getCompileTimeConstFromLiteralExpressionWithExpectedType(value, null);
}
@Nullable
public static CompileTimeConstant<?> getCompileTimeConstFromLiteralExpressionWithExpectedType(
@NotNull PsiLiteralExpression value,
@Nullable JetType expectedType
) {
Object literalValue = value.getValue();
if (literalValue instanceof String) {
return new StringValue((String) literalValue);
public static CompileTimeConstant<?> resolveCompileTimeConstantValue(@Nullable Object value, @Nullable JetType expectedType) {
if (value instanceof String) {
return new StringValue((String) value);
}
else if (literalValue instanceof Byte) {
return new ByteValue((Byte) literalValue);
else if (value instanceof Byte) {
return new ByteValue((Byte) value);
}
else if (literalValue instanceof Short) {
return new ShortValue((Short) literalValue);
else if (value instanceof Short) {
return new ShortValue((Short) value);
}
else if (literalValue instanceof Character) {
return new CharValue((Character) literalValue);
else if (value instanceof Character) {
return new CharValue((Character) value);
}
else if (literalValue instanceof Integer) {
else if (value instanceof Integer) {
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
Integer integer = (Integer) value;
if (builtIns.getShortType().equals(expectedType)) {
return new ShortValue(((Integer) literalValue).shortValue());
return new ShortValue(integer.shortValue());
}
else if (builtIns.getByteType().equals(expectedType)) {
return new ByteValue(((Integer) literalValue).byteValue());
return new ByteValue(integer.byteValue());
}
else if (builtIns.getCharType().equals(expectedType)) {
return new CharValue((char) ((Integer)literalValue).intValue());
return new CharValue((char) integer.intValue());
}
return new IntValue((Integer) literalValue);
return new IntValue(integer);
}
else if (literalValue instanceof Long) {
return new LongValue((Long) literalValue);
else if (value instanceof Long) {
return new LongValue((Long) value);
}
else if (literalValue instanceof Float) {
return new FloatValue((Float) literalValue);
else if (value instanceof Float) {
return new FloatValue((Float) value);
}
else if (literalValue instanceof Double) {
return new DoubleValue((Double) literalValue);
else if (value instanceof Double) {
return new DoubleValue((Double) value);
}
else if (literalValue instanceof Boolean) {
return ((Boolean) literalValue) ? BooleanValue.TRUE : BooleanValue.FALSE;
else if (value instanceof Boolean) {
return BooleanValue.valueOf((Boolean) value);
}
else if (literalValue == null) {
else if (value == null) {
return NullValue.NULL;
}
return null;
@@ -17,7 +17,10 @@
package org.jetbrains.jet.lang.resolve.java.resolver;
import com.google.common.collect.Sets;
import com.intellij.psi.*;
import com.intellij.psi.PsiEnumConstant;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiLiteralExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
@@ -29,8 +32,8 @@ import org.jetbrains.jet.lang.resolve.java.*;
import org.jetbrains.jet.lang.resolve.java.kotlinSignature.AlternativeFieldSignatureData;
import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils;
import org.jetbrains.jet.lang.resolve.java.kt.JetMethodAnnotation;
import org.jetbrains.jet.lang.resolve.java.provider.PsiDeclarationProvider;
import org.jetbrains.jet.lang.resolve.java.provider.NamedMembers;
import org.jetbrains.jet.lang.resolve.java.provider.PsiDeclarationProvider;
import org.jetbrains.jet.lang.resolve.java.wrapper.*;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
@@ -217,8 +220,8 @@ public final class JavaPropertyResolver {
if (AnnotationUtils.isPropertyAcceptableAsAnnotationParameter(propertyDescriptor) && psiData.getCharacteristicPsi() instanceof PsiField) {
PsiExpression initializer = ((PsiField) psiData.getCharacteristicPsi()).getInitializer();
if (initializer instanceof PsiLiteralExpression) {
CompileTimeConstant<?> constant = JavaCompileTimeConstResolver.getCompileTimeConstFromLiteralExpressionWithExpectedType(
(PsiLiteralExpression) initializer, propertyType);
CompileTimeConstant<?> constant = JavaCompileTimeConstResolver
.resolveCompileTimeConstantValue(((PsiLiteralExpression) initializer).getValue(), propertyType);
if (constant != null) {
trace.record(BindingContext.COMPILE_TIME_INITIALIZER, propertyDescriptor, constant);
}