Non-imported extension functions and properties in smart completion + adding import on completing of non-imported property

This commit is contained in:
Valentin Kipyatkov
2014-09-16 15:35:22 +04:00
parent 507bfe49aa
commit 75f7f296aa
23 changed files with 304 additions and 133 deletions
+1
View File
@@ -27,6 +27,7 @@
<patterns>
<pattern testClass="org.jetbrains.jet.completion.JvmSmartCompletionTestGenerated" />
<pattern testClass="org.jetbrains.jet.completion.handlers.SmartCompletionHandlerTestGenerated" />
<pattern testClass="org.jetbrains.jet.completion.handlers.SmartCompletionMultifileHandlerTest" />
</patterns>
<RunnerSettings RunnerId="Debug">
<option name="DEBUG_PORT" value="" />
@@ -31,7 +31,9 @@ import org.jetbrains.jet.plugin.completion.smart.SmartCompletion
import org.jetbrains.jet.plugin.references.JetSimpleNameReference
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
import org.jetbrains.jet.plugin.caches.KotlinIndicesHelper
import org.jetbrains.jet.plugin.search.searchScopeForSourceElementDependencies
import com.intellij.openapi.project.Project
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.module.Module
class CompletionSessionConfiguration(
val completeNonImportedDeclarations: Boolean,
@@ -44,7 +46,6 @@ fun CompletionSessionConfiguration(parameters: CompletionParameters) = Completio
abstract class CompletionSessionBase(protected val configuration: CompletionSessionConfiguration,
protected val parameters: CompletionParameters,
resultSet: CompletionResultSet) {
protected val position: PsiElement = parameters.getPosition()
protected val jetReference: JetSimpleNameReference? = position.getParent()?.getReferences()?.filterIsInstance(javaClass<JetSimpleNameReference>())?.firstOrNull()
protected val resolveSession: ResolveSessionForBodies = (position.getContainingFile() as JetFile).getLazyResolveSession()
@@ -59,6 +60,14 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
protected val prefixMatcher: PrefixMatcher = this.resultSet.getPrefixMatcher()
protected val collector: LookupElementsCollector = LookupElementsCollector(prefixMatcher, resolveSession, { isVisibleDescriptor(it) })
protected var anythingAdded: Boolean = false
protected val project: Project = position.getProject()
protected val indicesHelper: KotlinIndicesHelper = KotlinIndicesHelper(project)
protected val module: Module? = ModuleUtilCore.findModuleForPsiElement(parameters.getOriginalFile())
protected val searchScope: GlobalSearchScope = if (module != null) GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module) else GlobalSearchScope.EMPTY_SCOPE
protected fun isVisibleDescriptor(descriptor: DeclarationDescriptor): Boolean {
if (configuration.completeNonAccessibleDeclarations) return true
@@ -68,6 +77,46 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
return true
}
protected fun flushToResultSet() {
if (!collector.isEmpty) {
anythingAdded = true
}
collector.flushToResultSet(resultSet)
}
public fun complete(): Boolean {
doComplete()
flushToResultSet()
return anythingAdded
}
protected abstract fun doComplete()
protected fun shouldRunTopLevelCompletion(): Boolean {
if (!configuration.completeNonImportedDeclarations) return false
if (position.getNode()!!.getElementType() == JetTokens.IDENTIFIER) {
val parent = position.getParent()
if (parent is JetSimpleNameExpression && !JetPsiUtil.isSelectorInQualified(parent)) return true
}
return false
}
protected fun shouldRunExtensionsCompletion(): Boolean {
return configuration.completeNonImportedDeclarations || prefixMatcher.getPrefix().length >= 3
}
protected fun getKotlinTopLevelDeclarations(): Collection<DeclarationDescriptor> {
val filter = { (name: String) -> prefixMatcher.prefixMatches(name) }
return indicesHelper.getTopLevelCallables(filter, jetReference!!.expression, resolveSession, searchScope) +
indicesHelper.getTopLevelObjects(filter, resolveSession, searchScope)
}
protected fun getKotlinExtensions(): Collection<CallableDescriptor> {
return indicesHelper.getCallableExtensions({ prefixMatcher.prefixMatches(it) }, jetReference!!.expression, resolveSession, searchScope)
}
}
class BasicCompletionSession(configuration: CompletionSessionConfiguration,
@@ -75,14 +124,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
resultSet: CompletionResultSet)
: CompletionSessionBase(configuration, parameters, resultSet) {
private val collector = LookupElementsCollector(prefixMatcher, resolveSession, { isVisibleDescriptor(it) })
private var anythingAdded = false
private val project = position.getProject()
private val indicesHelper = KotlinIndicesHelper(project)
private val searchScope = searchScopeForSourceElementDependencies(parameters.getOriginalFile()) ?: GlobalSearchScope.EMPTY_SCOPE
public fun complete(): Boolean {
override fun doComplete() {
assert(parameters.getCompletionType() == CompletionType.BASIC)
if (!NamedParametersCompletion.isOnlyNamedParameterExpected(position)) {
@@ -111,16 +153,6 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
}
NamedParametersCompletion.complete(position, collector)
flushToResultSet()
return anythingAdded
}
private fun flushToResultSet() {
if (!collector.isEmpty) {
anythingAdded = true
}
collector.flushToResultSet(resultSet)
}
private fun addNonImported() {
@@ -137,11 +169,11 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
if (shouldRunTopLevelCompletion()) {
TypesCompletion(parameters, resolveSession, prefixMatcher).addAllTypes(collector)
addKotlinTopLevelDeclarations()
collector.addDescriptorElements(getKotlinTopLevelDeclarations())
}
if (shouldRunExtensionsCompletion()) {
addKotlinExtensions()
collector.addDescriptorElements(getKotlinExtensions())
}
}
@@ -162,16 +194,6 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
}
}
private fun addKotlinTopLevelDeclarations() {
val filter = { (name: String) -> prefixMatcher.prefixMatches(name) }
collector.addDescriptorElements(indicesHelper.getTopLevelCallables(filter, jetReference!!.expression, resolveSession, searchScope))
collector.addDescriptorElements(indicesHelper.getTopLevelObjects(filter, resolveSession, searchScope))
}
private fun addKotlinExtensions() {
collector.addDescriptorElements(indicesHelper.getCallableExtensions({ prefixMatcher.prefixMatches(it) }, jetReference!!.expression, resolveSession, searchScope))
}
private fun shouldRunOnlyTypeCompletion(): Boolean {
// Check that completion in the type annotation context and if there's a qualified
// expression we are at first of it
@@ -184,21 +206,6 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
return false
}
private fun shouldRunTopLevelCompletion(): Boolean {
if (!configuration.completeNonImportedDeclarations) return false
if (position.getNode()!!.getElementType() == JetTokens.IDENTIFIER) {
val parent = position.getParent()
if (parent is JetSimpleNameExpression && !JetPsiUtil.isSelectorInQualified(parent)) return true
}
return false
}
private fun shouldRunExtensionsCompletion(): Boolean {
return configuration.completeNonImportedDeclarations || prefixMatcher.getPrefix().length >= 3
}
private fun addReferenceVariants(filterCondition: (DeclarationDescriptor) -> Boolean = { true }) {
val descriptors = TipsManager.getReferenceVariants(jetReference!!.expression, bindingContext!!)
collector.addDescriptorElements(descriptors.filter { filterCondition(it) })
@@ -207,11 +214,43 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
class SmartCompletionSession(configuration: CompletionSessionConfiguration, parameters: CompletionParameters, resultSet: CompletionResultSet)
: CompletionSessionBase(configuration, parameters, resultSet) {
public fun complete() {
override fun doComplete() {
if (jetReference != null) {
val descriptors = TipsManager.getReferenceVariants(jetReference.expression, bindingContext!!)
val completion = SmartCompletion(jetReference.expression, resolveSession, { isVisibleDescriptor(it) }, parameters.getOriginalFile() as JetFile)
completion.buildLookupElements(descriptors)?.forEach { resultSet.addElement(it) }
val result = completion.execute()
if (result != null) {
collector.addElements(result.additionalItems)
val filter = result.declarationFilter
if (filter != null) {
TipsManager.getReferenceVariants(jetReference.expression, bindingContext!!)
.forEach { collector.addElements(filter(it)) }
flushToResultSet()
processNonImported { collector.addElements(filter(it)) }
}
}
}
}
private fun processNonImported(processor: (DeclarationDescriptor) -> Unit) {
val prefix = prefixMatcher.getPrefix()
// Try to avoid computing not-imported descriptors for empty prefix
if (prefix.isEmpty()) {
if (!configuration.completeNonImportedDeclarations) return
if (PsiTreeUtil.getParentOfType(jetReference!!.expression, javaClass<JetDotQualifiedExpression>()) == null) return
}
if (shouldRunTopLevelCompletion()) {
getKotlinTopLevelDeclarations().forEach(processor)
}
if (shouldRunExtensionsCompletion()) {
getKotlinExtensions().forEach(processor)
}
}
}
@@ -33,6 +33,7 @@ import org.jetbrains.jet.plugin.completion.handlers.JetClassInsertHandler
import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler
import org.jetbrains.jet.renderer.DescriptorRenderer
import org.jetbrains.jet.plugin.completion.handlers.BaseDeclarationInsertHandler
import org.jetbrains.jet.plugin.completion.handlers.JetPropertyInsertHandler
public object DescriptorLookupConverter {
public fun createLookupElement(analyzer: KotlinCodeAnalyzer, descriptor: DeclarationDescriptor, declaration: PsiElement?): LookupElement {
@@ -100,6 +101,8 @@ public object DescriptorLookupConverter {
}
}
is PropertyDescriptor -> JetPropertyInsertHandler
is ClassDescriptor -> JetClassInsertHandler
else -> BaseDeclarationInsertHandler()
@@ -83,4 +83,8 @@ class LookupElementsCollector(private val prefixMatcher: PrefixMatcher,
elements.add(element)
}
}
public fun addElements(elements: Iterable<LookupElement>) {
elements.forEach { addElement(it) }
}
}
@@ -28,7 +28,6 @@ import com.intellij.openapi.project.Project
import org.jetbrains.jet.plugin.formatter.JetCodeStyleSettings
import com.intellij.openapi.application.ApplicationManager
import org.jetbrains.jet.lang.psi.JetFile
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.plugin.quickfix.ImportInsertHelper
@@ -36,6 +35,46 @@ import com.intellij.openapi.editor.Document
import org.jetbrains.jet.lang.types.JetType
import com.intellij.openapi.util.TextRange
import org.jetbrains.jet.plugin.completion.DeclarationLookupObject
import org.jetbrains.jet.lang.descriptors.CallableDescriptor
public abstract class JetCallableInsertHandler : BaseDeclarationInsertHandler() {
public override fun handleInsert(context: InsertionContext, item: LookupElement) {
super.handleInsert(context, item)
addImport(context, item)
}
private fun addImport(context : InsertionContext, item : LookupElement) {
PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments()
ApplicationManager.getApplication()?.runReadAction { () : Unit ->
val startOffset = context.getStartOffset()
val element = context.getFile().findElementAt(startOffset)
if (element == null) return@runReadAction
val file = context.getFile()
val o = item.getObject()
if (file is JetFile && o is DeclarationLookupObject) {
val descriptor = o.descriptor as? CallableDescriptor
if (descriptor != null) {
if (PsiTreeUtil.getParentOfType(element, javaClass<JetQualifiedExpression>()) != null &&
descriptor.getReceiverParameter() == null) {
return@runReadAction
}
if (DescriptorUtils.isTopLevelDeclaration(descriptor)) {
ApplicationManager.getApplication()?.runWriteAction {
ImportInsertHelper.addImportDirectiveIfNeeded(DescriptorUtils.getFqNameSafe(descriptor), file)
}
}
}
}
}
}
}
public object JetPropertyInsertHandler : JetCallableInsertHandler()
public enum class CaretPosition {
IN_BRACKETS
@@ -44,7 +83,7 @@ public enum class CaretPosition {
public data class GenerateLambdaInfo(val lambdaType: JetType, val explicitParameters: Boolean)
public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val lambdaInfo: GenerateLambdaInfo?) : BaseDeclarationInsertHandler() {
public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val lambdaInfo: GenerateLambdaInfo?) : JetCallableInsertHandler() {
{
if (caretPosition == CaretPosition.AFTER_BRACKETS && lambdaInfo != null) {
throw IllegalArgumentException("CaretPosition.AFTER_BRACKETS with lambdaInfo != null combination is not supported")
@@ -54,7 +93,10 @@ public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val lam
public override fun handleInsert(context: InsertionContext, item: LookupElement) {
super.handleInsert(context, item)
PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments()
val psiDocumentManager = PsiDocumentManager.getInstance(context.getProject())
psiDocumentManager.commitAllDocuments()
psiDocumentManager.doPostponedOperationsAndUnblockDocument(context.getDocument())
if (context.getCompletionChar() == '(') {
context.setAddCompletionChar(false)
}
@@ -62,13 +104,9 @@ public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val lam
val startOffset = context.getStartOffset()
val element = context.getFile().findElementAt(startOffset)
if (element == null) return
if (shouldAddBrackets(element)) {
if (element != null && shouldAddBrackets(element)) {
addBrackets(context, element)
}
addImports(context, item)
}
private fun addBrackets(context : InsertionContext, offsetElement : PsiElement) {
@@ -145,36 +183,8 @@ public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val lam
return -1
}
private open fun isInsertSpacesInOneLineFunctionEnabled(project : Project)
private fun isInsertSpacesInOneLineFunctionEnabled(project : Project)
= CodeStyleSettingsManager.getSettings(project)
.getCustomSettings(javaClass<JetCodeStyleSettings>())!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD
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
val file = context.getFile()
val o = item.getObject()
if (file is JetFile && o is DeclarationLookupObject) {
val descriptor = o.descriptor as? SimpleFunctionDescriptor
if (descriptor != null) {
if (PsiTreeUtil.getParentOfType(element, javaClass<JetQualifiedExpression>()) != null &&
descriptor.getReceiverParameter() == null) {
return@runReadAction
}
if (DescriptorUtils.isTopLevelDeclaration(descriptor)) {
ApplicationManager.getApplication()?.runWriteAction {
val fqn = DescriptorUtils.getFqNameSafe(descriptor)
ImportInsertHelper.addImportDirectiveIfNeeded(fqn, file)
}
}
}
}
}
}
}
}
@@ -37,15 +37,17 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
val resolveSession: ResolveSessionForBodies,
val visibilityFilter: (DeclarationDescriptor) -> Boolean,
val originalFile: JetFile) {
private val bindingContext = resolveSession.resolveToElement(expression)
private val moduleDescriptor = resolveSession.getModuleDescriptor()
private val project = expression.getProject()
public fun buildLookupElements(referenceVariants: Iterable<DeclarationDescriptor>): Collection<LookupElement>? {
return buildLookupElementsInternal(referenceVariants)?.map {
if (it.getUserData(KEEP_OLD_ARGUMENT_LIST_ON_TAB_KEY) == null) {
object : LookupElementDecorator<LookupElement>(it) {
public data class Result(val declarationFilter: ((DeclarationDescriptor) -> Collection<LookupElement>)?,
val additionalItems: Collection<LookupElement>)
public fun execute(): Result? {
fun postProcess(item: LookupElement): LookupElement {
return if (item.getUserData(KEEP_OLD_ARGUMENT_LIST_ON_TAB_KEY) == null) {
object : LookupElementDecorator<LookupElement>(item) {
override fun handleInsert(context: InsertionContext) {
if (context.getCompletionChar() == Lookup.REPLACE_SELECT_CHAR) {
val offset = context.getOffsetMap().getOffset(SmartCompletion.OLD_ARGUMENTS_REPLACEMENT_OFFSET)
@@ -59,14 +61,23 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
}
}
else {
it
item
}
}
val result = executeInternal() ?: return null
// TODO: code could be more simple, see KT-5726
val additionalItems = result.additionalItems.map(::postProcess)
val filter = result.declarationFilter
return if (filter != null)
Result({ filter(it).map(::postProcess) }, additionalItems)
else
Result(null, additionalItems)
}
private fun buildLookupElementsInternal(referenceVariants: Iterable<DeclarationDescriptor>): Collection<LookupElement>? {
val elements = buildForAsTypePosition()
if (elements != null) return elements
private fun executeInternal(): Result? {
val asTypePositionResult = buildForAsTypePosition()
if (asTypePositionResult != null) return asTypePositionResult
val parent = expression.getParent()
val expressionWithType: JetExpression
@@ -90,46 +101,47 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
else
filteredExpectedInfos
val result = ArrayList<LookupElement>()
val typesWithAutoCasts: (DeclarationDescriptor) -> Iterable<JetType> = TypesWithAutoCasts(bindingContext).calculate(expressionWithType, receiver)
val itemsToSkip = calcItemsToSkip(expressionWithType)
val functionExpectedInfos = expectedInfos.filter { KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(it.`type`) }
for (descriptor in referenceVariants) {
if (itemsToSkip.contains(descriptor)) continue
fun filterDeclaration(descriptor: DeclarationDescriptor): Collection<LookupElement> {
val result = ArrayList<LookupElement>()
if (!itemsToSkip.contains(descriptor)) {
val types = typesWithAutoCasts(descriptor)
val nonNullTypes = types.map { it.makeNotNullable() }
val classifier = { (expectedInfo: ExpectedInfo) ->
when {
types.any { it.isSubtypeOf(expectedInfo.`type`) } -> ExpectedInfoClassification.MATCHES
nonNullTypes.any { it.isSubtypeOf(expectedInfo.`type`) } -> ExpectedInfoClassification.MAKE_NOT_NULLABLE
else -> ExpectedInfoClassification.NOT_MATCHES
}
}
result.addLookupElements(expectedInfos, classifier, { createLookupElement(descriptor, resolveSession) })
val types = typesWithAutoCasts(descriptor)
val nonNullTypes = types.map { it.makeNotNullable() }
val classifier = { (expectedInfo: ExpectedInfo) ->
when {
types.any { it.isSubtypeOf(expectedInfo.`type`) } -> ExpectedInfoClassification.MATCHES
nonNullTypes.any { it.isSubtypeOf(expectedInfo.`type`) } -> ExpectedInfoClassification.MAKE_NOT_NULLABLE
else -> ExpectedInfoClassification.NOT_MATCHES
if (receiver == null) {
toFunctionReferenceLookupElement(descriptor, functionExpectedInfos)?.let { result.add(it) }
}
}
result.addLookupElements(expectedInfos, classifier, { createLookupElement(descriptor, resolveSession) })
if (receiver == null) {
toFunctionReferenceLookupElement(descriptor, functionExpectedInfos)?.let { result.add(it) }
}
return result
}
val additionalItems = ArrayList<LookupElement>()
if (receiver == null) {
TypeInstantiationItems(resolveSession, visibilityFilter).addToCollection(result, expectedInfos)
TypeInstantiationItems(resolveSession, visibilityFilter).addToCollection(additionalItems, expectedInfos)
StaticMembers(bindingContext, resolveSession).addToCollection(result, expectedInfos, expression, itemsToSkip)
StaticMembers(bindingContext, resolveSession).addToCollection(additionalItems, expectedInfos, expression, itemsToSkip)
ThisItems(bindingContext).addToCollection(result, expressionWithType, expectedInfos)
ThisItems(bindingContext).addToCollection(additionalItems, expressionWithType, expectedInfos)
LambdaItems.addToCollection(result, functionExpectedInfos)
LambdaItems.addToCollection(additionalItems, functionExpectedInfos)
KeywordValues.addToCollection(result, filteredExpectedInfos/* use filteredExpectedInfos to not include null after == */, expressionWithType)
KeywordValues.addToCollection(additionalItems, filteredExpectedInfos/* use filteredExpectedInfos to not include null after == */, expressionWithType)
}
return result
return Result(::filterDeclaration, additionalItems)
}
private fun calcExpectedInfos(expression: JetExpression): Collection<ExpectedInfo>? {
@@ -258,26 +270,23 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
return null
}
private fun buildForAsTypePosition(): Collection<LookupElement>? {
private fun buildForAsTypePosition(): Result? {
val binaryExpression = ((expression.getParent() as? JetUserType)
?.getParent() as? JetTypeReference)
?.getParent() as? JetBinaryExpressionWithTypeRHS
if (binaryExpression != null) {
val elementType = binaryExpression.getOperationReference().getReferencedNameElementType()
if (elementType == JetTokens.AS_KEYWORD || elementType == JetTokens.AS_SAFE) {
val expectedInfos = calcExpectedInfos(binaryExpression) ?: return null
?: return null
val elementType = binaryExpression.getOperationReference().getReferencedNameElementType()
if (elementType != JetTokens.AS_KEYWORD && elementType != JetTokens.AS_SAFE) return null
val expectedInfos = calcExpectedInfos(binaryExpression) ?: return null
val expectedInfosGrouped: Map<JetType, List<ExpectedInfo>> = expectedInfos.groupBy { it.`type`.makeNotNullable() }
val expectedInfosGrouped: Map<JetType, List<ExpectedInfo>> = expectedInfos.groupBy { it.`type`.makeNotNullable() }
val result = ArrayList<LookupElement>()
for ((jetType, infos) in expectedInfosGrouped) {
val lookupElement = lookupElementForType(jetType) ?: continue
result.add(lookupElement.addTail(infos))
}
return result
}
val items = ArrayList<LookupElement>()
for ((jetType, infos) in expectedInfosGrouped) {
val lookupElement = lookupElementForType(jetType) ?: continue
items.add(lookupElement.addTail(infos))
}
return null
return Result(null, items)
}
private fun lookupElementForType(jetType: JetType): LookupElement? {
@@ -0,0 +1,5 @@
package first
fun foo() {
"".ext<caret>
}
@@ -0,0 +1,4 @@
package second
val String.extensionProp: Int
get() = 1
@@ -0,0 +1,7 @@
package first
import second.extensionProp
fun foo() {
"".extensionProp<caret>
}
@@ -0,0 +1,5 @@
package some
fun other() {
somePr<caret>
}
@@ -0,0 +1,3 @@
package other
val someProp: Int = 1
@@ -0,0 +1,7 @@
package some
import other.someProp
fun other() {
someProp<caret>
}
@@ -0,0 +1 @@
fun foo(s: String): String = s.ext<caret>
@@ -0,0 +1,3 @@
package other
fun String.extensionFun() = ""
@@ -0,0 +1,3 @@
import other.extensionFun
fun foo(s: String): String = s.extensionFun()<caret>
@@ -0,0 +1 @@
fun foo(s: String): Int = s.ext<caret>
@@ -0,0 +1,3 @@
package other
val String.extensionProp: Int get() = this.size
@@ -0,0 +1,3 @@
import other.extensionProp
fun foo(s: String): Int = s.extensionProp<caret>
@@ -22,7 +22,11 @@ import org.jetbrains.jet.plugin.PluginTestCaseBase;
import java.io.File;
public class CompletionMultifileHandlerTest extends KotlinCompletionTestCase {
public void testExtensionFunctions() throws Exception {
public void testExtensionFunctionImport() throws Exception {
doTest();
}
public void testExtensionPropertyImport() throws Exception {
doTest();
}
@@ -42,6 +46,10 @@ public class CompletionMultifileHandlerTest extends KotlinCompletionTestCase {
doTest();
}
public void testTopLevelPropertyImport() throws Exception {
doTest();
}
public void testNoParenthesisInImports() throws Exception {
doTest();
}
@@ -0,0 +1,52 @@
/*
* Copyright 2010-2014 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.jet.completion.handlers;
import com.intellij.codeInsight.completion.CompletionType;
import org.jetbrains.jet.plugin.KotlinCompletionTestCase;
import org.jetbrains.jet.plugin.PluginTestCaseBase;
import java.io.File;
public class SmartCompletionMultifileHandlerTest extends KotlinCompletionTestCase {
public void testImportExtensionFunction() throws Exception {
doTest();
}
public void testImportExtensionProperty() throws Exception {
doTest();
}
@Override
protected void setUp() throws Exception {
setType(CompletionType.SMART);
super.setUp();
}
public void doTest() throws Exception {
String fileName = getTestName(false);
configureByFiles(null, fileName + "-1.kt", fileName + "-2.kt");
complete(1);
checkResultByFile(fileName + ".kt.after");
}
@Override
protected String getTestDataPath() {
return new File(PluginTestCaseBase.getTestDataPathBase(), "/completion/handlers/multifile/smart/").getPath() + File.separator;
}
}