New diagnostic for non-local return annotation
This commit is contained in:
@@ -594,6 +594,7 @@ public interface Errors {
|
||||
|
||||
//Inline and inlinable parameters
|
||||
DiagnosticFactory2<JetElement, DeclarationDescriptor, DeclarationDescriptor> INVISIBLE_MEMBER_FROM_INLINE = DiagnosticFactory2.create(ERROR, CALL_ELEMENT);
|
||||
DiagnosticFactory3<JetElement, JetElement, DeclarationDescriptor, DeclarationDescriptor> NON_LOCAL_RETURN_NOT_ALLOWED = DiagnosticFactory3.create(ERROR, CALL_ELEMENT);
|
||||
DiagnosticFactory2<JetElement, JetNamedDeclaration, DeclarationDescriptor> NOT_YET_SUPPORTED_IN_INLINE = DiagnosticFactory2.create(ERROR);
|
||||
DiagnosticFactory1<JetFunction, DeclarationDescriptor> NOTHING_TO_INLINE = DiagnosticFactory1.create(WARNING, NAMED_ELEMENT);
|
||||
DiagnosticFactory2<JetElement, JetExpression, DeclarationDescriptor> USAGE_IS_NOT_INLINABLE = DiagnosticFactory2.create(ERROR);
|
||||
|
||||
+2
@@ -515,6 +515,8 @@ public class DefaultErrorMessages {
|
||||
MAP.put(USAGE_IS_NOT_INLINABLE, "Illegal usage of inline-parameter ''{0}'' in ''{1}''. Annotate the parameter with [noinline]", ELEMENT_TEXT, SHORT_NAMES_IN_TYPES);
|
||||
MAP.put(NULLABLE_INLINE_PARAMETER, "Inline-parameter ''{0}'' of ''{1}'' must not be nullable. Annotate the parameter with [noinline] or make not nullable", ELEMENT_TEXT, SHORT_NAMES_IN_TYPES);
|
||||
MAP.put(RECURSION_IN_INLINE, "Inline-function ''{1}'' can't be recursive", ELEMENT_TEXT, SHORT_NAMES_IN_TYPES);
|
||||
//Inline non Locals
|
||||
MAP.put(NON_LOCAL_RETURN_NOT_ALLOWED, "Can''t inline ''{0}'' here: it may contain non-local returns. Annotate parameter declaration ''{0}'' with ''inlineOptions(ONLY_LOCAL_RETURNS)''", ELEMENT_TEXT, SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES);
|
||||
|
||||
MAP.setImmutable();
|
||||
|
||||
|
||||
@@ -884,4 +884,37 @@ public class JetPsiUtil {
|
||||
return element instanceof JetSimpleNameExpression &&
|
||||
((JetSimpleNameExpression) element).getReferencedNameElementType() == JetTokens.LABEL_IDENTIFIER;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JetExpression getParentCallIfPresent(@NotNull JetExpression expression) {
|
||||
PsiElement parent = expression.getParent();
|
||||
while (parent != null) {
|
||||
if (parent instanceof JetBinaryExpression ||
|
||||
parent instanceof JetUnaryExpression ||
|
||||
parent instanceof JetLabeledExpression ||
|
||||
parent instanceof JetDotQualifiedExpression ||
|
||||
parent instanceof JetCallExpression ||
|
||||
parent instanceof JetArrayAccessExpression ||
|
||||
parent instanceof JetMultiDeclaration) {
|
||||
|
||||
if (parent instanceof JetLabeledExpression) {
|
||||
parent = parent.getParent();
|
||||
continue;
|
||||
}
|
||||
|
||||
//check that it's in inlineable call would be in resolve call of parent
|
||||
return (JetExpression) parent;
|
||||
}
|
||||
else if (parent instanceof JetParenthesizedExpression || parent instanceof JetBinaryExpressionWithTypeRHS) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
else if (parent instanceof JetValueArgument || parent instanceof JetValueArgumentList) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,17 +328,18 @@ public class BindingContextUtils {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Pair<FunctionDescriptor, PsiElement> getLambdaContainingFunction(
|
||||
@NotNull FunctionDescriptor lambdaDescriptor,
|
||||
@NotNull BindingContext context
|
||||
public static Pair<FunctionDescriptor, PsiElement> getContainingFunctionSkipFunctionLiterals(
|
||||
@NotNull BindingContext context,
|
||||
@Nullable DeclarationDescriptor startDescriptor,
|
||||
boolean strict
|
||||
) {
|
||||
FunctionDescriptor containingFunctionDescriptor = lambdaDescriptor;
|
||||
PsiElement containingFunction;
|
||||
do {
|
||||
FunctionDescriptor containingFunctionDescriptor = DescriptorUtils.getParentOfType(startDescriptor, FunctionDescriptor.class, strict);
|
||||
PsiElement containingFunction = containingFunctionDescriptor != null ? callableDescriptorToDeclaration(context, containingFunctionDescriptor) : null;
|
||||
while (containingFunction instanceof JetFunctionLiteral) {
|
||||
containingFunctionDescriptor = DescriptorUtils.getParentOfType(containingFunctionDescriptor, FunctionDescriptor.class);
|
||||
containingFunction = containingFunctionDescriptor != null ? callableDescriptorToDeclaration(context,
|
||||
containingFunctionDescriptor) : null;
|
||||
} while (containingFunction instanceof JetFunctionLiteral);
|
||||
}
|
||||
|
||||
return new Pair<FunctionDescriptor, PsiElement>(containingFunctionDescriptor, containingFunction);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.lang.resolve;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
|
||||
public class InlineDescriptorUtils {
|
||||
|
||||
public static boolean checkNonLocalReturnUsage(@NotNull DeclarationDescriptor fromFunction, @NotNull JetExpression startExpression, @NotNull BindingTrace trace) {
|
||||
PsiElement containingFunction = PsiTreeUtil.getParentOfType(startExpression, JetClassOrObject.class, JetDeclarationWithBody.class);
|
||||
if (containingFunction == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DeclarationDescriptor containingFunctionDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, containingFunction);
|
||||
if (containingFunctionDescriptor == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BindingContext bindingContext = trace.getBindingContext();
|
||||
|
||||
while (containingFunction instanceof JetFunctionLiteral && fromFunction != containingFunctionDescriptor) {
|
||||
//JetFunctionLiteralExpression
|
||||
containingFunction = containingFunction.getParent();
|
||||
boolean isInlinedLambda = false;
|
||||
JetExpression call = JetPsiUtil.getParentCallIfPresent((JetFunctionLiteralExpression) containingFunction);
|
||||
if (call != null) {
|
||||
//TODO: ask sveta
|
||||
ResolvedCall<?> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, JetPsiUtil.getCalleeExpressionIfAny(call));
|
||||
CallableDescriptor resultingDescriptor = resolvedCall == null ? null : resolvedCall.getResultingDescriptor();
|
||||
if (resultingDescriptor instanceof SimpleFunctionDescriptor) {
|
||||
isInlinedLambda = ((SimpleFunctionDescriptor) resultingDescriptor).getInlineStrategy().isInline();
|
||||
}
|
||||
}
|
||||
if (!isInlinedLambda) {
|
||||
return false;
|
||||
}
|
||||
|
||||
containingFunctionDescriptor = getContainingClassOrFunctionDescriptor(containingFunctionDescriptor, true);
|
||||
|
||||
containingFunction = containingFunctionDescriptor != null
|
||||
? BindingContextUtils.descriptorToDeclaration(bindingContext, containingFunctionDescriptor)
|
||||
: null;
|
||||
}
|
||||
|
||||
return fromFunction == containingFunctionDescriptor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static DeclarationDescriptor getContainingClassOrFunctionDescriptor(@NotNull DeclarationDescriptor descriptor, boolean strict) {
|
||||
DeclarationDescriptor currentDescriptor = strict ? descriptor.getContainingDeclaration() : descriptor;
|
||||
while (currentDescriptor != null) {
|
||||
if (currentDescriptor instanceof FunctionDescriptor || currentDescriptor instanceof ClassDescriptor) {
|
||||
return currentDescriptor;
|
||||
}
|
||||
currentDescriptor = currentDescriptor.getContainingDeclaration();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+92
-59
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.jet.lang.resolve.calls;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
@@ -24,11 +25,9 @@ import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.InlineDescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.DefaultValueArgument;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.VarargValueArgument;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.*;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||
@@ -39,6 +38,7 @@ import org.jetbrains.jet.lexer.JetToken;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class InlineCallResolverExtension implements CallResolverExtension {
|
||||
@@ -82,69 +82,65 @@ public class InlineCallResolverExtension implements CallResolverExtension {
|
||||
checkCallWithReceiver(context, targetDescriptor, resolvedCall.getReceiverArgument(), expression);
|
||||
|
||||
if (inlinableParameters.contains(targetDescriptor)) {
|
||||
if (!couldAccessVariable(expression)) {
|
||||
if (!isInsideCall(expression)) {
|
||||
context.trace.report(Errors.USAGE_IS_NOT_INLINABLE.on(expression, expression, descriptor));
|
||||
}
|
||||
}
|
||||
|
||||
for (ResolvedValueArgument value : resolvedCall.getValueArguments().values()) {
|
||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : resolvedCall.getValueArguments().entrySet()) {
|
||||
ResolvedValueArgument value = entry.getValue();
|
||||
ValueParameterDescriptor valueDescriptor = entry.getKey();
|
||||
if (!(value instanceof DefaultValueArgument)) {
|
||||
for (ValueArgument argument : value.getArguments()) {
|
||||
checkValueParameter(context, targetDescriptor, argument, value instanceof VarargValueArgument);
|
||||
checkValueParameter(context, targetDescriptor, argument, valueDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkVisibility(targetDescriptor, expression, context);
|
||||
checkRecursion(targetDescriptor, expression, context);
|
||||
checkRecursion(context, targetDescriptor, expression);
|
||||
}
|
||||
|
||||
private static boolean couldAccessVariable(JetExpression expression) {
|
||||
PsiElement parent = expression.getParent();
|
||||
while (parent != null) {
|
||||
if (parent instanceof JetValueArgument ||
|
||||
parent instanceof JetBinaryExpression ||
|
||||
parent instanceof JetUnaryExpression ||
|
||||
parent instanceof JetLabeledExpression ||
|
||||
parent instanceof JetDotQualifiedExpression ||
|
||||
parent instanceof JetCallExpression ||
|
||||
parent instanceof JetArrayAccessExpression ||
|
||||
parent instanceof JetMultiDeclaration) {
|
||||
|
||||
if (parent instanceof JetLabeledExpression) {
|
||||
parent = parent.getParent();
|
||||
continue;
|
||||
}
|
||||
else if (parent instanceof JetBinaryExpression) {
|
||||
JetToken token = JetPsiUtil.getOperationToken((JetOperationExpression) parent);
|
||||
if (token == JetTokens.EQ || token == JetTokens.ANDAND || token == JetTokens.OROR) {
|
||||
//assignment
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//check that it's in inlineable call would be in resolve call of parent
|
||||
return true;
|
||||
}
|
||||
else if (parent instanceof JetParenthesizedExpression || parent instanceof JetBinaryExpressionWithTypeRHS) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
else {
|
||||
private static boolean isInsideCall(JetExpression expression) {
|
||||
JetElement parent = JetPsiUtil.getParentCallIfPresent(expression);
|
||||
if (parent instanceof JetBinaryExpression) {
|
||||
JetToken token = JetPsiUtil.getOperationToken((JetOperationExpression) parent);
|
||||
if (token == JetTokens.EQ || token == JetTokens.ANDAND || token == JetTokens.OROR) {
|
||||
//assignment
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
return parent != null;
|
||||
}
|
||||
|
||||
private void checkValueParameter(BasicCallResolutionContext context, CallableDescriptor targetDescriptor, ValueArgument argument, boolean isVararg) {
|
||||
JetExpression jetExpression = argument.getArgumentExpression();
|
||||
if (jetExpression == null) {
|
||||
|
||||
|
||||
private void checkValueParameter(
|
||||
@NotNull BasicCallResolutionContext context,
|
||||
@NotNull CallableDescriptor targetDescriptor,
|
||||
@NotNull ValueArgument targetArgument,
|
||||
@NotNull ValueParameterDescriptor targetParameterDescriptor
|
||||
) {
|
||||
JetExpression argumentExpression = targetArgument.getArgumentExpression();
|
||||
if (argumentExpression == null) {
|
||||
return;
|
||||
}
|
||||
CallableDescriptor varDescriptor = getDescriptor(context, jetExpression);
|
||||
CallableDescriptor argumentCallee = getCalleeDescriptor(context, argumentExpression, false);
|
||||
|
||||
if (varDescriptor != null && inlinableParameters.contains(varDescriptor)) {
|
||||
checkFunctionCall(context, targetDescriptor, jetExpression, isVararg);
|
||||
if (argumentCallee != null && inlinableParameters.contains(argumentCallee)) {
|
||||
boolean isTargetInlineFunction = targetDescriptor instanceof SimpleFunctionDescriptor &&
|
||||
((SimpleFunctionDescriptor) targetDescriptor).getInlineStrategy().isInline();
|
||||
|
||||
if (!isTargetInlineFunction || !isInlinableParameter(targetParameterDescriptor)) {
|
||||
context.trace.report(Errors.USAGE_IS_NOT_INLINABLE.on(argumentExpression, argumentExpression, descriptor));
|
||||
} else {
|
||||
if (allowsNonLocalReturns(argumentCallee) && !allowsNonLocalReturns(targetParameterDescriptor)) {
|
||||
context.trace.report(Errors.NON_LOCAL_RETURN_NOT_ALLOWED.on(argumentExpression, argumentExpression, argumentCallee, descriptor));
|
||||
} else {
|
||||
checkNonLocalReturn(context, argumentCallee, argumentExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +156,7 @@ public class InlineCallResolverExtension implements CallResolverExtension {
|
||||
JetExpression receiverExpression = null;
|
||||
if (receiver instanceof ExpressionReceiver) {
|
||||
receiverExpression = ((ExpressionReceiver) receiver).getExpression();
|
||||
varDescriptor = getDescriptor(context, receiverExpression);
|
||||
varDescriptor = getCalleeDescriptor(context, receiverExpression, true);
|
||||
}
|
||||
else if (receiver instanceof ExtensionReceiver) {
|
||||
ExtensionReceiver extensionReceiver = (ExtensionReceiver) receiver;
|
||||
@@ -174,35 +170,42 @@ public class InlineCallResolverExtension implements CallResolverExtension {
|
||||
|
||||
if (inlinableParameters.contains(varDescriptor)) {
|
||||
//check that it's invoke or inlinable extension
|
||||
checkFunctionCall(context, targetDescriptor, receiverExpression, false);
|
||||
checkLambdaInvokeOrExtensionCall(context, varDescriptor, targetDescriptor, receiverExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static CallableDescriptor getDescriptor(
|
||||
private static CallableDescriptor getCalleeDescriptor(
|
||||
@NotNull BasicCallResolutionContext context,
|
||||
@NotNull JetExpression expression
|
||||
@NotNull JetExpression expression,
|
||||
boolean unwrapVariableAsFunction
|
||||
) {
|
||||
// todo ask sveta
|
||||
ResolvedCall<?> thisCall = context.trace.get(BindingContext.RESOLVED_CALL, expression);
|
||||
if (unwrapVariableAsFunction && thisCall instanceof VariableAsFunctionResolvedCall) {
|
||||
return ((VariableAsFunctionResolvedCall) thisCall).getVariableCall().getResultingDescriptor();
|
||||
}
|
||||
return thisCall != null ? thisCall.getResultingDescriptor() : null;
|
||||
}
|
||||
|
||||
private void checkFunctionCall(
|
||||
BasicCallResolutionContext context,
|
||||
CallableDescriptor targetDescriptor,
|
||||
JetExpression receiverExpresssion,
|
||||
boolean isVararg
|
||||
private void checkLambdaInvokeOrExtensionCall(
|
||||
@NotNull BasicCallResolutionContext context,
|
||||
@NotNull CallableDescriptor lambdaDescriptor,
|
||||
@NotNull CallableDescriptor callDescriptor,
|
||||
@NotNull JetExpression receiverExpresssion
|
||||
) {
|
||||
boolean inlinableCall = isInvokeOrInlineExtension(targetDescriptor);
|
||||
if (!inlinableCall || isVararg) {
|
||||
boolean inlinableCall = isInvokeOrInlineExtension(callDescriptor);
|
||||
if (!inlinableCall) {
|
||||
context.trace.report(Errors.USAGE_IS_NOT_INLINABLE.on(receiverExpresssion, receiverExpresssion, descriptor));
|
||||
} else {
|
||||
checkNonLocalReturn(context, lambdaDescriptor, receiverExpresssion);
|
||||
}
|
||||
}
|
||||
|
||||
public void checkRecursion(
|
||||
@NotNull BasicCallResolutionContext context,
|
||||
@NotNull CallableDescriptor targetDescriptor,
|
||||
@NotNull JetElement expression,
|
||||
@NotNull BasicCallResolutionContext context
|
||||
@NotNull JetElement expression
|
||||
) {
|
||||
if (targetDescriptor.getOriginal() == descriptor) {
|
||||
context.trace.report(Errors.RECURSION_IN_INLINE.on(expression, expression, descriptor));
|
||||
@@ -248,4 +251,34 @@ public class InlineCallResolverExtension implements CallResolverExtension {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void checkNonLocalReturn(
|
||||
@NotNull BasicCallResolutionContext context,
|
||||
@NotNull CallableDescriptor inlinableParameterDescriptor,
|
||||
@NotNull JetExpression parameterUsage
|
||||
) {
|
||||
if (!allowsNonLocalReturns(inlinableParameterDescriptor)) return;
|
||||
|
||||
if (!InlineDescriptorUtils.checkNonLocalReturnUsage(descriptor, parameterUsage, context.trace)) {
|
||||
context.trace.report(Errors.NON_LOCAL_RETURN_NOT_ALLOWED.on(parameterUsage, parameterUsage, inlinableParameterDescriptor, descriptor));
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiElement getDeclaration(JetExpression expression) {
|
||||
do {
|
||||
expression = PsiTreeUtil.getParentOfType(expression, JetDeclaration.class);
|
||||
} while (expression instanceof JetMultiDeclaration || expression instanceof JetProperty);
|
||||
return expression;
|
||||
}
|
||||
|
||||
private static boolean allowsNonLocalReturns(CallableDescriptor lambdaDescriptor) {
|
||||
if (lambdaDescriptor instanceof ValueParameterDescriptor) {
|
||||
if (InlineUtil.hasOnlyLocalReturn((ValueParameterDescriptor) lambdaDescriptor)) {
|
||||
//annotated
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+14
-23
@@ -22,16 +22,10 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorResolver;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.MutableDataFlowInfoForArguments;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
@@ -451,27 +445,24 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
// In a default value for parameter
|
||||
context.trace.report(RETURN_NOT_ALLOWED.on(expression));
|
||||
}
|
||||
assert parentDeclaration != null;
|
||||
DeclarationDescriptor declarationDescriptor = context.trace.get(DECLARATION_TO_DESCRIPTOR, parentDeclaration);
|
||||
FunctionDescriptor containingFunctionDescriptor = DescriptorUtils.getParentOfType(declarationDescriptor, FunctionDescriptor.class, false);
|
||||
|
||||
if (expression.getTargetLabel() == null) {
|
||||
if (containingFunctionDescriptor != null) {
|
||||
PsiElement containingFunction = BindingContextUtils.callableDescriptorToDeclaration(context.trace.getBindingContext(), containingFunctionDescriptor);
|
||||
assert containingFunction != null;
|
||||
if (containingFunction instanceof JetFunctionLiteral) {
|
||||
Pair<FunctionDescriptor, PsiElement> result = BindingContextUtils
|
||||
.getLambdaContainingFunction(containingFunctionDescriptor, context.trace.getBindingContext());
|
||||
containingFunctionDescriptor = result.getFirst();
|
||||
containingFunction = result.getSecond();
|
||||
assert parentDeclaration != null;
|
||||
DeclarationDescriptor declarationDescriptor = context.trace.get(DECLARATION_TO_DESCRIPTOR, parentDeclaration);
|
||||
Pair<FunctionDescriptor, PsiElement> containingFunInfo =
|
||||
BindingContextUtils.getContainingFunctionSkipFunctionLiterals(context.trace.getBindingContext(), declarationDescriptor,
|
||||
false);
|
||||
FunctionDescriptor containingFunctionDescriptor = containingFunInfo.getFirst();
|
||||
|
||||
if (containingFunctionDescriptor != null) {
|
||||
if (!InlineDescriptorUtils.checkNonLocalReturnUsage(containingFunctionDescriptor, expression, context.trace) ||
|
||||
containingFunctionDescriptor instanceof ConstructorDescriptor) {
|
||||
// Unqualified, in a function literal
|
||||
context.trace.report(RETURN_NOT_ALLOWED.on(expression));
|
||||
resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE);
|
||||
}
|
||||
if (containingFunctionDescriptor != null) {
|
||||
expectedType = getFunctionExpectedReturnType(containingFunctionDescriptor, (JetElement) containingFunction);
|
||||
}
|
||||
|
||||
expectedType = getFunctionExpectedReturnType(containingFunctionDescriptor, (JetElement) containingFunInfo.getSecond());
|
||||
}
|
||||
else {
|
||||
// Outside a function
|
||||
@@ -483,7 +474,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
SimpleFunctionDescriptor functionDescriptor = context.trace.get(FUNCTION, labelTargetElement);
|
||||
if (functionDescriptor != null) {
|
||||
expectedType = getFunctionExpectedReturnType(functionDescriptor, labelTargetElement);
|
||||
if (functionDescriptor != containingFunctionDescriptor) {
|
||||
if (!InlineDescriptorUtils.checkNonLocalReturnUsage(functionDescriptor, expression, context.trace)) {
|
||||
// Qualified, non-local
|
||||
context.trace.report(RETURN_NOT_ALLOWED.on(expression));
|
||||
resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE -ONLY_LOCAL_RETURN
|
||||
|
||||
fun <T, U> Function1<T, U>.minusAssign(p: Function1<T, U>) {}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
inline fun <R> onlyLocal(p: () -> R) {
|
||||
inlineAll(<!USAGE_IS_NOT_INLINABLE!>p<!>)
|
||||
}
|
||||
|
||||
<!NOTHING_TO_INLINE!>inline fun <R> inlineAll(noinline p: () -> R)<!> {
|
||||
p()
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
|
||||
import kotlin.InlineOption.*
|
||||
|
||||
inline fun <R> inlineFunOnlyLocal(inlineOptions(ONLY_LOCAL_RETURN)p: () -> R) {
|
||||
val s = object {
|
||||
|
||||
val z = p()
|
||||
|
||||
fun a() {
|
||||
p()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <R> inlineFun(p: () -> R) {
|
||||
val s = object {
|
||||
|
||||
val z = <!NON_LOCAL_RETURN_NOT_ALLOWED!>p<!>()
|
||||
|
||||
fun a() {
|
||||
<!NON_LOCAL_RETURN_NOT_ALLOWED!>p<!>()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
|
||||
import kotlin.InlineOption.*
|
||||
|
||||
inline fun <R> inlineFunOnlyLocal(inlineOptions(ONLY_LOCAL_RETURN)p: () -> R) {
|
||||
val s = object {
|
||||
|
||||
val z = p();
|
||||
|
||||
{
|
||||
doCall {
|
||||
p()
|
||||
}
|
||||
}
|
||||
|
||||
fun a() {
|
||||
doCall {
|
||||
p()
|
||||
}
|
||||
|
||||
p()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <R> inlineFun(p: () -> R) {
|
||||
val s = object {
|
||||
|
||||
val z = <!NON_LOCAL_RETURN_NOT_ALLOWED!>p<!>();
|
||||
|
||||
{
|
||||
doCall {
|
||||
<!NON_LOCAL_RETURN_NOT_ALLOWED!>p<!>()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun a() {
|
||||
doCall {
|
||||
<!NON_LOCAL_RETURN_NOT_ALLOWED!>p<!>()
|
||||
}
|
||||
|
||||
<!NON_LOCAL_RETURN_NOT_ALLOWED!>p<!>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <R> doCall(p: () -> R) {
|
||||
p()
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
fun inlineCallExplicitError(): String {
|
||||
inlineFun @lamba {
|
||||
if (true) {
|
||||
<!RETURN_NOT_ALLOWED_EXPLICIT_RETURN_TYPE_REQUIRED!>return@lamba 2<!>
|
||||
}
|
||||
1
|
||||
}
|
||||
|
||||
return "x"
|
||||
}
|
||||
|
||||
fun inlineCall(): String {
|
||||
inlineFun @lamba {
|
||||
(): Int ->
|
||||
if (true) {
|
||||
return@lamba 2
|
||||
}
|
||||
1
|
||||
}
|
||||
|
||||
return "x"
|
||||
}
|
||||
|
||||
inline fun inlineFun(s: () -> Int) {
|
||||
s()
|
||||
}
|
||||
|
||||
|
||||
fun noInlineCall(): String {
|
||||
noInline @lambda {
|
||||
(): Int ->
|
||||
if (true) {
|
||||
return@lambda 2
|
||||
}
|
||||
1
|
||||
}
|
||||
return "x"
|
||||
}
|
||||
|
||||
|
||||
fun noInline(s: () -> Int) {
|
||||
s()
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import kotlin.InlineOption.*
|
||||
|
||||
inline fun <R> onlyLocal(inlineOptions(ONLY_LOCAL_RETURN)p: () -> R) {
|
||||
inlineAll(p)
|
||||
}
|
||||
|
||||
inline fun <R> inlineAll(p: () -> R) {
|
||||
p()
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import kotlin.InlineOption.*
|
||||
|
||||
inline fun <R> inlineFunWithAnnotation(inlineOptions(ONLY_LOCAL_RETURN) p: () -> R) {
|
||||
inlineFun {
|
||||
p()
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <R> inlineFun2(p: () -> R) {
|
||||
inlineFun {
|
||||
p()
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <R> inlineFun(p: () -> R) {
|
||||
p()
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
fun inlineCall(): String {
|
||||
inlineFun {
|
||||
if (true) {
|
||||
return@inlineCall ""
|
||||
}
|
||||
1
|
||||
}
|
||||
|
||||
return "x"
|
||||
}
|
||||
|
||||
inline fun inlineFun(s: ()->Int) {
|
||||
s()
|
||||
}
|
||||
|
||||
|
||||
fun noInlineCall(): String {
|
||||
noInline {
|
||||
if (true) {
|
||||
<!RETURN_NOT_ALLOWED!>return@noInlineCall ""<!>
|
||||
}
|
||||
1
|
||||
}
|
||||
|
||||
return "x"
|
||||
}
|
||||
|
||||
|
||||
fun noInline(s: ()->Int) {
|
||||
s()
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
|
||||
import kotlin.InlineOption.*
|
||||
|
||||
inline fun <R> inlineFunOnlyLocal(inlineOptions(ONLY_LOCAL_RETURN)p: () -> R) {
|
||||
<!NOT_YET_SUPPORTED_IN_INLINE!>fun a() {
|
||||
val z = p()
|
||||
}<!>
|
||||
a()
|
||||
}
|
||||
|
||||
inline fun <R> inlineFun(p: () -> R) {
|
||||
<!NOT_YET_SUPPORTED_IN_INLINE!>fun a() {
|
||||
<!NON_LOCAL_RETURN_NOT_ALLOWED!>p<!>()
|
||||
}<!>
|
||||
a()
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import Kind.EXT_RETURN
|
||||
import Kind.GLOBAL_RETURN
|
||||
|
||||
enum class Kind {
|
||||
LOCAL
|
||||
EXT_RETURN
|
||||
GLOBAL_RETURN
|
||||
}
|
||||
|
||||
class Internal(val value: String)
|
||||
|
||||
class External(val value: String)
|
||||
|
||||
class Global(val value: String)
|
||||
|
||||
fun test1(intKind: Kind, extKind: Kind): Global {
|
||||
|
||||
var externalResult = doCall @ext {
|
||||
() : External ->
|
||||
|
||||
val internalResult = doCall @int {
|
||||
() : Internal ->
|
||||
if (intKind == Kind.LOCAL) {
|
||||
return@test1 Global("internal to global")
|
||||
} else if (intKind == EXT_RETURN) {
|
||||
return@ext External("internal to external")
|
||||
}
|
||||
return@int Internal("internal to local")
|
||||
}
|
||||
|
||||
if (extKind == GLOBAL_RETURN || extKind == EXT_RETURN) {
|
||||
return Global("external to global")
|
||||
}
|
||||
|
||||
External(internalResult.value + " to local");
|
||||
}
|
||||
|
||||
return Global(externalResult.value + " to exit")
|
||||
}
|
||||
|
||||
public inline fun <R> doCall(block: ()-> R) : R {
|
||||
return block()
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
|
||||
import kotlin.InlineOption.*
|
||||
|
||||
inline fun <R> inlineFunOnlyLocal(inlineOptions(ONLY_LOCAL_RETURN)p: () -> R) {
|
||||
{
|
||||
p()
|
||||
}()
|
||||
}
|
||||
|
||||
inline fun <R> inlineFun(p: () -> R) {
|
||||
{
|
||||
<!NON_LOCAL_RETURN_NOT_ALLOWED!>p<!>()
|
||||
}()
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
|
||||
import kotlin.InlineOption.*
|
||||
|
||||
inline fun <R> inlineFunOnlyLocal(inlineOptions(ONLY_LOCAL_RETURN)p: () -> R) {
|
||||
<!NOT_YET_SUPPORTED_IN_INLINE!>class A {
|
||||
|
||||
val z = p()
|
||||
|
||||
fun a() {
|
||||
p()
|
||||
}
|
||||
}<!>
|
||||
}
|
||||
|
||||
inline fun <R> inlineFun(p: () -> R) {
|
||||
<!NOT_YET_SUPPORTED_IN_INLINE!>class A {
|
||||
|
||||
val z = <!NON_LOCAL_RETURN_NOT_ALLOWED!>p<!>()
|
||||
|
||||
fun a() {
|
||||
<!NON_LOCAL_RETURN_NOT_ALLOWED!>p<!>()
|
||||
}
|
||||
}<!>
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
inline fun <R> doCall(p: () -> R) {
|
||||
p()
|
||||
}
|
||||
|
||||
inline fun <R> doCallInt(p: () -> R): R {
|
||||
return p()
|
||||
}
|
||||
|
||||
class A {
|
||||
var result: Int = doCallInt { <!RETURN_NOT_ALLOWED!>return this<!> };
|
||||
|
||||
var field: Int
|
||||
get() {
|
||||
doCall { return 1 }
|
||||
return 2
|
||||
}
|
||||
set(v: Int) {
|
||||
doCall {
|
||||
result = v / 2
|
||||
return
|
||||
}
|
||||
result = v
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import kotlin.InlineOption.*
|
||||
|
||||
inline fun <R> toOnlyLocal(inlineOptions(ONLY_LOCAL_RETURN) p: () -> R) {
|
||||
p()
|
||||
}
|
||||
|
||||
inline fun <R> inlineAll(p: () -> R) {
|
||||
toOnlyLocal(<!NON_LOCAL_RETURN_NOT_ALLOWED!>p<!>)
|
||||
}
|
||||
@@ -4464,7 +4464,7 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/inline")
|
||||
@InnerTestClasses({Inline.BinaryExpressions.class, Inline.NonPublicMember.class, Inline.Regressions.class, Inline.UnaryExpressions.class})
|
||||
@InnerTestClasses({Inline.BinaryExpressions.class, Inline.NonLocalReturns.class, Inline.NonPublicMember.class, Inline.Regressions.class, Inline.UnaryExpressions.class})
|
||||
public static class Inline extends AbstractJetDiagnosticsTest {
|
||||
public void testAllFilesPresentInInline() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/tests/inline"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
@@ -4500,6 +4500,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest("compiler/testData/diagnostics/tests/inline/extensionOnFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("fromInlineToNoInline.kt")
|
||||
public void testFromInlineToNoInline() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inline/fromInlineToNoInline.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functions.kt")
|
||||
public void testFunctions() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inline/functions.kt");
|
||||
@@ -4628,6 +4633,74 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/inline/nonLocalReturns")
|
||||
public static class NonLocalReturns extends AbstractJetDiagnosticsTest {
|
||||
public void testAllFilesPresentInNonLocalReturns() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/tests/inline/nonLocalReturns"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("anonymousObjects.kt")
|
||||
public void testAnonymousObjects() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inline/nonLocalReturns/anonymousObjects.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("anonymousObjectsNested.kt")
|
||||
public void testAnonymousObjectsNested() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inline/nonLocalReturns/anonymousObjectsNested.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("explicitReturnType.kt")
|
||||
public void testExplicitReturnType() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inline/nonLocalReturns/explicitReturnType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("fromOnlyLocal.kt")
|
||||
public void testFromOnlyLocal() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inline/nonLocalReturns/fromOnlyLocal.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineLambda.kt")
|
||||
public void testInlineLambda() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inline/nonLocalReturns/inlineLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("labeledReturn.kt")
|
||||
public void testLabeledReturn() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inline/nonLocalReturns/labeledReturn.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("localFun.kt")
|
||||
public void testLocalFun() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inline/nonLocalReturns/localFun.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nestedNonLocals.kt")
|
||||
public void testNestedNonLocals() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inline/nonLocalReturns/nestedNonLocals.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noInlineLambda.kt")
|
||||
public void testNoInlineLambda() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inline/nonLocalReturns/noInlineLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nonInlinedClass.kt")
|
||||
public void testNonInlinedClass() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inline/nonLocalReturns/nonInlinedClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyAccessorsAndConstructor.kt")
|
||||
public void testPropertyAccessorsAndConstructor() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inline/nonLocalReturns/propertyAccessorsAndConstructor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("toOnlyLocal.kt")
|
||||
public void testToOnlyLocal() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inline/nonLocalReturns/toOnlyLocal.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/inline/nonPublicMember")
|
||||
public static class NonPublicMember extends AbstractJetDiagnosticsTest {
|
||||
public void testAllFilesPresentInNonPublicMember() throws Exception {
|
||||
@@ -4706,6 +4779,7 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
TestSuite suite = new TestSuite("Inline");
|
||||
suite.addTestSuite(Inline.class);
|
||||
suite.addTestSuite(BinaryExpressions.class);
|
||||
suite.addTestSuite(NonLocalReturns.class);
|
||||
suite.addTestSuite(NonPublicMember.class);
|
||||
suite.addTestSuite(Regressions.class);
|
||||
suite.addTestSuite(UnaryExpressions.class);
|
||||
|
||||
@@ -24,3 +24,11 @@ public enum class InlineStrategy {
|
||||
AS_FUNCTION
|
||||
IN_PLACE
|
||||
}
|
||||
|
||||
|
||||
public annotation class inlineOptions(vararg val value: InlineOption)
|
||||
|
||||
public enum class InlineOption {
|
||||
LOCAL_CONTINUE_AND_BREAK
|
||||
ONLY_LOCAL_RETURN
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.lang.types.lang;
|
||||
|
||||
public enum InlineOption {
|
||||
LOCAL_CONTINUE_AND_BREAK,
|
||||
ONLY_LOCAL_RETURN
|
||||
}
|
||||
@@ -23,9 +23,12 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.jet.lang.resolve.constants.ArrayValue;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.constants.EnumValue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class InlineUtil {
|
||||
|
||||
public static boolean hasNoinlineAnnotation(@NotNull CallableDescriptor valueParameterDescriptor) {
|
||||
@@ -68,6 +71,40 @@ public class InlineUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean hasOnlyLocalContinueAndBreak(@NotNull ValueParameterDescriptor descriptor) {
|
||||
return hasInlineOption(descriptor, InlineOption.LOCAL_CONTINUE_AND_BREAK);
|
||||
}
|
||||
|
||||
public static boolean hasOnlyLocalReturn(@NotNull ValueParameterDescriptor descriptor) {
|
||||
return hasInlineOption(descriptor, InlineOption.ONLY_LOCAL_RETURN);
|
||||
}
|
||||
|
||||
private static boolean hasInlineOption(@NotNull ValueParameterDescriptor descriptor, @NotNull InlineOption option) {
|
||||
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
|
||||
ClassDescriptor annotationClass = builtIns.getInlineOptionsClassAnnotation();
|
||||
AnnotationDescriptor optionsAnnotation = getAnnotation(descriptor.getAnnotations(), annotationClass);
|
||||
|
||||
if (optionsAnnotation != null) {
|
||||
ValueParameterDescriptor parameterDescriptor = annotationClass.getConstructors().iterator().next().getValueParameters().get(0);
|
||||
CompileTimeConstant<?> argument = optionsAnnotation.getValueArgument(parameterDescriptor);
|
||||
|
||||
if (argument == null) {
|
||||
return false;
|
||||
} else {
|
||||
if (argument instanceof ArrayValue) {
|
||||
List<CompileTimeConstant<?>> values = ((ArrayValue) argument).getValue();
|
||||
|
||||
for (CompileTimeConstant<?> value : values) {
|
||||
if (value instanceof EnumValue) {
|
||||
if (((EnumValue) value).getValue().getName().asString().equals(option.name())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -307,6 +307,11 @@ public class KotlinBuiltIns {
|
||||
return getBuiltInClassByName("inline");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ClassDescriptor getInlineOptionsClassAnnotation() {
|
||||
return getBuiltInClassByName("inlineOptions");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ClassDescriptor getTailRecursiveAnnotationClass() {
|
||||
return getBuiltInClassByName("tailRecursive");
|
||||
|
||||
Reference in New Issue
Block a user