[java-highlighting] IDEA-357214 'Module' is highlighted as an error when module name is expected

GitOrigin-RevId: c7ca9de1821e79b96a05ab74a3cbad7052ceb827
This commit is contained in:
Mikhail Pyltsin
2024-10-10 14:06:10 +02:00
committed by intellij-monorepo-bot
parent 59cadbb09a
commit 7e9f1978a2
8 changed files with 161 additions and 1 deletions

View File

@@ -3537,6 +3537,20 @@ public final class HighlightUtil {
return null;
}
//do not highlight module keyword if the statement is not complete
//see com.intellij.lang.java.parser.BasicFileParser.parseImportStatement
if (PsiKeyword.MODULE.equals(ref.getText()) && refParent instanceof PsiImportStatement &&
PsiUtil.isAvailable(JavaFeature.MODULE_IMPORT_DECLARATIONS, ref)) {
PsiElement importKeywordExpected = PsiTreeUtil.skipWhitespacesAndCommentsBackward(ref);
PsiElement errorElementExpected = PsiTreeUtil.skipWhitespacesAndCommentsForward(ref);
if (importKeywordExpected instanceof PsiKeyword keyword &&
keyword.textMatches(PsiKeyword.IMPORT) &&
errorElementExpected instanceof PsiErrorElement errorElement &&
JavaPsiBundle.message("expected.identifier.or.semicolon").equals(errorElement.getErrorDescription())) {
return null;
}
}
JavaResolveResult[] results = ref.multiResolve(true);
String description;
if (results.length > 1) {

View File

@@ -161,6 +161,7 @@ expected.rbracket=']' expected
expected.resource=Resource definition expected
expected.rparen=')' expected
expected.semicolon=';' expected
expected.identifier.or.semicolon=Identifier or ';' expected
expected.statement=Statement expected
expected.string=String literal expected
expected.switch.label='case', 'default' or '}' expected

View File

@@ -193,6 +193,7 @@ public class BasicFileParser {
PsiBuilder.Marker statement = builder.mark();
builder.advanceLexer();
String identifierText = builder.getTokenText();
IElementType type = getImportType(builder);
boolean isStatic = type == myJavaElementTypeContainer.IMPORT_STATIC_STATEMENT;
boolean isModule = type == myJavaElementTypeContainer.IMPORT_MODULE_STATEMENT;
@@ -202,7 +203,15 @@ public class BasicFileParser {
} else {
isOk = myParser.getReferenceParser().parseImportCodeReference(builder, isStatic);
}
if (isOk) semicolon(builder);
//if it is `module` it should expect or `;` or `identifier`
if (isOk && !isModule && !isStatic && builder.getTokenType() != JavaTokenType.SEMICOLON &&
PsiKeyword.MODULE.equals(identifierText)) {
BasicJavaParserUtil.error(builder, JavaPsiBundle.message("expected.identifier.or.semicolon"));
}
else if (isOk) {
semicolon(builder);
}
done(statement, type, myWhiteSpaceAndCommentSetHolder);
return statement;

View File

@@ -18,4 +18,5 @@ public abstract class AbstractBasicImportParsingTest extends AbstractBasicJavaPa
public void testModuleImport() { doTest(true); }
public void testImportWithModulePackage() { doTest(true); }
public void testImportWithModuleClass() { doTest(true); }
public void testImportModuleBrokenStatement() { doTest(true); }
}

View File

@@ -0,0 +1,7 @@
import module;
import module
import module
import module a;
public class Test {
}

View File

@@ -0,0 +1,57 @@
PsiJavaFile:ImportModuleBrokenStatement.java
PsiImportList
PsiImportStatement
PsiKeyword:import('import')
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:module
PsiIdentifier:module('module')
PsiReferenceParameterList
<empty list>
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace('\n')
PsiImportStatement
PsiKeyword:import('import')
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:module
PsiIdentifier:module('module')
PsiReferenceParameterList
<empty list>
PsiErrorElement:Identifier or ';' expected
<empty list>
PsiWhiteSpace('\n')
PsiImportStatement
PsiKeyword:import('import')
PsiWhiteSpace(' ')
PsiJavaCodeReferenceElement:module
PsiIdentifier:module('module')
PsiReferenceParameterList
<empty list>
PsiErrorElement:Identifier or ';' expected
<empty list>
PsiWhiteSpace('\n')
PsiImportModuleStatement
PsiKeyword:import('import')
PsiWhiteSpace(' ')
PsiKeyword:module('module')
PsiWhiteSpace(' ')
PsiJavaModuleReference
PsiIdentifier:a('a')
PsiJavaToken:SEMICOLON(';')
PsiWhiteSpace('\n\n')
PsiClass:Test
PsiModifierList:public
PsiKeyword:public('public')
PsiWhiteSpace(' ')
PsiKeyword:class('class')
PsiWhiteSpace(' ')
PsiIdentifier:Test('Test')
PsiTypeParameterList
<empty list>
PsiReferenceList
<empty list>
PsiReferenceList
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:LBRACE('{')
PsiWhiteSpace('\n')
PsiJavaToken:RBRACE('}')

View File

@@ -0,0 +1,57 @@
java.FILE
IMPORT_LIST
IMPORT_STATEMENT
IMPORT_KEYWORD
WHITE_SPACE
JAVA_CODE_REFERENCE
IDENTIFIER
REFERENCE_PARAMETER_LIST
<empty list>
SEMICOLON
WHITE_SPACE
IMPORT_STATEMENT
IMPORT_KEYWORD
WHITE_SPACE
JAVA_CODE_REFERENCE
IDENTIFIER
REFERENCE_PARAMETER_LIST
<empty list>
ERROR_ELEMENT
<empty list>
WHITE_SPACE
IMPORT_STATEMENT
IMPORT_KEYWORD
WHITE_SPACE
JAVA_CODE_REFERENCE
IDENTIFIER
REFERENCE_PARAMETER_LIST
<empty list>
ERROR_ELEMENT
<empty list>
WHITE_SPACE
IMPORT_MODULE_STATEMENT
IMPORT_KEYWORD
WHITE_SPACE
MODULE
WHITE_SPACE
MODULE_REFERENCE
IDENTIFIER
SEMICOLON
WHITE_SPACE
CLASS
MODIFIER_LIST
PUBLIC_KEYWORD
WHITE_SPACE
CLASS_KEYWORD
WHITE_SPACE
IDENTIFIER
TYPE_PARAMETER_LIST
<empty list>
EXTENDS_LIST
<empty list>
IMPLEMENTS_LIST
<empty list>
WHITE_SPACE
LBRACE
WHITE_SPACE
RBRACE

View File

@@ -27,6 +27,7 @@ import com.intellij.openapi.vfs.ex.temp.TempFileSystem
import com.intellij.platform.backend.workspace.WorkspaceModel
import com.intellij.platform.workspace.jps.entities.ModuleId
import com.intellij.platform.workspace.jps.entities.modifyModuleEntity
import com.intellij.pom.java.JavaFeature
import com.intellij.pom.java.LanguageLevel
import com.intellij.psi.JavaCompilerConfigurationProxy
import com.intellij.psi.PsiJavaModule
@@ -765,6 +766,19 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
""".trimIndent())
}
fun testBrokenImportModuleStatement() {
IdeaTestUtil.withLevel(module, JavaFeature.MODULE_IMPORT_DECLARATIONS.minimumLevel){
highlight("A.java", """
package a;
import module<error descr="Identifier or ';' expected"> </error>
public class A {
}
""".trimIndent())
}
}
private fun addVirtualManifest(moduleName: String, attributes: Map<String, String>) {
runWriteActionAndWait {
WorkspaceModel.getInstance(myFixture.project).updateProjectModel { storage ->