Moved live templates support into separate module
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="kotlin-runtime" level="project" />
|
||||
<orderEntry type="module" module-name="idea-core" />
|
||||
<orderEntry type="module" module-name="descriptors" />
|
||||
<orderEntry type="library" name="idea-full" level="project" />
|
||||
<orderEntry type="module" module-name="idea-analysis" />
|
||||
<orderEntry type="module" module-name="frontend" />
|
||||
<orderEntry type="module" module-name="idea-test-framework" scope="TEST" />
|
||||
<orderEntry type="module" module-name="idea" scope="RUNTIME" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="junit-plugin" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.intellij.codeInsight.template.impl.DefaultLiveTemplatesProvider;
|
||||
|
||||
public class KotlinLiveTemplatesProvider implements DefaultLiveTemplatesProvider {
|
||||
@Override
|
||||
public String[] getDefaultLiveTemplateFiles() {
|
||||
return new String[]{"liveTemplates/Kotlin"};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getHiddenLiveTemplateFiles() {
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.intellij.codeInsight.template.impl.TemplateOptionalProcessor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.codeInsight.template.Template
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.editor.RangeMarker
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.codeInsight.CodeInsightBundle
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||
import com.intellij.psi.util.PsiUtilBase
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
public class KotlinShortenFQNamesProcessor : TemplateOptionalProcessor {
|
||||
override fun processText(project: Project, template: Template, document: Document, templateRange: RangeMarker, editor: Editor) {
|
||||
if (!template.isToShortenLongNames()) return
|
||||
|
||||
PsiDocumentManager.getInstance(project).commitDocument(document)
|
||||
|
||||
val file = PsiUtilBase.getPsiFileInEditor(editor, project) as? KtFile ?: return
|
||||
ShortenReferences.DEFAULT.process(file, templateRange.getStartOffset(), templateRange.getEndOffset())
|
||||
|
||||
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(document)
|
||||
}
|
||||
|
||||
override fun getOptionName(): String {
|
||||
return CodeInsightBundle.message("dialog.edit.template.checkbox.shorten.fq.names")!!
|
||||
}
|
||||
|
||||
override fun isEnabled(template: Template) = template.isToShortenLongNames()
|
||||
|
||||
override fun setEnabled(template: Template, value: Boolean) {
|
||||
}
|
||||
|
||||
override fun isVisible(template: Template) = false
|
||||
}
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.intellij.codeInsight.template.EverywhereContextType;
|
||||
import com.intellij.codeInsight.template.TemplateContextType;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.psi.PsiComment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilBase;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
|
||||
public abstract class KotlinTemplateContextType extends TemplateContextType {
|
||||
protected KotlinTemplateContextType(@NotNull @NonNls String id, @NotNull String presentableName, @Nullable java.lang.Class<? extends TemplateContextType> baseContextType) {
|
||||
super(id, presentableName, baseContextType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInContext(@NotNull PsiFile file, int offset) {
|
||||
if (PsiUtilBase.getLanguageAtOffset(file, offset).isKindOf(KotlinLanguage.INSTANCE)) {
|
||||
PsiElement element = file.findElementAt(offset);
|
||||
if (element == null) {
|
||||
element = file.findElementAt(offset - 1);
|
||||
}
|
||||
if (element instanceof PsiWhiteSpace) {
|
||||
return false;
|
||||
}
|
||||
else if (PsiTreeUtil.getParentOfType(element, PsiComment.class, false) != null) {
|
||||
return isCommentInContext();
|
||||
}
|
||||
else if (PsiTreeUtil.getParentOfType(element, KtPackageDirective.class) != null
|
||||
|| PsiTreeUtil.getParentOfType(element, KtImportDirective.class) != null) {
|
||||
return false;
|
||||
}
|
||||
else if (element instanceof LeafPsiElement) {
|
||||
IElementType elementType = ((LeafPsiElement) element).getElementType();
|
||||
if (elementType == KtTokens.IDENTIFIER) {
|
||||
PsiElement parent = element.getParent();
|
||||
if (parent instanceof KtReferenceExpression) {
|
||||
PsiElement parentOfParent = parent.getParent();
|
||||
KtQualifiedExpression qualifiedExpression = PsiTreeUtil.getParentOfType(element, KtQualifiedExpression.class);
|
||||
if (qualifiedExpression != null && qualifiedExpression.getSelectorExpression() == parentOfParent) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return element != null && isInContext(element);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isCommentInContext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected abstract boolean isInContext(@NotNull PsiElement element);
|
||||
|
||||
public static class Generic extends KotlinTemplateContextType {
|
||||
public Generic() {
|
||||
super("KOTLIN", KotlinLanguage.NAME, EverywhereContextType.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isInContext(@NotNull PsiElement element) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isCommentInContext() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TopLevel extends KotlinTemplateContextType {
|
||||
public TopLevel() {
|
||||
super("KOTLIN_TOPLEVEL", "Top-level", Generic.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isInContext(@NotNull PsiElement element) {
|
||||
PsiElement e = element;
|
||||
while (e != null) {
|
||||
if (e instanceof KtModifierList) {
|
||||
// skip property/function/class or object which is owner of modifier list
|
||||
e = e.getParent();
|
||||
if (e != null) {
|
||||
e = e.getParent();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (e instanceof KtProperty || e instanceof KtNamedFunction
|
||||
|| e instanceof KtClassOrObject) {
|
||||
return false;
|
||||
}
|
||||
e = e.getParent();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Class extends KotlinTemplateContextType {
|
||||
public Class() {
|
||||
super("KOTLIN_CLASS", "Class", Generic.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isInContext(@NotNull PsiElement element) {
|
||||
PsiElement e = element;
|
||||
while (e != null && !(e instanceof KtClassOrObject)) {
|
||||
if (e instanceof KtModifierList) {
|
||||
// skip property/function/class or object which is owner of modifier list
|
||||
e = e.getParent();
|
||||
if (e != null) {
|
||||
e = e.getParent();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (e instanceof KtProperty || e instanceof KtNamedFunction) {
|
||||
return false;
|
||||
}
|
||||
e = e.getParent();
|
||||
}
|
||||
return e != null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Statement extends KotlinTemplateContextType {
|
||||
public Statement() {
|
||||
super("KOTLIN_STATEMENT", "Statement", Generic.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isInContext(@NotNull PsiElement element) {
|
||||
PsiElement parentStatement = PsiTreeUtil.findFirstParent(element, new Condition<PsiElement>() {
|
||||
@Override
|
||||
public boolean value(PsiElement element) {
|
||||
return element instanceof KtExpression && (element.getParent() instanceof KtBlockExpression);
|
||||
}
|
||||
});
|
||||
|
||||
if (parentStatement == null) return false;
|
||||
|
||||
// We are in the leftmost position in parentStatement
|
||||
return element.getTextOffset() == parentStatement.getTextOffset();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Expression extends KotlinTemplateContextType {
|
||||
public Expression() {
|
||||
super("KOTLIN_EXPRESSION", "Expression", Generic.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isInContext(@NotNull PsiElement element) {
|
||||
return element.getParent() instanceof KtExpression && !(element.getParent() instanceof KtConstantExpression) &&
|
||||
!(element.getParent().getParent() instanceof KtDotQualifiedExpression)
|
||||
&& !(element.getParent() instanceof KtParameter);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Comment extends KotlinTemplateContextType {
|
||||
public Comment() {
|
||||
super("KOTLIN_COMMENT", "Comment", Generic.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isInContext(@NotNull PsiElement element) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isCommentInContext() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
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.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered
|
||||
|
||||
class AnonymousSuperMacro : Macro() {
|
||||
override fun getName() = "anonymousSuper"
|
||||
override fun getPresentableName() = "anonymousSuper()"
|
||||
|
||||
override fun calculateResult(params: Array<Expression>, context: ExpressionContext): Result? {
|
||||
val editor = context.editor
|
||||
if (editor != null) {
|
||||
AnonymousTemplateEditingListener.registerListener(editor, context.project)
|
||||
}
|
||||
|
||||
val vars = getSupertypes(params, context)
|
||||
if (vars.isEmpty()) return null
|
||||
return KotlinPsiElementResult(vars.first())
|
||||
}
|
||||
|
||||
override fun calculateLookupItems(params: Array<Expression>, context: ExpressionContext): Array<LookupElement>? {
|
||||
val superTypes = getSupertypes(params, context)
|
||||
if (superTypes.size < 2) return null
|
||||
return superTypes.map { LookupElementBuilder.create(it) }.toTypedArray()
|
||||
}
|
||||
|
||||
private fun getSupertypes(params: Array<Expression>, context: ExpressionContext): Collection<PsiNamedElement> {
|
||||
if (params.size != 0) return emptyList()
|
||||
|
||||
val psiDocumentManager = PsiDocumentManager.getInstance(context.project)
|
||||
psiDocumentManager.commitAllDocuments()
|
||||
|
||||
val psiFile = psiDocumentManager.getPsiFile(context.editor!!.document) as? KtFile ?: return emptyList()
|
||||
|
||||
val expression = PsiTreeUtil.getParentOfType(psiFile.findElementAt(context.startOffset), KtExpression::class.java) ?: return emptyList()
|
||||
|
||||
val bindingContext = expression.analyze(BodyResolveMode.FULL)
|
||||
val resolutionScope = expression.getResolutionScope(bindingContext, expression.getResolutionFacade())
|
||||
|
||||
return resolutionScope
|
||||
.collectDescriptorsFiltered(DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS)
|
||||
.filter { it is ClassDescriptor && it.modality.isOverridable && (it.kind == ClassKind.CLASS || it.kind == ClassKind.INTERFACE) }
|
||||
.mapNotNull { DescriptorToSourceUtils.descriptorToDeclaration(it) as PsiNamedElement? }
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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 com.intellij.openapi.util.UserDataHolder
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
|
||||
class AnyVariableMacro : BaseKotlinVariableMacro() {
|
||||
override fun getName() = "kotlinAnyVariable"
|
||||
override fun getPresentableName() = "kotlinAnyVariable()"
|
||||
|
||||
override fun isSuitable(variableDescriptor: VariableDescriptor, project: Project, userData: UserDataHolder) = true
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.openapi.util.UserDataHolder
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper
|
||||
import org.jetbrains.kotlin.idea.core.isVisible
|
||||
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.util.slicedMap.UserDataHolderImpl
|
||||
import java.util.*
|
||||
|
||||
abstract class BaseKotlinVariableMacro : Macro() {
|
||||
private fun getVariables(params: Array<Expression>, context: ExpressionContext): Collection<PsiNamedElement> {
|
||||
if (params.size != 0) return emptyList()
|
||||
|
||||
val project = context.project
|
||||
val psiDocumentManager = PsiDocumentManager.getInstance(project)
|
||||
psiDocumentManager.commitAllDocuments()
|
||||
|
||||
val psiFile = psiDocumentManager.getPsiFile(context.editor!!.document) as? KtFile ?: return emptyList()
|
||||
|
||||
val contextElement = psiFile.findElementAt(context.startOffset)?.getNonStrictParentOfType<KtElement>() ?: return emptyList()
|
||||
|
||||
val resolutionFacade = psiFile.getResolutionFacade()
|
||||
|
||||
val bindingContext = resolutionFacade.analyze(contextElement, BodyResolveMode.PARTIAL_FOR_COMPLETION)
|
||||
|
||||
fun isVisible(descriptor: DeclarationDescriptor): Boolean {
|
||||
return descriptor !is DeclarationDescriptorWithVisibility || descriptor.isVisible(contextElement, null, bindingContext, resolutionFacade)
|
||||
}
|
||||
|
||||
val userData = UserDataHolderImpl()
|
||||
initUserData(userData, contextElement, bindingContext)
|
||||
|
||||
val helper = ReferenceVariantsHelper(bindingContext, resolutionFacade, resolutionFacade.moduleDescriptor, ::isVisible)
|
||||
val variants = helper
|
||||
.getReferenceVariants(contextElement, CallTypeAndReceiver.DEFAULT, DescriptorKindFilter.VARIABLES, { true })
|
||||
.filter { isSuitable(it as VariableDescriptor, project, userData) }
|
||||
|
||||
val declarations = ArrayList<PsiNamedElement>()
|
||||
for (descriptor in variants) {
|
||||
val declaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? PsiNamedElement ?: continue
|
||||
declarations.add(declaration)
|
||||
}
|
||||
return declarations
|
||||
}
|
||||
|
||||
protected open fun initUserData(userData: UserDataHolder, contextElement: KtElement, bindingContext: BindingContext) {
|
||||
}
|
||||
|
||||
protected abstract fun isSuitable(
|
||||
variableDescriptor: VariableDescriptor,
|
||||
project: Project,
|
||||
userData: UserDataHolder): Boolean
|
||||
|
||||
override fun calculateResult(params: Array<Expression>, context: ExpressionContext): Result? {
|
||||
val vars = getVariables(params, context)
|
||||
if (vars.isEmpty()) return null
|
||||
return KotlinPsiElementResult(vars.first())
|
||||
}
|
||||
|
||||
override fun calculateLookupItems(params: Array<Expression>, context: ExpressionContext): Array<LookupElement>? {
|
||||
val vars = getVariables(params, context)
|
||||
if (vars.size < 2) return null
|
||||
return vars.map { LookupElementBuilder.create(it) }.toTypedArray()
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.psi.KtFunction
|
||||
import java.util.*
|
||||
|
||||
class FunctionParametersMacro : Macro() {
|
||||
override fun getName() = "functionParameters"
|
||||
override fun getPresentableName() = "functionParameters()"
|
||||
|
||||
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?) = context is JavaCodeContextType
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.JavaPsiElementResult
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
|
||||
class KotlinPsiElementResult(element: PsiNamedElement) : JavaPsiElementResult(element) {
|
||||
override fun toString() = (element as PsiNamedElement).name ?: ""
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.*
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.IterableTypesDetection
|
||||
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||
import org.jetbrains.kotlin.idea.resolve.ideService
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtWithExpressionInitializer
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
class SuggestVariableNameMacro : Macro() {
|
||||
override fun getName() = "kotlinSuggestVariableName"
|
||||
override fun getPresentableName() = "kotlinSuggestVariableName()"
|
||||
|
||||
override fun calculateResult(params: Array<out Expression>, context: ExpressionContext): Result? {
|
||||
return nameSuggestions(context).firstOrNull()?.let { TextResult(it) }
|
||||
}
|
||||
|
||||
override fun calculateLookupItems(params: Array<out Expression>, context: ExpressionContext): Array<out LookupElement>? {
|
||||
val suggestions = nameSuggestions(context)
|
||||
if (suggestions.size < 2) return null
|
||||
return suggestions.map { LookupElementBuilder.create(it) }.toTypedArray()
|
||||
}
|
||||
|
||||
private fun nameSuggestions(context: ExpressionContext): Collection<String> {
|
||||
val project = context.project
|
||||
val psiDocumentManager = PsiDocumentManager.getInstance(project)
|
||||
psiDocumentManager.commitAllDocuments()
|
||||
|
||||
val psiFile = psiDocumentManager.getPsiFile(context.editor!!.document) as? KtFile ?: return emptyList()
|
||||
val token = psiFile.findElementAt(context.startOffset) ?: return emptyList()
|
||||
val declaration = token.parent as? KtCallableDeclaration ?: return emptyList()
|
||||
if (token != declaration.nameIdentifier) return emptyList()
|
||||
|
||||
val nameValidator: (String) -> Boolean = { true }
|
||||
|
||||
val initializer = (declaration as? KtWithExpressionInitializer)?.initializer
|
||||
if (initializer != null) {
|
||||
val bindingContext = initializer.analyze(BodyResolveMode.PARTIAL)
|
||||
return KotlinNameSuggester.suggestNamesByExpressionAndType(initializer, bindingContext, nameValidator, null)
|
||||
}
|
||||
|
||||
val parent = declaration.parent
|
||||
if (parent is KtForExpression && declaration == parent.loopParameter) {
|
||||
iterationVariableNameSuggestions(parent, nameValidator)?.let { return it }
|
||||
}
|
||||
|
||||
val descriptor = declaration.resolveToDescriptor() as? VariableDescriptor ?: return emptyList()
|
||||
return KotlinNameSuggester.suggestNamesByType(descriptor.type, nameValidator, null)
|
||||
}
|
||||
|
||||
private fun iterationVariableNameSuggestions(forExpression: KtForExpression, nameValidator: (String) -> Boolean): Collection<String>? {
|
||||
val loopRange = forExpression.loopRange ?: return null
|
||||
val resolutionFacade = forExpression.getResolutionFacade()
|
||||
val bindingContext = resolutionFacade.analyze(loopRange, BodyResolveMode.PARTIAL)
|
||||
val type = bindingContext.getType(loopRange) ?: return null
|
||||
val scope = loopRange.getResolutionScope(bindingContext, resolutionFacade)
|
||||
val detector = resolutionFacade.ideService<IterableTypesDetection>().createDetector(scope)
|
||||
val elementType = detector.elementType(type)?.type ?: return null
|
||||
return KotlinNameSuggester.suggestIterationVariableNames(loopRange, elementType, bindingContext, nameValidator, null)
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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 com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.UserDataHolder
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.core.ExpectedInfo
|
||||
import org.jetbrains.kotlin.idea.core.ExpectedInfos
|
||||
import org.jetbrains.kotlin.idea.core.SmartCastCalculator
|
||||
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
||||
import org.jetbrains.kotlin.idea.util.FuzzyType
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
class SuitableVariableMacro : BaseKotlinVariableMacro() {
|
||||
private companion object {
|
||||
val EXPECTED_INFOS_KEY = Key<Collection<ExpectedInfo>>("EXPECTED_INFOS_KEY")
|
||||
val SMART_CAST_CALCULATOR_KEY = Key<SmartCastCalculator>("SMART_CAST_CALCULATOR_KEY")
|
||||
}
|
||||
|
||||
override fun getName() = "kotlinVariable"
|
||||
override fun getPresentableName() = "kotlinVariable()"
|
||||
|
||||
override fun initUserData(userData: UserDataHolder, contextElement: KtElement, bindingContext: BindingContext) {
|
||||
val resolutionFacade = contextElement.getResolutionFacade()
|
||||
if (contextElement is KtNameReferenceExpression) {
|
||||
val callTypeAndReceiver = CallTypeAndReceiver.detect(contextElement)
|
||||
if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) {
|
||||
val expectedInfos = ExpectedInfos(bindingContext, resolutionFacade).calculate(contextElement)
|
||||
if (expectedInfos.isNotEmpty()) {
|
||||
userData.putUserData(EXPECTED_INFOS_KEY, expectedInfos)
|
||||
|
||||
val scope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
|
||||
val smartCastCalculator = SmartCastCalculator(bindingContext, scope.ownerDescriptor, contextElement, null, resolutionFacade)
|
||||
userData.putUserData(SMART_CAST_CALCULATOR_KEY, smartCastCalculator)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isSuitable(variableDescriptor: VariableDescriptor, project: Project, userData: UserDataHolder): Boolean {
|
||||
val expectedInfos = userData.getUserData(EXPECTED_INFOS_KEY) ?: return true
|
||||
val smartCastCalculator = userData.getUserData(SMART_CAST_CALCULATOR_KEY)!!
|
||||
val types = smartCastCalculator.types(variableDescriptor)
|
||||
return expectedInfos.any { expectedInfo -> types.any { expectedInfo.filter.matchingSubstitutor(FuzzyType(it, emptyList())) != null } }
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.intellij.codeInsight.template.TemplateContextType
|
||||
import com.intellij.testFramework.UsefulTestCase
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||
import java.io.File
|
||||
|
||||
public class LiveTemplatesContextTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
override fun getTestDataPath(): String =
|
||||
File(PluginTestCaseBase.getTestDataPathBase(), "/templates/context").getPath() + File.separator
|
||||
|
||||
public fun testInDocComment() {
|
||||
myFixture.configureByFile(getTestName(false) + ".kt")
|
||||
assertInContexts(
|
||||
KotlinTemplateContextType.Generic::class.java,
|
||||
KotlinTemplateContextType.Comment::class.java)
|
||||
}
|
||||
|
||||
public fun testTopLevel() {
|
||||
myFixture.configureByFile(getTestName(false) + ".kt")
|
||||
assertInContexts(
|
||||
KotlinTemplateContextType.Generic::class.java,
|
||||
KotlinTemplateContextType.TopLevel::class.java)
|
||||
}
|
||||
|
||||
public fun testInExpression() {
|
||||
myFixture.configureByFile(getTestName(false) + ".kt")
|
||||
assertInContexts(
|
||||
KotlinTemplateContextType.Generic::class.java,
|
||||
KotlinTemplateContextType.Expression::class.java)
|
||||
}
|
||||
|
||||
private fun assertInContexts(vararg expectedContexts: Class<out KotlinTemplateContextType>) {
|
||||
val allContexts = TemplateContextType.EP_NAME.getExtensions().filter { it is KotlinTemplateContextType }
|
||||
val enabledContexts = allContexts.filter { it.isInContext(myFixture.getFile(), myFixture.getCaretOffset()) }.map { it.javaClass }
|
||||
UsefulTestCase.assertSameElements(enabledContexts, *expectedContexts)
|
||||
}
|
||||
}
|
||||
+337
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupEx;
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.codeInsight.template.TemplateManager;
|
||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
|
||||
import com.intellij.codeInsight.template.impl.TemplateState;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import junit.framework.TestCase;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase;
|
||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor;
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class LiveTemplatesTest extends KotlinLightCodeInsightFixtureTestCase {
|
||||
@Override
|
||||
protected void setUp() {
|
||||
super.setUp();
|
||||
myFixture.setTestDataPath(new File(PluginTestCaseBase.getTestDataPathBase(), "/templates").getPath() + File.separator);
|
||||
((TemplateManagerImpl) TemplateManager.getInstance(getProject())).setTemplateTesting(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() {
|
||||
((TemplateManagerImpl) TemplateManager.getInstance(getProject())).setTemplateTesting(false);
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testSout() {
|
||||
paremeterless();
|
||||
}
|
||||
|
||||
public void testSout_BeforeCall() {
|
||||
paremeterless();
|
||||
}
|
||||
|
||||
public void testSout_BeforeCallSpace() {
|
||||
paremeterless();
|
||||
}
|
||||
|
||||
public void testSout_BeforeBinary() {
|
||||
paremeterless();
|
||||
}
|
||||
|
||||
public void testSout_InCallArguments() {
|
||||
paremeterless();
|
||||
}
|
||||
|
||||
public void testSout_BeforeQualifiedCall() {
|
||||
paremeterless();
|
||||
}
|
||||
|
||||
public void testSout_AfterSemicolon() {
|
||||
paremeterless();
|
||||
}
|
||||
|
||||
public void testSerr() {
|
||||
paremeterless();
|
||||
}
|
||||
|
||||
public void testMain() {
|
||||
paremeterless();
|
||||
}
|
||||
|
||||
public void testSoutv() {
|
||||
start();
|
||||
|
||||
assertStringItems("args", "x", "y");
|
||||
typeAndNextTab("y");
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
public void testSoutp() {
|
||||
paremeterless();
|
||||
}
|
||||
|
||||
public void testFun0() {
|
||||
start();
|
||||
|
||||
type("foo");
|
||||
nextTab(2);
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
public void testFun1() {
|
||||
start();
|
||||
|
||||
type("foo");
|
||||
nextTab(4);
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
public void testFun2() {
|
||||
start();
|
||||
|
||||
type("foo");
|
||||
nextTab(6);
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
public void testExfun() {
|
||||
start();
|
||||
|
||||
typeAndNextTab("Int");
|
||||
typeAndNextTab("foo");
|
||||
typeAndNextTab("arg : Int");
|
||||
nextTab();
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
public void testExval() {
|
||||
start();
|
||||
|
||||
typeAndNextTab("Int");
|
||||
nextTab();
|
||||
typeAndNextTab("Int");
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
public void testExvar() {
|
||||
start();
|
||||
|
||||
typeAndNextTab("Int");
|
||||
nextTab();
|
||||
typeAndNextTab("Int");
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
public void testClosure() {
|
||||
start();
|
||||
|
||||
typeAndNextTab("param");
|
||||
nextTab();
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
public void testInterface() {
|
||||
start();
|
||||
|
||||
typeAndNextTab("SomeTrait");
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
public void testSingleton() {
|
||||
start();
|
||||
|
||||
typeAndNextTab("MySingleton");
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
public void testVoid() {
|
||||
start();
|
||||
|
||||
typeAndNextTab("foo");
|
||||
typeAndNextTab("x : Int");
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
public void testIter() {
|
||||
start();
|
||||
|
||||
assertStringItems("args", "myList", "o", "str", "stream");
|
||||
type("args");
|
||||
nextTab(2);
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
public void testAnonymous_1() {
|
||||
start();
|
||||
|
||||
typeAndNextTab("Runnable");
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
public void testAnonymous_2() {
|
||||
start();
|
||||
|
||||
typeAndNextTab("Thread");
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
private void doTestIfnInn() {
|
||||
start();
|
||||
|
||||
assertStringItems("b", "t", "y");
|
||||
typeAndNextTab("b");
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
public void testIfn() {
|
||||
doTestIfnInn();
|
||||
}
|
||||
|
||||
public void testInn() {
|
||||
doTestIfnInn();
|
||||
}
|
||||
|
||||
private void paremeterless() {
|
||||
start();
|
||||
|
||||
checkAfter();
|
||||
}
|
||||
|
||||
private void start() {
|
||||
myFixture.configureByFile(getTestName(true) + ".kt");
|
||||
myFixture.type(getTemplateName());
|
||||
|
||||
doAction("ExpandLiveTemplateByTab");
|
||||
}
|
||||
|
||||
private String getTemplateName() {
|
||||
String testName = getTestName(true);
|
||||
if (testName.contains("_")) {
|
||||
return testName.substring(0, testName.indexOf("_"));
|
||||
}
|
||||
return testName;
|
||||
}
|
||||
|
||||
private void checkAfter() {
|
||||
TestCase.assertNull(getTemplateState());
|
||||
myFixture.checkResultByFile(getTestName(true) + ".exp.kt", true);
|
||||
}
|
||||
|
||||
private void typeAndNextTab(String s) {
|
||||
type(s);
|
||||
nextTab();
|
||||
}
|
||||
|
||||
private void type(String s) {
|
||||
myFixture.type(s);
|
||||
}
|
||||
|
||||
private void nextTab() {
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getTemplateState().nextTab();
|
||||
}
|
||||
});
|
||||
}
|
||||
}, "nextTab", null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void nextTab(int times) {
|
||||
for (int i = 0; i < times; i++) {
|
||||
nextTab();
|
||||
}
|
||||
}
|
||||
|
||||
private TemplateState getTemplateState() {
|
||||
return TemplateManagerImpl.getTemplateState(myFixture.getEditor());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected LightProjectDescriptor getProjectDescriptor() {
|
||||
return KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE;
|
||||
}
|
||||
|
||||
private void doAction(@NotNull String actionId) {
|
||||
EditorActionManager actionManager = EditorActionManager.getInstance();
|
||||
EditorActionHandler actionHandler = actionManager.getActionHandler(actionId);
|
||||
actionHandler.execute(myFixture.getEditor(), DataManager.getInstance().getDataContext(myFixture.getEditor().getComponent()));
|
||||
}
|
||||
|
||||
private void assertStringItems(@NonNls String... items) {
|
||||
TestCase.assertEquals(Arrays.asList(items), Arrays.asList(getItemStringsSorted()));
|
||||
}
|
||||
|
||||
private String[] getItemStrings() {
|
||||
LookupEx lookup = LookupManager.getActiveLookup(myFixture.getEditor());
|
||||
TestCase.assertNotNull(lookup);
|
||||
ArrayList<String> result = new ArrayList<String>();
|
||||
for (LookupElement element : lookup.getItems()) {
|
||||
result.add(element.getLookupString());
|
||||
}
|
||||
return ArrayUtil.toStringArray(result);
|
||||
}
|
||||
|
||||
private String[] getItemStringsSorted() {
|
||||
String[] items = getItemStrings();
|
||||
Arrays.sort(items);
|
||||
return items;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user