001 /* 002 * Copyright 2010-2015 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.kotlin.resolve; 018 019 import com.google.common.collect.Lists; 020 import com.intellij.openapi.util.Pair; 021 import kotlin.Function1; 022 import kotlin.KotlinPackage; 023 import org.jetbrains.annotations.NotNull; 024 import org.jetbrains.annotations.Nullable; 025 import org.jetbrains.kotlin.descriptors.*; 026 import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; 027 import org.jetbrains.kotlin.descriptors.annotations.Annotations; 028 import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl; 029 import org.jetbrains.kotlin.diagnostics.Errors; 030 import org.jetbrains.kotlin.psi.*; 031 import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver; 032 import org.jetbrains.kotlin.resolve.calls.CallResolver; 033 import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage; 034 import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker; 035 import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker; 036 import org.jetbrains.kotlin.resolve.calls.checkers.CompositeChecker; 037 import org.jetbrains.kotlin.resolve.calls.context.ContextDependency; 038 import org.jetbrains.kotlin.resolve.calls.context.SimpleResolutionContext; 039 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; 040 import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument; 041 import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults; 042 import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; 043 import org.jetbrains.kotlin.resolve.calls.util.CallMaker; 044 import org.jetbrains.kotlin.resolve.constants.ArrayValue; 045 import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; 046 import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant; 047 import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator; 048 import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor; 049 import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationsContextImpl; 050 import org.jetbrains.kotlin.resolve.scopes.JetScope; 051 import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; 052 import org.jetbrains.kotlin.storage.StorageManager; 053 import org.jetbrains.kotlin.types.ErrorUtils; 054 import org.jetbrains.kotlin.types.JetType; 055 import org.jetbrains.kotlin.types.checker.JetTypeChecker; 056 057 import javax.inject.Inject; 058 import java.util.HashMap; 059 import java.util.List; 060 import java.util.Map; 061 062 import static org.jetbrains.kotlin.diagnostics.Errors.NOT_AN_ANNOTATION_CLASS; 063 import static org.jetbrains.kotlin.resolve.BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT; 064 import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE; 065 066 public class AnnotationResolver { 067 068 private CallResolver callResolver; 069 private StorageManager storageManager; 070 private TypeResolver typeResolver; 071 072 @Inject 073 public void setCallResolver(CallResolver callResolver) { 074 this.callResolver = callResolver; 075 } 076 077 @Inject 078 public void setStorageManager(StorageManager storageManager) { 079 this.storageManager = storageManager; 080 } 081 082 @Inject 083 public void setTypeResolver(TypeResolver typeResolver) { 084 this.typeResolver = typeResolver; 085 } 086 087 @NotNull 088 public Annotations resolveAnnotationsWithoutArguments( 089 @NotNull JetScope scope, 090 @Nullable JetModifierList modifierList, 091 @NotNull BindingTrace trace 092 ) { 093 return resolveAnnotations(scope, modifierList, trace, false); 094 } 095 096 @NotNull 097 public Annotations resolveAnnotationsWithArguments( 098 @NotNull JetScope scope, 099 @Nullable JetModifierList modifierList, 100 @NotNull BindingTrace trace 101 ) { 102 return resolveAnnotations(scope, modifierList, trace, true); 103 } 104 105 @NotNull 106 public Annotations resolveAnnotationsWithArguments( 107 @NotNull JetScope scope, 108 @NotNull List<JetAnnotationEntry> annotationEntries, 109 @NotNull BindingTrace trace 110 ) { 111 return resolveAnnotationEntries(scope, annotationEntries, trace, true); 112 } 113 114 private Annotations resolveAnnotations( 115 @NotNull JetScope scope, 116 @Nullable JetModifierList modifierList, 117 @NotNull BindingTrace trace, 118 boolean shouldResolveArguments 119 ) { 120 if (modifierList == null) { 121 return Annotations.EMPTY; 122 } 123 List<JetAnnotationEntry> annotationEntryElements = modifierList.getAnnotationEntries(); 124 125 return resolveAnnotationEntries(scope, annotationEntryElements, trace, shouldResolveArguments); 126 } 127 128 private Annotations resolveAnnotationEntries( 129 @NotNull JetScope scope, 130 @NotNull List<JetAnnotationEntry> annotationEntryElements, 131 @NotNull BindingTrace trace, 132 boolean shouldResolveArguments 133 ) { 134 if (annotationEntryElements.isEmpty()) return Annotations.EMPTY; 135 List<AnnotationDescriptor> result = Lists.newArrayList(); 136 for (JetAnnotationEntry entryElement : annotationEntryElements) { 137 AnnotationDescriptor descriptor = trace.get(BindingContext.ANNOTATION, entryElement); 138 if (descriptor == null) { 139 descriptor = new LazyAnnotationDescriptor(new LazyAnnotationsContextImpl(this, storageManager, trace, scope), entryElement); 140 } 141 if (shouldResolveArguments) { 142 resolveAnnotationArguments(entryElement, trace); 143 } 144 145 result.add(descriptor); 146 } 147 return new AnnotationsImpl(result); 148 } 149 150 @NotNull 151 public JetType resolveAnnotationType(@NotNull JetScope scope, @NotNull JetAnnotationEntry entryElement) { 152 JetTypeReference typeReference = entryElement.getTypeReference(); 153 if (typeReference == null) { 154 return ErrorUtils.createErrorType("No type reference: " + entryElement.getText()); 155 } 156 157 JetType type = typeResolver.resolveType(scope, typeReference, new BindingTraceContext(), true); 158 if (!(type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor)) { 159 return ErrorUtils.createErrorType("Not an annotation: " + type); 160 } 161 return type; 162 } 163 164 public static void checkAnnotationType( 165 @NotNull JetAnnotationEntry entryElement, 166 @NotNull BindingTrace trace, 167 @NotNull OverloadResolutionResults<FunctionDescriptor> results 168 ) { 169 if (!results.isSingleResult()) return; 170 FunctionDescriptor descriptor = results.getResultingDescriptor(); 171 if (!ErrorUtils.isError(descriptor)) { 172 if (descriptor instanceof ConstructorDescriptor) { 173 ConstructorDescriptor constructor = (ConstructorDescriptor)descriptor; 174 ClassDescriptor classDescriptor = constructor.getContainingDeclaration(); 175 if (classDescriptor.getKind() != ClassKind.ANNOTATION_CLASS) { 176 trace.report(NOT_AN_ANNOTATION_CLASS.on(entryElement, classDescriptor)); 177 } 178 } 179 else { 180 trace.report(NOT_AN_ANNOTATION_CLASS.on(entryElement, descriptor)); 181 } 182 } 183 } 184 185 @NotNull 186 public OverloadResolutionResults<FunctionDescriptor> resolveAnnotationCall( 187 JetAnnotationEntry annotationEntry, 188 JetScope scope, 189 BindingTrace trace 190 ) { 191 return callResolver.resolveFunctionCall( 192 trace, scope, 193 CallMaker.makeCall(ReceiverValue.NO_RECEIVER, null, annotationEntry), 194 NO_EXPECTED_TYPE, 195 DataFlowInfo.EMPTY, 196 true 197 ); 198 } 199 200 public static void resolveAnnotationsArguments(@Nullable JetModifierList modifierList, @NotNull BindingTrace trace) { 201 if (modifierList == null) { 202 return; 203 } 204 205 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) { 206 resolveAnnotationArguments(annotationEntry, trace); 207 } 208 } 209 210 public static void resolveAnnotationsArguments(@NotNull Annotations annotations, @NotNull BindingTrace trace) { 211 for (AnnotationDescriptor annotationDescriptor : annotations) { 212 JetAnnotationEntry annotationEntry = trace.getBindingContext().get(ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotationDescriptor); 213 assert annotationEntry != null : "Cannot find annotation entry: " + annotationDescriptor; 214 resolveAnnotationArguments(annotationEntry, trace); 215 } 216 } 217 218 private static void resolveAnnotationArguments( 219 @NotNull JetAnnotationEntry annotationEntry, 220 @NotNull BindingTrace trace 221 ) { 222 AnnotationDescriptor annotationDescriptor = trace.getBindingContext().get(BindingContext.ANNOTATION, annotationEntry); 223 assert annotationDescriptor != null : "Annotation descriptor should be created before resolving arguments for " + annotationEntry.getText(); 224 if (annotationDescriptor instanceof LazyAnnotationDescriptor) { 225 ((LazyAnnotationDescriptor) annotationDescriptor).forceResolveAllContents(); 226 } 227 } 228 229 @NotNull 230 public static Map<ValueParameterDescriptor, CompileTimeConstant<?>> resolveAnnotationArguments( 231 @NotNull ResolvedCall<?> resolvedCall, 232 @NotNull BindingTrace trace 233 ) { 234 Map<ValueParameterDescriptor, CompileTimeConstant<?>> arguments = new HashMap<ValueParameterDescriptor, CompileTimeConstant<?>>(); 235 for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> descriptorToArgument : resolvedCall.getValueArguments().entrySet()) { 236 ValueParameterDescriptor parameterDescriptor = descriptorToArgument.getKey(); 237 ResolvedValueArgument resolvedArgument = descriptorToArgument.getValue(); 238 239 CompileTimeConstant<?> value = getAnnotationArgumentValue(trace, parameterDescriptor, resolvedArgument); 240 if (value != null) { 241 arguments.put(parameterDescriptor, value); 242 } 243 } 244 return arguments; 245 } 246 247 @Nullable 248 public static CompileTimeConstant<?> getAnnotationArgumentValue( 249 BindingTrace trace, 250 ValueParameterDescriptor parameterDescriptor, 251 ResolvedValueArgument resolvedArgument 252 ) { 253 JetType varargElementType = parameterDescriptor.getVarargElementType(); 254 boolean argumentsAsVararg = varargElementType != null && !hasSpread(resolvedArgument); 255 List<CompileTimeConstant<?>> constants = resolveValueArguments( 256 resolvedArgument, argumentsAsVararg ? varargElementType : parameterDescriptor.getType(), trace); 257 258 if (argumentsAsVararg) { 259 260 boolean usesVariableAsConstant = KotlinPackage.any(constants, new Function1<CompileTimeConstant<?>, Boolean>() { 261 @Override 262 public Boolean invoke(CompileTimeConstant<?> constant) { 263 return constant.usesVariableAsConstant(); 264 } 265 }); 266 267 return new ArrayValue(constants, parameterDescriptor.getType(), true, usesVariableAsConstant); 268 } 269 else { 270 // we should actually get only one element, but just in case of getting many, we take the last one 271 return !constants.isEmpty() ? KotlinPackage.last(constants) : null; 272 } 273 } 274 275 private static void checkCompileTimeConstant( 276 @NotNull JetExpression argumentExpression, 277 @NotNull JetType expectedType, 278 @NotNull BindingTrace trace 279 ) { 280 JetType expressionType = trace.get(BindingContext.EXPRESSION_TYPE, argumentExpression); 281 282 if (expressionType == null || !JetTypeChecker.DEFAULT.isSubtypeOf(expressionType, expectedType)) { 283 // TYPE_MISMATCH should be reported otherwise 284 return; 285 } 286 287 // array(1, <!>null<!>, 3) - error should be reported on inner expression 288 if (argumentExpression instanceof JetCallExpression) { 289 Pair<List<JetExpression>, JetType> arrayArgument = getArgumentExpressionsForArrayCall((JetCallExpression) argumentExpression, trace); 290 if (arrayArgument != null) { 291 for (JetExpression expression : arrayArgument.getFirst()) { 292 checkCompileTimeConstant(expression, arrayArgument.getSecond(), trace); 293 } 294 } 295 } 296 297 CompileTimeConstant<?> constant = trace.get(BindingContext.COMPILE_TIME_VALUE, argumentExpression); 298 if (constant != null && constant.canBeUsedInAnnotations()) { 299 return; 300 } 301 302 ClassifierDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor(); 303 if (descriptor != null && DescriptorUtils.isEnumClass(descriptor)) { 304 trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST.on(argumentExpression)); 305 } 306 else if (descriptor instanceof ClassDescriptor && CompileTimeConstantUtils.isJavaLangClass((ClassDescriptor) descriptor)) { 307 trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CLASS_LITERAL.on(argumentExpression)); 308 } 309 else { 310 trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CONST.on(argumentExpression)); 311 } 312 } 313 314 @Nullable 315 private static Pair<List<JetExpression>, JetType> getArgumentExpressionsForArrayCall( 316 @NotNull JetCallExpression expression, 317 @NotNull BindingTrace trace 318 ) { 319 ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, trace.getBindingContext()); 320 if (resolvedCall == null || !CompileTimeConstantUtils.isArrayMethodCall(resolvedCall)) { 321 return null; 322 } 323 324 assert resolvedCall.getValueArguments().size() == 1 : "Array function should have only one vararg parameter"; 325 Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> argumentEntry = resolvedCall.getValueArguments().entrySet().iterator().next(); 326 327 List<JetExpression> result = Lists.newArrayList(); 328 JetType elementType = argumentEntry.getKey().getVarargElementType(); 329 for (ValueArgument valueArgument : argumentEntry.getValue().getArguments()) { 330 JetExpression valueArgumentExpression = valueArgument.getArgumentExpression(); 331 if (valueArgumentExpression != null) { 332 if (elementType != null) { 333 result.add(valueArgumentExpression); 334 } 335 } 336 } 337 return new Pair<List<JetExpression>, JetType>(result, elementType); 338 } 339 340 private static boolean hasSpread(@NotNull ResolvedValueArgument argument) { 341 List<ValueArgument> arguments = argument.getArguments(); 342 return arguments.size() == 1 && arguments.get(0).getSpreadElement() != null; 343 } 344 345 @NotNull 346 private static List<CompileTimeConstant<?>> resolveValueArguments( 347 @NotNull ResolvedValueArgument resolvedValueArgument, 348 @NotNull JetType expectedType, 349 @NotNull BindingTrace trace 350 ) { 351 List<CompileTimeConstant<?>> constants = Lists.newArrayList(); 352 for (ValueArgument argument : resolvedValueArgument.getArguments()) { 353 JetExpression argumentExpression = argument.getArgumentExpression(); 354 if (argumentExpression != null) { 355 CompileTimeConstant<?> constant = ConstantExpressionEvaluator.evaluate(argumentExpression, trace, expectedType); 356 if (constant instanceof IntegerValueTypeConstant) { 357 JetType defaultType = ((IntegerValueTypeConstant) constant).getType(expectedType); 358 SimpleResolutionContext context = 359 new SimpleResolutionContext(trace, JetScope.Empty.INSTANCE$, NO_EXPECTED_TYPE, DataFlowInfo.EMPTY, 360 ContextDependency.INDEPENDENT, 361 new CompositeChecker(Lists.<CallChecker>newArrayList()), 362 new AdditionalTypeChecker.Composite(Lists.<AdditionalTypeChecker>newArrayList()), 363 StatementFilter.NONE); 364 ArgumentTypeResolver.updateNumberType(defaultType, argumentExpression, context); 365 } 366 if (constant != null) { 367 constants.add(constant); 368 } 369 checkCompileTimeConstant(argumentExpression, expectedType, trace); 370 } 371 } 372 return constants; 373 } 374 375 public static void reportUnsupportedAnnotationForTypeParameter(@NotNull JetTypeParameter jetTypeParameter, @NotNull BindingTrace trace) { 376 JetModifierList modifierList = jetTypeParameter.getModifierList(); 377 if (modifierList == null) return; 378 379 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) { 380 trace.report(Errors.UNSUPPORTED.on(annotationEntry, "Annotations for type parameters are not supported yet")); 381 } 382 } 383 }