Inline util functions renaming

This commit is contained in:
Michael Bogdanov
2015-04-28 17:28:55 +03:00
parent fe23f23664
commit 49f063522c
14 changed files with 55 additions and 58 deletions
@@ -152,7 +152,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
@Nullable @Nullable
@Override @Override
protected ClassDescriptor classForInnerClassRecord() { protected ClassDescriptor classForInnerClassRecord() {
return JvmCodegenUtil.isLambdaWhichWillBeInlined(bindingContext, funDescriptor) ? null : classDescriptor; return JvmCodegenUtil.isArgumentWhichWillBeInlined(bindingContext, funDescriptor) ? null : classDescriptor;
} }
@Override @Override
@@ -1849,7 +1849,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
if (isFunctionLiteral(descriptor)) { if (isFunctionLiteral(descriptor)) {
//non labeled return couldn't be local in lambda //non labeled return couldn't be local in lambda
FunctionDescriptor containingFunction = FunctionDescriptor containingFunction =
BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, false).getFirst(); BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, true).getFirst();
//FIRST_FUN_LABEL to prevent clashing with existing labels //FIRST_FUN_LABEL to prevent clashing with existing labels
return new NonLocalReturnInfo(typeMapper.mapReturnType(containingFunction), InlineCodegenUtil.FIRST_FUN_LABEL); return new NonLocalReturnInfo(typeMapper.mapReturnType(containingFunction), InlineCodegenUtil.FIRST_FUN_LABEL);
} else { } else {
@@ -230,10 +230,10 @@ public class JvmCodegenUtil {
: descriptor; : descriptor;
} }
public static boolean isLambdaWhichWillBeInlined(@NotNull BindingContext bindingContext, @NotNull DeclarationDescriptor descriptor) { public static boolean isArgumentWhichWillBeInlined(@NotNull BindingContext bindingContext, @NotNull DeclarationDescriptor descriptor) {
PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor); PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
return InlineUtil.isFunctionalExpression(declaration) && return InlineUtil.canBeInlineArgument(declaration) &&
InlineUtil.isInlineLambda((JetFunction)declaration, bindingContext, false); InlineUtil.isInlinedArgument((JetFunction) declaration, bindingContext, false);
} }
@Nullable @Nullable
@@ -174,7 +174,7 @@ public class CodegenBinding {
// Note: at the moment this is needed for light classes only // Note: at the moment this is needed for light classes only
// TODO: refactor this out // TODO: refactor this out
if (enclosing != null && !JvmCodegenUtil.isLambdaWhichWillBeInlined(trace.getBindingContext(), classDescriptor)) { if (enclosing != null && !JvmCodegenUtil.isArgumentWhichWillBeInlined(trace.getBindingContext(), classDescriptor)) {
recordInnerClass(trace, enclosing, classDescriptor); recordInnerClass(trace, enclosing, classDescriptor);
} }
} }
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.codegen.inline; package org.jetbrains.kotlin.codegen.inline;
import com.google.common.collect.ImmutableSet;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
@@ -60,7 +59,6 @@ import java.util.*;
import static org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags; import static org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags;
import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive; import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker; import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isFunctionExpression;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isFunctionLiteral; import static org.jetbrains.kotlin.resolve.DescriptorUtils.isFunctionLiteral;
import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCallWithAssert; import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCallWithAssert;
@@ -69,9 +69,9 @@ class CapturingInClosureChecker : CallChecker {
context: BindingContext, scopeContainer: DeclarationDescriptor, variableParent: DeclarationDescriptor context: BindingContext, scopeContainer: DeclarationDescriptor, variableParent: DeclarationDescriptor
): Boolean { ): Boolean {
val scopeDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(scopeContainer) val scopeDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(scopeContainer)
if (!InlineUtil.isFunctionalExpression(scopeDeclaration)) return false if (!InlineUtil.canBeInlineArgument(scopeDeclaration)) return false
if (InlineUtil.isInlineLambda(scopeDeclaration as JetFunction, context, false)) { if (InlineUtil.isInlinedArgument(scopeDeclaration as JetFunction, context, false)) {
val scopeContainerParent = scopeContainer.getContainingDeclaration() val scopeContainerParent = scopeContainer.getContainingDeclaration()
assert(scopeContainerParent != null) { "parent is null for " + scopeContainer } assert(scopeContainerParent != null) { "parent is null for " + scopeContainer }
return !isCapturedVariable(variableParent, scopeContainerParent) || isCapturedInInline(context, scopeContainerParent, variableParent) return !isCapturedVariable(variableParent, scopeContainerParent) || isCapturedInInline(context, scopeContainerParent, variableParent)
@@ -102,8 +102,8 @@ public class InlineUtil {
BindingContext bindingContext = trace.getBindingContext(); BindingContext bindingContext = trace.getBindingContext();
while (isFunctionalExpression(containingFunction) && fromFunction != containingFunctionDescriptor) { while (canBeInlineArgument(containingFunction) && fromFunction != containingFunctionDescriptor) {
if (!isInlineLambda((JetFunction) containingFunction, bindingContext, true)) { if (!isInlinedArgument((JetFunction) containingFunction, bindingContext, true)) {
return false; return false;
} }
@@ -117,20 +117,20 @@ public class InlineUtil {
return fromFunction == containingFunctionDescriptor; return fromFunction == containingFunctionDescriptor;
} }
public static boolean isInlineLambda( public static boolean isInlinedArgument(
@NotNull JetFunction functionalExpression, @NotNull JetFunction argument,
@NotNull BindingContext bindingContext, @NotNull BindingContext bindingContext,
boolean checkNonLocalReturn boolean checkNonLocalReturn
) { ) {
if (!isFunctionalExpression(functionalExpression)) return false; if (!canBeInlineArgument(argument)) return false;
JetExpression call = JetPsiUtil.getParentCallIfPresent(functionalExpression); JetExpression call = JetPsiUtil.getParentCallIfPresent(argument);
if (call != null) { if (call != null) {
ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(call, bindingContext); ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(call, bindingContext);
if (resolvedCall != null && isInline(resolvedCall.getResultingDescriptor())) { if (resolvedCall != null && isInline(resolvedCall.getResultingDescriptor())) {
ValueArgument argument = CallUtilPackage.getValueArgumentForExpression(resolvedCall.getCall(), functionalExpression); ValueArgument valueArgument = CallUtilPackage.getValueArgumentForExpression(resolvedCall.getCall(), argument);
if (argument != null) { if (valueArgument != null) {
ArgumentMapping mapping = resolvedCall.getArgumentMapping(argument); ArgumentMapping mapping = resolvedCall.getArgumentMapping(valueArgument);
if (mapping instanceof ArgumentMatch) { if (mapping instanceof ArgumentMatch) {
ValueParameterDescriptor parameter = ((ArgumentMatch) mapping).getValueParameter(); ValueParameterDescriptor parameter = ((ArgumentMatch) mapping).getValueParameter();
if (isInlineLambdaParameter(parameter)) { if (isInlineLambdaParameter(parameter)) {
@@ -143,7 +143,7 @@ public class InlineUtil {
return false; return false;
} }
public static boolean isFunctionalExpression(@Nullable PsiElement functionalExpression) { public static boolean canBeInlineArgument(@Nullable PsiElement functionalExpression) {
return functionalExpression instanceof JetFunctionLiteral || functionalExpression instanceof JetNamedFunction; return functionalExpression instanceof JetFunctionLiteral || functionalExpression instanceof JetNamedFunction;
} }
@@ -27,11 +27,11 @@ import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.util.text.CharArrayUtil; import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.JetType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.*; import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.*;
@@ -138,35 +138,37 @@ public class CodeInsightUtils {
return element; return element;
} }
@Nullable @NotNull
public static PsiElement[] findElementsOfClassInRange(@NotNull PsiFile file, int startOffset, int endOffset, Class<? extends PsiElement> aClass) { public static List<PsiElement> findElementsOfClassInRange(@NotNull PsiFile file, int startOffset, int endOffset, Class<? extends PsiElement> ... classes) {
PsiElement element1 = getElementAtOffsetIgnoreWhitespaceBefore(file, startOffset); PsiElement element1 = getElementAtOffsetIgnoreWhitespaceBefore(file, startOffset);
PsiElement element2 = getElementAtOffsetIgnoreWhitespaceAfter(file, endOffset); PsiElement element2 = getElementAtOffsetIgnoreWhitespaceAfter(file, endOffset);
if (element1 == null || element2 == null) return PsiElement.EMPTY_ARRAY; if (element1 == null || element2 == null) return Collections.emptyList();
startOffset = element1.getTextRange().getStartOffset(); startOffset = element1.getTextRange().getStartOffset();
endOffset = element2.getTextRange().getEndOffset(); endOffset = element2.getTextRange().getEndOffset();
PsiElement parent = PsiTreeUtil.findCommonParent(element1, element2); PsiElement parent = PsiTreeUtil.findCommonParent(element1, element2);
if (parent == null) return PsiElement.EMPTY_ARRAY; if (parent == null) return Collections.emptyList();
element1 = getTopmostParentInside(element1, parent); element1 = getTopmostParentInside(element1, parent);
if (startOffset != element1.getTextRange().getStartOffset()) return PsiElement.EMPTY_ARRAY; if (startOffset != element1.getTextRange().getStartOffset()) return Collections.emptyList();
element2 = getTopmostParentInside(element2, parent); element2 = getTopmostParentInside(element2, parent);
if (endOffset != element2.getTextRange().getEndOffset()) return PsiElement.EMPTY_ARRAY; if (endOffset != element2.getTextRange().getEndOffset()) return Collections.emptyList();
PsiElement stopElement = element2.getNextSibling(); PsiElement stopElement = element2.getNextSibling();
List<PsiElement> array = new ArrayList<PsiElement>(); List<PsiElement> result = new ArrayList<PsiElement>();
for (PsiElement currentElement = element1; currentElement != stopElement && currentElement != null; currentElement = currentElement.getNextSibling()) { for (PsiElement currentElement = element1; currentElement != stopElement && currentElement != null; currentElement = currentElement.getNextSibling()) {
if (aClass.isInstance(currentElement)) { for (Class aClass : classes) {
array.add(currentElement); if (aClass.isInstance(currentElement)) {
result.add(currentElement);
}
result.addAll(PsiTreeUtil.findChildrenOfType(currentElement, aClass));
} }
array.addAll(PsiTreeUtil.findChildrenOfType(currentElement, aClass));
} }
return PsiUtilCore.toPsiElementArray(array); return result;
} }
@NotNull @NotNull
@@ -83,9 +83,9 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Mult
if (lineNumber >= 0) { if (lineNumber >= 0) {
val lambdaIfInside = getLambdaOrFunIfInside(location, psiFile as JetFile, lineNumber) val lambdaOrFunIfInside = getLambdaOrFunIfInside(location, psiFile as JetFile, lineNumber)
if (lambdaIfInside != null) { if (lambdaOrFunIfInside != null) {
return SourcePosition.createFromElement(lambdaIfInside.getBodyExpression()) return SourcePosition.createFromElement(lambdaOrFunIfInside.getBodyExpression())
} }
return SourcePosition.createFromLine(psiFile, lineNumber) return SourcePosition.createFromLine(psiFile, lineNumber)
} }
@@ -101,15 +101,11 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Mult
val end = CodeInsightUtils.getEndLineOffset(file, lineNumber) val end = CodeInsightUtils.getEndLineOffset(file, lineNumber)
if (start == null || end == null) return null if (start == null || end == null) return null
val functionLiterals: Array<out PsiElement>? = CodeInsightUtils.findElementsOfClassInRange(file, start, end, javaClass<JetFunctionLiteral>()) val literalsOrFunctions = CodeInsightUtils.
val functionalExpression: Array<out PsiElement>? = CodeInsightUtils.findElementsOfClassInRange(file, start, end, javaClass<JetNamedFunction>()) findElementsOfClassInRange(file, start, end, javaClass<JetFunctionLiteral>(), javaClass<JetNamedFunction>()).
val literals = filter { JetPsiUtil.getParentCallIfPresent(it as JetExpression) != null }
if (functionLiterals == null) functionalExpression
else if (functionalExpression == null) functionLiterals
else functionLiterals.plus(functionalExpression).toTypedArray()
if (literalsOrFunctions.isEmpty()) return null;
if (literals == null || literals.size() == 0) return null;
val isInLibrary = LibraryUtil.findLibraryEntry(file.getVirtualFile(), file.getProject()) != null val isInLibrary = LibraryUtil.findLibraryEntry(file.getVirtualFile(), file.getProject()) != null
val typeMapper = if (!isInLibrary) val typeMapper = if (!isInLibrary)
@@ -118,7 +114,7 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Mult
createTypeMapperForLibraryFile(file.findElementAt(start), file) createTypeMapperForLibraryFile(file.findElementAt(start), file)
val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).getInternalName() val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).getInternalName()
for (literal in literals) { for (literal in literalsOrFunctions) {
val functionLiteral = literal as JetFunction val functionLiteral = literal as JetFunction
if (isInlinedLambda(functionLiteral, typeMapper.getBindingContext())) { if (isInlinedLambda(functionLiteral, typeMapper.getBindingContext())) {
continue continue
@@ -400,7 +396,7 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Mult
} }
public fun isInlinedLambda(functionLiteral: JetFunction, context: BindingContext): Boolean { public fun isInlinedLambda(functionLiteral: JetFunction, context: BindingContext): Boolean {
return InlineUtil.isInlineLambda(functionLiteral, context, false) return InlineUtil.isInlinedArgument(functionLiteral, context, false)
} }
private fun createKeyForTypeMapper(file: JetFile) = PackagePartClassUtils.getPackagePartInternalName(file) private fun createKeyForTypeMapper(file: JetFile) = PackagePartClassUtils.getPackagePartInternalName(file)
@@ -84,9 +84,8 @@ private fun JetExpression.getRelevantFunction(): JetFunction? {
(this.getTargetLabel()?.getReference()?.resolve() as? JetFunction)?.let { return it } (this.getTargetLabel()?.getReference()?.resolve() as? JetFunction)?.let { return it }
} }
for (parent in parents(false)) { for (parent in parents(false)) {
when (parent) { if (InlineUtil.canBeInlineArgument(parent) && !InlineUtil.isInlinedArgument(parent as JetFunction, parent.analyze(), false)) {
is JetFunctionLiteral, return parent as JetFunction
is JetNamedFunction -> if (!InlineUtil.isInlineLambda(parent as JetFunction, parent.analyze(), false)) return parent
} }
} }
return null return null
@@ -56,8 +56,8 @@ public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
private fun getEnclosingFunction(element: JetElement): JetNamedFunction? { private fun getEnclosingFunction(element: JetElement): JetNamedFunction? {
for (parent in element.parents(false)) { for (parent in element.parents(false)) {
when (parent) { when (parent) {
is JetFunctionLiteral -> if (!InlineUtil.isInlineLambda(parent, parent.analyze(), false)) return null is JetFunctionLiteral -> if (!InlineUtil.isInlinedArgument(parent, parent.analyze(), false)) return null
is JetNamedFunction -> if (!InlineUtil.isInlineLambda(parent, parent.analyze(), false)) return parent is JetNamedFunction -> if (!InlineUtil.isInlinedArgument(parent, parent.analyze(), false)) return parent
is JetClassOrObject -> return null is JetClassOrObject -> return null
} }
} }
@@ -1,5 +1,5 @@
fun f(a: Int) { fun f(a: Int) {
run(fun () { run2(fun () {
<lineMarker>f</lineMarker>(a - 1) <lineMarker>f</lineMarker>(a - 1)
}) })
} }
@@ -12,3 +12,5 @@ fun ff(a: Int) {
inline fun <T> run1(noinline f: () -> T): T { } inline fun <T> run1(noinline f: () -> T): T { }
inline fun <T> run2(f: () -> T): T { }
@@ -5,4 +5,4 @@ fun test() {
<lineMarker descr="Recursive call">f</lineMarker>(a-1) <lineMarker descr="Recursive call">f</lineMarker>(a-1)
} }
} }
} }
@@ -202,12 +202,6 @@ public class LineMarkersTestGenerated extends AbstractLineMarkersTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("functionalExpression.kt")
public void testFunctionalExpression() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/functionalExpression.kt");
doTest(fileName);
}
@TestMetadata("generic.kt") @TestMetadata("generic.kt")
public void testGeneric() throws Exception { public void testGeneric() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/generic.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/generic.kt");
@@ -238,6 +232,12 @@ public class LineMarkersTestGenerated extends AbstractLineMarkersTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("localFun.kt")
public void testLocalFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/localFun.kt");
doTest(fileName);
}
@TestMetadata("methodReference.kt") @TestMetadata("methodReference.kt")
public void testMethodReference() throws Exception { public void testMethodReference() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/methodReference.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/methodReference.kt");