Converted to Kotlin
This commit is contained in:
-109
@@ -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<AnonymousTemplateEditingListener> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+96
@@ -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<AnonymousTemplateEditingListener>("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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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<VariableDescriptor> filteredDescriptors = new ArrayList<VariableDescriptor>();
|
||||
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<KtNamedDeclaration> declarations = new ArrayList<KtNamedDeclaration>();
|
||||
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<DeclarationDescriptor> getAllVariables(LexicalScope scope) {
|
||||
Collection<DeclarationDescriptor> 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<LookupElement> set = new LinkedHashSet<LookupElement>();
|
||||
for (PsiNamedElement var : vars) {
|
||||
set.add(LookupElementBuilder.create(var));
|
||||
}
|
||||
return set.toArray(new LookupElement[set.size()]);
|
||||
}
|
||||
}
|
||||
@@ -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<Expression>, context: ExpressionContext): Array<KtNamedDeclaration>? {
|
||||
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<VariableDescriptor>()
|
||||
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<KtNamedDeclaration>()
|
||||
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<DeclarationDescriptor> {
|
||||
val result = ContainerUtil.newArrayList<DeclarationDescriptor>()
|
||||
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<Expression>, 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<Expression>, context: ExpressionContext): Array<LookupElement>? {
|
||||
val vars = getVariables(params, context)
|
||||
if (vars == null || vars.size < 2) return null
|
||||
val set = LinkedHashSet<LookupElement>()
|
||||
for (`var` in vars) {
|
||||
set.add(LookupElementBuilder.create(`var`))
|
||||
}
|
||||
return set.toArray<LookupElement>(arrayOfNulls<LookupElement>(set.size))
|
||||
}
|
||||
}
|
||||
@@ -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> result = new ArrayList<Result>();
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Expression>, 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<Result>()
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
+6
-11
@@ -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 ?: ""
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user