mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-highlighting] checkUnderscore, checkUnnamedVariableDeclaration migrated
Part of IDEA-365344 Create a new Java error highlighter with minimal dependencies (PSI only) GitOrigin-RevId: c6dbe7c307f68e1270c5c6b6b5e7972e9c3cf417
This commit is contained in:
committed by
intellij-monorepo-bot
parent
60119c1cbf
commit
0831efe6c2
@@ -313,3 +313,12 @@ import.single.static.field.already.defined=Field ''{0}'' is already defined in a
|
||||
import.single.static.field.ambiguous=Field ''{0}'' is ambiguous in a single static import
|
||||
import.static.on.demand.resolves.to.class=Class {0} not found
|
||||
|
||||
underscore.identifier=Since Java 9, '_' is a keyword, and may not be used as an identifier
|
||||
underscore.identifier.unnamed=Using '_' as a reference is not allowed
|
||||
underscore.identifier.lambda=Use of '_' as a lambda parameter name is not allowed
|
||||
|
||||
unnamed.field.not.allowed=Unnamed field is not allowed
|
||||
unnamed.method.parameter.not.allowed=Unnamed method parameter is not allowed
|
||||
unnamed.variable.not.allowed.in.this.context=Unnamed variable declaration is not allowed in this context
|
||||
unnamed.variable.brackets=Brackets are not allowed after an unnamed variable declaration
|
||||
unnamed.variable.without.initializer=Unnamed variable declaration must have an initializer
|
||||
|
||||
+52
@@ -3,12 +3,14 @@ package com.intellij.java.codeserver.highlighting;
|
||||
|
||||
import com.intellij.codeInsight.ExceptionUtil;
|
||||
import com.intellij.core.JavaPsiBundle;
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKind;
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds;
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaIncompatibleTypeErrorContext;
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaMismatchedCallContext;
|
||||
import com.intellij.openapi.project.IndexNotReadyException;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.pom.java.JavaFeature;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.IncompleteModelUtil;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
|
||||
@@ -724,6 +726,56 @@ final class ExpressionChecker {
|
||||
}
|
||||
}
|
||||
|
||||
void checkUnderscore(@NotNull PsiIdentifier identifier) {
|
||||
if ("_".equals(identifier.getText())) {
|
||||
PsiElement parent = identifier.getParent();
|
||||
LanguageLevel languageLevel = myVisitor.languageLevel();
|
||||
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_9) && !(parent instanceof PsiUnnamedPattern) &&
|
||||
!(parent instanceof PsiVariable var && var.isUnnamed())) {
|
||||
JavaErrorKind.Simple<PsiIdentifier> text = myVisitor.isApplicable(JavaFeature.UNNAMED_PATTERNS_AND_VARIABLES) ?
|
||||
JavaErrorKinds.UNDERSCORE_IDENTIFIER_UNNAMED :
|
||||
JavaErrorKinds.UNDERSCORE_IDENTIFIER;
|
||||
myVisitor.report(text.create(identifier));
|
||||
}
|
||||
else if (myVisitor.isApplicable(JavaFeature.LAMBDA_EXPRESSIONS)) {
|
||||
if (parent instanceof PsiParameter parameter && parameter.getDeclarationScope() instanceof PsiLambdaExpression &&
|
||||
!parameter.isUnnamed()) {
|
||||
myVisitor.report(JavaErrorKinds.UNDERSCORE_IDENTIFIER_LAMBDA.create(identifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isArrayDeclaration(@NotNull PsiVariable variable) {
|
||||
// Java-style 'var' arrays are prohibited by the parser; for C-style ones, looking for a bracket is enough
|
||||
return ContainerUtil.or(variable.getChildren(), e -> PsiUtil.isJavaToken(e, JavaTokenType.LBRACKET));
|
||||
}
|
||||
|
||||
void checkUnnamedVariableDeclaration(@NotNull PsiVariable variable) {
|
||||
if (isArrayDeclaration(variable)) {
|
||||
myVisitor.report(JavaErrorKinds.UNNAMED_VARIABLE_BRACKETS.create(variable));
|
||||
return;
|
||||
}
|
||||
if (variable instanceof PsiPatternVariable) return;
|
||||
if (variable instanceof PsiResourceVariable) return;
|
||||
if (variable instanceof PsiLocalVariable local) {
|
||||
if (local.getInitializer() == null) {
|
||||
myVisitor.report(JavaErrorKinds.UNNAMED_VARIABLE_WITHOUT_INITIALIZER.create(local));
|
||||
}
|
||||
}
|
||||
else if (variable instanceof PsiParameter parameter) {
|
||||
if (parameter.getDeclarationScope() instanceof PsiMethod) {
|
||||
myVisitor.report(JavaErrorKinds.UNNAMED_METHOD_PARAMETER_NOT_ALLOWED.create(parameter));
|
||||
}
|
||||
}
|
||||
else if (variable instanceof PsiField field) {
|
||||
myVisitor.report(JavaErrorKinds.UNNAMED_FIELD_NOT_ALLOWED.create(field));
|
||||
}
|
||||
else {
|
||||
myVisitor.report(JavaErrorKinds.UNNAMED_VARIABLE_NOT_ALLOWED_IN_THIS_CONTEXT.create(variable));
|
||||
}
|
||||
}
|
||||
|
||||
private static @NotNull PsiJavaCodeReferenceElement getOuterReferenceParent(@NotNull PsiJavaCodeReferenceElement ref) {
|
||||
PsiJavaCodeReferenceElement element = ref;
|
||||
while (true) {
|
||||
|
||||
+8
-1
@@ -386,7 +386,13 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
public void visitIdentifier(@NotNull PsiIdentifier identifier) {
|
||||
PsiElement parent = identifier.getParent();
|
||||
if (parent instanceof PsiVariable variable) {
|
||||
if (variable instanceof PsiField field) {
|
||||
if (variable.isUnnamed()) {
|
||||
checkFeature(variable, JavaFeature.UNNAMED_PATTERNS_AND_VARIABLES);
|
||||
if (!hasErrorResults()) {
|
||||
myExpressionChecker.checkUnnamedVariableDeclaration(variable);
|
||||
}
|
||||
}
|
||||
else if (variable instanceof PsiField field) {
|
||||
myClassChecker.checkImplicitClassMember(field);
|
||||
}
|
||||
}
|
||||
@@ -400,6 +406,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
else if (parent instanceof PsiMethod method) {
|
||||
myClassChecker.checkImplicitClassMember(method);
|
||||
}
|
||||
myExpressionChecker.checkUnderscore(identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+29
@@ -11,6 +11,7 @@ import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.pom.java.JavaFeature;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
@@ -21,6 +22,7 @@ import org.jetbrains.annotations.PropertyKey;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.intellij.java.codeserver.highlighting.JavaCompilationErrorBundle.message;
|
||||
import static com.intellij.java.codeserver.highlighting.errors.JavaErrorFormatUtil.*;
|
||||
@@ -885,6 +887,33 @@ public final class JavaErrorKinds {
|
||||
error(PsiJavaCodeReferenceElement.class, "import.static.on.demand.resolves.to.class")
|
||||
.withAnchor(ref -> requireNonNullElse(ref.getReferenceNameElement(), ref))
|
||||
.withRawDescription(ref -> message("import.static.on.demand.resolves.to.class", ref.getCanonicalText()));
|
||||
|
||||
public static final Simple<PsiIdentifier> UNDERSCORE_IDENTIFIER = error("underscore.identifier");
|
||||
public static final Simple<PsiIdentifier> UNDERSCORE_IDENTIFIER_UNNAMED = error("underscore.identifier.unnamed");
|
||||
public static final Simple<PsiIdentifier> UNDERSCORE_IDENTIFIER_LAMBDA = error("underscore.identifier.lambda");
|
||||
|
||||
public static final Simple<PsiVariable> UNNAMED_VARIABLE_BRACKETS =
|
||||
error(PsiVariable.class, "unnamed.variable.brackets")
|
||||
.withRange(var -> {
|
||||
TokenSet brackets = TokenSet.create(JavaTokenType.LBRACKET, JavaTokenType.RBRACKET);
|
||||
return Stream.of(var.getChildren())
|
||||
.filter(t -> PsiUtil.isJavaToken(t, brackets))
|
||||
.map(PsiElement::getTextRangeInParent)
|
||||
.reduce(TextRange::union)
|
||||
.orElseThrow(); // Must have at least one
|
||||
});
|
||||
public static final Simple<PsiLocalVariable> UNNAMED_VARIABLE_WITHOUT_INITIALIZER =
|
||||
error(PsiLocalVariable.class, "unnamed.variable.without.initializer")
|
||||
.withRange(var -> TextRange.create(0, requireNonNull(var.getNameIdentifier()).getTextRangeInParent().getEndOffset()));
|
||||
public static final Simple<PsiField> UNNAMED_FIELD_NOT_ALLOWED =
|
||||
error(PsiField.class, "unnamed.field.not.allowed")
|
||||
.withRange(var -> TextRange.create(0, requireNonNull(var.getNameIdentifier()).getTextRangeInParent().getEndOffset()));
|
||||
public static final Simple<PsiParameter> UNNAMED_METHOD_PARAMETER_NOT_ALLOWED =
|
||||
error(PsiParameter.class, "unnamed.method.parameter.not.allowed")
|
||||
.withRange(var -> TextRange.create(0, requireNonNull(var.getNameIdentifier()).getTextRangeInParent().getEndOffset()));
|
||||
public static final Simple<PsiVariable> UNNAMED_VARIABLE_NOT_ALLOWED_IN_THIS_CONTEXT =
|
||||
error(PsiVariable.class, "unnamed.variable.not.allowed.in.this.context")
|
||||
.withRange(var -> TextRange.create(0, requireNonNull(var.getNameIdentifier()).getTextRangeInParent().getEndOffset()));
|
||||
|
||||
private static @NotNull <Psi extends PsiElement> Simple<Psi> error(
|
||||
@NotNull @PropertyKey(resourceBundle = JavaCompilationErrorBundle.BUNDLE) String key) {
|
||||
|
||||
-67
@@ -20,7 +20,6 @@ import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixUpdater;
|
||||
import com.intellij.codeInspection.dataFlow.fix.RedundantInstanceofFix;
|
||||
import com.intellij.core.JavaPsiBundle;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.java.analysis.JavaAnalysisBundle;
|
||||
import com.intellij.modcommand.ModCommandAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.LanguageLevelUtil;
|
||||
@@ -47,7 +46,6 @@ import com.intellij.psi.scope.processor.VariablesNotProcessor;
|
||||
import com.intellij.psi.scope.util.PsiScopesUtil;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.refactoring.util.RefactoringChangeUtil;
|
||||
import com.intellij.ui.ColorUtil;
|
||||
@@ -63,7 +61,6 @@ import com.siyeh.ig.psiutils.ControlFlowUtils;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import com.siyeh.ig.psiutils.InstanceOfUtils;
|
||||
import com.siyeh.ig.psiutils.VariableAccessUtils;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
import java.awt.*;
|
||||
@@ -639,70 +636,6 @@ public final class HighlightUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkUnderscore(@NotNull PsiIdentifier identifier, @NotNull LanguageLevel languageLevel) {
|
||||
if ("_".equals(identifier.getText())) {
|
||||
PsiElement parent = identifier.getParent();
|
||||
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_9) && !(parent instanceof PsiUnnamedPattern) &&
|
||||
!(parent instanceof PsiVariable var && var.isUnnamed())) {
|
||||
String text = JavaFeature.UNNAMED_PATTERNS_AND_VARIABLES.isSufficient(languageLevel) ?
|
||||
JavaErrorBundle.message("underscore.identifier.error.unnamed") :
|
||||
JavaErrorBundle.message("underscore.identifier.error");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(identifier).descriptionAndTooltip(text);
|
||||
}
|
||||
else if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
|
||||
if (parent instanceof PsiParameter parameter && parameter.getDeclarationScope() instanceof PsiLambdaExpression &&
|
||||
!parameter.isUnnamed()) {
|
||||
String text = JavaErrorBundle.message("underscore.lambda.identifier");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(identifier).descriptionAndTooltip(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkUnnamedVariableDeclaration(@NotNull PsiVariable variable) {
|
||||
if (isArrayDeclaration(variable)) {
|
||||
IntentionAction fix = new NormalizeBracketsFix(variable).asIntention();
|
||||
TokenSet brackets = TokenSet.create(JavaTokenType.LBRACKET, JavaTokenType.RBRACKET);
|
||||
TextRange range = StreamEx.of(variable.getChildren())
|
||||
.filter(t -> PsiUtil.isJavaToken(t, brackets))
|
||||
.map(PsiElement::getTextRangeInParent)
|
||||
.reduce(TextRange::union)
|
||||
.orElseThrow()
|
||||
.shiftRight(variable.getTextRange().getStartOffset());// Must have at least one
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip(
|
||||
JavaAnalysisBundle.message("error.unnamed.variable.brackets")).registerFix(fix, null, null, null, null);
|
||||
}
|
||||
if (variable instanceof PsiPatternVariable) return null;
|
||||
if (variable instanceof PsiResourceVariable) return null;
|
||||
String message;
|
||||
IntentionAction fix = null;
|
||||
if (variable instanceof PsiLocalVariable local) {
|
||||
if (local.getInitializer() != null) return null;
|
||||
message = JavaAnalysisBundle.message("error.unnamed.variable.without.initializer");
|
||||
fix = getFixFactory().createAddVariableInitializerFix(local);
|
||||
}
|
||||
else if (variable instanceof PsiParameter parameter) {
|
||||
PsiElement scope = parameter.getDeclarationScope();
|
||||
if (!(scope instanceof PsiMethod)) return null;
|
||||
message = JavaAnalysisBundle.message("error.unnamed.method.parameter.not.allowed");
|
||||
}
|
||||
else if (variable instanceof PsiField) {
|
||||
message = JavaAnalysisBundle.message("error.unnamed.field.not.allowed");
|
||||
}
|
||||
else {
|
||||
message = JavaAnalysisBundle.message("error.unnamed.variable.not.allowed.in.this.context");
|
||||
}
|
||||
TextRange range = TextRange.create(variable.getTextRange().getStartOffset(),
|
||||
Objects.requireNonNull(variable.getNameIdentifier()).getTextRange().getEndOffset());
|
||||
HighlightInfo.Builder builder = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip(message);
|
||||
if (fix != null) {
|
||||
builder.registerFix(fix, null, null, null, null);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static @NotNull @NlsSafe String formatClass(@NotNull PsiClass aClass) {
|
||||
return formatClass(aClass, true);
|
||||
}
|
||||
|
||||
-10
@@ -565,14 +565,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
PsiElement parent = identifier.getParent();
|
||||
if (parent instanceof PsiVariable variable) {
|
||||
add(HighlightUtil.checkVariableAlreadyDefined(variable));
|
||||
if (variable.isUnnamed()) {
|
||||
HighlightInfo.Builder notAvailable = checkFeature(variable, JavaFeature.UNNAMED_PATTERNS_AND_VARIABLES);
|
||||
if (notAvailable != null) {
|
||||
add(notAvailable);
|
||||
} else {
|
||||
add(HighlightUtil.checkUnnamedVariableDeclaration(variable));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (parent instanceof PsiClass aClass) {
|
||||
if (!hasErrorResults() && JavaFeature.EXTENSION_METHODS.isSufficient(myLanguageLevel)) {
|
||||
@@ -600,8 +592,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
}
|
||||
}
|
||||
|
||||
add(HighlightUtil.checkUnderscore(identifier, myLanguageLevel));
|
||||
|
||||
super.visitIdentifier(identifier);
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -109,6 +109,7 @@ final class JavaErrorFixProvider {
|
||||
createConstructorFixes();
|
||||
createMethodFixes();
|
||||
createExpressionFixes();
|
||||
createVariableFixes();
|
||||
createExceptionFixes();
|
||||
createGenericFixes();
|
||||
createRecordFixes();
|
||||
@@ -244,6 +245,11 @@ final class JavaErrorFixProvider {
|
||||
fix(MODIFIER_INCOMPATIBLE, removeModifier);
|
||||
fix(MODIFIER_NOT_ALLOWED_NON_SEALED, removeModifier);
|
||||
}
|
||||
|
||||
private void createVariableFixes() {
|
||||
fix(UNNAMED_VARIABLE_BRACKETS, error -> new NormalizeBracketsFix(error.psi()));
|
||||
fix(UNNAMED_VARIABLE_WITHOUT_INITIALIZER, error -> myFactory.createAddVariableInitializerFix(error.psi()));
|
||||
}
|
||||
|
||||
private void createExpressionFixes() {
|
||||
fix(NEW_EXPRESSION_QUALIFIED_MALFORMED, error -> myFactory.createRemoveNewQualifierFix(error.psi(), null));
|
||||
|
||||
Reference in New Issue
Block a user