Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AT Overhaul #2365

Open
wants to merge 20 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@

- `plugin.yml`, `paper-plugin.yml` and `bungee.yml` main class reference and validity inspection

### Changed

- Overhauled Access Transformer support:
- many lexing errors should now be fixed
- class names and member names now have their own references, replacing the custom Goto handler
- SRG names are no longer used on NeoForge 1.20.2+ and a new copy action is available for it
- the usage inspection no longer incorrectly reports methods overridden in your code or entries covering super methods
- suppressing inspections is now possible by adding `# Suppress:AtInspectionName` after an entry or at the start of the file, or using the built-in suppress action
- added an inspection to report unresolved references, to help find out old, superfluous entries
- added an inspection to report duplicate entries in the same file
- added formatting support, class and member names are configured to align by default

## [1.8.1] - 2024-08-10

### Added
Expand Down
12 changes: 8 additions & 4 deletions src/main/grammars/AtLexer.flex
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,20 @@ import static com.intellij.psi.TokenType.*;
PRIMITIVE=[ZBCSIFDJV]
CLASS_VALUE=(\[+[ZBCSIFDJ]|(\[*L[^;\n]+;))
KEYWORD_ELEMENT=(public|private|protected|default)([-+]f)?
NAME_ELEMENT=([\p{L}_\p{Sc}][\p{L}\p{N}_\p{Sc}]*)|<init>
CLASS_NAME_ELEMENT=([\p{L}_\p{Sc}][\p{L}\p{N}_\p{Sc}]*\.)*[\p{L}_\p{Sc}][\p{L}\p{N}_\p{Sc}]*
IDENTIFIER=[\p{L}_\p{Sc}][\p{L}\p{N}_\p{Sc}]*
NAME_ELEMENT=({IDENTIFIER})|<init>
CLASS_NAME_ELEMENT=({IDENTIFIER}*\.)*{IDENTIFIER}
COMMENT=#.*
CRLF=\n|\r|\r\n
WHITE_SPACE=\s

%%

<YYINITIAL> {
{KEYWORD_ELEMENT} { yybegin(CLASS_NAME); return KEYWORD_ELEMENT; }
// Force a whitespace because otherwise the keyword and class name can be right next to each other
{KEYWORD_ELEMENT}/{WHITE_SPACE} { yybegin(CLASS_NAME); return KEYWORD_ELEMENT; }
// Fallback to avoid breaking code highlighting at the keyword
{NAME_ELEMENT} { return NAME_ELEMENT; }
}

<CLASS_NAME> {
Expand All @@ -73,7 +77,7 @@ WHITE_SPACE=\s
"(" { return OPEN_PAREN; }
")" { return CLOSE_PAREN; }
{CLASS_VALUE} { return CLASS_VALUE; }
{PRIMITIVE} ({PRIMITIVE}|{CLASS_VALUE})* { zzMarkedPos = zzStartRead + 1; return PRIMITIVE; }
{PRIMITIVE} { return PRIMITIVE; }
}

{CRLF} { yybegin(YYINITIAL); return CRLF; }
Expand Down
4 changes: 3 additions & 1 deletion src/main/grammars/AtParser.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
elementTypeClass="com.demonwav.mcdev.platform.mcp.at.psi.AtElementType"
tokenTypeClass="com.demonwav.mcdev.platform.mcp.at.psi.AtTokenType"

consumeTokenMethod="consumeTokenFast"
consumeTokenMethod(".*_recover")="consumeTokenFast"
}

at_file ::= line*
Expand Down Expand Up @@ -60,7 +60,9 @@ keyword ::= KEYWORD_ELEMENT {
methods=[
keywordElement="KEYWORD_ELEMENT"
]
recoverWhile=keyword_recover
}
private keyword_recover ::= !(NAME_ELEMENT | CLASS_NAME_ELEMENT)

class_name ::= CLASS_NAME_ELEMENT {
mixin="com.demonwav.mcdev.platform.mcp.at.psi.mixins.impl.AtClassNameImplMixin"
Expand Down
98 changes: 98 additions & 0 deletions src/main/kotlin/platform/mcp/actions/CopyNeoForgeAtAction.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Minecraft Development for IntelliJ
*
* https://mcdev.io/
*
* Copyright (C) 2024 minecraft-dev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, version 3.0 only.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.demonwav.mcdev.platform.mcp.actions

import com.demonwav.mcdev.platform.mcp.actions.SrgActionBase.Companion.showBalloon
import com.demonwav.mcdev.platform.mcp.actions.SrgActionBase.Companion.showSuccessBalloon
import com.demonwav.mcdev.platform.mcp.at.usesSrgMemberNames
import com.demonwav.mcdev.platform.mixin.handlers.ShadowHandler
import com.demonwav.mcdev.util.descriptor
import com.demonwav.mcdev.util.getDataFromActionEvent
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiField
import com.intellij.psi.PsiMember
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiReference
import java.awt.Toolkit
import java.awt.datatransfer.StringSelection

class CopyNeoForgeAtAction : AnAction() {

override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT

override fun update(e: AnActionEvent) {
e.presentation.isEnabledAndVisible = isAvailable(e)
}

private fun isAvailable(e: AnActionEvent): Boolean {
val data = getDataFromActionEvent(e) ?: return false
return !data.instance.usesSrgMemberNames()
}

override fun actionPerformed(e: AnActionEvent) {
val data = getDataFromActionEvent(e) ?: return

var parent = data.element.parent
if (parent is PsiMember) {
val shadowTarget = ShadowHandler.getInstance()?.findFirstShadowTargetForReference(parent)?.element
if (shadowTarget != null) {
parent = shadowTarget
}
}

if (parent is PsiReference) {
parent = parent.resolve() ?: return showBalloon("Not a valid element", e)
}

when (parent) {
is PsiClass -> {
val fqn = parent.qualifiedName ?: return showBalloon("Could not find class FQN", e)
copyToClipboard(data.editor, data.element, fqn)
}
is PsiField -> {
val classFqn = parent.containingClass?.qualifiedName
?: return showBalloon("Could not find class FQN", e)
copyToClipboard(data.editor, data.element, "$classFqn ${parent.name}")
}
is PsiMethod -> {
val classFqn = parent.containingClass?.qualifiedName
?: return showBalloon("Could not find class FQN", e)
val methodDescriptor = parent.descriptor
?: return showBalloon("Could not compute method descriptor", e)
copyToClipboard(data.editor, data.element, "$classFqn ${parent.name}$methodDescriptor")
}
else -> showBalloon("Not a valid element", e)
}
return
}

private fun copyToClipboard(editor: Editor, element: PsiElement, text: String) {
val stringSelection = StringSelection(text)
val clpbrd = Toolkit.getDefaultToolkit().systemClipboard
clpbrd.setContents(stringSelection, null)
showSuccessBalloon(editor, element, "Copied $text")
}
}
34 changes: 34 additions & 0 deletions src/main/kotlin/platform/mcp/at/AtFile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,51 @@ package com.demonwav.mcdev.platform.mcp.at
import com.demonwav.mcdev.asset.PlatformAssets
import com.demonwav.mcdev.facet.MinecraftFacet
import com.demonwav.mcdev.platform.mcp.McpModuleType
import com.demonwav.mcdev.platform.mcp.at.gen.psi.AtEntry
import com.intellij.extapi.psi.PsiFileBase
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.psi.FileViewProvider
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement

class AtFile(viewProvider: FileViewProvider) : PsiFileBase(viewProvider, AtLanguage) {

init {
setup()
}

val headComments: List<PsiComment>
get() {
val comments = mutableListOf<PsiComment>()
for (child in children) {
if (child is AtEntry) {
break
}

if (child is PsiComment) {
comments.add(child)
}
}

return comments
}

fun addHeadComment(text: String) {
val toAdd = text.lines().flatMap { listOf(AtElementFactory.createComment(project, it)) }
val lastHeadComment = headComments.lastOrNull()
if (lastHeadComment == null) {
for (comment in toAdd.reversed()) {
addAfter(comment, null)
}
} else {
var previousComment: PsiElement? = lastHeadComment
for (comment in toAdd) {
previousComment = addAfter(comment, previousComment)
}
}
}

private fun setup() {
if (ApplicationManager.getApplication().isUnitTestMode) {
return
Expand Down
110 changes: 0 additions & 110 deletions src/main/kotlin/platform/mcp/at/AtGotoDeclarationHandler.kt

This file was deleted.

16 changes: 8 additions & 8 deletions src/main/kotlin/platform/mcp/at/AtParserDefinition.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,22 @@ class AtParserDefinition : ParserDefinition {
override fun createElement(node: ASTNode): PsiElement = AtTypes.Factory.createElement(node)

override fun spaceExistenceTypeBetweenTokens(left: ASTNode, right: ASTNode) =
map.entries.firstOrNull { e -> left.elementType == e.key.first || right.elementType == e.key.second }?.value
?: ParserDefinition.SpaceRequirements.MUST_NOT
map[left.elementType to right.elementType] ?: ParserDefinition.SpaceRequirements.MUST_NOT

companion object {
private val COMMENTS = TokenSet.create(AtTypes.COMMENT)

private val FILE = IFileElementType(Language.findInstance(AtLanguage::class.java))

private val map: Map<Pair<IElementType, IElementType>, ParserDefinition.SpaceRequirements> = mapOf(
(AtTypes.KEYWORD to AtTypes.CLASS_NAME) to ParserDefinition.SpaceRequirements.MUST,
(AtTypes.CLASS_NAME to AtTypes.FIELD_NAME) to ParserDefinition.SpaceRequirements.MUST,
(AtTypes.CLASS_NAME to AtTypes.FUNCTION) to ParserDefinition.SpaceRequirements.MUST,
(AtTypes.CLASS_NAME to AtTypes.ASTERISK) to ParserDefinition.SpaceRequirements.MUST,
(AtTypes.KEYWORD_ELEMENT to AtTypes.CLASS_NAME_ELEMENT) to ParserDefinition.SpaceRequirements.MUST,
(AtTypes.CLASS_NAME_ELEMENT to AtTypes.FIELD_NAME) to ParserDefinition.SpaceRequirements.MUST,
(AtTypes.CLASS_NAME_ELEMENT to AtTypes.FUNCTION) to ParserDefinition.SpaceRequirements.MUST,
(AtTypes.CLASS_NAME_ELEMENT to AtTypes.ASTERISK_ELEMENT) to ParserDefinition.SpaceRequirements.MUST,
(AtTypes.CLASS_NAME_ELEMENT to AtTypes.COMMENT) to ParserDefinition.SpaceRequirements.MUST,
(AtTypes.FIELD_NAME to AtTypes.COMMENT) to ParserDefinition.SpaceRequirements.MUST,
(AtTypes.ASTERISK to AtTypes.COMMENT) to ParserDefinition.SpaceRequirements.MUST,
(AtTypes.COMMENT to AtTypes.KEYWORD) to ParserDefinition.SpaceRequirements.MUST_LINE_BREAK,
(AtTypes.ASTERISK_ELEMENT to AtTypes.COMMENT) to ParserDefinition.SpaceRequirements.MUST,
(AtTypes.COMMENT to AtTypes.KEYWORD_ELEMENT) to ParserDefinition.SpaceRequirements.MUST_LINE_BREAK,
(AtTypes.COMMENT to AtTypes.COMMENT) to ParserDefinition.SpaceRequirements.MUST_LINE_BREAK,
(AtTypes.FUNCTION to AtTypes.COMMENT) to ParserDefinition.SpaceRequirements.MUST,
)
Expand Down
Loading
Loading