@@ -22,13 +22,18 @@ package com.demonwav.mcdev.platform.mcp.at.inspections
2222
2323import com.demonwav.mcdev.platform.mcp.at.AtFileType
2424import com.demonwav.mcdev.platform.mcp.at.gen.psi.AtEntry
25+ import com.demonwav.mcdev.platform.mcp.at.gen.psi.AtVisitor
2526import com.demonwav.mcdev.util.excludeFileTypes
2627import com.intellij.codeInspection.LocalInspectionTool
28+ import com.intellij.codeInspection.LocalQuickFix
2729import com.intellij.codeInspection.ProblemsHolder
30+ import com.intellij.openapi.fileTypes.FileType
2831import com.intellij.psi.PsiClass
2932import com.intellij.psi.PsiElement
3033import com.intellij.psi.PsiElementVisitor
34+ import com.intellij.psi.PsiFile
3135import com.intellij.psi.PsiMethod
36+ import com.intellij.psi.PsiReference
3237import com.intellij.psi.search.GlobalSearchScope
3338import com.intellij.psi.search.searches.OverridingMethodsSearch
3439import com.intellij.psi.search.searches.ReferencesSearch
@@ -40,81 +45,90 @@ class AtUsageInspection : LocalInspectionTool() {
4045 }
4146
4247 override fun buildVisitor (holder : ProblemsHolder , isOnTheFly : Boolean ): PsiElementVisitor {
43- return object : PsiElementVisitor () {
44- override fun visitElement (element : PsiElement ) {
45- if (element !is AtEntry ) {
46- return
47- }
48+ return object : AtVisitor () {
49+
50+ private val fixProvider = { it: AtEntry -> RemoveAtEntryFix .forWholeLine(it, true ) }
4851
49- val function = element.function
52+ override fun visitEntry (entry : AtEntry ) {
53+ val function = entry.function
5054 if (function != null ) {
51- checkElement(element, function)
55+ checkElement(entry, function, holder, AtFileType , fixProvider) { file, toSkip ->
56+ file.children.asSequence()
57+ .filterIsInstance<AtEntry >()
58+ .filter { it != toSkip }
59+ .mapNotNull { it.function?.reference }
60+ }
5261 return
5362 }
5463
55- val fieldName = element .fieldName
64+ val fieldName = entry .fieldName
5665 if (fieldName != null ) {
57- checkElement(element , fieldName)
66+ checkElement(entry , fieldName, holder, AtFileType , fixProvider )
5867 return
5968 }
6069
6170 // Only check class names if it is the target of the entry
62- checkElement(element, element.className)
71+ checkElement(entry, entry.className, holder, AtFileType , fixProvider)
72+ }
73+ }
74+ }
75+
76+ companion object {
77+
78+ @JvmStatic
79+ fun <E : PsiElement > checkElement (
80+ entry : E ,
81+ element : PsiElement ,
82+ holder : ProblemsHolder ,
83+ fileType : FileType ,
84+ fixProvider : (entry: E ) -> LocalQuickFix ,
85+ entriesReferenceProvider : (PsiFile , toSkip: E ) -> Sequence <PsiReference > = { _, _ -> emptySequence() }
86+ ) {
87+ val referenced = element.reference?.resolve() ? : return
88+ val scope = GlobalSearchScope .projectScope(element.project)
89+ .excludeFileTypes(element.project, fileType)
90+ val query = ReferencesSearch .search(referenced, scope, true )
91+ if (query.any()) {
92+ return
6393 }
6494
65- private fun checkElement (entry : AtEntry , element : PsiElement ) {
66- val referenced = element.reference?.resolve() ? : return
67- val scope = GlobalSearchScope .projectScope(element.project)
68- .excludeFileTypes(element.project, AtFileType )
69- val query = ReferencesSearch .search(referenced, scope, true )
70- if (query.any()) {
95+ if (referenced is PsiMethod ) {
96+ // The regular references search doesn't cover overridden methods
97+ val overridingQuery = OverridingMethodsSearch .search(referenced, scope, true )
98+ if (overridingQuery.any()) {
7199 return
72100 }
73101
74- if (referenced is PsiMethod ) {
75- // The regular references search doesn't cover overridden methods
76- val overridingQuery = OverridingMethodsSearch .search(referenced, scope, true )
77- if (overridingQuery.any()) {
102+ // Also ignore if other entries cover super methods
103+ val superMethods = referenced.findSuperMethods()
104+ for (reference in entriesReferenceProvider(entry.containingFile, entry)) {
105+ val otherResolved = reference.resolve()
106+ if (superMethods.contains(otherResolved)) {
78107 return
79108 }
80-
81- // Also ignore if other entries cover super methods
82- val superMethods = referenced.findSuperMethods()
83- for (childEntry in entry.containingFile.children) {
84- if (childEntry !is AtEntry || childEntry == entry) {
85- continue
86- }
87-
88- val function = childEntry.function ? : continue
89- val otherResolved = function.reference?.resolve()
90- if (superMethods.contains(otherResolved)) {
91- return
92- }
93- }
94109 }
110+ }
95111
96- if (referenced is PsiClass ) {
97- // Do not report classes whose members are used in the mod
98- for (field in referenced.fields) {
99- if (ReferencesSearch .search(field, scope, true ).any()) {
100- return
101- }
112+ if (referenced is PsiClass ) {
113+ // Do not report classes whose members are used in the mod
114+ for (field in referenced.fields) {
115+ if (ReferencesSearch .search(field, scope, true ).any()) {
116+ return
102117 }
103- for (method in referenced.methods) {
104- if ( ReferencesSearch .search( method, scope, true ).any() ) {
105- return
106- }
118+ }
119+ for ( method in referenced.methods ) {
120+ if ( ReferencesSearch .search(method, scope, true ).any()) {
121+ return
107122 }
108- for (innerClass in referenced.innerClasses) {
109- if ( ReferencesSearch .search( innerClass, scope, true ).any() ) {
110- return
111- }
123+ }
124+ for ( innerClass in referenced.innerClasses ) {
125+ if ( ReferencesSearch .search(innerClass, scope, true ).any()) {
126+ return
112127 }
113128 }
114-
115- val fix = RemoveAtEntryFix .forWholeLine(entry, true )
116- holder.registerProblem(entry, " Access Transformer entry is never used" , fix)
117129 }
130+
131+ holder.registerProblem(entry, " Entry is never used" , fixProvider(entry))
118132 }
119133 }
120134}
0 commit comments