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