FIR IDE: Add more correct importing of the callables
Now we use scopes to decide if the callable really needs to be inserted
This commit is contained in:
+12
@@ -0,0 +1,12 @@
|
||||
// FIR_COMPARISON
|
||||
package test
|
||||
|
||||
class AClass
|
||||
|
||||
val AClass.ext get() = this
|
||||
|
||||
fun usage(a: AClass) {
|
||||
a.ex<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: ext
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// FIR_COMPARISON
|
||||
package test
|
||||
|
||||
class AClass
|
||||
|
||||
val AClass.ext get() = this
|
||||
|
||||
fun usage(a: AClass) {
|
||||
a.ext<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: ext
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
// FIR_COMPARISON
|
||||
package first
|
||||
|
||||
fun foo() {
|
||||
"".extensi<caret>
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
package first
|
||||
|
||||
val String.extensionProp: Int
|
||||
get() = 1
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
// FIR_COMPARISON
|
||||
package first
|
||||
|
||||
fun foo() {
|
||||
"".extensionProp<caret>
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
// FIR_COMPARISON
|
||||
package some
|
||||
|
||||
fun other() {
|
||||
somePr<caret>
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
package some
|
||||
|
||||
val someProp: Int = 1
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
// FIR_COMPARISON
|
||||
package some
|
||||
|
||||
fun other() {
|
||||
someProp<caret>
|
||||
}
|
||||
+5
@@ -79,6 +79,11 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion
|
||||
runTest("idea/idea-completion/testData/handlers/basic/ExtensionFunctionTypeVariable2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ExtensionPropertyFromSameFile.kt")
|
||||
public void testExtensionPropertyFromSameFile() throws Exception {
|
||||
runTest("idea/idea-completion/testData/handlers/basic/ExtensionPropertyFromSameFile.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ExtensionReceiverTypeArg.kt")
|
||||
public void testExtensionReceiverTypeArg() throws Exception {
|
||||
runTest("idea/idea-completion/testData/handlers/basic/ExtensionReceiverTypeArg.kt");
|
||||
|
||||
+8
@@ -26,6 +26,10 @@ open class CompletionMultiFileHandlerTest : KotlinFixtureCompletionBaseTestCase(
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun testExtensionPropertyInSamePackageNoImport() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun testImportAlreadyImportedObject() {
|
||||
doTest()
|
||||
}
|
||||
@@ -50,6 +54,10 @@ open class CompletionMultiFileHandlerTest : KotlinFixtureCompletionBaseTestCase(
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun testTopLevelPropertyInSamePackageNoImport() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun testTopLevelValImportInStringTemplate() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
+5
@@ -79,6 +79,11 @@ public class HighLevelPerformanceBasicCompletionHandlerTestGenerated extends Abs
|
||||
runTest("idea/idea-completion/testData/handlers/basic/ExtensionFunctionTypeVariable2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ExtensionPropertyFromSameFile.kt")
|
||||
public void testExtensionPropertyFromSameFile() throws Exception {
|
||||
runTest("idea/idea-completion/testData/handlers/basic/ExtensionPropertyFromSameFile.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ExtensionReceiverTypeArg.kt")
|
||||
public void testExtensionReceiverTypeArg() throws Exception {
|
||||
runTest("idea/idea-completion/testData/handlers/basic/ExtensionReceiverTypeArg.kt");
|
||||
|
||||
+58
-21
@@ -121,24 +121,10 @@ private class VariableLookupElementFactory {
|
||||
return if (symbol.canBeCalledByFqName) {
|
||||
ShorteningVariableInsertionHandler(callableId)
|
||||
} else {
|
||||
SimpleVariableInsertionHandler(callableId)
|
||||
SimpleVariableInsertionHandler(symbol.name, symbol.importableFqName)
|
||||
}
|
||||
}
|
||||
|
||||
private val KtVariableLikeSymbol.callableIdIfExists: FqName?
|
||||
get() = when (this) {
|
||||
is KtJavaFieldSymbol -> callableIdIfNonLocal
|
||||
is KtKotlinPropertySymbol -> callableIdIfNonLocal
|
||||
is KtSyntheticJavaPropertySymbol -> callableIdIfNonLocal
|
||||
|
||||
// Compiler will complain if there would be a new type in the hierarchy
|
||||
is KtEnumEntrySymbol,
|
||||
is KtLocalVariableSymbol,
|
||||
is KtFunctionParameterSymbol,
|
||||
is KtConstructorParameterSymbol,
|
||||
is KtSetterParameterSymbol -> null
|
||||
}
|
||||
|
||||
private val KtVariableLikeSymbol.canBeCalledByFqName: Boolean
|
||||
get() = when (this) {
|
||||
is KtKotlinPropertySymbol -> dispatchType == null && receiverType == null
|
||||
@@ -318,9 +304,10 @@ private class SimpleFunctionInsertionHandler(
|
||||
val element = context.file.findElementAt(startOffset) ?: return
|
||||
|
||||
addArguments(context, element)
|
||||
context.commitDocument()
|
||||
|
||||
if (nameToImport != null && targetFile.importDirectives.none { it.importPath?.fqName == nameToImport }) {
|
||||
addImportToFile(context.project, targetFile, nameToImport)
|
||||
if (nameToImport != null) {
|
||||
addCallableImportIfRequired(targetFile, nameToImport)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,15 +353,15 @@ private class ShorteningVariableInsertionHandler(private val name: FqName) : Ins
|
||||
}
|
||||
}
|
||||
|
||||
private class SimpleVariableInsertionHandler(private val nameToImport: FqName) :
|
||||
QuotedNamesAwareInsertionHandler(nameToImport.shortName()) {
|
||||
private class SimpleVariableInsertionHandler(name: Name, private val nameToImport: FqName?) :
|
||||
QuotedNamesAwareInsertionHandler(name) {
|
||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||
super.handleInsert(context, item)
|
||||
|
||||
val targetFile = context.file as? KtFile ?: return
|
||||
|
||||
if (targetFile.importDirectives.none { it.importPath?.fqName == nameToImport }) {
|
||||
addImportToFile(context.project, targetFile, nameToImport)
|
||||
if (nameToImport != null) {
|
||||
addCallableImportIfRequired(targetFile, nameToImport)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -391,6 +378,56 @@ private open class QuotedNamesAwareInsertionHandler(private val name: Name) : In
|
||||
}
|
||||
}
|
||||
|
||||
private fun addCallableImportIfRequired(targetFile: KtFile, nameToImport: FqName) {
|
||||
if (!alreadyHasImport(targetFile, nameToImport)) {
|
||||
addImportToFile(targetFile.project, targetFile, nameToImport)
|
||||
}
|
||||
}
|
||||
|
||||
private fun alreadyHasImport(file: KtFile, nameToImport: FqName): Boolean {
|
||||
if (file.importDirectives.any { it.importPath?.fqName == nameToImport }) return false
|
||||
|
||||
withAllowedResolve {
|
||||
analyze(file) {
|
||||
val scopes = file.getScopeContextForFile().scopes
|
||||
if (!scopes.containsName(nameToImport.shortName())) return false
|
||||
|
||||
return scopes
|
||||
.getCallableSymbols { it == nameToImport.shortName() }
|
||||
.any {
|
||||
it is KtVariableLikeSymbol && it.callableIdIfExists == nameToImport ||
|
||||
it is KtFunctionSymbol && it.callableIdIfNonLocal == nameToImport
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val KtVariableLikeSymbol.callableIdIfExists: FqName?
|
||||
get() = when (this) {
|
||||
is KtJavaFieldSymbol -> callableIdIfNonLocal
|
||||
is KtKotlinPropertySymbol -> callableIdIfNonLocal
|
||||
is KtSyntheticJavaPropertySymbol -> callableIdIfNonLocal
|
||||
|
||||
// Compiler will complain if there would be a new type in the hierarchy
|
||||
is KtEnumEntrySymbol,
|
||||
is KtLocalVariableSymbol,
|
||||
is KtFunctionParameterSymbol,
|
||||
is KtConstructorParameterSymbol,
|
||||
is KtSetterParameterSymbol -> null
|
||||
}
|
||||
|
||||
private val KtVariableLikeSymbol.importableFqName: FqName?
|
||||
get() = when (this) {
|
||||
is KtKotlinPropertySymbol -> if (dispatchType == null) callableIdIfNonLocal else null
|
||||
|
||||
is KtEnumEntrySymbol,
|
||||
is KtJavaFieldSymbol,
|
||||
is KtSyntheticJavaPropertySymbol,
|
||||
is KtLocalVariableSymbol,
|
||||
is KtFunctionParameterSymbol,
|
||||
is KtConstructorParameterSymbol,
|
||||
is KtSetterParameterSymbol -> null
|
||||
}
|
||||
|
||||
private object ShortNamesRenderer {
|
||||
fun KtAnalysisSession.renderFunctionParameters(function: KtFunctionSymbol): String =
|
||||
|
||||
+5
@@ -79,6 +79,11 @@ public class HighLevelBasicCompletionHandlerTestGenerated extends AbstractHighLe
|
||||
runTest("idea/idea-completion/testData/handlers/basic/ExtensionFunctionTypeVariable2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ExtensionPropertyFromSameFile.kt")
|
||||
public void testExtensionPropertyFromSameFile() throws Exception {
|
||||
runTest("idea/idea-completion/testData/handlers/basic/ExtensionPropertyFromSameFile.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ExtensionReceiverTypeArg.kt")
|
||||
public void testExtensionReceiverTypeArg() throws Exception {
|
||||
runTest("idea/idea-completion/testData/handlers/basic/ExtensionReceiverTypeArg.kt");
|
||||
|
||||
+5
@@ -79,6 +79,11 @@ public class PerformanceBasicCompletionHandlerTestGenerated extends AbstractPerf
|
||||
runTest("idea/idea-completion/testData/handlers/basic/ExtensionFunctionTypeVariable2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ExtensionPropertyFromSameFile.kt")
|
||||
public void testExtensionPropertyFromSameFile() throws Exception {
|
||||
runTest("idea/idea-completion/testData/handlers/basic/ExtensionPropertyFromSameFile.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ExtensionReceiverTypeArg.kt")
|
||||
public void testExtensionReceiverTypeArg() throws Exception {
|
||||
runTest("idea/idea-completion/testData/handlers/basic/ExtensionReceiverTypeArg.kt");
|
||||
|
||||
Reference in New Issue
Block a user