diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java index 7ad7d24b8e6a..e0ba7d7262f7 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java @@ -27,6 +27,7 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.JavaResolveUtil; import com.intellij.psi.search.GlobalSearchScope; @@ -251,17 +252,28 @@ public class HighlightClassUtil { return errorResult; } - static HighlightInfo checkVarClassConflict(@NotNull PsiClass psiClass, @NotNull PsiIdentifier identifier) { - String className = psiClass.getName(); - if (PsiKeyword.VAR.equals(className)) { + static HighlightInfo checkClassRestrictedKeyword(@NotNull LanguageLevel level, @NotNull PsiIdentifier identifier) { + String className = identifier.getText(); + if (isRestrictedIdentifier(className, level)) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) - .descriptionAndTooltip("'var' is a restricted local variable type and cannot be used for type declarations") + .descriptionAndTooltip(JavaErrorBundle.message("restricted.identifier", className)) .range(identifier) .create(); } return null; } - + + /** + * @param typeName name of the type to test + * @param level language level + * @return true if given name cannot be used as a type name at given language level + */ + public static boolean isRestrictedIdentifier(String typeName, @NotNull LanguageLevel level) { + return PsiKeyword.VAR.equals(typeName) && HighlightUtil.Feature.LVTI.isSufficient(level) || + PsiKeyword.YIELD.equals(typeName) && HighlightUtil.Feature.SWITCH_EXPRESSION.isSufficient(level) || + PsiKeyword.RECORD.equals(typeName) && HighlightUtil.Feature.RECORDS.isSufficient(level); + } + static HighlightInfo checkClassAndPackageConflict(@NotNull PsiClass aClass) { String name = aClass.getQualifiedName(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index 6c42d3bb4bc5..5c15de9f7e60 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -412,9 +412,12 @@ public class HighlightUtil extends HighlightUtilBase { return highlightInfo; } - static HighlightInfo checkLegalVarReference(@NotNull PsiJavaCodeReferenceElement ref, @NotNull PsiClass resolved) { - if (PsiKeyword.VAR.equals(resolved.getName()) && PsiUtil.getLanguageLevel(ref).isAtLeast(LanguageLevel.JDK_10)) { - String message = JavaErrorBundle.message("lvti.illegal"); + static HighlightInfo checkRestrictedIdentifierReference(@NotNull PsiJavaCodeReferenceElement ref, + @NotNull PsiClass resolved, + @NotNull LanguageLevel languageLevel) { + String name = resolved.getName(); + if (HighlightClassUtil.isRestrictedIdentifier(name, languageLevel)) { + String message = JavaErrorBundle.message("restricted.identifier.reference", name); PsiElement range = ObjectUtils.notNull(ref.getReferenceNameElement(), ref); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(message).range(range).create(); } @@ -3193,6 +3196,7 @@ public class HighlightUtil extends HighlightUtilBase { STATIC_INTERFACE_CALLS(LanguageLevel.JDK_1_8, "feature.static.interface.calls"), REFS_AS_RESOURCE(LanguageLevel.JDK_1_9, "feature.try.with.resources.refs"), MODULES(LanguageLevel.JDK_1_9, "feature.modules"), + LVTI(LanguageLevel.JDK_10, "feature.lvti"), ENHANCED_SWITCH(LanguageLevel.JDK_13_PREVIEW, "feature.enhanced.switch"){ @Override boolean isSufficient(LanguageLevel useSiteLevel) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 47561b43e7d1..16d9031bc07b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -698,8 +698,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!(parent instanceof PsiAnonymousClass) && aClass.getNameIdentifier() == identifier) { myHolder.add(HighlightNamesUtil.highlightClassName(aClass, identifier, colorsScheme)); } - if (!myHolder.hasErrorResults() && myLanguageLevel.isAtLeast(LanguageLevel.JDK_10)) { - myHolder.add(HighlightClassUtil.checkVarClassConflict(aClass, identifier)); + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightClassUtil.checkClassRestrictedKeyword(myLanguageLevel, identifier)); } if (!myHolder.hasErrorResults() && myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { myHolder.add(GenericsHighlightUtil.checkUnrelatedDefaultMethods(aClass, identifier)); @@ -1260,10 +1260,15 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkPackageAndClassConflict(ref, myFile)); - if (!myHolder.hasErrorResults() && resolved instanceof PsiClass) myHolder.add(HighlightUtil.checkLegalVarReference(ref, (PsiClass)resolved)); - if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkMemberReferencedBeforeConstructorCalled(ref, resolved, myFile, myInsideConstructorOfClass)); - + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkPackageAndClassConflict(ref, myFile)); + } + if (!myHolder.hasErrorResults() && resolved instanceof PsiClass) { + myHolder.add(HighlightUtil.checkRestrictedIdentifierReference(ref, (PsiClass)resolved, myLanguageLevel)); + } + if (!myHolder.hasErrorResults()) { + myHolder.add(HighlightUtil.checkMemberReferencedBeforeConstructorCalled(ref, resolved, myFile, myInsideConstructorOfClass)); + } return result; } diff --git a/java/java-impl/src/com/intellij/ide/actions/CreateClassAction.java b/java/java-impl/src/com/intellij/ide/actions/CreateClassAction.java index 6eac2249bcce..3ade2f6b356b 100644 --- a/java/java-impl/src/com/intellij/ide/actions/CreateClassAction.java +++ b/java/java-impl/src/com/intellij/ide/actions/CreateClassAction.java @@ -3,6 +3,8 @@ package com.intellij.ide.actions; import com.intellij.codeInsight.CodeInsightBundle; +import com.intellij.codeInsight.daemon.JavaErrorBundle; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightClassUtil; import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil; import com.intellij.ide.IdeBundle; import com.intellij.ide.fileTemplates.FileTemplate; @@ -59,8 +61,9 @@ public class CreateClassAction extends JavaCreateTemplateInPackageAction 0 && !PsiNameHelper.getInstance(project).isQualifiedName(inputString)) { return "This is not a valid Java qualified name"; } - if (level.isAtLeast(LanguageLevel.JDK_10) && PsiKeyword.VAR.equals(StringUtil.getShortName(inputString))) { - return "var cannot be used for type declarations"; + String shortName = StringUtil.getShortName(inputString); + if (HighlightClassUtil.isRestrictedIdentifier(shortName, level)) { + return JavaErrorBundle.message("restricted.identifier", shortName); } return null; } diff --git a/java/java-psi-impl/src/messages/JavaErrorBundle.properties b/java/java-psi-impl/src/messages/JavaErrorBundle.properties index 2694328812a5..11eb0fec6261 100644 --- a/java/java-psi-impl/src/messages/JavaErrorBundle.properties +++ b/java/java-psi-impl/src/messages/JavaErrorBundle.properties @@ -457,7 +457,9 @@ module.access.does.not.read=Package ''{0}'' is declared in module ''{1}'', but m module.access.not.in.graph=Package ''{0}'' is declared in module ''{1}'', which is not in the module graph module.access.bad.name=Package ''{0}'' is declared in module with an invalid name (''{1}'') -lvti.illegal=Illegal reference to restricted type 'var' +restricted.identifier=''{0}'' is a restricted identifier and cannot be used for type declarations +restricted.identifier.reference=Illegal reference to restricted type ''{0}'' + lvti.no.initializer=Cannot infer type: 'var' on variable without initializer lvti.lambda=Cannot infer type: lambda expression requires an explicit target type lvti.method.ref=Cannot infer type: method reference requires an explicit target type @@ -509,6 +511,7 @@ feature.intersections.in.casts=Intersection types in casts feature.static.interface.calls=Static interface method calls feature.try.with.resources.refs=Resource references feature.modules=Modules +feature.lvti=Local variable type inference feature.text.blocks=Text block literals feature.enhanced.switch=Enhanced 'switch' blocks feature.switch.expressions='switch' expressions diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingRecords/RecordBasics.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingRecords/RecordBasics.java index ec5b3ff7feea..31484c4eb754 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingRecords/RecordBasics.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingRecords/RecordBasics.java @@ -1,5 +1,8 @@ import java.lang.annotation.*; +class record { + void x(record r) {} +} record NoComponentList {} record NoComponents() {} class ClassWithComponents(int x) {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advLVTI/VarClassNameConflicts.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advLVTI/VarClassNameConflicts.java index feb95207d044..24ec837b9b0f 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advLVTI/VarClassNameConflicts.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advLVTI/VarClassNameConflicts.java @@ -1,7 +1,7 @@ class Main { - class var {} + class var {} - <var extends String> void foo() {} + <var extends String> void foo() {} class Usage { var field = new var(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/YieldStatements.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/YieldStatements.java index 04593e8a837f..aefee430d995 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/YieldStatements.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/YieldStatements.java @@ -47,4 +47,11 @@ class YieldStatements { }); } } + + class yield { + void test(yield yield) { + + } + } + } \ No newline at end of file