From 1b391123e653f50355a633a1465a3e6f6e89a967 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Mon, 11 Jul 2016 16:03:46 +0300 Subject: [PATCH] Implement for/iter postfix templates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit   #KT-4710 In Progress --- .../org/jetbrains/kotlin/types/TypeUtils.kt | 1 + .../after.kt.template | 4 ++ .../before.kt.template | 3 ++ .../KtForEachPostfixTemplate/description.html | 5 ++ .../postfix/KtPostfixTemplateProvider.kt | 4 +- .../postfix/stringBasedPostfixTemplates.kt | 46 +++++++++++++++++++ .../macro/SuggestVariableNameMacro.kt | 0 idea/testData/codeInsight/postfix/for.kt | 3 ++ .../testData/codeInsight/postfix/for.kt.after | 5 ++ idea/testData/codeInsight/postfix/iter.kt | 3 ++ .../codeInsight/postfix/iter.kt.after | 5 ++ .../PostfixTemplateProviderTestGenerated.java | 12 +++++ 12 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 idea/resources/postfixTemplates/KtForEachPostfixTemplate/after.kt.template create mode 100644 idea/resources/postfixTemplates/KtForEachPostfixTemplate/before.kt.template create mode 100644 idea/resources/postfixTemplates/KtForEachPostfixTemplate/description.html create mode 100644 idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/stringBasedPostfixTemplates.kt rename idea/{idea-live-templates => }/src/org/jetbrains/kotlin/idea/liveTemplates/macro/SuggestVariableNameMacro.kt (100%) create mode 100644 idea/testData/codeInsight/postfix/for.kt create mode 100644 idea/testData/codeInsight/postfix/for.kt.after create mode 100644 idea/testData/codeInsight/postfix/iter.kt create mode 100644 idea/testData/codeInsight/postfix/iter.kt.after diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt index 669f22d3fd4..8ec661e88ae 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt @@ -60,6 +60,7 @@ fun KotlinType.isBoolean(): Boolean = KotlinBuiltIns.isBoolean(this) fun KotlinType.isPrimitiveNumberType(): Boolean = KotlinBuiltIns.isPrimitiveType(this) && !isBoolean() fun KotlinType.isBooleanOrNullableBoolean(): Boolean = KotlinBuiltIns.isBooleanOrNullableBoolean(this) fun KotlinType.isThrowable(): Boolean = isConstructedFromClassWithGivenFqName(KotlinBuiltIns.FQ_NAMES.throwable) && !isMarkedNullable +fun KotlinType.isIterator(): Boolean = isConstructedFromClassWithGivenFqName(KotlinBuiltIns.FQ_NAMES.iterator) && !isMarkedNullable fun KotlinType.isConstructedFromClassWithGivenFqName(fqName: FqName) = (constructor.declarationDescriptor as? ClassDescriptor)?.fqNameUnsafe == fqName.toUnsafe() diff --git a/idea/resources/postfixTemplates/KtForEachPostfixTemplate/after.kt.template b/idea/resources/postfixTemplates/KtForEachPostfixTemplate/after.kt.template new file mode 100644 index 00000000000..92982c00af0 --- /dev/null +++ b/idea/resources/postfixTemplates/KtForEachPostfixTemplate/after.kt.template @@ -0,0 +1,4 @@ +fun bar() = 1 +fun foo() { + val bar = bar() +} diff --git a/idea/resources/postfixTemplates/KtForEachPostfixTemplate/before.kt.template b/idea/resources/postfixTemplates/KtForEachPostfixTemplate/before.kt.template new file mode 100644 index 00000000000..c6173d0124c --- /dev/null +++ b/idea/resources/postfixTemplates/KtForEachPostfixTemplate/before.kt.template @@ -0,0 +1,3 @@ +fun foo(list: List) { + list$key +} diff --git a/idea/resources/postfixTemplates/KtForEachPostfixTemplate/description.html b/idea/resources/postfixTemplates/KtForEachPostfixTemplate/description.html new file mode 100644 index 00000000000..3fa69a7ad05 --- /dev/null +++ b/idea/resources/postfixTemplates/KtForEachPostfixTemplate/description.html @@ -0,0 +1,5 @@ + + +Creates for statement from given iterable expression. + + diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KtPostfixTemplateProvider.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KtPostfixTemplateProvider.kt index 8b791af0f84..6a84ad86950 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KtPostfixTemplateProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KtPostfixTemplateProvider.kt @@ -44,7 +44,9 @@ class KtPostfixTemplateProvider : PostfixTemplateProvider { KtWhenExpressionPostfixTemplate, KtTryPostfixTemplate, KtIntroduceVariablePostfixTemplate("val"), - KtIntroduceVariablePostfixTemplate("var") + KtIntroduceVariablePostfixTemplate("var"), + KtForEachPostfixTemplate("for"), + KtForEachPostfixTemplate("iter") ) override fun isTerminalSymbol(currentChar: Char) = currentChar == '.' || currentChar == '!' diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/stringBasedPostfixTemplates.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/stringBasedPostfixTemplates.kt new file mode 100644 index 00000000000..ff2466bdde4 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/stringBasedPostfixTemplates.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2010-2016 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.idea.codeInsight.postfix + +import com.intellij.codeInsight.template.Template +import com.intellij.codeInsight.template.impl.ConstantNode +import com.intellij.codeInsight.template.impl.MacroCallNode +import com.intellij.codeInsight.template.postfix.templates.StringBasedPostfixTemplate +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.idea.liveTemplates.macro.SuggestVariableNameMacro +import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.typeUtil.isIterator +import org.jetbrains.kotlin.util.OperatorNameConventions + +internal class KtForEachPostfixTemplate( + name: String +) : StringBasedPostfixTemplate(name, "for (item in expr)", createExpressionSelector(statementsOnly = true, predicate = KotlinType::containsIteratorMethod)) { + override fun getTemplateString(element: PsiElement) = "for (\$name$ in \$expr$) {\n \$END$\n}" + + override fun setVariables(template: Template, element: PsiElement) { + val name = MacroCallNode(SuggestVariableNameMacro()) + template.addVariable("name", name, ConstantNode("item"), true) + } + + override fun getElementToRemove(expr: PsiElement?) = expr +} + +private fun KotlinType.containsIteratorMethod() = + memberScope.getContributedFunctions(OperatorNameConventions.ITERATOR, NoLookupLocation.FROM_IDE).any { + it.returnType?.isIterator() ?: false && it.valueParameters.isEmpty() + } diff --git a/idea/idea-live-templates/src/org/jetbrains/kotlin/idea/liveTemplates/macro/SuggestVariableNameMacro.kt b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/SuggestVariableNameMacro.kt similarity index 100% rename from idea/idea-live-templates/src/org/jetbrains/kotlin/idea/liveTemplates/macro/SuggestVariableNameMacro.kt rename to idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/SuggestVariableNameMacro.kt diff --git a/idea/testData/codeInsight/postfix/for.kt b/idea/testData/codeInsight/postfix/for.kt new file mode 100644 index 00000000000..072482cd876 --- /dev/null +++ b/idea/testData/codeInsight/postfix/for.kt @@ -0,0 +1,3 @@ +fun foo(list: List) { + list.for +} diff --git a/idea/testData/codeInsight/postfix/for.kt.after b/idea/testData/codeInsight/postfix/for.kt.after new file mode 100644 index 00000000000..5deb3937017 --- /dev/null +++ b/idea/testData/codeInsight/postfix/for.kt.after @@ -0,0 +1,5 @@ +fun foo(list: List) { + for (s in list) { + + } +} diff --git a/idea/testData/codeInsight/postfix/iter.kt b/idea/testData/codeInsight/postfix/iter.kt new file mode 100644 index 00000000000..76826ed31ab --- /dev/null +++ b/idea/testData/codeInsight/postfix/iter.kt @@ -0,0 +1,3 @@ +fun foo(list: List) { + list.iter +} diff --git a/idea/testData/codeInsight/postfix/iter.kt.after b/idea/testData/codeInsight/postfix/iter.kt.after new file mode 100644 index 00000000000..5deb3937017 --- /dev/null +++ b/idea/testData/codeInsight/postfix/iter.kt.after @@ -0,0 +1,5 @@ +fun foo(list: List) { + for (s in list) { + + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/postfix/PostfixTemplateProviderTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/postfix/PostfixTemplateProviderTestGenerated.java index ec9d5fc3358..d1aef6ea8c7 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/postfix/PostfixTemplateProviderTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/postfix/PostfixTemplateProviderTestGenerated.java @@ -41,12 +41,24 @@ public class PostfixTemplateProviderTestGenerated extends AbstractPostfixTemplat doTest(fileName); } + @TestMetadata("for.kt") + public void testFor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/postfix/for.kt"); + doTest(fileName); + } + @TestMetadata("if.kt") public void testIf() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/postfix/if.kt"); doTest(fileName); } + @TestMetadata("iter.kt") + public void testIter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/postfix/iter.kt"); + doTest(fileName); + } + @TestMetadata("notBoolean.kt") public void testNotBoolean() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/postfix/notBoolean.kt");