Code completion: template item for function taking lambda with 2 or more parameters (KT-4855) + better handling of type instantiation in smart completion

This commit is contained in:
Valentin Kipyatkov
2014-04-22 22:10:42 +04:00
parent 0057843c08
commit e8805f69bf
33 changed files with 428 additions and 269 deletions
@@ -54,6 +54,11 @@ public class JetCallExpression extends JetReferenceExpression implements JetCall
return (JetTypeArgumentList) findChildByType(JetNodeTypes.TYPE_ARGUMENT_LIST);
}
/**
* Normally there should be only one (or zero) function literal arguments.
* The returned value is a list for better handling of commonly made mistake of a function taking a lambda and returning another function.
* Most of users can simply ignore lists of more than one element.
*/
@Override
@NotNull
public List<JetExpression> getFunctionLiteralArguments() {
@@ -37,14 +37,11 @@ import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.plugin.JetDescriptorIconProvider;
import org.jetbrains.jet.plugin.completion.handlers.JetClassInsertHandler;
import org.jetbrains.jet.plugin.completion.handlers.JetJavaClassInsertHandler;
import org.jetbrains.jet.plugin.completion.handlers.*;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import java.util.List;
import static org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler.*;
public final class DescriptorLookupConverter {
private DescriptorLookupConverter() {}
@@ -91,7 +88,11 @@ public final class DescriptorLookupConverter {
typeText = DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor);
}
element = element.withInsertHandler(getInsertHandler(descriptor));
InsertHandler<LookupElement> insertHandler = getDefaultInsertHandler(descriptor);
element = element.withInsertHandler(insertHandler);
if (insertHandler instanceof JetFunctionInsertHandler && ((JetFunctionInsertHandler)insertHandler).getLambdaInfo() != null) {
element.putUserData(JetCompletionCharFilter.ACCEPT_OPENING_BRACE, true);
}
element = element.withTailText(tailText, true).withTypeText(typeText).withPresentableText(presentableText);
element = element.withIcon(JetDescriptorIconProvider.getIcon(descriptor, Iconable.ICON_FLAG_VISIBILITY));
element = element.withStrikeoutness(KotlinBuiltIns.getInstance().isDeprecated(descriptor));
@@ -100,20 +101,26 @@ public final class DescriptorLookupConverter {
}
@Nullable
public static InsertHandler<LookupElement> getInsertHandler(@NotNull DeclarationDescriptor descriptor) {
public static InsertHandler<LookupElement> getDefaultInsertHandler(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters();
if (functionDescriptor.getValueParameters().isEmpty()) {
return EMPTY_FUNCTION_HANDLER;
if (parameters.isEmpty()) {
return JetFunctionInsertHandler.NO_PARAMETERS_HANDLER;
}
if (functionDescriptor.getValueParameters().size() == 1 &&
KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(functionDescriptor.getValueParameters().get(0).getType())) {
return PARAMS_BRACES_FUNCTION_HANDLER;
if (parameters.size() == 1) {
JetType parameterType = parameters.get(0).getType();
if (KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(parameterType)) {
int parameterCount = KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(parameterType).size();
if (parameterCount <= 1) { // otherwise additional item with lambda template is to be added
return new JetFunctionInsertHandler(CaretPosition.IN_BRACKETS, new GenerateLambdaInfo(parameterType, false));
}
}
}
return PARAMS_PARENTHESIS_FUNCTION_HANDLER;
return JetFunctionInsertHandler.WITH_PARAMETERS_HANDLER;
}
if (descriptor instanceof ClassDescriptor) {
@@ -136,7 +143,7 @@ public final class DescriptorLookupConverter {
PsiClass containingClass = ((PsiMember) declaration).getContainingClass();
if (containingClass != null && !JavaResolverPsiUtils.isCompiledKotlinClassOrPackageClass(containingClass)) {
if (declaration instanceof PsiMethod) {
InsertHandler<LookupElement> handler = getInsertHandler(descriptor);
InsertHandler<LookupElement> handler = getDefaultInsertHandler(descriptor);
assert handler != null:
"Special kotlin handler is expected for function: " + declaration.getText() +
" and descriptor: " + DescriptorRenderer.FQNAMES_IN_TYPES.render(descriptor);
@@ -1,4 +1,4 @@
package org.jetbrains.jet.plugin.completion.smart
package org.jetbrains.jet.plugin.completion
import org.jetbrains.jet.lang.psi.JetExpression
import org.jetbrains.jet.lang.resolve.BindingContext
@@ -23,17 +23,25 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
import java.util.HashSet
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor
import org.jetbrains.jet.lang.types.JetType
enum class Tail {
COMMA
PARENTHESIS
}
data class ExpectedInfo(val `type`: JetType, val tail: Tail?)
class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: ModuleDescriptor) {
public fun calculate(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
val expectedInfos = calculateForArgument(expressionWithType)
if (expectedInfos != null) {
return expectedInfos
}
else {
val expectedType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, expressionWithType] ?: return null
return listOf(ExpectedInfo(expectedType, null))
}
val expectedInfos1 = calculateForArgument(expressionWithType)
if (expectedInfos1 != null) return expectedInfos1
val expectedInfos2 = calculateForFunctionLiteralArgument(expressionWithType)
if (expectedInfos2 != null) return expectedInfos2
val expectedType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, expressionWithType] ?: return null
return listOf(ExpectedInfo(expectedType, null))
}
private fun calculateForArgument(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
@@ -42,6 +50,21 @@ class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: Mo
val argumentList = argument.getParent() as JetValueArgumentList
val argumentIndex = argumentList.getArguments().indexOf(argument)
val callExpression = argumentList.getParent() as? JetCallExpression ?: return null
return calculateForArgument(callExpression, argumentIndex, false)
}
private fun calculateForFunctionLiteralArgument(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
val callExpression = expressionWithType.getParent() as? JetCallExpression
if (callExpression != null) {
val arguments = callExpression.getFunctionLiteralArguments()
if (arguments.size > 0 && arguments[0] == expressionWithType) {
return calculateForArgument(callExpression, callExpression.getValueArguments().size, true)
}
}
return null
}
private fun calculateForArgument(callExpression: JetCallExpression, argumentIndex: Int, isFunctionLiteralArgument: Boolean): Collection<ExpectedInfo>? {
val calleeExpression = callExpression.getCalleeExpression()
val parent = callExpression.getParent()
@@ -62,7 +85,7 @@ class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: Mo
val resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, calleeExpression] ?: return null //TODO: discuss it
val callResolutionContext = BasicCallResolutionContext.create(
DelegatingBindingTrace(bindingContext, "Temporary trace for smart completion"),
DelegatingBindingTrace(bindingContext, "Temporary trace for completion"),
resolutionScope,
call,
bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, callExpression] ?: TypeUtils.NO_EXPECTED_TYPE,
@@ -71,15 +94,20 @@ class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: Mo
CheckValueArgumentsMode.ENABLED,
CompositeExtension(listOf()),
false).replaceCollectAllCandidates(true)
val callResolver = InjectorForMacros(expressionWithType.getProject(), moduleDescriptor).getCallResolver()!!
val callResolver = InjectorForMacros(callExpression.getProject(), moduleDescriptor).getCallResolver()!!
val results: OverloadResolutionResults<FunctionDescriptor> = callResolver.resolveFunctionCall(callResolutionContext)
val expectedInfos = HashSet<ExpectedInfo>()
for (candidate: ResolvedCall<FunctionDescriptor> in results.getAllCandidates()!!) {
val parameters = candidate.getResultingDescriptor().getValueParameters()
if (parameters.size <= argumentIndex) continue
if (isFunctionLiteralArgument) {
if (argumentIndex != parameters.size - 1) continue
}
else{
if (parameters.size <= argumentIndex) continue
}
val parameterDescriptor = parameters[argumentIndex]
val tail = if (argumentIndex == parameters.size - 1) Tail.PARENTHESIS else Tail.COMMA
val tail = if (isFunctionLiteralArgument) null else if (argumentIndex == parameters.size - 1) Tail.PARENTHESIS else Tail.COMMA
expectedInfos.add(ExpectedInfo(parameterDescriptor.getType(), tail))
}
return expectedInfos
@@ -21,55 +21,37 @@ import com.intellij.codeInsight.lookup.Lookup
import com.intellij.codeInsight.lookup.CharFilter.Result
import org.jetbrains.jet.lang.psi.JetFile
import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler
import com.intellij.openapi.util.Key
public open class JetCompletionCharFilter() : CharFilter() {
class object {
public val ACCEPT_OPENING_BRACE: Key<Boolean> = Key<Boolean>("JetCompletionCharFilter.ACCEPT_OPENNING_BRACE")
}
public override fun acceptChar(c : Char, prefixLength : Int, lookup : Lookup) : Result? {
if (lookup.getPsiFile() !is JetFile) return null
fun checkHideLookupForRangeOperator(): Result? {
if (c == '.' && prefixLength == 0 && !lookup.isSelectionTouched()) {
val caret = lookup.getEditor().getCaretModel().getOffset()
if (caret > 0 && (lookup.getEditor().getDocument().getCharsSequence().charAt(caret - 1)) == '.') {
return Result.HIDE_LOOKUP
}
if (c == '.' && prefixLength == 0 && !lookup.isSelectionTouched()) {
val caret = lookup.getEditor().getCaretModel().getOffset()
if (caret > 0 && (lookup.getEditor().getDocument().getCharsSequence().charAt(caret - 1)) == '.') {
return Result.HIDE_LOOKUP
}
return null
}
fun checkFinishCompletionForOpenBrace(): Result? {
if (c == '{') {
val currentItem = lookup.getCurrentItem()
if (currentItem != null && (currentItem.getObject() is JetLookupObject)) {
val lookupObject = (currentItem.getObject() as JetLookupObject)
val descriptor = lookupObject.getDescriptor()
if (descriptor != null) {
val handler = DescriptorLookupConverter.getInsertHandler(descriptor)
if (handler == JetFunctionInsertHandler.PARAMS_BRACES_FUNCTION_HANDLER) {
return Result.SELECT_ITEM_AND_FINISH_LOOKUP
}
}
}
if (c == '{') {
val currentItem = lookup.getCurrentItem()
if (currentItem != null && currentItem.getUserData(ACCEPT_OPENING_BRACE) ?: false) {
return Result.SELECT_ITEM_AND_FINISH_LOOKUP
}
return null
}
fun checkFinishCompletionForEqual(): Result? {
if (c == '=') {
val currentItem = lookup.getCurrentItem()
if (currentItem != null && (currentItem.getObject() is KotlinNamedParametersContributor.NamedParameterLookupObject)) {
return Result.SELECT_ITEM_AND_FINISH_LOOKUP
}
if (c == '=') {
val currentItem = lookup.getCurrentItem()
if (currentItem != null && (currentItem.getObject() is KotlinNamedParametersContributor.NamedParameterLookupObject)) {
return Result.SELECT_ITEM_AND_FINISH_LOOKUP
}
return null
}
return checkHideLookupForRangeOperator() ?:
checkFinishCompletionForOpenBrace() ?:
checkFinishCompletionForEqual() ?:
null
return null
}
}
@@ -17,14 +17,27 @@
package org.jetbrains.jet.plugin.completion;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementDecorator;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Conditions;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.plugin.completion.handlers.CaretPosition;
import org.jetbrains.jet.plugin.completion.handlers.GenerateLambdaInfo;
import org.jetbrains.jet.plugin.completion.handlers.HandlersPackage;
import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler;
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies;
import java.util.List;
public class JetCompletionResultSet {
private final ResolveSessionForBodies resolveSession;
private final BindingContext bindingContext;
@@ -74,12 +87,38 @@ public class JetCompletionResultSet {
}
addElement(DescriptorLookupConverter.createLookupElement(resolveSession, bindingContext, descriptor));
// add special item for function with one argument of function type with more than one parameter
if (descriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters();
if (parameters.size() == 1) {
final JetType parameterType = parameters.get(0).getType();
if (KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(parameterType)) {
int parameterCount = KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(parameterType).size();
if (parameterCount > 1) {
LookupElement lookupElement = DescriptorLookupConverter.createLookupElement(resolveSession, bindingContext, descriptor);
addElement(new LookupElementDecorator<LookupElement>(lookupElement) {
@Override
public void renderElement(LookupElementPresentation presentation) {
super.renderElement(presentation);
presentation.setItemText(getLookupString() + " " + HandlersPackage.buildLambdaPresentation(parameterType));
}
@Override
public void handleInsert(InsertionContext context) {
new JetFunctionInsertHandler(CaretPosition.IN_BRACKETS, new GenerateLambdaInfo(parameterType, true))
.handleInsert(context, this);
}
});
}
}
}
}
}
public void addElement(@NotNull LookupElement element) {
if (!result.getPrefixMatcher().prefixMatches(element)) {
return;
}
if (!result.getPrefixMatcher().prefixMatches(element)) return;
result.addElement(element);
isSomethingAdded = true;
@@ -279,7 +279,7 @@ public open class JetKeywordCompletionContributor() : CompletionContributor() {
lookupElementBuilder.withInsertHandler(JetKeywordCompletionContributor.KEYWORDS_INSERT_HANDLER)
}
else {
lookupElementBuilder.withInsertHandler(JetFunctionInsertHandler.EMPTY_FUNCTION_HANDLER)
lookupElementBuilder.withInsertHandler(JetFunctionInsertHandler.NO_PARAMETERS_HANDLER)
}
}
}
@@ -0,0 +1,128 @@
package org.jetbrains.jet.plugin.completion.handlers
import com.intellij.openapi.command.CommandProcessor
import com.intellij.codeInsight.completion.InsertionContext
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.Computable
import com.intellij.codeInsight.template.TemplateManager
import com.intellij.openapi.util.TextRange
import com.intellij.codeInsight.template.Template
import org.jetbrains.jet.plugin.refactoring.JetNameValidator
import org.jetbrains.jet.plugin.refactoring.JetNameSuggester
import org.jetbrains.jet.renderer.DescriptorRenderer
import com.intellij.codeInsight.template.Expression
import com.intellij.codeInsight.template.ExpressionContext
import com.intellij.codeInsight.template.TextResult
import com.intellij.codeInsight.template.Result
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementBuilder
import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.jet.lang.psi.JetExpression
import org.jetbrains.jet.plugin.completion.ExpectedInfos
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
import org.jetbrains.jet.lang.psi.JetFile
fun insertLambdaTemplate(context: InsertionContext, placeholderRange: TextRange, lambdaType: JetType) {
val explicitParameterTypes = needExplicitParameterTypes(context, placeholderRange, lambdaType)
// we start template later to not interfere with insertion of tail type
val commandProcessor = CommandProcessor.getInstance()
val commandName = commandProcessor.getCurrentCommandName()
val commandGroupId = commandProcessor.getCurrentCommandGroupId()
val rangeMarker = context.getDocument().createRangeMarker(placeholderRange)
context.setLaterRunnable {
commandProcessor.executeCommand(context.getProject(), {
ApplicationManager.getApplication()!!.runWriteAction(Computable<Unit> {
try {
if (rangeMarker.isValid()) {
context.getDocument().deleteString(rangeMarker.getStartOffset(), rangeMarker.getEndOffset())
context.getEditor().getCaretModel().moveToOffset(rangeMarker.getStartOffset())
val template = buildTemplate(lambdaType, explicitParameterTypes, context.getProject())
TemplateManager.getInstance(context.getProject()).startTemplate(context.getEditor(), template)
}
}
finally {
rangeMarker.dispose()
}
})
}, commandName, commandGroupId)
}
}
fun buildLambdaPresentation(lambdaType: JetType): String {
val parameterTypes = functionParameterTypes(lambdaType)
val parametersPresentation = parameterTypes.map { DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(it) }.makeString(", ")
fun wrap(s: String) = if (parameterTypes.size != 1) "($s)" else s
return "{ ${wrap(parametersPresentation)} -> ... }"
}
private fun needExplicitParameterTypes(context: InsertionContext, placeholderRange: TextRange, lambdaType: JetType): Boolean {
PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments()
val file = context.getFile() as JetFile
val expression = PsiTreeUtil.findElementOfClassAtRange(file, placeholderRange.getStartOffset(), placeholderRange.getEndOffset(), javaClass<JetExpression>())
if (expression == null) return false
val resolveSession = AnalyzerFacadeWithCache.getLazyResolveSessionForFile(file)
val bindingContext = resolveSession.resolveToElement(expression)
val expectedInfos = ExpectedInfos(bindingContext, resolveSession.getModuleDescriptor()).calculate(expression) ?: return false
val functionTypes = expectedInfos.map { it.`type` }.filter { KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(it) }.toSet()
if (functionTypes.size <= 1) return false
val lambdaParameterCount = KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(lambdaType).size
return functionTypes.filter { KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(it).size == lambdaParameterCount}.size > 1
}
private fun buildTemplate(lambdaType: JetType, explicitParameterTypes: Boolean, project: Project): Template {
val parameterTypes = functionParameterTypes(lambdaType)
val nameValidator = JetNameValidator.getEmptyValidator(project) //TODO: check for names in scope
val useParenthesis = explicitParameterTypes || parameterTypes.size != 1
val manager = TemplateManager.getInstance(project)
val template = manager.createTemplate("", "")
template.setToShortenLongNames(true)
//template.setToReformat(true) //TODO
template.addTextSegment("{ ")
if (useParenthesis) {
template.addTextSegment("(")
}
for (i in parameterTypes.indices) {
val parameterType = parameterTypes[i]
if (i > 0) {
template.addTextSegment(", ")
}
template.addVariable(ParameterNameExpression(JetNameSuggester.suggestNames(parameterType, nameValidator, "p")), true)
if (explicitParameterTypes) {
template.addTextSegment(": " + DescriptorRenderer.SOURCE_CODE.renderType(parameterType))
}
}
if (useParenthesis) {
template.addTextSegment(")")
}
template.addTextSegment(" -> ")
template.addEndVariable()
template.addTextSegment(" }")
return template
}
private class ParameterNameExpression(val nameSuggestions: Array<String>) : Expression() {
override fun calculateResult(context: ExpressionContext?) = TextResult(nameSuggestions[0])
override fun calculateQuickResult(context: ExpressionContext?): Result? = null
override fun calculateLookupItems(context: ExpressionContext?)
= Array<LookupElement>(nameSuggestions.size, { LookupElementBuilder.create(nameSuggestions[it]) })
}
fun functionParameterTypes(functionType: JetType): List<JetType>
= KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(functionType).map { it.getType() }
@@ -33,22 +33,22 @@ import org.jetbrains.jet.plugin.completion.JetLookupObject
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor
import org.jetbrains.jet.lang.psi.JetQualifiedExpression
import org.jetbrains.jet.lang.resolve.DescriptorUtils
import org.jetbrains.jet.lang.resolve.name.FqName
import org.jetbrains.jet.plugin.quickfix.ImportInsertHelper
import com.intellij.openapi.editor.Document
import org.jetbrains.jet.lang.types.JetType
import com.intellij.openapi.util.TextRange
public enum class CaretPosition {
IN_BRACKETS
AFTER_BRACKETS
}
public enum class BracketType {
PARENTHESIS
BRACES
}
public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val bracketType : BracketType) : InsertHandler<LookupElement> {
public data class GenerateLambdaInfo(val lambdaType: JetType, val explicitParameters: Boolean)
public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val lambdaInfo: GenerateLambdaInfo?) : InsertHandler<LookupElement> {
{
if (caretPosition == CaretPosition.AFTER_BRACKETS && bracketType == BracketType.BRACES) {
throw IllegalArgumentException("CaretPosition.AFTER_BRACKETS with bracketType == BracketType.BRACES combination is not supported")
if (caretPosition == CaretPosition.AFTER_BRACKETS && lambdaInfo != null) {
throw IllegalArgumentException("CaretPosition.AFTER_BRACKETS with lambdaInfo != null combination is not supported")
}
}
@@ -67,32 +67,29 @@ public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val bra
addBrackets(context, element)
}
addImport(context, item)
addImports(context, item)
}
private fun addBrackets(context : InsertionContext, offsetElement : PsiElement) {
val offset = context.getSelectionEndOffset()
val offset = context.getTailOffset()
val document = context.getDocument()
val completionChar = context.getCompletionChar()
var documentText = document.getText()
val forceParenthesis = bracketType == BracketType.BRACES && completionChar == '\t' && documentText.charAt(offset) == '('
val braces = bracketType == BracketType.BRACES && completionChar != '(' && !forceParenthesis
val forceParenthesis = lambdaInfo != null && completionChar == '\t' && document.getCharsSequence().charAt(offset) == '('
val braces = lambdaInfo != null && completionChar != '(' && !forceParenthesis
val openingBracket = if (braces) '{' else '('
val closingBracket = if (braces) '}' else ')'
var openingBracketIndex = indexOfSkippingSpace(documentText, openingBracket, offset)
var openingBracketOffset = indexOfSkippingSpace(document, openingBracket, offset)
var inBracketsShift = 0
if (openingBracketIndex == -1) {
if (openingBracketOffset == -1) {
if (braces) {
if (completionChar == ' ' || completionChar == '{') {
context.setAddCompletionChar(false)
}
if (isInsertSpacesInOneLineFunctionEnabled(offsetElement.getProject())) {
if (isInsertSpacesInOneLineFunctionEnabled(context.getProject())) {
document.insertString(offset, " { }")
inBracketsShift = 1
}
@@ -104,74 +101,69 @@ public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val bra
document.insertString(offset, "()")
}
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document)
documentText = document.getText()
}
openingBracketIndex = indexOfSkippingSpace(documentText, openingBracket, offset)
assert (openingBracketIndex != -1) { "If there wasn't open bracket it should already have been inserted" }
openingBracketOffset = indexOfSkippingSpace(document, openingBracket, offset)
assert (openingBracketOffset != -1) { "If there wasn't open bracket it should already have been inserted" }
val closeBracketIndex = indexOfSkippingSpace(documentText, closingBracket, openingBracketIndex + 1)
val closeBracketOffset = indexOfSkippingSpace(document, closingBracket, openingBracketOffset + 1)
val editor = context.getEditor()
var forcePlaceCaretIntoParentheses : Boolean = completionChar == '('
if (caretPosition == CaretPosition.IN_BRACKETS || forcePlaceCaretIntoParentheses || closeBracketIndex == -1) {
editor.getCaretModel().moveToOffset(openingBracketIndex + 1 + inBracketsShift)
if (caretPosition == CaretPosition.IN_BRACKETS || forcePlaceCaretIntoParentheses || closeBracketOffset == -1) {
editor.getCaretModel().moveToOffset(openingBracketOffset + 1 + inBracketsShift)
AutoPopupController.getInstance(context.getProject())?.autoPopupParameterInfo(editor, offsetElement)
}
else {
editor.getCaretModel().moveToOffset(closeBracketIndex + 1)
editor.getCaretModel().moveToOffset(closeBracketOffset + 1)
}
PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getDocument())
if (lambdaInfo != null && lambdaInfo.explicitParameters) {
insertLambdaTemplate(context, TextRange(openingBracketOffset, closeBracketOffset + 1), lambdaInfo.lambdaType)
}
}
class object {
public val EMPTY_FUNCTION_HANDLER: JetFunctionInsertHandler = JetFunctionInsertHandler(CaretPosition.AFTER_BRACKETS, BracketType.PARENTHESIS)
public val PARAMS_PARENTHESIS_FUNCTION_HANDLER: JetFunctionInsertHandler = JetFunctionInsertHandler(CaretPosition.IN_BRACKETS, BracketType.PARENTHESIS)
public val PARAMS_BRACES_FUNCTION_HANDLER: JetFunctionInsertHandler = JetFunctionInsertHandler(CaretPosition.IN_BRACKETS, BracketType.BRACES)
public val NO_PARAMETERS_HANDLER: JetFunctionInsertHandler = JetFunctionInsertHandler(CaretPosition.AFTER_BRACKETS, null)
public val WITH_PARAMETERS_HANDLER: JetFunctionInsertHandler = JetFunctionInsertHandler(CaretPosition.IN_BRACKETS, null)
private fun shouldAddBrackets(element : PsiElement) : Boolean {
return PsiTreeUtil.getParentOfType(element, javaClass<JetImportDirective>()) == null
}
private fun indexOfSkippingSpace(str : String, ch : Char, startIndex : Int) : Int {
for (i in startIndex..str.length() - 1) {
val currentChar = str.charAt(i)
if (ch == currentChar) {
return i
}
if (!Character.isWhitespace(currentChar)) {
return -1
}
private fun indexOfSkippingSpace(document: Document, ch : Char, startIndex : Int) : Int {
val text = document.getCharsSequence()
for (i in startIndex..text.length() - 1) {
val currentChar = text.charAt(i)
if (ch == currentChar) return i
if (!Character.isWhitespace(currentChar)) return -1
}
return -1
}
private open fun isInsertSpacesInOneLineFunctionEnabled(project : Project) : Boolean {
val settings = CodeStyleSettingsManager.getSettings(project)
val jetSettings = settings.getCustomSettings(javaClass<JetCodeStyleSettings>())!!
return jetSettings.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD
}
private open fun isInsertSpacesInOneLineFunctionEnabled(project : Project)
= CodeStyleSettingsManager.getSettings(project)
.getCustomSettings(javaClass<JetCodeStyleSettings>())!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD
private open fun addImport(context : InsertionContext, item : LookupElement) {
private open fun addImports(context : InsertionContext, item : LookupElement) {
ApplicationManager.getApplication()?.runReadAction { () : Unit ->
val startOffset = context.getStartOffset()
val element = context.getFile().findElementAt(startOffset)
if (element == null) return@runReadAction
if (context.getFile() is JetFile && item.getObject() is JetLookupObject) {
val file = context.getFile()
if (file is JetFile && item.getObject() is JetLookupObject) {
val descriptor = (item.getObject() as JetLookupObject).getDescriptor()
if (descriptor is SimpleFunctionDescriptor) {
val file = context.getFile() as JetFile
val functionDescriptor = descriptor as SimpleFunctionDescriptor
if (PsiTreeUtil.getParentOfType(element, javaClass<JetQualifiedExpression>()) != null &&
functionDescriptor.getReceiverParameter() == null) {
functionDescriptor.getReceiverParameter() == null) {
return@runReadAction
}
@@ -3,7 +3,6 @@ package org.jetbrains.jet.plugin.completion.handlers
import com.intellij.codeInsight.completion.*
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.openapi.editor.event.*
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiDocumentManager
import com.intellij.codeInsight.AutoPopupController
@@ -46,7 +45,7 @@ abstract class WithTailInsertHandlerBase : InsertHandler<LookupElement> {
class WithTailCharInsertHandler(val tailChar: Char, val spaceAfter: Boolean) : WithTailInsertHandlerBase() {
override fun insertTail(context: InsertionContext, offset: Int, moveCaret: Boolean) {
val document = context.getDocument()
fun isCharAt(offset: Int, c: Char) = offset < document.getTextLength() && document.getText(TextRange(offset, offset + 1))[0] == c
fun isCharAt(offset: Int, c: Char) = offset < document.getTextLength() && document.getCharsSequence().charAt(offset) == c
if (isCharAt(offset, tailChar)) {
document.deleteString(offset, offset + 1)
@@ -3,133 +3,45 @@ package org.jetbrains.jet.plugin.completion.smart
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementBuilder
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.plugin.completion.handlers.functionParameterTypes
import org.jetbrains.jet.renderer.DescriptorRenderer
import org.jetbrains.jet.plugin.refactoring.JetNameValidator
import org.jetbrains.jet.plugin.refactoring.JetNameSuggester
import com.intellij.openapi.project.Project
import com.intellij.codeInsight.completion.InsertHandler
import com.intellij.codeInsight.completion.InsertionContext
import com.intellij.codeInsight.template.*
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.Computable
import org.jetbrains.jet.plugin.completion.handlers.insertLambdaTemplate
import com.intellij.openapi.util.TextRange
import org.jetbrains.jet.plugin.completion.JetCompletionCharFilter
import org.jetbrains.jet.plugin.completion.ExpectedInfo
import org.jetbrains.jet.plugin.completion.handlers.buildLambdaPresentation
class LambdaItems(val project: Project) {
object LambdaItems {
public fun addToCollection(collection: MutableCollection<LookupElement>, functionExpectedInfos: Collection<ExpectedInfo>) {
val distinctTypes = functionExpectedInfos.map { it.`type` }.toSet()
fun createLookupElement(lookupString: String, textBeforeCaret: String, textAfterCaret: String, shortenRefs: Boolean)
= LookupElementBuilder.create(lookupString)
.withInsertHandler(ArtificialElementInsertHandler(textBeforeCaret, textAfterCaret, shortenRefs))
.suppressAutoInsertion()
val singleType = if (distinctTypes.size == 1) distinctTypes.single() else null
val singleSignatureLength = singleType?.let { KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(it).size }
val offerNoParametersLambda = singleSignatureLength == 0 || singleSignatureLength == 1
if (offerNoParametersLambda) {
val lookupElement = createLookupElement("{...}", "{ ", " }", shortenRefs = false)
collection.add(lookupElement.addTail(functionExpectedInfos))
val lookupElement = LookupElementBuilder.create("{...}")
.withInsertHandler(ArtificialElementInsertHandler("{ ", " }", false))
.suppressAutoInsertion()
.addTail(functionExpectedInfos)
lookupElement.putUserData(JetCompletionCharFilter.ACCEPT_OPENING_BRACE, true)
collection.add(lookupElement)
}
if (singleSignatureLength != 0) {
for (functionType in distinctTypes) {
val parameterTypes = functionParameterTypes(functionType)
val parametersPresentation = parameterTypes.map { DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(it) }.makeString(", ")
val useExplicitTypes = distinctTypes.stream().any { it != functionType && functionParameterTypes(it).size == parameterTypes.size }
fun wrap(s: String) = if (useParenthesis(useExplicitTypes, parameterTypes)) "($s)" else s
val lookupString = "{ ${wrap(parametersPresentation)} -> ... }"
val lookupString = buildLambdaPresentation(functionType)
val lookupElement = LookupElementBuilder.create(lookupString)
.withInsertHandler(LambdaInsertHandler(functionType, useExplicitTypes))
.withInsertHandler({ (context, lookupElement) ->
val offset = context.getStartOffset()
val placeholder = "{}"
context.getDocument().replaceString(offset, context.getTailOffset(), placeholder)
insertLambdaTemplate(context, TextRange(offset, offset + placeholder.length), functionType)
})
.suppressAutoInsertion()
collection.add(lookupElement.addTail(functionExpectedInfos.filter { it.`type` == functionType }))
.addTail(functionExpectedInfos.filter { it.`type` == functionType })
lookupElement.putUserData(JetCompletionCharFilter.ACCEPT_OPENING_BRACE, true)
collection.add(lookupElement)
}
}
}
private fun useParenthesis(useExplicitTypes: Boolean, parameterTypes: List<JetType>) = useExplicitTypes || parameterTypes.size != 1
private inner class LambdaInsertHandler(val functionType: JetType, val useExplicitTypes: Boolean) : InsertHandler<LookupElement> {
override fun handleInsert(context: InsertionContext, item: LookupElement) {
val document = context.getDocument()
val editor = context.getEditor()
val offset = context.getStartOffset()
val placeholder = "{}"
document.replaceString(offset, context.getTailOffset(), placeholder)
val rangeMarker = document.createRangeMarker(offset, offset + placeholder.length)
// we start template later to not interfere with insertion of tail type
val commandProcessor = CommandProcessor.getInstance()
val commandName = commandProcessor.getCurrentCommandName()
val commandGroupId = commandProcessor.getCurrentCommandGroupId()
context.setLaterRunnable {
commandProcessor.executeCommand(project, {
ApplicationManager.getApplication()!!.runWriteAction(Computable<Unit> {
try {
if (rangeMarker.isValid()) {
document.deleteString(rangeMarker.getStartOffset(), rangeMarker.getEndOffset())
editor.getCaretModel().moveToOffset(rangeMarker.getStartOffset())
TemplateManager.getInstance(project).startTemplate(editor, buildTemplate())
}
}
finally {
rangeMarker.dispose()
}
})
}, commandName, commandGroupId)
}
}
private fun buildTemplate(): Template {
val parameterTypes = functionParameterTypes(functionType)
val nameValidator = JetNameValidator.getEmptyValidator(project) //TODO: check for names in scope
val useParenthesis = useParenthesis(useExplicitTypes, parameterTypes)
val manager = TemplateManager.getInstance(project)
val template = manager.createTemplate("", "")
template.setToShortenLongNames(true)
//template.setToReformat(true) //TODO
template.addTextSegment("{ ")
if (useParenthesis) {
template.addTextSegment("(")
}
for (i in parameterTypes.indices) {
val parameterType = parameterTypes[i]
if (i > 0) {
template.addTextSegment(", ")
}
template.addVariable(ParameterNameExpression(JetNameSuggester.suggestNames(parameterType, nameValidator, "p")), true)
if (useExplicitTypes) {
template.addTextSegment(": " + DescriptorRenderer.SOURCE_CODE.renderType(parameterType))
}
}
if (useParenthesis) {
template.addTextSegment(")")
}
template.addTextSegment(" -> ")
template.addEndVariable()
template.addTextSegment(" }")
return template
}
}
private fun functionParameterTypes(functionType: JetType): List<JetType>
= KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(functionType).map { it.getType() }
private class ParameterNameExpression(val nameSuggestions: Array<String>) : Expression() {
override fun calculateResult(context: ExpressionContext?) = TextResult(nameSuggestions[0])
override fun calculateQuickResult(context: ExpressionContext?): Result? = null
override fun calculateLookupItems(context: ExpressionContext?)
= Array<LookupElement>(nameSuggestions.size, { LookupElementBuilder.create(nameSuggestions[it]) })
}
}
@@ -9,16 +9,9 @@ import org.jetbrains.jet.lang.types.*
import com.intellij.codeInsight.lookup.*
import com.intellij.codeInsight.completion.*
import java.util.*
import org.jetbrains.jet.plugin.completion.DescriptorLookupConverter
import org.jetbrains.jet.plugin.completion.*
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
enum class Tail {
COMMA
PARENTHESIS
}
data class ExpectedInfo(val `type`: JetType, val tail: Tail?)
class SmartCompletion(val expression: JetSimpleNameExpression,
val resolveSession: ResolveSessionForBodies,
val visibilityFilter: (DeclarationDescriptor) -> Boolean) {
@@ -78,7 +71,7 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
ThisItems(bindingContext).addToCollection(result, expressionWithType, expectedInfos)
LambdaItems(project).addToCollection(result, functionExpectedInfos)
LambdaItems.addToCollection(result, functionExpectedInfos)
}
return result
@@ -21,6 +21,7 @@ import com.intellij.codeInsight.completion.InsertionContext
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.psi.JetExpression
import org.jetbrains.jet.plugin.completion.ExpectedInfo
import java.util.ArrayList
// adds java static members, enum members and members from class object
@@ -18,6 +18,7 @@ import org.jetbrains.jet.lang.psi.JetCallExpression
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.types.TypeUtils
import org.jetbrains.jet.plugin.completion.ExpectedInfo
class ThisItems(val bindingContext: BindingContext) {
public fun addToCollection(collection: MutableCollection<LookupElement>, context: JetExpression, expectedInfos: Collection<ExpectedInfo>) {
@@ -13,13 +13,13 @@ import org.jetbrains.jet.lang.descriptors.Modality
import org.jetbrains.jet.lang.descriptors.ClassKind
import org.jetbrains.jet.plugin.codeInsight.ImplementMethodsHandler
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor
import org.jetbrains.jet.plugin.completion.handlers.CaretPosition
import com.intellij.codeInsight.lookup.LookupElementDecorator
import com.intellij.codeInsight.lookup.LookupElementPresentation
import com.intellij.codeInsight.completion.InsertionContext
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
import com.intellij.codeInsight.AutoPopupController
import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler
import org.jetbrains.jet.plugin.completion.*
class TypeInstantiationItems(val bindingContext: BindingContext, val resolveSession: ResolveSessionForBodies) {
public fun addToCollection(collection: MutableCollection<LookupElement>, expectedInfos: Collection<ExpectedInfo>) {
@@ -65,26 +65,28 @@ class TypeInstantiationItems(val bindingContext: BindingContext, val resolveSess
lookupElement = lookupElement.suppressAutoInsertion()
}
else {
//TODO: when constructor has one parameter of lambda type with more than one parameter, generate special additional item
itemText += "()"
val constructors: Collection<ConstructorDescriptor> = classifier.getConstructors()
val caretPosition =
val constructors = classifier.getConstructors()
val baseInsertHandler =
if (constructors.size == 0)
CaretPosition.AFTER_BRACKETS
JetFunctionInsertHandler.NO_PARAMETERS_HANDLER
else if (constructors.size == 1)
if (constructors.first().getValueParameters().isEmpty()) CaretPosition.AFTER_BRACKETS else CaretPosition.IN_BRACKETS
DescriptorLookupConverter.getDefaultInsertHandler(constructors.first())!!
else
CaretPosition.IN_BRACKETS
insertHandler = InsertHandler<LookupElement> {(context, item) ->
val editor = context.getEditor()
val startOffset = context.getStartOffset()
val text = typeText + "()"
editor.getDocument().replaceString(startOffset, context.getTailOffset(), text)
val endOffset = startOffset + text.length
editor.getCaretModel().moveToOffset(if (caretPosition == CaretPosition.IN_BRACKETS) endOffset - 1 else endOffset)
JetFunctionInsertHandler.WITH_PARAMETERS_HANDLER
insertHandler = object : InsertHandler<LookupElement> {
override fun handleInsert(context: InsertionContext, item: LookupElement) {
context.getDocument().replaceString(context.getStartOffset(), context.getTailOffset(), typeText)
context.setTailOffset(context.getStartOffset() + typeText.length)
shortenReferences(context, startOffset, endOffset)
baseInsertHandler.handleInsert(context, item)
AutoPopupController.getInstance(context.getProject())?.autoPopupParameterInfo(editor, null)
shortenReferences(context, context.getStartOffset(), context.getTailOffset())
}
}
if ((baseInsertHandler as JetFunctionInsertHandler).lambdaInfo != null) {
lookupElement.putUserData(JetCompletionCharFilter.ACCEPT_OPENING_BRACE, true)
}
}
@@ -17,6 +17,7 @@ import org.jetbrains.jet.lang.types.checker.JetTypeChecker
import com.intellij.codeInsight.lookup.LookupElementPresentation
import org.jetbrains.jet.plugin.completion.handlers.WithTailStringInsertHandler
import java.util.ArrayList
import org.jetbrains.jet.plugin.completion.*
class ArtificialElementInsertHandler(
val textBeforeCaret: String, val textAfterCaret: String, val shortenRefs: Boolean) : InsertHandler<LookupElement>{
@@ -0,0 +1,8 @@
fun foo(p: (String, Char) -> Unit){}
fun test() {
fo<caret>
}
// EXIST: { lookupString:"foo", itemText: "foo(p: (String, Char) -> Unit)", typeText:"Unit" }
// EXIST: { lookupString:"foo", itemText: "foo { (String, Char) -> ... }", typeText:"Unit" }
@@ -0,0 +1,5 @@
fun foo(p : (String, Char) -> Boolean){}
fun main(args: Array<String>) {
fo<caret>
}
@@ -0,0 +1,5 @@
fun foo(p : (String, Char) -> Boolean){}
fun main(args: Array<String>) {
foo { (s, c) -> <caret> }
}
@@ -0,0 +1,5 @@
fun foo(p : (String, Char) -> Boolean){}
fun main(args: Array<String>) {
fo<caret>
}
@@ -0,0 +1,5 @@
fun foo(p : (String, Char) -> Boolean){}
fun main(args: Array<String>) {
foo(<caret>)
}
@@ -0,0 +1,6 @@
fun foo(p : (String, Char) -> Boolean){}
fun foo(p : (String, Boolean) -> Boolean){}
fun main(args: Array<String>) {
fo<caret>
}
@@ -0,0 +1,6 @@
fun foo(p : (String, Char) -> Boolean){}
fun foo(p : (String, Boolean) -> Boolean){}
fun main(args: Array<String>) {
foo { (s: String, c: Char) -> <caret> }
}
@@ -0,0 +1,3 @@
class Foo(p : () -> Unit)
var a : Foo = <caret>
@@ -0,0 +1,3 @@
class Foo(p : () -> Unit)
var a : Foo = Foo { <caret> }
@@ -0,0 +1,3 @@
class Foo(p : (String) -> Unit)
var a : Foo = <caret>
@@ -0,0 +1,3 @@
class Foo(p : (String) -> Unit)
var a : Foo = Foo { <caret> }
@@ -5,4 +5,4 @@ fun bar() {
foo(<caret>)
}
// ELEMENT: "{ (Date) -> ... }"
// ELEMENT: "{ Date -> ... }"
@@ -7,4 +7,4 @@ fun bar() {
foo({ (date: Date) -> <caret> })
}
// ELEMENT: "{ (Date) -> ... }"
// ELEMENT: "{ Date -> ... }"
+2 -2
View File
@@ -6,5 +6,5 @@ fun bar() {
}
// ABSENT: "{...}"
// EXIST: "{ (String) -> ... }"
// EXIST: "{ (Int) -> ... }"
// EXIST: "{ String -> ... }"
// EXIST: "{ Int -> ... }"
@@ -189,6 +189,11 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
doTest("idea/testData/completion/basic/common/FunctionCompletionFormatting.kt");
}
@TestMetadata("HigherOrderFunction1.kt")
public void testHigherOrderFunction1() throws Exception {
doTest("idea/testData/completion/basic/common/HigherOrderFunction1.kt");
}
@TestMetadata("InCallExpression.kt")
public void testInCallExpression() throws Exception {
doTest("idea/testData/completion/basic/common/InCallExpression.kt");
@@ -16,17 +16,14 @@
package org.jetbrains.jet.completion;
import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestSuite;
import java.io.File;
import java.util.regex.Pattern;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.InnerTestClasses;
import org.jetbrains.jet.test.TestMetadata;
import org.jetbrains.jet.completion.AbstractJvmBasicCompletionTest;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@@ -189,6 +186,11 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
doTest("idea/testData/completion/basic/common/FunctionCompletionFormatting.kt");
}
@TestMetadata("HigherOrderFunction1.kt")
public void testHigherOrderFunction1() throws Exception {
doTest("idea/testData/completion/basic/common/HigherOrderFunction1.kt");
}
@TestMetadata("InCallExpression.kt")
public void testInCallExpression() throws Exception {
doTest("idea/testData/completion/basic/common/InCallExpression.kt");
@@ -46,6 +46,12 @@ public class BasicCompletionHandlerTest : CompletionHandlerTestBase(){
fun testHigherOrderFunctionWithArg() = doTest(2, "filterNot", null, '\n')
fun testHigherOrderFunctionWithArgs1() = doTest(1, "foo", "foo { (String, Char) -> ... }", null, '\n')
fun testHigherOrderFunctionWithArgs2() = doTest(1, "foo", "foo(p: (String, Char) -> Boolean)", null, '\n')
fun testHigherOrderFunctionWithArgs3() = doTest(1, "foo", "foo { (String, Char) -> ... }", null, '\n')
fun testForceParenthesisForTabChar() = doTest(0, "some", null, '\t')
fun testTabInsertAtTheFileEnd() = doTest(0, "vvvvv", null, '\t')
@@ -16,17 +16,11 @@
package org.jetbrains.jet.completion.handlers;
import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.TestMetadata;
import java.io.File;
import java.util.regex.Pattern;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.InnerTestClasses;
import org.jetbrains.jet.test.TestMetadata;
import org.jetbrains.jet.completion.handlers.AbstractSmartCompletionHandlerTest;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@@ -151,6 +145,16 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
doTest("idea/testData/completion/handlers/smart/ConstructorInsertsImport2.kt");
}
@TestMetadata("ConstructorWithLambdaParameter1.kt")
public void testConstructorWithLambdaParameter1() throws Exception {
doTest("idea/testData/completion/handlers/smart/ConstructorWithLambdaParameter1.kt");
}
@TestMetadata("ConstructorWithLambdaParameter2.kt")
public void testConstructorWithLambdaParameter2() throws Exception {
doTest("idea/testData/completion/handlers/smart/ConstructorWithLambdaParameter2.kt");
}
@TestMetadata("ConstructorWithParameters.kt")
public void testConstructorWithParameters() throws Exception {
doTest("idea/testData/completion/handlers/smart/ConstructorWithParameters.kt");