-
Notifications
You must be signed in to change notification settings - Fork 651
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[IJ/AS Plugin] Add unused operation and unused field inspections (#5069)
- Loading branch information
Showing
26 changed files
with
515 additions
and
55 deletions.
There are no files selected for viewing
72 changes: 72 additions & 0 deletions
72
...ugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloUnusedFieldInspection.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package com.apollographql.ijplugin.inspection | ||
|
||
import com.apollographql.ijplugin.ApolloBundle | ||
import com.apollographql.ijplugin.navigation.compat.KotlinFindUsagesHandlerFactoryCompat | ||
import com.apollographql.ijplugin.navigation.findKotlinFieldDefinitions | ||
import com.apollographql.ijplugin.navigation.findKotlinFragmentSpreadDefinitions | ||
import com.apollographql.ijplugin.navigation.findKotlinInlineFragmentDefinitions | ||
import com.apollographql.ijplugin.project.apolloProjectService | ||
import com.apollographql.ijplugin.util.isProcessCanceled | ||
import com.intellij.codeInspection.LocalInspectionTool | ||
import com.intellij.codeInspection.ProblemsHolder | ||
import com.intellij.lang.jsgraphql.psi.GraphQLField | ||
import com.intellij.lang.jsgraphql.psi.GraphQLFragmentSpread | ||
import com.intellij.lang.jsgraphql.psi.GraphQLIdentifier | ||
import com.intellij.lang.jsgraphql.psi.GraphQLInlineFragment | ||
import com.intellij.lang.jsgraphql.psi.GraphQLSelection | ||
import com.intellij.lang.jsgraphql.psi.GraphQLTypeName | ||
import com.intellij.lang.jsgraphql.psi.GraphQLTypedOperationDefinition | ||
import com.intellij.lang.jsgraphql.psi.GraphQLVisitor | ||
import com.intellij.psi.PsiElementVisitor | ||
import com.intellij.psi.util.findParentOfType | ||
|
||
class ApolloUnusedFieldInspection : LocalInspectionTool() { | ||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { | ||
var isUnusedOperation = false | ||
return object : GraphQLVisitor() { | ||
override fun visitIdentifier(o: GraphQLIdentifier) { | ||
if (isProcessCanceled()) return | ||
if (!o.project.apolloProjectService.apolloVersion.isAtLeastV3) return | ||
if (isUnusedOperation) return | ||
val operation = o.findParentOfType<GraphQLTypedOperationDefinition>() | ||
if (operation != null && ApolloUnusedOperationInspection.isUnusedOperation(operation)) { | ||
// The whole operation is unused, no need to check the fields | ||
isUnusedOperation = true | ||
return | ||
} | ||
|
||
var isFragment = false | ||
val ktDefinitions = when (val parent = o.parent) { | ||
is GraphQLField -> findKotlinFieldDefinitions(parent) | ||
is GraphQLFragmentSpread -> { | ||
isFragment = true | ||
findKotlinFragmentSpreadDefinitions(parent) | ||
} | ||
is GraphQLTypeName -> { | ||
val inlineFragment = parent.parent?.parent as? GraphQLInlineFragment ?: return | ||
isFragment = true | ||
findKotlinInlineFragmentDefinitions(inlineFragment) | ||
} | ||
else -> return | ||
}.ifEmpty { return } | ||
|
||
val kotlinFindUsagesHandlerFactory = KotlinFindUsagesHandlerFactoryCompat(o.project) | ||
val hasUsageProcessor = HasUsageProcessor() | ||
for (kotlinDefinition in ktDefinitions) { | ||
if (kotlinFindUsagesHandlerFactory.canFindUsages(kotlinDefinition)) { | ||
val kotlinFindUsagesHandler = kotlinFindUsagesHandlerFactory.createFindUsagesHandler(kotlinDefinition, false) | ||
?: return | ||
val findUsageOptions = kotlinFindUsagesHandlerFactory.findPropertyOptions ?: return | ||
kotlinFindUsagesHandler.processElementUsages(kotlinDefinition, hasUsageProcessor, findUsageOptions) | ||
if (hasUsageProcessor.foundUsage) return | ||
} | ||
} | ||
holder.registerProblem( | ||
if (isFragment) o.findParentOfType<GraphQLSelection>()!! else o, | ||
ApolloBundle.message("inspection.unusedField.reportText"), | ||
DeleteElementQuickFix("inspection.unusedField.quickFix") { it.findParentOfType<GraphQLSelection>(strict = false)!! }, | ||
) | ||
} | ||
} | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
.../src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloUnusedOperationInspection.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package com.apollographql.ijplugin.inspection | ||
|
||
import com.apollographql.ijplugin.ApolloBundle | ||
import com.apollographql.ijplugin.navigation.compat.KotlinFindUsagesHandlerFactoryCompat | ||
import com.apollographql.ijplugin.navigation.findKotlinOperationDefinitions | ||
import com.apollographql.ijplugin.project.apolloProjectService | ||
import com.apollographql.ijplugin.util.isProcessCanceled | ||
import com.intellij.codeInspection.LocalInspectionTool | ||
import com.intellij.codeInspection.ProblemsHolder | ||
import com.intellij.lang.jsgraphql.psi.GraphQLTypedOperationDefinition | ||
import com.intellij.lang.jsgraphql.psi.GraphQLVisitor | ||
import com.intellij.psi.PsiElementVisitor | ||
|
||
class ApolloUnusedOperationInspection : LocalInspectionTool() { | ||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { | ||
return object : GraphQLVisitor() { | ||
override fun visitTypedOperationDefinition(o: GraphQLTypedOperationDefinition) { | ||
if (isUnusedOperation(o)) { | ||
holder.registerProblem( | ||
o, | ||
ApolloBundle.message("inspection.unusedOperation.reportText"), | ||
DeleteElementQuickFix("inspection.unusedOperation.quickFix") { it } | ||
) | ||
} | ||
} | ||
} | ||
} | ||
|
||
companion object { | ||
fun isUnusedOperation(operationDefinition: GraphQLTypedOperationDefinition): Boolean { | ||
if (isProcessCanceled()) return false | ||
if (!operationDefinition.project.apolloProjectService.apolloVersion.isAtLeastV3) return false | ||
val ktClasses = findKotlinOperationDefinitions(operationDefinition).ifEmpty { | ||
// Didn't find any generated class: maybe in the middle of writing a new operation, let's not report an error yet. | ||
return false | ||
} | ||
val kotlinFindUsagesHandlerFactory = KotlinFindUsagesHandlerFactoryCompat(operationDefinition.project) | ||
val hasUsageProcessor = HasUsageProcessor() | ||
for (kotlinDefinition in ktClasses) { | ||
if (kotlinFindUsagesHandlerFactory.canFindUsages(kotlinDefinition)) { | ||
val kotlinFindUsagesHandler = kotlinFindUsagesHandlerFactory.createFindUsagesHandler(kotlinDefinition, false) | ||
?: return false | ||
val findUsageOptions = kotlinFindUsagesHandlerFactory.findClassOptions ?: return false | ||
kotlinFindUsagesHandler.processElementUsages(kotlinDefinition, hasUsageProcessor, findUsageOptions) | ||
if (hasUsageProcessor.foundUsage) return false | ||
} | ||
} | ||
return true | ||
} | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
...lij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/DeleteElementQuickFix.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.apollographql.ijplugin.inspection | ||
|
||
import com.apollographql.ijplugin.ApolloBundle | ||
import com.intellij.codeInsight.intention.FileModifier.SafeFieldForPreview | ||
import com.intellij.codeInspection.LocalQuickFix | ||
import com.intellij.codeInspection.ProblemDescriptor | ||
import com.intellij.openapi.project.Project | ||
import com.intellij.psi.PsiElement | ||
|
||
class DeleteElementQuickFix( | ||
private val label: String, | ||
|
||
@SafeFieldForPreview | ||
private val elementToDelete: (PsiElement) -> PsiElement, | ||
) : LocalQuickFix { | ||
override fun getName() = ApolloBundle.message(label) | ||
|
||
override fun getFamilyName() = name | ||
|
||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { | ||
elementToDelete(descriptor.psiElement).delete() | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/HasUsageProcessor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.apollographql.ijplugin.inspection | ||
|
||
import com.apollographql.ijplugin.util.isGenerated | ||
import com.intellij.usageView.UsageInfo | ||
import com.intellij.util.Processor | ||
|
||
class HasUsageProcessor : Processor<UsageInfo> { | ||
var foundUsage = false | ||
private set | ||
|
||
override fun process(usageInfo: UsageInfo): Boolean { | ||
if (usageInfo.virtualFile?.isGenerated(usageInfo.project) == false) { | ||
foundUsage = true | ||
return false | ||
} | ||
return true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/util/Threading.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,20 @@ | ||
package com.apollographql.ijplugin.util | ||
|
||
import com.intellij.openapi.application.ApplicationManager | ||
import com.intellij.openapi.progress.ProcessCanceledException | ||
import com.intellij.openapi.progress.ProgressManager | ||
|
||
fun runWriteActionInEdt(action: () -> Unit) { | ||
ApplicationManager.getApplication().invokeLater { | ||
ApplicationManager.getApplication().runWriteAction<Unit>(action) | ||
} | ||
} | ||
|
||
fun isProcessCanceled(): Boolean { | ||
try { | ||
ProgressManager.checkCanceled() | ||
} catch (e: ProcessCanceledException) { | ||
return true | ||
} | ||
return false | ||
} |
Oops, something went wrong.