001/* 002 * Copyright 2010-2013 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 017package org.jetbrains.jet.lang.resolve.java.resolver; 018 019import com.google.common.collect.Lists; 020import com.intellij.psi.*; 021import org.jetbrains.annotations.Nullable; 022import org.jetbrains.jet.lang.descriptors.*; 023import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; 024import org.jetbrains.jet.lang.resolve.constants.*; 025import org.jetbrains.jet.lang.resolve.constants.StringValue; 026import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils; 027import org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule; 028import org.jetbrains.jet.lang.resolve.name.FqName; 029import org.jetbrains.jet.lang.resolve.name.Name; 030import org.jetbrains.jet.lang.resolve.scopes.JetScope; 031import org.jetbrains.jet.lang.types.JetType; 032import org.jetbrains.jet.lang.types.TypeProjection; 033 034import javax.inject.Inject; 035import java.util.ArrayList; 036import java.util.Collection; 037import java.util.List; 038 039public final class JavaCompileTimeConstResolver { 040 private JavaAnnotationResolver annotationResolver; 041 private JavaClassResolver classResolver; 042 043 public JavaCompileTimeConstResolver() { 044 } 045 046 @Inject 047 public void setAnnotationResolver(JavaAnnotationResolver annotationResolver) { 048 this.annotationResolver = annotationResolver; 049 } 050 051 @Inject 052 public void setClassResolver(JavaClassResolver classResolver) { 053 this.classResolver = classResolver; 054 } 055 056 @Nullable 057 public CompileTimeConstant<?> getCompileTimeConstFromExpression( 058 FqName annotationFqName, Name parameterName, 059 PsiAnnotationMemberValue value, PostponedTasks postponedTasks 060 ) { 061 if (value instanceof PsiLiteralExpression) { 062 return getCompileTimeConstFromLiteralExpression((PsiLiteralExpression) value); 063 } 064 // Enum 065 else if (value instanceof PsiReferenceExpression) { 066 return getCompileTimeConstFromReferenceExpression((PsiReferenceExpression) value, postponedTasks); 067 } 068 // Array 069 else if (value instanceof PsiArrayInitializerMemberValue) { 070 return getCompileTimeConstFromArrayExpression(annotationFqName, parameterName, (PsiArrayInitializerMemberValue) value, 071 postponedTasks); 072 } 073 // Annotation 074 else if (value instanceof PsiAnnotation) { 075 return getCompileTimeConstFromAnnotation((PsiAnnotation) value, postponedTasks); 076 } 077 return null; 078 } 079 080 @Nullable 081 private CompileTimeConstant<?> getCompileTimeConstFromAnnotation(PsiAnnotation value, PostponedTasks taskList) { 082 AnnotationDescriptor annotationDescriptor = annotationResolver.resolveAnnotation(value, taskList); 083 if (annotationDescriptor != null) { 084 return new AnnotationValue(annotationDescriptor); 085 } 086 return null; 087 } 088 089 @Nullable 090 private CompileTimeConstant<?> getCompileTimeConstFromArrayExpression( 091 FqName annotationFqName, 092 Name valueName, PsiArrayInitializerMemberValue value, 093 PostponedTasks taskList 094 ) { 095 PsiAnnotationMemberValue[] initializers = value.getInitializers(); 096 List<CompileTimeConstant<?>> values = getCompileTimeConstantForArrayValues(annotationFqName, valueName, taskList, initializers); 097 098 ClassDescriptor classDescriptor = 099 classResolver.resolveClass(annotationFqName, DescriptorSearchRule.INCLUDE_KOTLIN, taskList); 100 101 //TODO: nullability issues 102 ValueParameterDescriptor valueParameterDescriptor = 103 DescriptorResolverUtils.getValueParameterDescriptorForAnnotationParameter(valueName, classDescriptor); 104 if (valueParameterDescriptor == null) { 105 return null; 106 } 107 JetType expectedArrayType = valueParameterDescriptor.getType(); 108 return new ArrayValue(values, expectedArrayType); 109 } 110 111 private List<CompileTimeConstant<?>> getCompileTimeConstantForArrayValues( 112 FqName annotationQualifiedName, 113 Name valueName, 114 PostponedTasks taskList, 115 PsiAnnotationMemberValue[] initializers 116 ) { 117 List<CompileTimeConstant<?>> values = new ArrayList<CompileTimeConstant<?>>(); 118 for (PsiAnnotationMemberValue initializer : initializers) { 119 CompileTimeConstant<?> compileTimeConstant = 120 getCompileTimeConstFromExpression(annotationQualifiedName, valueName, initializer, taskList); 121 if (compileTimeConstant == null) { 122 compileTimeConstant = NullValue.NULL; 123 } 124 values.add(compileTimeConstant); 125 } 126 return values; 127 } 128 129 @Nullable 130 private CompileTimeConstant<?> getCompileTimeConstFromReferenceExpression(PsiReferenceExpression value, PostponedTasks taskList) { 131 PsiElement resolveElement = value.resolve(); 132 if (resolveElement instanceof PsiEnumConstant) { 133 PsiElement psiElement = resolveElement.getParent(); 134 if (psiElement instanceof PsiClass) { 135 PsiClass psiClass = (PsiClass) psiElement; 136 String fqName = psiClass.getQualifiedName(); 137 if (fqName == null) { 138 return null; 139 } 140 141 JetScope scope; 142 ClassDescriptor classDescriptor = classResolver.resolveClass(new FqName(fqName), DescriptorSearchRule.INCLUDE_KOTLIN, taskList); 143 if (classDescriptor == null) { 144 return null; 145 } 146 ClassDescriptor classObjectDescriptor = classDescriptor.getClassObjectDescriptor(); 147 if (classObjectDescriptor == null) { 148 return null; 149 } 150 scope = classObjectDescriptor.getMemberScope(Lists.<TypeProjection>newArrayList()); 151 152 Name identifier = Name.identifier(((PsiEnumConstant) resolveElement).getName()); 153 Collection<VariableDescriptor> properties = scope.getProperties(identifier); 154 for (VariableDescriptor variableDescriptor : properties) { 155 if (variableDescriptor.getReceiverParameter() == null) { 156 return new EnumValue((PropertyDescriptor) variableDescriptor); 157 } 158 } 159 return null; 160 } 161 } 162 return null; 163 } 164 165 @Nullable 166 private static CompileTimeConstant<?> getCompileTimeConstFromLiteralExpression(PsiLiteralExpression value) { 167 Object literalValue = value.getValue(); 168 if (literalValue instanceof String) { 169 return new StringValue((String) literalValue); 170 } 171 else if (literalValue instanceof Byte) { 172 return new ByteValue((Byte) literalValue); 173 } 174 else if (literalValue instanceof Short) { 175 return new ShortValue((Short) literalValue); 176 } 177 else if (literalValue instanceof Character) { 178 return new CharValue((Character) literalValue); 179 } 180 else if (literalValue instanceof Integer) { 181 return new IntValue((Integer) literalValue); 182 } 183 else if (literalValue instanceof Long) { 184 return new LongValue((Long) literalValue); 185 } 186 else if (literalValue instanceof Float) { 187 return new FloatValue((Float) literalValue); 188 } 189 else if (literalValue instanceof Double) { 190 return new DoubleValue((Double) literalValue); 191 } 192 else if (literalValue == null) { 193 return NullValue.NULL; 194 } 195 return null; 196 } 197}