001 /*
002 * Copyright 2010-2014 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.jet.lang.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.jet.lang.descriptors.*;
024 import org.jetbrains.jet.lang.psi.*;
025 import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage;
026 import org.jetbrains.jet.lang.resolve.calls.model.ArgumentMapping;
027 import org.jetbrains.jet.lang.resolve.calls.model.ArgumentMatch;
028 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
029 import org.jetbrains.jet.lang.types.lang.InlineUtil;
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 }