From f53af70ad6466dcdf1333d1945f174abd9f3526a Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Wed, 3 Apr 2013 20:32:12 +0400 Subject: [PATCH] Added separate highlighting keys for variables invoked as function and function-like. --- .../jetbrains/jet/plugin/JetBundle.properties | 1 + .../FunctionsHighlightingVisitor.java | 84 ++++++++++++++----- .../highlighter/JetColorSettingsPage.java | 5 +- .../highlighter/JetHighlightingColors.java | 5 ++ .../checker/infos/VariableAsFunction.kt | 6 +- 5 files changed, 77 insertions(+), 24 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties index f0eb6b1fa3a..5b3239298a4 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties +++ b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties @@ -116,6 +116,7 @@ options.jet.attribute.descriptor.namespace.fun.call=Package-level function call options.jet.attribute.descriptor.extension.fun.call=Extension function call options.jet.attribute.descriptor.constructor.call=Constructor call options.jet.attribute.descriptor.variable.as.function.call=Variable as function call +options.jet.attribute.descriptor.variable.as.function.like.call=Variable as function-like call options.jet.attribute.descriptor.auto.casted=Smart-cast value options.jet.attribute.descriptor.label=Label change.to.function.invocation=Change to function invocation diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/FunctionsHighlightingVisitor.java b/idea/src/org/jetbrains/jet/plugin/highlighter/FunctionsHighlightingVisitor.java index 6a27a905708..b396ff14a15 100644 --- a/idea/src/org/jetbrains/jet/plugin/highlighter/FunctionsHighlightingVisitor.java +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/FunctionsHighlightingVisitor.java @@ -22,6 +22,11 @@ import org.jetbrains.jet.lang.descriptors.*; 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.calls.model.ResolvedCall; +import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeUtils; +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; public class FunctionsHighlightingVisitor extends AfterAnalysisHighlightingVisitor { public FunctionsHighlightingVisitor(AnnotationHolder holder, BindingContext bindingContext) { @@ -58,33 +63,72 @@ public class FunctionsHighlightingVisitor extends AfterAnalysisHighlightingVisit public void visitCallExpression(JetCallExpression expression) { JetExpression callee = expression.getCalleeExpression(); if (callee instanceof JetReferenceExpression) { - DeclarationDescriptor calleeDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetReferenceExpression)callee); - if (calleeDescriptor != null) { - if (calleeDescriptor instanceof ConstructorDescriptor) { - JetPsiChecker.highlightName(holder, callee, JetHighlightingColors.CONSTRUCTOR_CALL); + ResolvedCall resolvedCall = + bindingContext.get(BindingContext.RESOLVED_CALL, (JetReferenceExpression) callee); + if (resolvedCall != null) { + if (resolvedCall instanceof VariableAsFunctionResolvedCall) { + highlightVariableAsFunctionCall(callee, (VariableAsFunctionResolvedCall) resolvedCall); } - else if (calleeDescriptor instanceof FunctionDescriptor) { - FunctionDescriptor fun = (FunctionDescriptor)calleeDescriptor; - JetPsiChecker.highlightName(holder, callee, JetHighlightingColors.FUNCTION_CALL); - if (DescriptorUtils.isTopLevelDeclaration(fun)) { - JetPsiChecker.highlightName(holder, callee, JetHighlightingColors.NAMESPACE_FUNCTION_CALL); + else { + DeclarationDescriptor calleeDescriptor = resolvedCall.getResultingDescriptor(); + if (calleeDescriptor instanceof ConstructorDescriptor) { + JetPsiChecker.highlightName(holder, callee, JetHighlightingColors.CONSTRUCTOR_CALL); } - if (fun.getReceiverParameter() != null) { - JetPsiChecker.highlightName(holder, callee, JetHighlightingColors.EXTENSION_FUNCTION_CALL); + else if (calleeDescriptor instanceof FunctionDescriptor) { + FunctionDescriptor fun = (FunctionDescriptor) calleeDescriptor; + JetPsiChecker.highlightName(holder, callee, JetHighlightingColors.FUNCTION_CALL); + if (DescriptorUtils.isTopLevelDeclaration(fun)) { + JetPsiChecker.highlightName(holder, callee, JetHighlightingColors.NAMESPACE_FUNCTION_CALL); + } + if (fun.getReceiverParameter() != null) { + JetPsiChecker.highlightName(holder, callee, JetHighlightingColors.EXTENSION_FUNCTION_CALL); + } } } - else if (calleeDescriptor instanceof VariableDescriptor) { - String kind = calleeDescriptor instanceof ValueParameterDescriptor - ? "parameter" - : calleeDescriptor instanceof PropertyDescriptor - ? "property" - : "variable"; - holder.createInfoAnnotation(callee, "Calling " + kind + " as function").setTextAttributes( - JetHighlightingColors.VARIABLE_AS_FUNCTION_CALL); - } } } super.visitCallExpression(expression); } + + private void highlightVariableAsFunctionCall(JetExpression callee, VariableAsFunctionResolvedCall resolvedCall) { + VariableDescriptor variableDescriptor = resolvedCall.getVariableCall().getResultingDescriptor(); + + String kind = variableDescriptor instanceof ValueParameterDescriptor + ? "parameter" + : variableDescriptor instanceof PropertyDescriptor + ? "property" + : "variable"; + + if (containedInFunctionClassOrSubclass(resolvedCall.getFunctionCall().getResultingDescriptor())) { + holder.createInfoAnnotation(callee, "Calling " + kind + " as function").setTextAttributes( + JetHighlightingColors.VARIABLE_AS_FUNCTION_CALL); + } + else { + holder.createInfoAnnotation(callee, "Calling " + kind + " as function-like").setTextAttributes( + JetHighlightingColors.VARIABLE_AS_FUNCTION_LIKE_CALL); + } + } + + private static boolean containedInFunctionClassOrSubclass(DeclarationDescriptor calleeDescriptor) { + DeclarationDescriptor parent = calleeDescriptor.getContainingDeclaration(); + if (!(parent instanceof ClassDescriptor)) { + return false; + } + + KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); + JetType defaultType = ((ClassDescriptor) parent).getDefaultType(); + + if (builtIns.isFunctionOrExtensionFunctionType(defaultType)) { + return true; + } + + for (JetType supertype : TypeUtils.getAllSupertypes(defaultType)) { + if (builtIns.isFunctionOrExtensionFunctionType(supertype)) { + return true; + } + } + + return false; + } } diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/JetColorSettingsPage.java b/idea/src/org/jetbrains/jet/plugin/highlighter/JetColorSettingsPage.java index 814d761199f..4e55276ed3b 100644 --- a/idea/src/org/jetbrains/jet/plugin/highlighter/JetColorSettingsPage.java +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/JetColorSettingsPage.java @@ -58,10 +58,10 @@ public class JetColorSettingsPage implements ColorSettingsPage { " */\n" + "[Deprecated]\n" + "public class MyClass<out T : Iterable<T>>(var prop1 : Int) {\n" + - " fun foo(nullable : String?, r : Runnable, f : () -> Int) {\n" + + " fun foo(nullable : String?, r : Runnable, f : () -> Int, fl : FunctionLike) {\n" + " println(\"length\\nis ${nullable?.length} \\e\")\n" + " val ints = java.util.ArrayList(2)\n" + - " ints[0] = 102 + f()\n" + + " ints[0] = 102 + f() + fl()\n" + " val myFun = { -> \"\" };\n" + " var ref = ints.size()\n" + " if (!ints.empty) {\n" + @@ -156,6 +156,7 @@ public class JetColorSettingsPage implements ColorSettingsPage { new AttributesDescriptor(JetBundle.message("options.jet.attribute.descriptor.extension.fun.call"), JetHighlightingColors.EXTENSION_FUNCTION_CALL), new AttributesDescriptor(JetBundle.message("options.jet.attribute.descriptor.constructor.call"), JetHighlightingColors.CONSTRUCTOR_CALL), new AttributesDescriptor(JetBundle.message("options.jet.attribute.descriptor.variable.as.function.call"), JetHighlightingColors.VARIABLE_AS_FUNCTION_CALL), + new AttributesDescriptor(JetBundle.message("options.jet.attribute.descriptor.variable.as.function.like.call"), JetHighlightingColors.VARIABLE_AS_FUNCTION_LIKE_CALL), new AttributesDescriptor(OptionsBundle.message("options.java.attribute.descriptor.bad.character"), JetHighlightingColors.BAD_CHARACTER), diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/JetHighlightingColors.java b/idea/src/org/jetbrains/jet/plugin/highlighter/JetHighlightingColors.java index f9c81757ccb..2f769c9354d 100644 --- a/idea/src/org/jetbrains/jet/plugin/highlighter/JetHighlightingColors.java +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/JetHighlightingColors.java @@ -241,6 +241,11 @@ public class JetHighlightingColors { new TextAttributes() ); + public static final TextAttributesKey VARIABLE_AS_FUNCTION_LIKE_CALL = TextAttributesKey.createTextAttributesKey( + "KOTLIN_VARIABLE_AS_FUNCTION_LIKE", + new TextAttributes() + ); + public static final TextAttributesKey BAD_CHARACTER = TextAttributesKey.createTextAttributesKey( "KOTLIN_BAD_CHARACTER", HighlighterColors.BAD_CHARACTER.getDefaultAttributes() diff --git a/idea/testData/checker/infos/VariableAsFunction.kt b/idea/testData/checker/infos/VariableAsFunction.kt index 129e3656184..04104a1a7bf 100644 --- a/idea/testData/checker/infos/VariableAsFunction.kt +++ b/idea/testData/checker/infos/VariableAsFunction.kt @@ -7,7 +7,7 @@ val property = {} fun foo(param: (Int) -> Int, functionLike: FunctionLike) { param(1) - functionLike() + functionLike() val v1 = param var v2 = param @@ -15,5 +15,7 @@ fun foo(param: (Int) -> Int, functionLike: FunctionLike) { v1(1) v2(1) - property() + property(); + + {}() //should not be highlighted as "calling variable as function" } \ No newline at end of file