diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt index 5b421812ec7..54b06946750 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt @@ -586,3 +586,13 @@ public val PsiElement.startOffset: Int public val PsiElement.endOffset: Int get() = getTextRange().getEndOffset() + +// Annotations on labeled expression lies on it's base expression +public fun JetExpression.getAnnotationEntries(): List { + val parent = getParent() + return when (parent) { + is JetAnnotatedExpression -> parent.getAnnotationEntries() + is JetLabeledExpression -> parent.getAnnotationEntries() + else -> emptyList() + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt index 87eeffa4ed3..043008f24ff 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.diagnostics.DiagnosticUtils import org.jetbrains.kotlin.diagnostics.Errors.* import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getAnnotationEntries import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.BindingContext.EXPECTED_RETURN_TYPE import org.jetbrains.kotlin.resolve.scopes.WritableScope @@ -156,8 +157,11 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express context: ExpressionTypingContext ): AnonymousFunctionDescriptor { val functionLiteral = expression.getFunctionLiteral() - val functionDescriptor = AnonymousFunctionDescriptor(context.scope.getContainingDeclaration(), Annotations.EMPTY, - CallableMemberDescriptor.Kind.DECLARATION, functionLiteral.toSourceElement()) + val functionDescriptor = AnonymousFunctionDescriptor( + context.scope.getContainingDeclaration(), + components.annotationResolver.resolveAnnotationsWithArguments(context.scope, expression.getAnnotationEntries(), context.trace), + CallableMemberDescriptor.Kind.DECLARATION, functionLiteral.toSourceElement() + ) components.functionDescriptorResolver. initializeFunctionDescriptorAndExplicitReturnType(context.scope.getContainingDeclaration(), context.scope, functionLiteral, functionDescriptor, context.trace, context.expectedType) diff --git a/compiler/testData/renderFunctionDescriptorInExpression/basicFunExpr.kt b/compiler/testData/renderFunctionDescriptorInExpression/basicFunExpr.kt new file mode 100644 index 00000000000..840aca6000d --- /dev/null +++ b/compiler/testData/renderFunctionDescriptorInExpression/basicFunExpr.kt @@ -0,0 +1,9 @@ +annotation class Ann(val x: String) + +fun foo(block: () -> Unit) = block.javaClass + +fun box() { + foo( @Ann("OK1") fun() {}) +} + +//Ann(x = "OK1": kotlin.String) local final fun (): kotlin.Unit defined in box \ No newline at end of file diff --git a/compiler/testData/renderFunctionDescriptorInExpression/basicFunExprArgs.kt b/compiler/testData/renderFunctionDescriptorInExpression/basicFunExprArgs.kt new file mode 100644 index 00000000000..2a4d5708c63 --- /dev/null +++ b/compiler/testData/renderFunctionDescriptorInExpression/basicFunExprArgs.kt @@ -0,0 +1,9 @@ +annotation class Ann(val x: String) + +fun foo(block: (Int, String) -> Unit) = block.javaClass + +fun box() { + foo( @Ann("OK1") fun(@Ann("1") x: Int, @Ann("2") y: String) {}) +} + +//Ann(x = "OK1": kotlin.String) local final fun (/*0*/ Ann(x = "1": kotlin.String) x: kotlin.Int, /*1*/ Ann(x = "2": kotlin.String) y: kotlin.String): kotlin.Unit defined in box \ No newline at end of file diff --git a/compiler/testData/renderFunctionDescriptorInExpression/basicLambda.kt b/compiler/testData/renderFunctionDescriptorInExpression/basicLambda.kt new file mode 100644 index 00000000000..6109ff196ac --- /dev/null +++ b/compiler/testData/renderFunctionDescriptorInExpression/basicLambda.kt @@ -0,0 +1,12 @@ +annotation class Ann(val x: String) + +fun foo(block: () -> Unit) = block.javaClass + +fun box() { + foo( @Ann("OK1") { }) + + foo() @Ann("OK2") { } +} + +//Ann(x = "OK1": kotlin.String) local final fun (): kotlin.Unit defined in box +//Ann(x = "OK2": kotlin.String) local final fun (): kotlin.Unit defined in box diff --git a/compiler/testData/renderFunctionDescriptorInExpression/labeledLambda.kt b/compiler/testData/renderFunctionDescriptorInExpression/labeledLambda.kt new file mode 100644 index 00000000000..30a78fdc556 --- /dev/null +++ b/compiler/testData/renderFunctionDescriptorInExpression/labeledLambda.kt @@ -0,0 +1,12 @@ +annotation class Ann(val x: String) + +fun foo(block: () -> Unit) = block.javaClass + +fun box() { + foo( @Ann("OK1") label@{ }) + + foo() @Ann("OK2") label@{ } +} + +//Ann(x = "OK1": kotlin.String) local final fun (): kotlin.Unit defined in box +//Ann(x = "OK2": kotlin.String) local final fun (): kotlin.Unit defined in box diff --git a/compiler/testData/renderFunctionDescriptorInExpression/parenthesizedFunExpr.kt b/compiler/testData/renderFunctionDescriptorInExpression/parenthesizedFunExpr.kt new file mode 100644 index 00000000000..3460c6ed036 --- /dev/null +++ b/compiler/testData/renderFunctionDescriptorInExpression/parenthesizedFunExpr.kt @@ -0,0 +1,9 @@ +annotation class Ann(val x: String) + +fun foo(block: () -> Unit) = block.javaClass + +fun box() { + foo( @Ann("OK1") (fun() {})) +} + +//local final fun (): kotlin.Unit defined in box \ No newline at end of file diff --git a/compiler/testData/renderFunctionDescriptorInExpression/parenthesizedLambda.kt b/compiler/testData/renderFunctionDescriptorInExpression/parenthesizedLambda.kt new file mode 100644 index 00000000000..58a61ae3d00 --- /dev/null +++ b/compiler/testData/renderFunctionDescriptorInExpression/parenthesizedLambda.kt @@ -0,0 +1,9 @@ +annotation class Ann(val x: String) + +fun foo(block: () -> Unit) = block.javaClass + +fun box() { + foo( @Ann("OK1") ({ })) +} + +//local final fun (): kotlin.Unit defined in box diff --git a/compiler/tests/org/jetbrains/kotlin/renderer/AbstractFunctionDescriptorInExpressionRendererTest.kt b/compiler/tests/org/jetbrains/kotlin/renderer/AbstractFunctionDescriptorInExpressionRendererTest.kt new file mode 100644 index 00000000000..7875ca2ac1e --- /dev/null +++ b/compiler/tests/org/jetbrains/kotlin/renderer/AbstractFunctionDescriptorInExpressionRendererTest.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2010-2015 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.kotlin.renderer + +import com.intellij.openapi.editor.impl.DocumentImpl +import com.intellij.openapi.util.io.FileUtil +import com.intellij.testFramework.UsefulTestCase +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.impl.FunctionExpressionDescriptor +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil +import org.jetbrains.kotlin.resolve.lazy.KotlinTestWithEnvironment +import org.jetbrains.kotlin.test.ConfigurationKind +import org.jetbrains.kotlin.test.JetTestUtils +import org.jetbrains.kotlin.utils.addIfNotNull +import java.io.File + +abstract public class AbstractFunctionDescriptorInExpressionRendererTest : KotlinTestWithEnvironment() { + public fun doTest(path: String) { + val fileText = FileUtil.loadFile(File(path), true) + val file = JetPsiFactory(getProject()).createFile(fileText) + val bindingContext = JvmResolveUtil.analyzeOneFileWithJavaIntegration(file).bindingContext + + val descriptors = arrayListOf() + + file.accept(object : JetTreeVisitorVoid() { + override fun visitNamedFunction(function: JetNamedFunction) { + function.acceptChildren(this) + descriptors.addIfNotNull(bindingContext.get(BindingContext.FUNCTION, function) as? FunctionExpressionDescriptor) + } + override fun visitFunctionLiteralExpression(expression: JetFunctionLiteralExpression) { + expression.acceptChildren(this) + descriptors.add(bindingContext.get(BindingContext.FUNCTION, expression.getFunctionLiteral())) + } + }) + + val renderer = DescriptorRendererBuilder().setNameShortness(NameShortness.FULLY_QUALIFIED).setVerbose(true).build() + val renderedDescriptors = descriptors.map { renderer.render(it) }.joinToString(separator = "\n") + + val document = DocumentImpl(file.getText()) + UsefulTestCase.assertSameLines(JetTestUtils.getLastCommentedLines(document), renderedDescriptors.toString()) + } + + override fun createEnvironment(): KotlinCoreEnvironment { + return createEnvironmentWithMockJdk(ConfigurationKind.JDK_ONLY) + } +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/renderer/FunctionDescriptorInExpressionRendererTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/renderer/FunctionDescriptorInExpressionRendererTestGenerated.java new file mode 100644 index 00000000000..169d23b04c5 --- /dev/null +++ b/compiler/tests/org/jetbrains/kotlin/renderer/FunctionDescriptorInExpressionRendererTestGenerated.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010-2015 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.kotlin.renderer; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.JetTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/testData/renderFunctionDescriptorInExpression") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class FunctionDescriptorInExpressionRendererTestGenerated extends AbstractFunctionDescriptorInExpressionRendererTest { + public void testAllFilesPresentInRenderFunctionDescriptorInExpression() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/renderFunctionDescriptorInExpression"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("basicFunExpr.kt") + public void testBasicFunExpr() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/renderFunctionDescriptorInExpression/basicFunExpr.kt"); + doTest(fileName); + } + + @TestMetadata("basicFunExprArgs.kt") + public void testBasicFunExprArgs() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/renderFunctionDescriptorInExpression/basicFunExprArgs.kt"); + doTest(fileName); + } + + @TestMetadata("basicLambda.kt") + public void testBasicLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/renderFunctionDescriptorInExpression/basicLambda.kt"); + doTest(fileName); + } + + @TestMetadata("labeledLambda.kt") + public void testLabeledLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/renderFunctionDescriptorInExpression/labeledLambda.kt"); + doTest(fileName); + } + + @TestMetadata("parenthesizedFunExpr.kt") + public void testParenthesizedFunExpr() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/renderFunctionDescriptorInExpression/parenthesizedFunExpr.kt"); + doTest(fileName); + } + + @TestMetadata("parenthesizedLambda.kt") + public void testParenthesizedLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/renderFunctionDescriptorInExpression/parenthesizedLambda.kt"); + doTest(fileName); + } +} diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 922a4e87893..69530231434 100644 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -105,6 +105,7 @@ import org.jetbrains.kotlin.modules.xml.AbstractModuleXmlParserTest import org.jetbrains.kotlin.parsing.AbstractJetParsingTest import org.jetbrains.kotlin.psi.patternMatching.AbstractJetPsiUnifierTest import org.jetbrains.kotlin.renderer.AbstractDescriptorRendererTest +import org.jetbrains.kotlin.renderer.AbstractFunctionDescriptorInExpressionRendererTest import org.jetbrains.kotlin.repl.AbstractReplInterpreterTest import org.jetbrains.kotlin.resolve.AbstractResolveTest import org.jetbrains.kotlin.resolve.annotation.AbstractAnnotationParameterTest @@ -247,6 +248,10 @@ fun main(args: Array) { model("renderer") } + testClass(javaClass()) { + model("renderFunctionDescriptorInExpression") + } + testClass(javaClass()) { model("modules.xml", extension = "xml") }