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 boolean allowsNonLocalReturns = false;
050 JetExpression call = JetPsiUtil.getParentCallIfPresent((JetFunctionLiteralExpression) containingFunction);
051 if (call != null) {
052 ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(call, bindingContext);
053 CallableDescriptor resultingDescriptor = resolvedCall == null ? null : resolvedCall.getResultingDescriptor();
054 if (resultingDescriptor instanceof SimpleFunctionDescriptor &&
055 ((SimpleFunctionDescriptor) resultingDescriptor).getInlineStrategy().isInline()) {
056 ValueArgument argument = CallUtilPackage.getValueArgumentForExpression(
057 resolvedCall.getCall(), (JetFunctionLiteralExpression) containingFunction);
058 if (argument != null) {
059 ArgumentMapping mapping = resolvedCall.getArgumentMapping(argument);
060 if (mapping instanceof ArgumentMatch) {
061 allowsNonLocalReturns = allowsNonLocalReturns(((ArgumentMatch) mapping).getValueParameter());
062 }
063 }
064 }
065 }
066 if (!allowsNonLocalReturns) {
067 return false;
068 }
069
070 containingFunctionDescriptor = getContainingClassOrFunctionDescriptor(containingFunctionDescriptor, true);
071
072 containingFunction = containingFunctionDescriptor != null
073 ? DescriptorToSourceUtils.descriptorToDeclaration(containingFunctionDescriptor)
074 : null;
075 }
076
077 return fromFunction == containingFunctionDescriptor;
078 }
079
080 @Nullable
081 public static DeclarationDescriptor getContainingClassOrFunctionDescriptor(@NotNull DeclarationDescriptor descriptor, boolean strict) {
082 DeclarationDescriptor currentDescriptor = strict ? descriptor.getContainingDeclaration() : descriptor;
083 while (currentDescriptor != null) {
084 if (currentDescriptor instanceof FunctionDescriptor || currentDescriptor instanceof ClassDescriptor) {
085 return currentDescriptor;
086 }
087 currentDescriptor = currentDescriptor.getContainingDeclaration();
088 }
089
090 return null;
091 }
092
093 public static boolean allowsNonLocalReturns(@NotNull CallableDescriptor lambdaDescriptor) {
094 if (lambdaDescriptor instanceof ValueParameterDescriptor) {
095 if (InlineUtil.hasOnlyLocalReturn((ValueParameterDescriptor) lambdaDescriptor)) {
096 //annotated
097 return false;
098 }
099 }
100 return true;
101 }
102 }