Skip to content

Commit 85d2569

Browse files
committed
Enhance AW support too
Pretty much identical to what was done to AT support
1 parent 367aa7a commit 85d2569

37 files changed

+1507
-167
lines changed

changelog.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
### Changed
5353

54-
- Overhauled Access Transformer support:
54+
- Overhauled Access Transformer and Access Widener support:
5555
- many lexing errors should now be fixed
5656
- class names and member names now have their own references, replacing the custom Goto handler
5757
- SRG names are no longer used on NeoForge 1.20.2+ and a new copy action is available for it

src/main/grammars/AwLexer.flex

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,23 @@ CLASS_ELEMENT=class
5656
METHOD_ELEMENT=method
5757
FIELD_ELEMENT=field
5858
NAME_ELEMENT=\w+|<init>
59-
CLASS_NAME_ELEMENT=(\w+\/)*\w+(\$\w+)*
59+
CLASS_NAME_ELEMENT=[\w/$]+
6060
COMMENT=#.*
6161
CRLF=\n|\r|\r\n
6262
WHITE_SPACE=\s
6363

6464
%%
6565

66+
{COMMENT} { return COMMENT; }
67+
6668
<YYINITIAL> {
6769
{HEADER_NAME} { yybegin(HEADER); return HEADER_NAME; }
6870
{ACCESS_ELEMENT} { return ACCESS_ELEMENT; }
6971
{CLASS_ELEMENT} { yybegin(CLASS_NAME); return CLASS_ELEMENT; }
7072
{METHOD_ELEMENT} { yybegin(CLASS_NAME); return METHOD_ELEMENT; }
7173
{FIELD_ELEMENT} { yybegin(CLASS_NAME); return FIELD_ELEMENT; }
74+
// Fallback to avoid breaking code highlighting at the access or target kind while editing
75+
\S+ { return NAME_ELEMENT; }
7276
}
7377

7478
<HEADER> {
@@ -94,5 +98,4 @@ WHITE_SPACE=\s
9498
{CRLF} { yybegin(YYINITIAL); return CRLF; }
9599
{WHITE_SPACE} { return WHITE_SPACE; }
96100

97-
{COMMENT} { return COMMENT; }
98101
[^] { return BAD_CHARACTER; }

src/main/grammars/AwParser.bnf

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,56 +32,52 @@
3232
elementTypeClass="com.demonwav.mcdev.platform.mcp.aw.psi.AwElementType"
3333
tokenTypeClass="com.demonwav.mcdev.platform.mcp.aw.psi.AwTokenType"
3434

35-
consumeTokenMethod="consumeTokenFast"
35+
consumeTokenMethod(".*_recover")="consumeTokenFast"
3636
}
3737

38-
aw_file ::= header_line line*
38+
aw_file ::= header_line? line*
3939

4040
private header_line ::= !<<eof>> header COMMENT? end_line
4141

42-
private line ::= !<<eof>> entry? COMMENT? end_line
43-
private end_line ::= crlf | <<eof>>
42+
private line ::= !<<eof>> line_content end_line
43+
private line_recover ::= !(end_line | COMMENT)
44+
private end_line ::= CRLF | <<eof>>
45+
46+
private line_content ::= entry? COMMENT? {
47+
recoverWhile=line_recover
48+
}
4449

4550
header ::= HEADER_NAME HEADER_VERSION_ELEMENT HEADER_NAMESPACE_ELEMENT {
4651
mixin="com.demonwav.mcdev.platform.mcp.aw.psi.mixins.impl.AwHeaderImplMixin"
4752
implements="com.demonwav.mcdev.platform.mcp.aw.psi.mixins.AwHeaderMixin"
4853
}
4954

50-
private entry ::= class_entry | method_entry | field_entry {
55+
entry ::= class_entry | method_entry | field_entry {
5156
mixin="com.demonwav.mcdev.platform.mcp.aw.psi.mixins.impl.AwEntryImplMixin"
5257
implements="com.demonwav.mcdev.platform.mcp.aw.psi.mixins.AwEntryMixin"
53-
recoverWhile = line_recover
5458
}
5559

56-
class_entry ::= access class_literal class_name {
60+
class_entry ::= ACCESS_ELEMENT CLASS_ELEMENT class_name {
61+
extends=entry
5762
mixin="com.demonwav.mcdev.platform.mcp.aw.psi.mixins.impl.AwClassEntryImplMixin"
5863
implements="com.demonwav.mcdev.platform.mcp.aw.psi.mixins.AwClassEntryMixin"
64+
pin=2
5965
}
6066

61-
method_entry ::= access method_literal class_name member_name method_desc{
67+
method_entry ::= ACCESS_ELEMENT METHOD_ELEMENT class_name member_name method_desc {
68+
extends=entry
6269
mixin="com.demonwav.mcdev.platform.mcp.aw.psi.mixins.impl.AwMethodEntryImplMixin"
6370
implements="com.demonwav.mcdev.platform.mcp.aw.psi.mixins.AwMethodEntryMixin"
71+
pin=2
6472
}
6573

66-
field_entry ::= access field_literal class_name member_name field_desc{
74+
field_entry ::= ACCESS_ELEMENT FIELD_ELEMENT class_name member_name field_desc {
75+
extends=entry
6776
mixin="com.demonwav.mcdev.platform.mcp.aw.psi.mixins.impl.AwFieldEntryImplMixin"
6877
implements="com.demonwav.mcdev.platform.mcp.aw.psi.mixins.AwFieldEntryMixin"
78+
pin=2
6979
}
7080

71-
private line_recover ::= !(end_line | COMMENT)
72-
73-
access ::= ACCESS_ELEMENT {
74-
methods=[
75-
accessElement="ACCESS_ELEMENT"
76-
]
77-
}
78-
79-
class_literal ::= CLASS_ELEMENT
80-
81-
method_literal ::= METHOD_ELEMENT
82-
83-
field_literal ::= FIELD_ELEMENT
84-
8581
class_name ::= CLASS_NAME_ELEMENT {
8682
mixin="com.demonwav.mcdev.platform.mcp.aw.psi.mixins.impl.AwClassNameImplMixin"
8783
implements="com.demonwav.mcdev.platform.mcp.aw.psi.mixins.AwClassNameMixin"
@@ -98,7 +94,9 @@ member_name ::= NAME_ELEMENT {
9894
]
9995
}
10096

101-
method_desc ::= OPEN_PAREN desc_element* CLOSE_PAREN desc_element
97+
method_desc ::= OPEN_PAREN desc_element* CLOSE_PAREN desc_element {
98+
pin=1
99+
}
102100

103101
field_desc ::= desc_element
104102

@@ -109,4 +107,4 @@ desc_element ::= PRIMITIVE | CLASS_VALUE {
109107
primitive="PRIMITIVE"
110108
classValue="CLASS_VALUE"
111109
]
112-
}
110+
}

src/main/kotlin/platform/fabric/reference/FabricModJsonResolveScopeEnlarger.kt

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,46 @@
2121
package com.demonwav.mcdev.platform.fabric.reference
2222

2323
import com.demonwav.mcdev.platform.fabric.util.FabricConstants
24+
import com.demonwav.mcdev.platform.mcp.aw.AwFileType
25+
import com.demonwav.mcdev.platform.mcp.fabricloom.FabricLoomData
26+
import com.intellij.openapi.module.ModuleManager
2427
import com.intellij.openapi.module.ModuleUtilCore
2528
import com.intellij.openapi.project.Project
2629
import com.intellij.openapi.vfs.VirtualFile
2730
import com.intellij.psi.ResolveScopeEnlarger
2831
import com.intellij.psi.search.SearchScope
32+
import org.jetbrains.plugins.gradle.util.GradleUtil
2933

3034
class FabricModJsonResolveScopeEnlarger : ResolveScopeEnlarger() {
3135

3236
override fun getAdditionalResolveScope(file: VirtualFile, project: Project): SearchScope? {
33-
if (file.name != FabricConstants.FABRIC_MOD_JSON) {
34-
return null
37+
if (file.name == FabricConstants.FABRIC_MOD_JSON) {
38+
val module = ModuleUtilCore.findModuleForFile(file, project)
39+
?: return null
40+
return module.moduleWithDependentsScope.union(module.moduleTestsWithDependentsScope)
3541
}
3642

37-
val module = ModuleUtilCore.findModuleForFile(file, project)
38-
?: return null
39-
return module.moduleWithDependentsScope.union(module.moduleTestsWithDependentsScope)
43+
if (file.fileType is AwFileType) {
44+
var module = ModuleUtilCore.findModuleForFile(file, project)
45+
?: return null
46+
47+
val loomData = GradleUtil.findGradleModuleData(module)?.children
48+
?.find { it.key == FabricLoomData.KEY }?.data as? FabricLoomData
49+
?: return null
50+
51+
var moduleManager = ModuleManager.getInstance(project)
52+
var baseModuleName = module.name.substringBeforeLast('.')
53+
var scope = module.moduleWithLibrariesScope
54+
for ((_, sourceSets) in loomData.modSourceSets.orEmpty()) {
55+
for (name in sourceSets) {
56+
val otherModule = moduleManager.findModuleByName("$baseModuleName.$name") ?: continue
57+
scope = scope.union(otherModule.moduleWithLibrariesScope)
58+
}
59+
}
60+
61+
return scope
62+
}
63+
64+
return null
4065
}
4166
}

src/main/kotlin/platform/mcp/at/AtFile.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class AtFile(viewProvider: FileViewProvider) : PsiFileBase(viewProvider, AtLangu
5454
}
5555

5656
fun addHeadComment(text: String) {
57-
val toAdd = text.lines().flatMap { listOf(AtElementFactory.createComment(project, it)) }
57+
val toAdd = text.lines().map { AtElementFactory.createComment(project, it) }
5858
val lastHeadComment = headComments.lastOrNull()
5959
if (lastHeadComment == null) {
6060
for (comment in toAdd.reversed()) {

src/main/kotlin/platform/mcp/at/inspections/AtDuplicateEntryInspection.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ import com.intellij.psi.PsiElementVisitor
2929

3030
class AtDuplicateEntryInspection : LocalInspectionTool() {
3131

32-
override fun getStaticDescription(): String? = "Reports duplicate AT entries in the same file"
32+
override fun runForWholeFile(): Boolean = true
33+
34+
override fun getStaticDescription(): String = "Reports duplicate AT entries in the same file"
3335

3436
override fun buildVisitor(
3537
holder: ProblemsHolder,

src/main/kotlin/platform/mcp/at/inspections/AtUsageInspection.kt

Lines changed: 65 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,18 @@ package com.demonwav.mcdev.platform.mcp.at.inspections
2222

2323
import com.demonwav.mcdev.platform.mcp.at.AtFileType
2424
import com.demonwav.mcdev.platform.mcp.at.gen.psi.AtEntry
25+
import com.demonwav.mcdev.platform.mcp.at.gen.psi.AtVisitor
2526
import com.demonwav.mcdev.util.excludeFileTypes
2627
import com.intellij.codeInspection.LocalInspectionTool
28+
import com.intellij.codeInspection.LocalQuickFix
2729
import com.intellij.codeInspection.ProblemsHolder
30+
import com.intellij.openapi.fileTypes.FileType
2831
import com.intellij.psi.PsiClass
2932
import com.intellij.psi.PsiElement
3033
import com.intellij.psi.PsiElementVisitor
34+
import com.intellij.psi.PsiFile
3135
import com.intellij.psi.PsiMethod
36+
import com.intellij.psi.PsiReference
3237
import com.intellij.psi.search.GlobalSearchScope
3338
import com.intellij.psi.search.searches.OverridingMethodsSearch
3439
import 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

Comments
 (0)