diff --git a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/AnonymousTemplateEditingListener.java b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/AnonymousTemplateEditingListener.java deleted file mode 100644 index 171067f4bf3..00000000000 --- a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/AnonymousTemplateEditingListener.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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.idea.liveTemplates.macro; - -import com.intellij.codeInsight.template.Template; -import com.intellij.codeInsight.template.TemplateEditingAdapter; -import com.intellij.codeInsight.template.impl.TemplateManagerImpl; -import com.intellij.codeInsight.template.impl.TemplateState; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import org.jetbrains.kotlin.descriptors.ClassDescriptor; -import org.jetbrains.kotlin.descriptors.ClassKind; -import org.jetbrains.kotlin.descriptors.ConstructorDescriptor; -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils; -import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler; -import org.jetbrains.kotlin.psi.KtReferenceExpression; -import org.jetbrains.kotlin.resolve.BindingContext; -import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode; - -class AnonymousTemplateEditingListener extends TemplateEditingAdapter { - private KtReferenceExpression classRef; - private ClassDescriptor classDescriptor; - private final Editor editor; - private final PsiFile psiFile; - - private static final Key LISTENER_KEY = Key.create("kotlin.AnonymousTemplateEditingListener"); - - public AnonymousTemplateEditingListener(PsiFile psiFile, Editor editor) { - this.psiFile = psiFile; - this.editor = editor; - } - - @Override - public void currentVariableChanged(TemplateState templateState, Template template, int oldIndex, int newIndex) { - assert templateState.getTemplate() != null; - TextRange variableRange = templateState.getVariableRange("SUPERTYPE"); - if (variableRange == null) return; - PsiElement name = psiFile.findElementAt(variableRange.getStartOffset()); - if (name != null && name.getParent() instanceof KtReferenceExpression) { - KtReferenceExpression ref = (KtReferenceExpression) name.getParent(); - DeclarationDescriptor descriptor = ResolutionUtils.analyze(ref, BodyResolveMode.FULL).get(BindingContext.REFERENCE_TARGET, ref); - if (descriptor instanceof ClassDescriptor) { - classRef = ref; - classDescriptor = (ClassDescriptor) descriptor; - } - } - } - - @Override - public void templateFinished(Template template, boolean brokenOff) { - editor.putUserData(LISTENER_KEY, null); - if (brokenOff) { - return; - } - - if (classDescriptor != null) { - if (classDescriptor.getKind() == ClassKind.CLASS) { - int placeToInsert = classRef.getTextRange().getEndOffset(); - PsiDocumentManager.getInstance(psiFile.getProject()).getDocument(psiFile).insertString(placeToInsert, "()"); - - boolean hasConstructorsParameters = false; - for (ConstructorDescriptor cd : classDescriptor.getConstructors()) { - // TODO check for visibility - hasConstructorsParameters |= cd.getValueParameters().size() != 0; - } - - if (hasConstructorsParameters) { - editor.getCaretModel().moveToOffset(placeToInsert + 1); - } - } - - new ImplementMembersHandler().invoke(psiFile.getProject(), editor, psiFile, true); - } - } - - static void registerListener(Editor editor, Project project) { - if (editor.getUserData(LISTENER_KEY) != null) { - return; - } - PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); - assert psiFile != null; - TemplateState templateState = TemplateManagerImpl.getTemplateState(editor); - if (templateState != null) { - AnonymousTemplateEditingListener listener = new AnonymousTemplateEditingListener(psiFile, editor); - editor.putUserData(LISTENER_KEY, listener); - templateState.addTemplateStateListener(listener); - } - } -} diff --git a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/AnonymousTemplateEditingListener.kt b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/AnonymousTemplateEditingListener.kt new file mode 100644 index 00000000000..7551457b239 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/AnonymousTemplateEditingListener.kt @@ -0,0 +1,96 @@ +/* + * 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.idea.liveTemplates.macro + +import com.intellij.codeInsight.template.Template +import com.intellij.codeInsight.template.TemplateEditingAdapter +import com.intellij.codeInsight.template.impl.TemplateManagerImpl +import com.intellij.codeInsight.template.impl.TemplateState +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler +import org.jetbrains.kotlin.psi.KtReferenceExpression +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode + +internal class AnonymousTemplateEditingListener(private val psiFile: PsiFile, private val editor: Editor) : TemplateEditingAdapter() { + private var classRef: KtReferenceExpression? = null + private var classDescriptor: ClassDescriptor? = null + + override fun currentVariableChanged(templateState: TemplateState?, template: Template?, oldIndex: Int, newIndex: Int) { + assert(templateState!!.template != null) + val variableRange = templateState.getVariableRange("SUPERTYPE") ?: return + val name = psiFile.findElementAt(variableRange.startOffset) + if (name != null && name.parent is KtReferenceExpression) { + val ref = name.parent as KtReferenceExpression + val descriptor = ref.analyze(BodyResolveMode.FULL).get(BindingContext.REFERENCE_TARGET, ref) + if (descriptor is ClassDescriptor) { + classRef = ref + classDescriptor = descriptor + } + } + } + + override fun templateFinished(template: Template?, brokenOff: Boolean) { + editor.putUserData(LISTENER_KEY, null) + if (brokenOff) { + return + } + + if (classDescriptor != null) { + if (classDescriptor!!.kind == ClassKind.CLASS) { + val placeToInsert = classRef!!.textRange.endOffset + PsiDocumentManager.getInstance(psiFile.project).getDocument(psiFile)!!.insertString(placeToInsert, "()") + + var hasConstructorsParameters = false + for (cd in classDescriptor!!.constructors) { + // TODO check for visibility + hasConstructorsParameters = hasConstructorsParameters or (cd.valueParameters.size != 0) + } + + if (hasConstructorsParameters) { + editor.caretModel.moveToOffset(placeToInsert + 1) + } + } + + ImplementMembersHandler().invoke(psiFile.project, editor, psiFile, true) + } + } + + companion object { + + private val LISTENER_KEY = Key.create("kotlin.AnonymousTemplateEditingListener") + + fun registerListener(editor: Editor, project: Project) { + if (editor.getUserData(LISTENER_KEY) != null) return + + val psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.document)!! + val templateState = TemplateManagerImpl.getTemplateState(editor) + if (templateState != null) { + val listener = AnonymousTemplateEditingListener(psiFile, editor) + editor.putUserData(LISTENER_KEY, listener) + templateState.addTemplateStateListener(listener) + } + } + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/AnyVariableMacro.java b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/AnyVariableMacro.java deleted file mode 100644 index 6753a01b6cb..00000000000 --- a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/AnyVariableMacro.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.idea.liveTemplates.macro; - -import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.descriptors.VariableDescriptor; -import org.jetbrains.kotlin.idea.KotlinBundle; -import org.jetbrains.kotlin.idea.core.IterableTypesDetector; - -public class AnyVariableMacro extends BaseKotlinVariableMacro { - @Override - public String getName() { - return "kotlinVariable"; - } - - @Override - public String getPresentableName() { - return KotlinBundle.message("macro.variable.of.type"); - } - - @Override - protected boolean isSuitable( - @NotNull VariableDescriptor variableDescriptor, - @NotNull Project project, - @NotNull IterableTypesDetector iterableTypesDetector - ) { - return true; - } -} diff --git a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/AnyVariableMacro.kt b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/AnyVariableMacro.kt new file mode 100644 index 00000000000..0ed43279543 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/AnyVariableMacro.kt @@ -0,0 +1,39 @@ +/* + * 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.idea.liveTemplates.macro + +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.descriptors.VariableDescriptor +import org.jetbrains.kotlin.idea.KotlinBundle +import org.jetbrains.kotlin.idea.core.IterableTypesDetector + +class AnyVariableMacro : BaseKotlinVariableMacro() { + override fun getName(): String { + return "kotlinVariable" + } + + override fun getPresentableName(): String { + return KotlinBundle.message("macro.variable.of.type") + } + + override fun isSuitable( + variableDescriptor: VariableDescriptor, + project: Project, + iterableTypesDetector: IterableTypesDetector): Boolean { + return true + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/BaseKotlinVariableMacro.java b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/BaseKotlinVariableMacro.java deleted file mode 100644 index 582e22f3d73..00000000000 --- a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/BaseKotlinVariableMacro.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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.idea.liveTemplates.macro; - -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupElementBuilder; -import com.intellij.codeInsight.template.Expression; -import com.intellij.codeInsight.template.ExpressionContext; -import com.intellij.codeInsight.template.Macro; -import com.intellij.codeInsight.template.Result; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiNamedElement; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor; -import org.jetbrains.kotlin.descriptors.VariableDescriptor; -import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils; -import org.jetbrains.kotlin.idea.core.IterableTypesDetection; -import org.jetbrains.kotlin.idea.core.IterableTypesDetector; -import org.jetbrains.kotlin.idea.resolve.ResolutionFacade; -import org.jetbrains.kotlin.idea.util.ExtensionUtils; -import org.jetbrains.kotlin.idea.util.ScopeUtils; -import org.jetbrains.kotlin.psi.*; -import org.jetbrains.kotlin.resolve.BindingContext; -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; -import org.jetbrains.kotlin.resolve.DescriptorUtils; -import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt; -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; -import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode; -import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter; -import org.jetbrains.kotlin.resolve.scopes.MemberScope; -import org.jetbrains.kotlin.resolve.scopes.LexicalScope; -import org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtilsKt; - -import java.util.*; - -public abstract class BaseKotlinVariableMacro extends Macro { - @Nullable - private KtNamedDeclaration[] getVariables(Expression[] params, ExpressionContext context) { - if (params.length != 0) return null; - - Project project = context.getProject(); - PsiDocumentManager.getInstance(project).commitAllDocuments(); - - PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(context.getEditor().getDocument()); - if (!(psiFile instanceof KtFile)) return null; - - KtExpression contextExpression = findContextExpression(psiFile, context.getStartOffset()); - if (contextExpression == null) return null; - - ResolutionFacade resolutionFacade = ResolutionUtils.getResolutionFacade(contextExpression); - - BindingContext bindingContext = resolutionFacade.analyze(contextExpression, BodyResolveMode.FULL); - LexicalScope scope = ScopeUtils.getResolutionScope(contextExpression, bindingContext, resolutionFacade); - - IterableTypesDetector detector = resolutionFacade.getIdeService(IterableTypesDetection.class).createDetector(scope); - - DataFlowInfo dataFlowInfo = BindingContextUtilsKt.getDataFlowInfo(bindingContext, contextExpression); - - List filteredDescriptors = new ArrayList(); - for (DeclarationDescriptor declarationDescriptor : getAllVariables(scope)) { - if (declarationDescriptor instanceof VariableDescriptor) { - VariableDescriptor variableDescriptor = (VariableDescriptor) declarationDescriptor; - - if (variableDescriptor.getExtensionReceiverParameter() != null - && ExtensionUtils.substituteExtensionIfCallableWithImplicitReceiver( - variableDescriptor, scope, bindingContext, dataFlowInfo).isEmpty()) { - continue; - } - - if (isSuitable(variableDescriptor, project, detector)) { - filteredDescriptors.add(variableDescriptor); - } - } - } - - - List declarations = new ArrayList(); - for (DeclarationDescriptor declarationDescriptor : filteredDescriptors) { - PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(declarationDescriptor); - assert declaration == null || declaration instanceof PsiNamedElement; - - if (declaration instanceof KtProperty || declaration instanceof KtParameter) { - declarations.add((KtNamedDeclaration) declaration); - } - } - - return declarations.toArray(new KtNamedDeclaration[declarations.size()]); - } - - private static Collection getAllVariables(LexicalScope scope) { - Collection result = ContainerUtil.newArrayList(); - result.addAll(ScopeUtilsKt.collectDescriptorsFiltered(scope, DescriptorKindFilter.VARIABLES, MemberScope.Companion.getALL_NAME_FILTER())); - for (ReceiverParameterDescriptor implicitReceiver : ScopeUtilsKt.getImplicitReceiversHierarchy(scope)) { - result.addAll(DescriptorUtils.getAllDescriptors(implicitReceiver.getType().getMemberScope())); - } - return result; - } - - protected abstract boolean isSuitable( - @NotNull VariableDescriptor variableDescriptor, - @NotNull Project project, - @NotNull IterableTypesDetector iterableTypesDetector - ); - - @Nullable - private static KtExpression findContextExpression(PsiFile psiFile, int startOffset) { - PsiElement e = psiFile.findElementAt(startOffset); - while (e != null) { - if (e instanceof KtExpression) { - return (KtExpression) e; - } - e = e.getParent(); - } - return null; - } - - @Override - public Result calculateResult(@NotNull Expression[] params, ExpressionContext context) { - KtNamedDeclaration[] vars = getVariables(params, context); - if (vars == null || vars.length == 0) return null; - return new KotlinPsiElementResult(vars[0]); - } - - @Override - public LookupElement[] calculateLookupItems(@NotNull Expression[] params, ExpressionContext context) { - PsiNamedElement[] vars = getVariables(params, context); - if (vars == null || vars.length < 2) return null; - Set set = new LinkedHashSet(); - for (PsiNamedElement var : vars) { - set.add(LookupElementBuilder.create(var)); - } - return set.toArray(new LookupElement[set.size()]); - } -} diff --git a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/BaseKotlinVariableMacro.kt b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/BaseKotlinVariableMacro.kt new file mode 100644 index 00000000000..e9ce2a3168b --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/BaseKotlinVariableMacro.kt @@ -0,0 +1,141 @@ +/* + * 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.idea.liveTemplates.macro + +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.codeInsight.template.Expression +import com.intellij.codeInsight.template.ExpressionContext +import com.intellij.codeInsight.template.Macro +import com.intellij.codeInsight.template.Result +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiNamedElement +import com.intellij.util.containers.ContainerUtil +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade +import org.jetbrains.kotlin.idea.core.IterableTypesDetection +import org.jetbrains.kotlin.idea.core.IterableTypesDetector +import org.jetbrains.kotlin.idea.util.getResolutionScope +import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallableWithImplicitReceiver +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.resolve.scopes.LexicalScope +import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered +import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy +import java.util.* + +abstract class BaseKotlinVariableMacro : Macro() { + private fun getVariables(params: Array, context: ExpressionContext): Array? { + if (params.size != 0) return null + + val project = context.project + PsiDocumentManager.getInstance(project).commitAllDocuments() + + val psiFile = PsiDocumentManager.getInstance(project).getPsiFile(context.editor!!.document) + if (psiFile !is KtFile) return null + + val contextExpression = findContextExpression(psiFile, context.startOffset) ?: return null + + val resolutionFacade = contextExpression.getResolutionFacade() + + val bindingContext = resolutionFacade.analyze(contextExpression, BodyResolveMode.FULL) + val scope = contextExpression.getResolutionScope(bindingContext, resolutionFacade) + + val detector = resolutionFacade.getIdeService(IterableTypesDetection::class.java).createDetector(scope) + + val dataFlowInfo = bindingContext.getDataFlowInfo(contextExpression) + + val filteredDescriptors = ArrayList() + for (declarationDescriptor in getAllVariables(scope)) { + if (declarationDescriptor is VariableDescriptor) { + + if (declarationDescriptor.extensionReceiverParameter != null && declarationDescriptor.substituteExtensionIfCallableWithImplicitReceiver(scope, bindingContext, dataFlowInfo).isEmpty()) { + continue + } + + if (isSuitable(declarationDescriptor, project, detector)) { + filteredDescriptors.add(declarationDescriptor) + } + } + } + + + val declarations = ArrayList() + for (declarationDescriptor in filteredDescriptors) { + val declaration = DescriptorToSourceUtils.descriptorToDeclaration(declarationDescriptor) + assert(declaration == null || declaration is PsiNamedElement) + + if (declaration is KtProperty) { + declarations.add(declaration) + } + else if (declaration is KtParameter) { + declarations.add(declaration) + } + } + + return declarations.toTypedArray() + } + + private fun getAllVariables(scope: LexicalScope): Collection { + val result = ContainerUtil.newArrayList() + result.addAll(scope.collectDescriptorsFiltered(DescriptorKindFilter.VARIABLES, MemberScope.ALL_NAME_FILTER)) + for (implicitReceiver in scope.getImplicitReceiversHierarchy()) { + result.addAll(DescriptorUtils.getAllDescriptors(implicitReceiver.type.memberScope)) + } + return result + } + + protected abstract fun isSuitable( + variableDescriptor: VariableDescriptor, + project: Project, + iterableTypesDetector: IterableTypesDetector): Boolean + + private fun findContextExpression(psiFile: PsiFile, startOffset: Int): KtExpression? { + var e = psiFile.findElementAt(startOffset) + while (e != null) { + if (e is KtExpression) { + return e + } + e = e.parent + } + return null + } + + override fun calculateResult(params: Array, context: ExpressionContext): Result? { + val vars = getVariables(params, context) + if (vars == null || vars.size == 0) return null + return KotlinPsiElementResult(vars[0]) + } + + override fun calculateLookupItems(params: Array, context: ExpressionContext): Array? { + val vars = getVariables(params, context) + if (vars == null || vars.size < 2) return null + val set = LinkedHashSet() + for (`var` in vars) { + set.add(LookupElementBuilder.create(`var`)) + } + return set.toArray(arrayOfNulls(set.size)) + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/FunctionParametersMacro.java b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/FunctionParametersMacro.java deleted file mode 100644 index 960e5c7bf2f..00000000000 --- a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/FunctionParametersMacro.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.idea.liveTemplates.macro; - -import com.intellij.codeInsight.template.*; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.idea.KotlinBundle; -import org.jetbrains.kotlin.psi.KtFunction; -import org.jetbrains.kotlin.psi.KtParameter; - -import java.util.ArrayList; -import java.util.List; - -public class FunctionParametersMacro extends Macro { - @Override - public String getName() { - return "functionParameters"; - } - - @Override - public String getPresentableName() { - return KotlinBundle.message("macro.fun.parameters"); - } - - @Override - public Result calculateResult(@NotNull Expression[] params, ExpressionContext context) { - Project project = context.getProject(); - int templateStartOffset = context.getTemplateStartOffset(); - int offset = templateStartOffset > 0 ? context.getTemplateStartOffset() - 1 : context.getTemplateStartOffset(); - - PsiDocumentManager.getInstance(project).commitAllDocuments(); - - PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(context.getEditor().getDocument()); - if (file == null) return null; - PsiElement place = file.findElementAt(offset); - while (place != null){ - if (place instanceof KtFunction) { - List result = new ArrayList(); - for (KtParameter param : ((KtFunction) place).getValueParameters()) { - String name = param.getName(); - assert name != null; - result.add(new TextResult(name)); - } - return new ListResult(result); - } - place = place.getParent(); - } - return null; - } - - @Override - public boolean isAcceptableInContext(TemplateContextType context) { - return context instanceof JavaCodeContextType; - } - -} diff --git a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/FunctionParametersMacro.kt b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/FunctionParametersMacro.kt new file mode 100644 index 00000000000..d5a53582ca6 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/FunctionParametersMacro.kt @@ -0,0 +1,60 @@ +/* + * 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.idea.liveTemplates.macro + +import com.intellij.codeInsight.template.* +import com.intellij.psi.PsiDocumentManager +import org.jetbrains.kotlin.idea.KotlinBundle +import org.jetbrains.kotlin.psi.KtFunction +import java.util.* + +class FunctionParametersMacro : Macro() { + override fun getName(): String { + return "functionParameters" + } + + override fun getPresentableName(): String { + return KotlinBundle.message("macro.fun.parameters") + } + + override fun calculateResult(params: Array, context: ExpressionContext): Result? { + val project = context.project + val templateStartOffset = context.templateStartOffset + val offset = if (templateStartOffset > 0) context.templateStartOffset - 1 else context.templateStartOffset + + PsiDocumentManager.getInstance(project).commitAllDocuments() + + val file = PsiDocumentManager.getInstance(project).getPsiFile(context.editor!!.document) ?: return null + var place = file.findElementAt(offset) + while (place != null) { + if (place is KtFunction) { + val result = ArrayList() + for (param in place.valueParameters) { + result.add(TextResult(param.name!!)) + } + return ListResult(result) + } + place = place.parent + } + return null + } + + override fun isAcceptableInContext(context: TemplateContextType?): Boolean { + return context is JavaCodeContextType + } + +} diff --git a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/IterableVariableMacro.java b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/IterableVariableMacro.java deleted file mode 100644 index ac03d37374a..00000000000 --- a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/IterableVariableMacro.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.idea.liveTemplates.macro; - -import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.descriptors.VariableDescriptor; -import org.jetbrains.kotlin.idea.KotlinBundle; -import org.jetbrains.kotlin.idea.core.IterableTypesDetector; - -public class IterableVariableMacro extends BaseKotlinVariableMacro { - - @Override - public String getName() { - return "kotlinIterableVariable"; - } - - @Override - public String getPresentableName() { - return KotlinBundle.message("macro.iterable.variable"); - } - - @Override - protected boolean isSuitable( - @NotNull VariableDescriptor variableDescriptor, - @NotNull Project project, - @NotNull IterableTypesDetector iterableTypesDetector - ) { - //TODO: smart-casts - return iterableTypesDetector.isIterable(variableDescriptor.getType(), null); - } -} diff --git a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/IterableVariableMacro.kt b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/IterableVariableMacro.kt new file mode 100644 index 00000000000..3273cc49ce3 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/IterableVariableMacro.kt @@ -0,0 +1,41 @@ +/* + * 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.idea.liveTemplates.macro + +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.descriptors.VariableDescriptor +import org.jetbrains.kotlin.idea.KotlinBundle +import org.jetbrains.kotlin.idea.core.IterableTypesDetector + +class IterableVariableMacro : BaseKotlinVariableMacro() { + + override fun getName(): String { + return "kotlinIterableVariable" + } + + override fun getPresentableName(): String { + return KotlinBundle.message("macro.iterable.variable") + } + + override fun isSuitable( + variableDescriptor: VariableDescriptor, + project: Project, + iterableTypesDetector: IterableTypesDetector): Boolean { + //TODO: smart-casts + return iterableTypesDetector.isIterable(variableDescriptor.type, null) + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/KotlinPsiElementResult.java b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/KotlinPsiElementResult.kt similarity index 59% rename from idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/KotlinPsiElementResult.java rename to idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/KotlinPsiElementResult.kt index 2c9a5ab25c6..4ec860297b6 100644 --- a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/KotlinPsiElementResult.java +++ b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/KotlinPsiElementResult.kt @@ -14,18 +14,13 @@ * limitations under the License. */ -package org.jetbrains.kotlin.idea.liveTemplates.macro; +package org.jetbrains.kotlin.idea.liveTemplates.macro -import com.intellij.codeInsight.template.JavaPsiElementResult; -import com.intellij.psi.PsiNamedElement; +import com.intellij.codeInsight.template.JavaPsiElementResult +import com.intellij.psi.PsiNamedElement -public class KotlinPsiElementResult extends JavaPsiElementResult { - public KotlinPsiElementResult(PsiNamedElement element) { - super(element); - } - - @Override - public String toString() { - return ((PsiNamedElement) getElement()).getName(); +class KotlinPsiElementResult(element: PsiNamedElement) : JavaPsiElementResult(element) { + override fun toString(): String { + return (element as PsiNamedElement).name ?: "" } } diff --git a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/SuggestVariableNameMacro.java b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/SuggestVariableNameMacro.java deleted file mode 100644 index f16d9db7d11..00000000000 --- a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/SuggestVariableNameMacro.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.idea.liveTemplates.macro; - -import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.descriptors.VariableDescriptor; -import org.jetbrains.kotlin.idea.KotlinBundle; -import org.jetbrains.kotlin.idea.core.IterableTypesDetector; - -public class SuggestVariableNameMacro extends BaseKotlinVariableMacro { - @Override - public String getName() { - return "kotlinSuggestVariableName"; - } - - @Override - public String getPresentableName() { - return KotlinBundle.message("macro.suggest.variable.name"); - } - - @Override - protected boolean isSuitable( - @NotNull VariableDescriptor variableDescriptor, - @NotNull Project project, - @NotNull IterableTypesDetector iterableTypesDetector - ) { - return variableDescriptor.getType().isMarkedNullable(); - } -} diff --git a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/SuggestVariableNameMacro.kt b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/SuggestVariableNameMacro.kt new file mode 100644 index 00000000000..7fdd6da0fe1 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/SuggestVariableNameMacro.kt @@ -0,0 +1,39 @@ +/* + * 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.idea.liveTemplates.macro + +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.descriptors.VariableDescriptor +import org.jetbrains.kotlin.idea.KotlinBundle +import org.jetbrains.kotlin.idea.core.IterableTypesDetector + +class SuggestVariableNameMacro : BaseKotlinVariableMacro() { + override fun getName(): String { + return "kotlinSuggestVariableName" + } + + override fun getPresentableName(): String { + return KotlinBundle.message("macro.suggest.variable.name") + } + + override fun isSuitable( + variableDescriptor: VariableDescriptor, + project: Project, + iterableTypesDetector: IterableTypesDetector): Boolean { + return variableDescriptor.type.isMarkedNullable + } +}