Skip to content

Commit 34e601a

Browse files
authored
[IJ plugin] v3 -> v4 migration: deprecations/renames (#5099)
1 parent 95c842d commit 34e601a

File tree

8 files changed

+174
-7
lines changed

8 files changed

+174
-7
lines changed

intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/Refactoring.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ import com.intellij.psi.JavaPsiFacade
77
import com.intellij.psi.PsiClass
88
import com.intellij.psi.PsiClassType
99
import com.intellij.psi.PsiElement
10+
import com.intellij.psi.PsiMethod
1011
import com.intellij.psi.PsiMigration
1112
import com.intellij.psi.PsiPackage
1213
import com.intellij.psi.PsiReference
1314
import com.intellij.psi.search.GlobalSearchScope
1415
import com.intellij.psi.search.searches.ClassInheritorsSearch
1516
import com.intellij.psi.search.searches.ReferencesSearch
1617
import com.intellij.refactoring.rename.RenamePsiElementProcessor
18+
import org.jetbrains.kotlin.asJava.classes.KtLightClass
19+
import org.jetbrains.kotlin.psi.psiUtil.findPropertyByName
1720

1821
fun findOrCreatePackage(project: Project, migration: PsiMigration, qName: String): PsiPackage {
1922
val aPackage = JavaPsiFacade.getInstance(project).findPackage(qName)
@@ -49,16 +52,17 @@ fun findMethodReferences(
4952
className: String,
5053
methodName: String,
5154
extensionTargetClassName: String? = null,
55+
methodPredicate: (PsiMethod) -> Boolean = { true },
5256
): Collection<PsiReference> {
5357
val psiLookupClass = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project)) ?: return emptyList()
5458
val methods = psiLookupClass.findMethodsByName(methodName, false)
5559
.filter { method ->
56-
if (extensionTargetClassName == null) return@filter true
60+
if (extensionTargetClassName == null) return@filter methodPredicate(method)
5761
// In Kotlin extensions, the target is passed to the first parameter
5862
if (method.parameterList.parametersCount < 1) return@filter false
5963
val firstParameter = method.parameterList.parameters.first()
6064
val firstParameterType = (firstParameter.type as? PsiClassType)?.rawType()?.canonicalText
61-
firstParameterType == extensionTargetClassName
65+
firstParameterType == extensionTargetClassName && methodPredicate(method)
6266
}
6367
return methods.flatMap { method ->
6468
val processor = RenamePsiElementProcessor.forElement(method)
@@ -68,7 +72,10 @@ fun findMethodReferences(
6872

6973
fun findFieldReferences(project: Project, className: String, fieldName: String): Collection<PsiReference> {
7074
val psiLookupClass = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project)) ?: return emptyList()
71-
val field = psiLookupClass.findFieldByName(fieldName, true) ?: return emptyList()
75+
val field = psiLookupClass.findFieldByName(fieldName, true)
76+
// Fallback to Kotlin property
77+
?: (psiLookupClass as? KtLightClass)?.kotlinOrigin?.findPropertyByName(fieldName)
78+
?: return emptyList()
7279
val processor = RenamePsiElementProcessor.forElement(field)
7380
return processor.findReferences(field, GlobalSearchScope.projectScope(project), false)
7481
}

intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/UpdateFieldName.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import org.jetbrains.kotlin.psi.KtPsiFactory
99
class UpdateFieldName(
1010
private val className: String,
1111
private val oldFieldName: String,
12-
private val newFieldName: String,
12+
private val replacementExpression: String,
1313
) : MigrationItem() {
1414
override fun findUsages(project: Project, migration: PsiMigration, searchScope: GlobalSearchScope): List<MigrationItemUsageInfo> {
1515
return findFieldReferences(project = project, className = className, fieldName = oldFieldName).toMigrationItemUsageInfo()
1616
}
1717

1818
override fun performRefactoring(project: Project, migration: PsiMigration, usage: MigrationItemUsageInfo) {
19-
val newFieldReference = KtPsiFactory(project).createExpression(newFieldName)
19+
val newFieldReference = KtPsiFactory(project).createExpression(replacementExpression)
2020
usage.element.replace(newFieldReference)
2121
}
2222
}

intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/v3tov4/ApolloV3ToV4MigrationProcessor.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@ package com.apollographql.ijplugin.refactoring.migration.v3tov4
33
import com.apollographql.ijplugin.ApolloBundle
44
import com.apollographql.ijplugin.refactoring.migration.ApolloMigrationRefactoringProcessor
55
import com.apollographql.ijplugin.refactoring.migration.apollo3
6+
import com.apollographql.ijplugin.refactoring.migration.item.RemoveMethodCall
7+
import com.apollographql.ijplugin.refactoring.migration.item.UpdateClassName
8+
import com.apollographql.ijplugin.refactoring.migration.item.UpdateFieldName
69
import com.apollographql.ijplugin.refactoring.migration.item.UpdateGradleDependenciesBuildKts
710
import com.apollographql.ijplugin.refactoring.migration.item.UpdateGradleDependenciesInToml
811
import com.apollographql.ijplugin.refactoring.migration.item.UpdateGradlePluginInBuildKts
12+
import com.apollographql.ijplugin.refactoring.migration.item.UpdateMethodName
13+
import com.apollographql.ijplugin.refactoring.migration.v3tov4.item.RemoveWatchMethodArguments
14+
import com.apollographql.ijplugin.refactoring.migration.v3tov4.item.ReplaceExecuteCacheAndNetwork
915
import com.intellij.openapi.project.Project
1016

1117
private const val apollo4LatestVersion = "4.0.0-alpha.2"
@@ -19,6 +25,16 @@ class ApolloV3ToV4MigrationProcessor(project: Project) : ApolloMigrationRefactor
1925
override val noUsageMessage = ApolloBundle.message("ApolloV3ToV4MigrationProcessor.noUsage")
2026

2127
override val migrationItems = listOf(
28+
// Deprecations / renames
29+
UpdateFieldName("$apollo3.api.ApolloResponse", "dataAssertNoErrors", "dataOrThrow()"),
30+
UpdateFieldName("$apollo3.exception.ApolloCompositeException", "first", "suppressedExceptions.first()"),
31+
UpdateFieldName("$apollo3.exception.ApolloCompositeException", "second", "suppressedExceptions.getOrNull(1)"),
32+
UpdateClassName("$apollo3.exception.ApolloCompositeException", "$apollo3.exception.ApolloException"),
33+
UpdateMethodName("$apollo3.ast.GQLResult", "valueAssertNoErrors", "getOrThrow"),
34+
RemoveMethodCall("$apollo3.cache.normalized.NormalizedCache", "emitCacheMisses", extensionTargetClassName = "$apollo3.api.MutableExecutionOptions"),
35+
RemoveWatchMethodArguments,
36+
ReplaceExecuteCacheAndNetwork,
37+
2238
// Gradle
2339
UpdateGradlePluginInBuildKts(apollo3, apollo3, apollo4LatestVersion),
2440
UpdateGradleDependenciesInToml(apollo3, apollo3, apollo4LatestVersion),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.apollographql.ijplugin.refactoring.migration.v3tov4.item
2+
3+
import com.apollographql.ijplugin.refactoring.findMethodReferences
4+
import com.apollographql.ijplugin.refactoring.migration.apollo3
5+
import com.apollographql.ijplugin.refactoring.migration.item.MigrationItem
6+
import com.apollographql.ijplugin.refactoring.migration.item.MigrationItemUsageInfo
7+
import com.apollographql.ijplugin.refactoring.migration.item.toMigrationItemUsageInfo
8+
import com.intellij.openapi.project.Project
9+
import com.intellij.psi.PsiMigration
10+
import com.intellij.psi.search.GlobalSearchScope
11+
import com.intellij.psi.util.parentOfType
12+
import org.jetbrains.kotlin.psi.KtCallExpression
13+
import org.jetbrains.kotlin.psi.KtImportDirective
14+
15+
object RemoveWatchMethodArguments : MigrationItem() {
16+
override fun findUsages(project: Project, migration: PsiMigration, searchScope: GlobalSearchScope): List<MigrationItemUsageInfo> {
17+
return findMethodReferences(
18+
project = project,
19+
className = "$apollo3.cache.normalized.NormalizedCache",
20+
methodName = "watch",
21+
extensionTargetClassName = "$apollo3.ApolloCall",
22+
) { method -> method.parameterList.parameters.any { it.name == "fetchThrows" } }
23+
.toMigrationItemUsageInfo()
24+
}
25+
26+
override fun performRefactoring(project: Project, migration: PsiMigration, usage: MigrationItemUsageInfo) {
27+
val element = usage.element
28+
val importDirective = element.parentOfType<KtImportDirective>()
29+
if (importDirective != null) {
30+
// Reference is an import
31+
return
32+
}
33+
val methodCall = element.parentOfType<KtCallExpression>() ?: return
34+
val valueArgumentList = methodCall.valueArgumentList ?: return
35+
repeat(valueArgumentList.arguments.size) {
36+
valueArgumentList.removeArgument(0)
37+
}
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.apollographql.ijplugin.refactoring.migration.v3tov4.item
2+
3+
import com.apollographql.ijplugin.refactoring.findMethodReferences
4+
import com.apollographql.ijplugin.refactoring.migration.apollo3
5+
import com.apollographql.ijplugin.refactoring.migration.item.MigrationItem
6+
import com.apollographql.ijplugin.refactoring.migration.item.MigrationItemUsageInfo
7+
import com.apollographql.ijplugin.refactoring.migration.item.toMigrationItemUsageInfo
8+
import com.intellij.openapi.project.Project
9+
import com.intellij.psi.PsiMigration
10+
import com.intellij.psi.search.GlobalSearchScope
11+
import com.intellij.psi.util.parentOfType
12+
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
13+
import org.jetbrains.kotlin.psi.KtImportDirective
14+
import org.jetbrains.kotlin.psi.KtPsiFactory
15+
16+
object ReplaceExecuteCacheAndNetwork : MigrationItem() {
17+
override fun findUsages(project: Project, migration: PsiMigration, searchScope: GlobalSearchScope): List<MigrationItemUsageInfo> {
18+
return findMethodReferences(
19+
project = project,
20+
className = "$apollo3.cache.normalized.NormalizedCache",
21+
methodName = "executeCacheAndNetwork",
22+
extensionTargetClassName = "$apollo3.ApolloCall"
23+
).toMigrationItemUsageInfo()
24+
}
25+
26+
override fun performRefactoring(project: Project, migration: PsiMigration, usage: MigrationItemUsageInfo) {
27+
val element = usage.element
28+
val importDirective = element.parentOfType<KtImportDirective>()
29+
if (importDirective != null) {
30+
// Reference is an import
31+
return
32+
}
33+
element.parentOfType<KtDotQualifiedExpression>()?.selectorExpression?.replace(KtPsiFactory(project).createExpression("fetchPolicy(FetchPolicy.CacheAndNetwork).toFlow()"))
34+
}
35+
36+
override fun importsToAdd() = setOf("$apollo3.cache.normalized.fetchPolicy", "$apollo3.cache.normalized.FetchPolicy")
37+
}

intellij-plugin/src/test/kotlin/com/apollographql/ijplugin/ApolloV3ToV4MigrationTest.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ import org.junit.runners.JUnit4
1111
@RunWith(JUnit4::class)
1212
class ApolloV3ToV4MigrationTest : ApolloTestCase() {
1313
override val mavenLibraries = listOf(
14-
"com.apollographql.apollo3:apollo-api:3.8.2",
15-
"com.apollographql.apollo3:apollo-runtime:3.8.2",
14+
"com.apollographql.apollo3:apollo-annotations-jvm:3.8.2",
15+
"com.apollographql.apollo3:apollo-api-jvm:3.8.2",
16+
"com.apollographql.apollo3:apollo-mpp-utils-jvm:3.8.2",
17+
"com.apollographql.apollo3:apollo-runtime-jvm:3.8.2",
18+
"com.apollographql.apollo3:apollo-normalized-cache-jvm:3.8.2",
1619
)
1720

1821
override fun getTestDataPath() = "src/test/testData/migration/v3-to-v4"
@@ -26,6 +29,9 @@ class ApolloV3ToV4MigrationTest : ApolloTestCase() {
2629
@Test
2730
fun testUpdateGradleDependenciesInLibsVersionsToml() = runMigration(extension = "versions.toml", fileNameInProject = "libs.versions.toml")
2831

32+
@Test
33+
fun deprecations() = runMigration()
34+
2935
private fun runMigration(extension: String = "kt", fileNameInProject: String? = null) {
3036
val fileBaseName = getTestName(true)
3137
if (fileNameInProject != null) {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.example.myapplication
2+
3+
import com.apollographql.apollo3.ApolloClient
4+
import com.apollographql.apollo3.api.ApolloResponse
5+
import com.apollographql.apollo3.api.Query
6+
import com.apollographql.apollo3.cache.normalized.emitCacheMisses
7+
import com.apollographql.apollo3.cache.normalized.executeCacheAndNetwork
8+
import com.apollographql.apollo3.cache.normalized.watch
9+
import com.apollographql.apollo3.exception.ApolloCompositeException
10+
11+
suspend fun test() {
12+
val response: ApolloResponse<*>? = null
13+
println(response?.dataAssertNoErrors)
14+
15+
val apolloClient: ApolloClient? = null
16+
val query: Query<*>? = null
17+
18+
apolloClient!!.query(query!!).emitCacheMisses(true).toFlow()
19+
20+
apolloClient!!.query(query!!).watch(true, false)
21+
apolloClient!!.query(query!!).watch(true)
22+
apolloClient!!.query(query!!).watch(fetchThrows = true, refetchThrows = false)
23+
apolloClient!!.query(query!!).watch(fetchThrows = true)
24+
apolloClient!!.query(query!!).watch()
25+
26+
val compositeException: ApolloCompositeException? = null
27+
println(compositeException!!.first)
28+
println(compositeException!!.second)
29+
30+
apolloClient!!.query(query!!).executeCacheAndNetwork()
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.example.myapplication
2+
3+
import com.apollographql.apollo3.ApolloClient
4+
import com.apollographql.apollo3.api.ApolloResponse
5+
import com.apollographql.apollo3.api.Query
6+
import com.apollographql.apollo3.cache.normalized.watch
7+
import com.apollographql.apollo3.exception.ApolloException
8+
import com.apollographql.apollo3.cache.normalized.fetchPolicy
9+
import com.apollographql.apollo3.cache.normalized.FetchPolicy
10+
11+
suspend fun test() {
12+
val response: ApolloResponse<*>? = null
13+
println(response?.dataOrThrow())
14+
15+
val apolloClient: ApolloClient? = null
16+
val query: Query<*>? = null
17+
18+
apolloClient!!.query(query!!).toFlow()
19+
20+
apolloClient!!.query(query!!).watch()
21+
apolloClient!!.query(query!!).watch()
22+
apolloClient!!.query(query!!).watch()
23+
apolloClient!!.query(query!!).watch()
24+
apolloClient!!.query(query!!).watch()
25+
26+
val compositeException: ApolloException? = null
27+
println(compositeException!!.suppressedExceptions.first())
28+
println(compositeException!!.suppressedExceptions.getOrNull(1))
29+
30+
apolloClient!!.query(query!!).fetchPolicy(FetchPolicy.CacheAndNetwork).toFlow()
31+
}

0 commit comments

Comments
 (0)