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.intellij.psi.PsiElement; 020 import com.intellij.psi.util.PsiTreeUtil; 021 import org.jetbrains.annotations.NotNull; 022 import org.jetbrains.annotations.Nullable; 023 import org.jetbrains.kotlin.builtins.InlineUtil; 024 import org.jetbrains.kotlin.descriptors.*; 025 import org.jetbrains.kotlin.psi.*; 026 import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage; 027 import org.jetbrains.kotlin.resolve.calls.model.ArgumentMapping; 028 import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch; 029 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; 030 031 public class InlineDescriptorUtils { 032 033 public static boolean checkNonLocalReturnUsage(@NotNull DeclarationDescriptor fromFunction, @NotNull JetExpression startExpression, @NotNull BindingTrace trace) { 034 PsiElement containingFunction = PsiTreeUtil.getParentOfType(startExpression, JetClassOrObject.class, JetDeclarationWithBody.class); 035 if (containingFunction == null) { 036 return false; 037 } 038 039 DeclarationDescriptor containingFunctionDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, containingFunction); 040 if (containingFunctionDescriptor == null) { 041 return false; 042 } 043 044 BindingContext bindingContext = trace.getBindingContext(); 045 046 while (containingFunction instanceof JetFunctionLiteral && fromFunction != containingFunctionDescriptor) { 047 //JetFunctionLiteralExpression 048 containingFunction = containingFunction.getParent(); 049 if (!isInlineLambda((JetFunctionLiteralExpression) containingFunction, bindingContext, true)) { 050 return false; 051 } 052 053 containingFunctionDescriptor = getContainingClassOrFunctionDescriptor(containingFunctionDescriptor, true); 054 055 containingFunction = containingFunctionDescriptor != null 056 ? DescriptorToSourceUtils.descriptorToDeclaration(containingFunctionDescriptor) 057 : null; 058 } 059 060 return fromFunction == containingFunctionDescriptor; 061 } 062 063 public static boolean isInlineLambda( 064 @NotNull JetFunctionLiteralExpression lambdaExpression, 065 @NotNull BindingContext bindingContext, 066 boolean checkNonLocalReturn 067 ) { 068 JetExpression call = JetPsiUtil.getParentCallIfPresent(lambdaExpression); 069 if (call != null) { 070 ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(call, bindingContext); 071 CallableDescriptor resultingDescriptor = resolvedCall == null ? null : resolvedCall.getResultingDescriptor(); 072 if (resultingDescriptor instanceof SimpleFunctionDescriptor && 073 ((SimpleFunctionDescriptor) resultingDescriptor).getInlineStrategy().isInline()) { 074 ValueArgument argument = CallUtilPackage.getValueArgumentForExpression(resolvedCall.getCall(), lambdaExpression); 075 if (argument != null) { 076 ArgumentMapping mapping = resolvedCall.getArgumentMapping(argument); 077 if (mapping instanceof ArgumentMatch) { 078 ValueParameterDescriptor parameter = ((ArgumentMatch) mapping).getValueParameter(); 079 if (!InlineUtil.hasNoinlineAnnotation(parameter)) { 080 return !checkNonLocalReturn || allowsNonLocalReturns(parameter); 081 } 082 } 083 } 084 } 085 } 086 return false; 087 } 088 089 @Nullable 090 public static DeclarationDescriptor getContainingClassOrFunctionDescriptor(@NotNull DeclarationDescriptor descriptor, boolean strict) { 091 DeclarationDescriptor currentDescriptor = strict ? descriptor.getContainingDeclaration() : descriptor; 092 while (currentDescriptor != null) { 093 if (currentDescriptor instanceof FunctionDescriptor || currentDescriptor instanceof ClassDescriptor) { 094 return currentDescriptor; 095 } 096 currentDescriptor = currentDescriptor.getContainingDeclaration(); 097 } 098 099 return null; 100 } 101 102 public static boolean allowsNonLocalReturns(@NotNull CallableDescriptor lambdaDescriptor) { 103 if (lambdaDescriptor instanceof ValueParameterDescriptor) { 104 if (InlineUtil.hasOnlyLocalReturn((ValueParameterDescriptor) lambdaDescriptor)) { 105 //annotated 106 return false; 107 } 108 } 109 return true; 110 } 111 }