Adedd quickfix check if @PublishedApi stub already exists
This commit is contained in:
+32
-10
@@ -29,11 +29,14 @@ import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
|
||||
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.replaceWith.ReplaceProtectedToPublishedApiCallFix.Companion.newName
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
|
||||
class ReplaceProtectedToPublishedApiCallFix(
|
||||
@@ -41,27 +44,25 @@ class ReplaceProtectedToPublishedApiCallFix(
|
||||
val classOwnerPointer: SmartPsiElementPointer<KtClass>,
|
||||
val originalName: String,
|
||||
val paramNames: Map<String, String>,
|
||||
val signature: String,
|
||||
val newSignature: String,
|
||||
val isProperty: Boolean,
|
||||
val isVar: Boolean
|
||||
val isVar: Boolean,
|
||||
val isPublishedMemberAlreadyExists: Boolean
|
||||
) : KotlinQuickFixAction<KtExpression>(element) {
|
||||
|
||||
override fun getFamilyName() = "Replace with @PublishedApi bridge call"
|
||||
|
||||
val newName = "`${originalName.newName}`"
|
||||
|
||||
override fun getText() = "Replace with generated @PublishedApi bridge call '$newName${if (!isProperty) "(...)" else ""}'"
|
||||
override fun getText() = "Replace with generated @PublishedApi bridge call '${originalName.newNameQuoted}${if (!isProperty) "(...)" else ""}'"
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||
val element = element ?: return
|
||||
val isPublishedMemberAlreadyExists = false/*TODO*/
|
||||
if (!isPublishedMemberAlreadyExists) {
|
||||
val classOwner = classOwnerPointer.element ?: return
|
||||
val newMember: KtDeclaration =
|
||||
if (isProperty) {
|
||||
KtPsiFactory(classOwner).createProperty(
|
||||
"@kotlin.PublishedApi\n" +
|
||||
"internal " + signature.replaceFirst("$originalName:", "$newName:") +
|
||||
"internal " + newSignature +
|
||||
"\n" +
|
||||
"get() = $originalName\n" +
|
||||
if (isVar) "set(value) { $originalName = value }" else ""
|
||||
@@ -71,14 +72,14 @@ class ReplaceProtectedToPublishedApiCallFix(
|
||||
else {
|
||||
KtPsiFactory(classOwner).createFunction(
|
||||
"@kotlin.PublishedApi\n" +
|
||||
"internal " + signature.replaceFirst("$originalName(", "$newName(") +
|
||||
"internal " + newSignature +
|
||||
" = $originalName(${paramNames.keys.map { it }.joinToString(", ")})"
|
||||
)
|
||||
}
|
||||
|
||||
ShortenReferences.DEFAULT.process(classOwner.addDeclaration(newMember))
|
||||
}
|
||||
element.replace(KtPsiFactory(element).createExpression(newName))
|
||||
element.replace(KtPsiFactory(element).createExpression(originalName.newNameQuoted))
|
||||
}
|
||||
|
||||
companion object : KotlinSingleIntentionActionFactory() {
|
||||
@@ -97,15 +98,36 @@ class ReplaceProtectedToPublishedApiCallFix(
|
||||
val isVar = descriptor is PropertyDescriptor && descriptor.isVar
|
||||
|
||||
val signature = signatureRenderer.render(descriptor)
|
||||
val originalName = descriptor.name.asString()
|
||||
val newSignature =
|
||||
if (isProperty) {
|
||||
signature.replaceFirst("$originalName:", "${originalName.newNameQuoted}:")
|
||||
}
|
||||
else {
|
||||
signature.replaceFirst("$originalName(", "${originalName.newNameQuoted}(")
|
||||
}
|
||||
val paramNameAndType = descriptor.valueParameters.associate { it.name.asString() to it.type.getJetTypeFqName(false)}
|
||||
val classDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return null
|
||||
val source = classDescriptor.source.getPsi() as? KtClass ?: return null
|
||||
|
||||
val newName = Name.identifier(originalName.newName)
|
||||
val contributedDescriptors = classDescriptor.unsubstitutedMemberScope.getDescriptorsFiltered {
|
||||
it == newName
|
||||
}
|
||||
val isPublishedMemberAlreadyExists = contributedDescriptors.filterIsInstance<CallableMemberDescriptor>().any {
|
||||
signatureRenderer.render(it) == newSignature
|
||||
}
|
||||
|
||||
return ReplaceProtectedToPublishedApiCallFix(
|
||||
psiElement, source.createSmartPointer(), descriptor.name.asString(), paramNameAndType, signature, isProperty, isVar
|
||||
psiElement, source.createSmartPointer(), originalName, paramNameAndType, newSignature,
|
||||
isProperty, isVar, isPublishedMemberAlreadyExists
|
||||
)
|
||||
}
|
||||
|
||||
val String.newName: String
|
||||
get() = "access\$$this"
|
||||
|
||||
val String.newNameQuoted: String
|
||||
get() = "`$newName`"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// "Replace with generated @PublishedApi bridge call '`access$test`(...)'" "true"
|
||||
|
||||
open class ABase {
|
||||
protected fun test(p: Int) {
|
||||
}
|
||||
|
||||
|
||||
inline fun test() {
|
||||
{
|
||||
<caret>test(1)
|
||||
}()
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal fun `access$test`(p: Int) = test(p)
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Replace with generated @PublishedApi bridge call '`access$test`(...)'" "true"
|
||||
|
||||
open class ABase {
|
||||
protected fun test(p: Int) {
|
||||
}
|
||||
|
||||
|
||||
inline fun test() {
|
||||
{
|
||||
`access$test`(1)
|
||||
}()
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal fun `access$test`(p: Int) = test(p)
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// "Replace with generated @PublishedApi bridge call '`access$prop`'" "true"
|
||||
|
||||
open class ABase {
|
||||
protected var prop = 1
|
||||
|
||||
inline fun test() {
|
||||
{
|
||||
<caret>prop
|
||||
}()
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal var `access$prop`: Int
|
||||
get() = prop
|
||||
set(value) {
|
||||
prop = value
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// "Replace with generated @PublishedApi bridge call '`access$prop`'" "true"
|
||||
|
||||
open class ABase {
|
||||
protected var prop = 1
|
||||
|
||||
inline fun test() {
|
||||
{
|
||||
`access$prop`
|
||||
}()
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal var `access$prop`: Int
|
||||
get() = prop
|
||||
set(value) {
|
||||
prop = value
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ open class ABase {
|
||||
@Z
|
||||
protected var String.prop: Int
|
||||
get() = 1
|
||||
set(field) = {}
|
||||
set(field) {}
|
||||
|
||||
|
||||
inline fun test() {
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
// "Replace with generated @PublishedApi bridge call '`access$test`(...)'" "true"
|
||||
// "Replace with generated @PublishedApi bridge call '`access$prop`'" "true"
|
||||
annotation class Z
|
||||
|
||||
open class ABase {
|
||||
@Z
|
||||
protected var String.prop: Int
|
||||
get() = 1
|
||||
set(field) = {}
|
||||
set(field) {}
|
||||
|
||||
|
||||
inline fun test() {
|
||||
|
||||
@@ -4863,6 +4863,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/deprecatedSymbolUsage/publishedApi"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("existingStub.kt")
|
||||
public void testExistingStub() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/existingStub.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("existingStubForVar.kt")
|
||||
public void testExistingStubForVar() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/existingStubForVar.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("extension.kt")
|
||||
public void testExtension() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/publishedApi/extension.kt");
|
||||
|
||||
Reference in New Issue
Block a user