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.load.java.sam; 018 019 import org.jetbrains.annotations.NotNull; 020 import org.jetbrains.annotations.Nullable; 021 import org.jetbrains.kotlin.builtins.KotlinBuiltIns; 022 import org.jetbrains.kotlin.descriptors.*; 023 import org.jetbrains.kotlin.descriptors.annotations.Annotations; 024 import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl; 025 import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl; 026 import org.jetbrains.kotlin.load.java.components.DescriptorResolverUtils; 027 import org.jetbrains.kotlin.load.java.descriptors.*; 028 import org.jetbrains.kotlin.load.java.lazy.types.LazyJavaTypeResolver; 029 import org.jetbrains.kotlin.load.java.structure.*; 030 import org.jetbrains.kotlin.name.FqName; 031 import org.jetbrains.kotlin.name.Name; 032 import org.jetbrains.kotlin.resolve.DescriptorUtils; 033 import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; 034 import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolverKt; 035 import org.jetbrains.kotlin.resolve.jvm.JavaResolverUtils; 036 import org.jetbrains.kotlin.types.*; 037 038 import java.util.*; 039 040 import static org.jetbrains.kotlin.types.Variance.INVARIANT; 041 042 public class SingleAbstractMethodUtils { 043 private SingleAbstractMethodUtils() { 044 } 045 046 @NotNull 047 public static List<CallableMemberDescriptor> getAbstractMembers(@NotNull KotlinType type) { 048 List<CallableMemberDescriptor> abstractMembers = new ArrayList<CallableMemberDescriptor>(); 049 for (DeclarationDescriptor member : DescriptorUtils.getAllDescriptors(type.getMemberScope())) { 050 if (member instanceof CallableMemberDescriptor && ((CallableMemberDescriptor) member).getModality() == Modality.ABSTRACT) { 051 abstractMembers.add((CallableMemberDescriptor) member); 052 } 053 } 054 return abstractMembers; 055 } 056 057 private static KotlinType fixProjections(@NotNull KotlinType functionType) { 058 //removes redundant projection kinds and detects conflicts 059 060 List<TypeParameterDescriptor> typeParameters = functionType.getConstructor().getParameters(); 061 List<TypeProjection> arguments = new ArrayList<TypeProjection>(typeParameters.size()); 062 for (TypeParameterDescriptor typeParameter : typeParameters) { 063 Variance variance = typeParameter.getVariance(); 064 TypeProjection argument = functionType.getArguments().get(typeParameter.getIndex()); 065 Variance kind = argument.getProjectionKind(); 066 if (kind != INVARIANT && variance != INVARIANT) { 067 if (kind == variance) { 068 arguments.add(new TypeProjectionImpl(argument.getType())); 069 } 070 else { 071 return null; 072 } 073 } 074 else { 075 arguments.add(argument); 076 } 077 } 078 ClassifierDescriptor classifier = functionType.getConstructor().getDeclarationDescriptor(); 079 assert classifier instanceof ClassDescriptor : "Not class: " + classifier; 080 return KotlinTypeImpl.create( 081 functionType.getAnnotations(), 082 functionType.getConstructor(), 083 functionType.isMarkedNullable(), 084 arguments, 085 ((ClassDescriptor) classifier).getMemberScope(arguments) 086 ); 087 } 088 089 @Nullable 090 public static KotlinType getFunctionTypeForSamType(@NotNull KotlinType samType) { 091 // e.g. samType == Comparator<String>? 092 093 ClassifierDescriptor classifier = samType.getConstructor().getDeclarationDescriptor(); 094 if (classifier instanceof JavaClassDescriptor) { 095 // Function2<T, T, Int> 096 KotlinType functionTypeDefault = ((JavaClassDescriptor) classifier).getFunctionTypeForSamInterface(); 097 098 if (functionTypeDefault != null) { 099 // Function2<String, String, Int>? 100 KotlinType substitute = TypeSubstitutor.create(samType).substitute(functionTypeDefault, Variance.INVARIANT); 101 102 if (substitute == null) return null; 103 104 KotlinType type = fixProjections(substitute); 105 if (type == null) return null; 106 107 if (JavaDescriptorResolverKt.getPLATFORM_TYPES() && FlexibleTypesKt.isNullabilityFlexible(samType)) { 108 return LazyJavaTypeResolver.FlexibleJavaClassifierTypeCapabilities.create(type, TypeUtils.makeNullable(type)); 109 } 110 111 return TypeUtils.makeNullableAsSpecified(type, samType.isMarkedNullable()); 112 } 113 } 114 return null; 115 } 116 117 @NotNull 118 public static KotlinType getFunctionTypeForAbstractMethod(@NotNull FunctionDescriptor function) { 119 KotlinType returnType = function.getReturnType(); 120 assert returnType != null : "function is not initialized: " + function; 121 List<ValueParameterDescriptor> valueParameters = function.getValueParameters(); 122 List<KotlinType> parameterTypes = new ArrayList<KotlinType>(valueParameters.size()); 123 for (ValueParameterDescriptor parameter : valueParameters) { 124 parameterTypes.add(parameter.getType()); 125 } 126 return DescriptorUtilsKt.getBuiltIns(function).getFunctionType(Annotations.Companion.getEMPTY(), null, parameterTypes, returnType); 127 } 128 129 private static boolean isSamInterface(@NotNull ClassDescriptor klass) { 130 if (klass.getKind() != ClassKind.INTERFACE) { 131 return false; 132 } 133 134 List<CallableMemberDescriptor> abstractMembers = getAbstractMembers(klass.getDefaultType()); 135 if (abstractMembers.size() == 1) { 136 CallableMemberDescriptor member = abstractMembers.get(0); 137 if (member instanceof SimpleFunctionDescriptor) { 138 return member.getTypeParameters().isEmpty(); 139 } 140 } 141 return false; 142 } 143 144 @NotNull 145 public static SamConstructorDescriptor createSamConstructorFunction( 146 @NotNull DeclarationDescriptor owner, 147 @NotNull JavaClassDescriptor samInterface 148 ) { 149 assert isSamInterface(samInterface) : samInterface; 150 151 SamConstructorDescriptor result = new SamConstructorDescriptor(owner, samInterface); 152 153 TypeParameters typeParameters = recreateAndInitializeTypeParameters(samInterface.getTypeConstructor().getParameters(), result); 154 155 KotlinType parameterTypeUnsubstituted = getFunctionTypeForSamType(samInterface.getDefaultType()); 156 assert parameterTypeUnsubstituted != null : "couldn't get function type for SAM type " + samInterface.getDefaultType(); 157 KotlinType parameterType = typeParameters.substitutor.substitute(parameterTypeUnsubstituted, Variance.IN_VARIANCE); 158 assert parameterType != null : "couldn't substitute type: " + parameterTypeUnsubstituted + 159 ", substitutor = " + typeParameters.substitutor; 160 ValueParameterDescriptor parameter = new ValueParameterDescriptorImpl( 161 result, null, 0, Annotations.Companion.getEMPTY(), Name.identifier("function"), parameterType, 162 /* declaresDefaultValue = */ false, 163 /* isCrossinline = */ false, 164 /* isNoinline = */ false, 165 null, SourceElement.NO_SOURCE); 166 167 KotlinType returnType = typeParameters.substitutor.substitute(samInterface.getDefaultType(), Variance.OUT_VARIANCE); 168 assert returnType != null : "couldn't substitute type: " + samInterface.getDefaultType() + 169 ", substitutor = " + typeParameters.substitutor; 170 171 result.initialize( 172 null, 173 null, 174 typeParameters.descriptors, 175 Arrays.asList(parameter), 176 returnType, 177 Modality.FINAL, 178 samInterface.getVisibility() 179 ); 180 181 return result; 182 } 183 184 public static boolean isSamType(@NotNull KotlinType type) { 185 return getFunctionTypeForSamType(type) != null; 186 } 187 188 public static boolean isSamAdapterNecessary(@NotNull FunctionDescriptor fun) { 189 for (ValueParameterDescriptor param : fun.getValueParameters()) { 190 if (isSamType(param.getType())) { 191 return true; 192 } 193 } 194 return false; 195 } 196 197 @NotNull 198 public static SamAdapterDescriptor<JavaMethodDescriptor> createSamAdapterFunction(@NotNull final JavaMethodDescriptor original) { 199 final SamAdapterFunctionDescriptor result = new SamAdapterFunctionDescriptor(original); 200 return initSamAdapter(original, result, new FunctionInitializer() { 201 @Override 202 public void initialize( 203 @NotNull List<TypeParameterDescriptor> typeParameters, 204 @NotNull List<ValueParameterDescriptor> valueParameters, 205 @NotNull KotlinType returnType 206 ) { 207 result.initialize( 208 null, 209 original.getDispatchReceiverParameter(), 210 typeParameters, 211 valueParameters, 212 returnType, 213 Modality.FINAL, 214 original.getVisibility() 215 ); 216 } 217 }); 218 } 219 220 @NotNull 221 public static SamAdapterDescriptor<JavaConstructorDescriptor> createSamAdapterConstructor(@NotNull final JavaConstructorDescriptor original) { 222 final SamAdapterConstructorDescriptor result = new SamAdapterConstructorDescriptor(original); 223 return initSamAdapter(original, result, new FunctionInitializer() { 224 @Override 225 public void initialize( 226 @NotNull List<TypeParameterDescriptor> typeParameters, 227 @NotNull List<ValueParameterDescriptor> valueParameters, 228 @NotNull KotlinType returnType 229 ) { 230 result.initialize(typeParameters, valueParameters, original.getVisibility()); 231 result.setReturnType(returnType); 232 } 233 }); 234 } 235 236 @NotNull 237 private static <F extends FunctionDescriptor> SamAdapterDescriptor<F> initSamAdapter( 238 @NotNull F original, 239 @NotNull SamAdapterDescriptor<F> adapter, 240 @NotNull FunctionInitializer initializer 241 ) { 242 TypeParameters typeParameters = recreateAndInitializeTypeParameters(original.getTypeParameters(), adapter); 243 244 KotlinType returnTypeUnsubstituted = original.getReturnType(); 245 assert returnTypeUnsubstituted != null : "Creating SAM adapter for not initialized original: " + original; 246 247 TypeSubstitutor substitutor = typeParameters.substitutor; 248 KotlinType returnType = substitutor.substitute(returnTypeUnsubstituted, Variance.INVARIANT); 249 assert returnType != null : "couldn't substitute type: " + returnTypeUnsubstituted + 250 ", substitutor = " + substitutor; 251 252 253 List<ValueParameterDescriptor> valueParameters = createValueParametersForSamAdapter(original, adapter, substitutor); 254 255 initializer.initialize(typeParameters.descriptors, valueParameters, returnType); 256 257 return adapter; 258 } 259 260 public static List<ValueParameterDescriptor> createValueParametersForSamAdapter( 261 @NotNull FunctionDescriptor original, 262 @NotNull FunctionDescriptor samAdapter, 263 @NotNull TypeSubstitutor substitutor 264 ) { 265 List<ValueParameterDescriptor> originalValueParameters = original.getValueParameters(); 266 List<ValueParameterDescriptor> valueParameters = new ArrayList<ValueParameterDescriptor>(originalValueParameters.size()); 267 for (ValueParameterDescriptor originalParam : originalValueParameters) { 268 KotlinType originalType = originalParam.getType(); 269 KotlinType functionType = getFunctionTypeForSamType(originalType); 270 KotlinType newTypeUnsubstituted = functionType != null ? functionType : originalType; 271 KotlinType newType = substitutor.substitute(newTypeUnsubstituted, Variance.IN_VARIANCE); 272 assert newType != null : "couldn't substitute type: " + newTypeUnsubstituted + ", substitutor = " + substitutor; 273 274 ValueParameterDescriptor newParam = new ValueParameterDescriptorImpl( 275 samAdapter, null, originalParam.getIndex(), originalParam.getAnnotations(), 276 originalParam.getName(), newType, 277 /* declaresDefaultValue = */ false, 278 /* isCrossinline = */ false, 279 /* isNoinline = */ false, 280 null, SourceElement.NO_SOURCE 281 ); 282 valueParameters.add(newParam); 283 } 284 return valueParameters; 285 } 286 287 @NotNull 288 private static TypeParameters recreateAndInitializeTypeParameters( 289 @NotNull List<TypeParameterDescriptor> originalParameters, 290 @Nullable DeclarationDescriptor newOwner 291 ) { 292 Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> traitToFunTypeParameters = 293 JavaResolverUtils.recreateTypeParametersAndReturnMapping(originalParameters, newOwner); 294 TypeSubstitutor typeParametersSubstitutor = JavaResolverUtils.createSubstitutorForTypeParameters(traitToFunTypeParameters); 295 for (Map.Entry<TypeParameterDescriptor, TypeParameterDescriptorImpl> mapEntry : traitToFunTypeParameters.entrySet()) { 296 TypeParameterDescriptor traitTypeParameter = mapEntry.getKey(); 297 TypeParameterDescriptorImpl funTypeParameter = mapEntry.getValue(); 298 299 for (KotlinType upperBound : traitTypeParameter.getUpperBounds()) { 300 KotlinType upperBoundSubstituted = typeParametersSubstitutor.substitute(upperBound, Variance.INVARIANT); 301 assert upperBoundSubstituted != null : "couldn't substitute type: " + upperBound + ", substitutor = " + typeParametersSubstitutor; 302 funTypeParameter.addUpperBound(upperBoundSubstituted); 303 } 304 305 funTypeParameter.setInitialized(); 306 } 307 308 List<TypeParameterDescriptor> typeParameters = new ArrayList<TypeParameterDescriptor>(traitToFunTypeParameters.values()); 309 return new TypeParameters(typeParameters, typeParametersSubstitutor); 310 } 311 312 // Returns null if not SAM interface 313 @Nullable 314 public static JavaMethod getSamInterfaceMethod(@NotNull JavaClass javaClass) { 315 FqName fqName = javaClass.getFqName(); 316 if (fqName == null || fqName.toUnsafe().startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME)) { 317 return null; 318 } 319 if (!javaClass.isInterface() || javaClass.isAnnotationType()) { 320 return null; 321 } 322 323 return findOnlyAbstractMethod(javaClass); 324 } 325 326 @Nullable 327 private static JavaMethod findOnlyAbstractMethod(@NotNull JavaClass javaClass) { 328 OnlyAbstractMethodFinder finder = new OnlyAbstractMethodFinder(); 329 if (finder.find(javaClass.getDefaultType())) { 330 return finder.getFoundMethod(); 331 } 332 return null; 333 } 334 335 private static class TypeParameters { 336 public final List<TypeParameterDescriptor> descriptors; 337 public final TypeSubstitutor substitutor; 338 339 private TypeParameters(List<TypeParameterDescriptor> descriptors, TypeSubstitutor substitutor) { 340 this.descriptors = descriptors; 341 this.substitutor = substitutor; 342 } 343 } 344 345 private static abstract class FunctionInitializer { 346 public abstract void initialize( 347 @NotNull List<TypeParameterDescriptor> typeParameters, 348 @NotNull List<ValueParameterDescriptor> valueParameters, 349 @NotNull KotlinType returnType 350 ); 351 } 352 353 private static class OnlyAbstractMethodFinder { 354 private static final FqName OBJECT_FQ_NAME = new FqName("java.lang.Object"); 355 356 private JavaMethod foundMethod; 357 private JavaTypeSubstitutor foundClassSubstitutor; 358 359 private boolean find(@NotNull JavaClassifierType classifierType) { 360 JavaTypeSubstitutor classSubstitutor = classifierType.getSubstitutor(); 361 JavaClassifier classifier = classifierType.getClassifier(); 362 if (classifier == null) { 363 return false; // can't resolve class -> not a SAM interface 364 } 365 assert classifier instanceof JavaClass : "Classifier should be a class here: " + classifier; 366 JavaClass javaClass = (JavaClass) classifier; 367 if (OBJECT_FQ_NAME.equals(javaClass.getFqName())) { 368 return true; 369 } 370 for (JavaMethod method : javaClass.getMethods()) { 371 372 //skip java 8 default methods 373 if (!method.isAbstract()) { 374 continue; 375 } 376 377 if (DescriptorResolverUtils.isObjectMethod(method)) { // e.g., ignore toString() declared in interface 378 continue; 379 } 380 if (!method.getTypeParameters().isEmpty()) { 381 return false; // if interface has generic methods, it is not a SAM interface 382 } 383 384 if (foundMethod == null) { 385 foundMethod = method; 386 foundClassSubstitutor = classSubstitutor; 387 continue; 388 } 389 390 if (!areSignaturesErasureEqual(method, classSubstitutor, foundMethod, foundClassSubstitutor)) { 391 return false; // different signatures 392 } 393 } 394 395 for (JavaClassifierType t : classifierType.getSupertypes()) { 396 if (!find(t)) { 397 return false; 398 } 399 } 400 401 return true; 402 } 403 404 /** 405 * @see com.intellij.psi.util.MethodSignatureUtil#areSignaturesErasureEqual 406 */ 407 private static boolean areSignaturesErasureEqual( 408 @NotNull JavaMethod method1, 409 @NotNull JavaTypeSubstitutor substitutor1, 410 @NotNull JavaMethod method2, 411 @NotNull JavaTypeSubstitutor substitutor2 412 ) { 413 if (!method1.getName().equals(method2.getName())) return false; 414 415 Collection<JavaValueParameter> parameters1 = method1.getValueParameters(); 416 Collection<JavaValueParameter> parameters2 = method2.getValueParameters(); 417 if (parameters1.size() != parameters2.size()) return false; 418 419 for (Iterator<JavaValueParameter> it1 = parameters1.iterator(), it2 = parameters2.iterator(); it1.hasNext(); ) { 420 JavaValueParameter param1 = it1.next(); 421 JavaValueParameter param2 = it2.next(); 422 if (param1.isVararg() != param2.isVararg()) return false; 423 424 JavaType type1 = JavaResolverUtils.erasure(substitutor1.substitute(param1.getType()), substitutor1); 425 JavaType type2 = JavaResolverUtils.erasure(substitutor2.substitute(param2.getType()), substitutor2); 426 if (!(type1 == null ? type2 == null : type1.equals(type2))) return false; 427 } 428 429 return true; 430 } 431 432 @Nullable 433 private JavaMethod getFoundMethod() { 434 return foundMethod; 435 } 436 } 437 }