diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/extension/InlineAnalyzerExtension.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/extension/InlineAnalyzerExtension.java index 2b7e6bc50bc..2ed47229108 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/extension/InlineAnalyzerExtension.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/extension/InlineAnalyzerExtension.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.lang.resolve.extension; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; @@ -130,18 +131,20 @@ public class InlineAnalyzerExtension implements FunctionAnalyzerExtension.Analyz } } - private static boolean checkInlinableParameter( + public static boolean checkInlinableParameter( @NotNull CallableDescriptor parameter, @NotNull JetElement expression, - @NotNull FunctionDescriptor functionDescriptor, - @NotNull BindingTrace trace + @NotNull CallableDescriptor functionDescriptor, + @Nullable BindingTrace trace ) { KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); JetType type = parameter.getReturnType(); if (type != null && builtIns.isExactFunctionOrExtensionFunctionType(type)) { if (!InlineUtil.hasNoinlineAnnotation(parameter)) { if (type.isNullable()) { - trace.report(Errors.NULLABLE_INLINE_PARAMETER.on(expression, expression, functionDescriptor)); + if (trace != null) { + trace.report(Errors.NULLABLE_INLINE_PARAMETER.on(expression, expression, functionDescriptor)); + } } else { return true; diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java index e63081d8d09..62e865536bf 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java +++ b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java @@ -41,19 +41,22 @@ import org.jetbrains.jet.codegen.PackageCodegen; import org.jetbrains.jet.codegen.binding.CodegenBinding; import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument; +import org.jetbrains.jet.lang.resolve.extension.InlineAnalyzerExtension; import org.jetbrains.jet.lang.resolve.java.JetFilesProvider; import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.name.FqName; +import org.jetbrains.jet.lang.types.lang.InlineStrategy; +import org.jetbrains.jet.lang.types.lang.InlineUtil; import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache; import org.jetbrains.jet.plugin.util.DebuggerUtils; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.WeakHashMap; +import java.util.*; import static org.jetbrains.jet.codegen.binding.CodegenBinding.asmTypeForAnonymousClass; @@ -134,34 +137,44 @@ public class JetPositionManager implements PositionManager { JetFile file = (JetFile) sourcePosition.getFile(); JetTypeMapper typeMapper = prepareTypeMapper(file); - PsiElement element = PsiTreeUtil.getParentOfType(sourcePosition.getElementAt(), JetClassOrObject.class, JetFunctionLiteral.class, JetNamedFunction.class); - if (element instanceof JetClassOrObject) { - result.set(getJvmInternalNameForImpl(typeMapper, (JetClassOrObject) element)); - } - else if (element instanceof JetFunctionLiteral) { - Type asmType = asmTypeForAnonymousClass(typeMapper.getBindingContext(), ((JetFunctionLiteral) element)); - result.set(asmType.getInternalName()); - } - else if (element instanceof JetNamedFunction) { - PsiElement parent = PsiTreeUtil.getParentOfType(element, JetClassOrObject.class, JetFunctionLiteralExpression.class, JetNamedFunction.class); - if (parent instanceof JetClassOrObject) { - result.set(getJvmInternalNameForImpl(typeMapper, (JetClassOrObject) parent)); - } - else if (parent instanceof JetFunctionLiteralExpression || parent instanceof JetNamedFunction) { - Type asmType = asmTypeForAnonymousClass(typeMapper.getBindingContext(), (JetElement) element); - result.set(asmType.getInternalName()); - } - } - - if (result.isNull()) { - result.set(PackageCodegen.getPackagePartInternalName(file)); - } + result.set(getClassNameForElement(sourcePosition.getElementAt(), typeMapper, file)); } + }); return result.get(); } + @SuppressWarnings("unchecked") + private static String getClassNameForElement(@Nullable PsiElement notPositionedElement, @NotNull JetTypeMapper typeMapper, @NotNull JetFile file) { + PsiElement element = PsiTreeUtil.getParentOfType(notPositionedElement, JetClassOrObject.class, JetFunctionLiteral.class, JetNamedFunction.class); + + if (element instanceof JetClassOrObject) { + return getJvmInternalNameForImpl(typeMapper, (JetClassOrObject) element); + } + else if (element instanceof JetFunctionLiteral) { + if (isInlinedLambda((JetFunctionLiteral) element, typeMapper.getBindingContext())) { + return getClassNameForElement(element.getParent(), typeMapper, file); + } else { + Type asmType = asmTypeForAnonymousClass(typeMapper.getBindingContext(), ((JetFunctionLiteral) element)); + return asmType.getInternalName(); + } + } + else if (element instanceof JetNamedFunction) { + PsiElement parent = PsiTreeUtil.getParentOfType(element, JetClassOrObject.class, JetFunctionLiteralExpression.class, JetNamedFunction.class); + if (parent instanceof JetClassOrObject) { + return getJvmInternalNameForImpl(typeMapper, (JetClassOrObject) parent); + } + else if (parent instanceof JetFunctionLiteralExpression || parent instanceof JetNamedFunction) { + Type asmType = asmTypeForAnonymousClass(typeMapper.getBindingContext(), (JetElement) element); + return asmType.getInternalName(); + } + } + + return PackageCodegen.getPackagePartInternalName(file); + } + + @Nullable private static String getJvmInternalNameForImpl(JetTypeMapper typeMapper, JetClassOrObject jetClass) { ClassDescriptor classDescriptor = typeMapper.getBindingContext().get(BindingContext.CLASS, jetClass); @@ -244,4 +257,57 @@ public class JetPositionManager implements PositionManager { }, false); myTypeMappers.put(fqName, value); } + + + public static boolean isInlinedLambda(@NotNull JetFunctionLiteral functionLiteral, @NotNull BindingContext context) { + PsiElement functionLiteralExpression = functionLiteral.getParent(); + if (functionLiteralExpression == null) return false; + + PsiElement parent = functionLiteralExpression.getParent(); + + PsiElement valueArgument = functionLiteralExpression; + while (parent instanceof JetParenthesizedExpression || + parent instanceof JetBinaryExpressionWithTypeRHS || + parent instanceof JetPrefixExpression && JetPsiUtil.isLabeledExpression((JetPrefixExpression) parent)) { + valueArgument = parent; + parent = parent.getParent(); + } + + while (parent instanceof ValueArgument || + parent instanceof JetValueArgumentList) { + parent = parent.getParent(); + } + + if ((parent == null || !(parent instanceof JetBinaryExpression)) && !(parent instanceof JetCallExpression)) return false; + + ResolvedCall call = null; + if (parent instanceof JetCallExpression) { + call = context.get(BindingContext.RESOLVED_CALL, ((JetCallExpression) parent).getCalleeExpression()); + } + if (parent instanceof JetBinaryExpression) { + call = context.get(BindingContext.RESOLVED_CALL, ((JetBinaryExpression) parent).getOperationReference()); + } + + if (call == null) return false; + + InlineStrategy inlineType = InlineUtil.getInlineType(call.getResultingDescriptor().getAnnotations()); + if (!inlineType.isInline()) return false; + + for (Map.Entry entry : call.getValueArguments().entrySet()) { + ValueParameterDescriptor valueParameterDescriptor = entry.getKey(); + ResolvedValueArgument resolvedValueArgument = entry.getValue(); + + for (ValueArgument next : resolvedValueArgument.getArguments()) { + JetExpression expression = next.getArgumentExpression(); + if (valueArgument == expression) { + return InlineAnalyzerExtension.checkInlinableParameter( + valueParameterDescriptor, (JetElement) resolvedValueArgument, + call.getResultingDescriptor(), null + ); + } + } + } + return false; + } + }