IDEA-239649 Increase language level fix is not suggested for records

GitOrigin-RevId: 19843f9e1f610f7536b7e591012ec3eb64af6c43
This commit is contained in:
Tagir Valeev
2020-04-30 13:17:55 +07:00
committed by intellij-monorepo-bot
parent 642e4911cd
commit 618696f129
13 changed files with 175 additions and 60 deletions

View File

@@ -106,6 +106,7 @@ 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.var.lambda.parameter='var' in lambda parameters
feature.text.blocks=Text block literals
feature.enhanced.switch=Enhanced 'switch' blocks
feature.switch.expressions='switch' expressions

View File

@@ -7,6 +7,7 @@ import com.intellij.codeInsight.ExceptionUtil;
import com.intellij.codeInsight.JavaModuleSystemEx;
import com.intellij.codeInsight.JavaModuleSystemEx.ErrorWithFixes;
import com.intellij.codeInsight.daemon.JavaErrorBundle;
import com.intellij.codeInsight.daemon.QuickFixActionRegistrar;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
import com.intellij.codeInsight.daemon.impl.quickfix.*;
@@ -3239,14 +3240,21 @@ public class HighlightUtil {
if (file.getManager().isInProject(file) && !feature.isSufficient(level)) {
String message = getUnsupportedFeatureMessage(element, feature, level, file);
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(message).create();
QuickFixAction.registerQuickFixAction(info, getFixFactory().createIncreaseLanguageLevelFix(getApplicableLevel(file, feature)));
QuickFixAction.registerQuickFixAction(info, getFixFactory().createShowModulePropertiesFix(element));
registerIncreaseLanguageLevelFixes(new QuickFixActionRegistrarImpl(info), element, feature);
return info;
}
return null;
}
public static void registerIncreaseLanguageLevelFixes(@NotNull QuickFixActionRegistrar registrar,
@NotNull PsiElement element,
@NotNull HighlightingFeature feature) {
if (feature.isAvailable(element)) return;
registrar.register(getFixFactory().createIncreaseLanguageLevelFix(getApplicableLevel(element.getContainingFile(), feature)));
registrar.register(getFixFactory().createShowModulePropertiesFix(element));
}
private static @NotNull String getUnsupportedFeatureMessage(@NotNull PsiElement element,
@NotNull HighlightingFeature feature,
@NotNull LanguageLevel level,

View File

@@ -31,6 +31,7 @@ public enum HighlightingFeature {
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"),
VAR_LAMBDA_PARAMETER(LanguageLevel.JDK_11, "feature.var.lambda.parameter"),
ENHANCED_SWITCH(LanguageLevel.JDK_13_PREVIEW, "feature.enhanced.switch"){
@Override
boolean isSufficient(@NotNull LanguageLevel useSiteLevel) {

View File

@@ -5,12 +5,10 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.quickfix.AddExceptionToCatchFix;
import com.intellij.codeInsight.daemon.impl.quickfix.AddFinallyFix;
import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction;
import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixActionRegistrarImpl;
import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.core.JavaPsiBundle;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.PsiSwitchLabeledRuleStatement;
import com.intellij.psi.PsiTryStatement;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
public class JavaErrorQuickFixProvider implements ErrorQuickFixProvider {
@@ -29,5 +27,13 @@ public class JavaErrorQuickFixProvider implements ErrorQuickFixProvider {
QuickFixAction.registerQuickFixAction(
highlightInfo, QUICK_FIX_FACTORY.createWrapSwitchRuleStatementsIntoBlockFix((PsiSwitchLabeledRuleStatement)parent));
}
if (parent instanceof PsiJavaFile && errorElement.getErrorDescription().equals(
JavaPsiBundle.message("expected.class.or.interface"))) {
PsiElement child = errorElement.getFirstChild();
if (child instanceof PsiIdentifier && child.textMatches(PsiKeyword.RECORD)) {
HighlightUtil.registerIncreaseLanguageLevelFixes(
new QuickFixActionRegistrarImpl(highlightInfo), errorElement, HighlightingFeature.RECORDS);
}
}
}
}

View File

@@ -0,0 +1,57 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInsight.daemon.impl.analysis;
import com.intellij.codeInsight.daemon.QuickFixActionRegistrar;
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider;
import com.intellij.psi.*;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.NotNull;
public class JavaFutureKeywordUseFixProvider extends UnresolvedReferenceQuickFixProvider<PsiJavaCodeReferenceElement> {
@Override
public void registerFixes(@NotNull PsiJavaCodeReferenceElement ref, @NotNull QuickFixActionRegistrar registrar) {
PsiTypeElement typeElement = ObjectUtils.tryCast(ref.getParent(), PsiTypeElement.class);
if (typeElement == null || typeElement.getFirstChild() != typeElement.getLastChild()) return;
PsiElement parent = typeElement.getParent();
if (PsiKeyword.VAR.equals(ref.getReferenceName())) {
registerVarLanguageLevelFix(ref, parent, registrar);
}
if (PsiKeyword.RECORD.equals(ref.getReferenceName())) {
registerRecordLanguageLevelFix(ref, parent, registrar);
}
}
private static void registerRecordLanguageLevelFix(@NotNull PsiJavaCodeReferenceElement ref,
PsiElement parent,
@NotNull QuickFixActionRegistrar registrar) {
if ((parent instanceof PsiMethod || parent instanceof PsiField) && parent.getParent() instanceof PsiClass) {
// record R() {} is parsed as method if records aren't supported
// record R incomplete declaration is also possible
HighlightUtil.registerIncreaseLanguageLevelFixes(registrar, ref, HighlightingFeature.RECORDS);
}
if (parent instanceof PsiLocalVariable && parent.getParent() instanceof PsiDeclarationStatement
&& ((PsiDeclarationStatement)parent.getParent()).getDeclaredElements().length == 1) {
// record R() declaration inside method
HighlightUtil.registerIncreaseLanguageLevelFixes(registrar, ref, HighlightingFeature.RECORDS);
}
}
private static void registerVarLanguageLevelFix(@NotNull PsiJavaCodeReferenceElement ref,
PsiElement parent,
@NotNull QuickFixActionRegistrar registrar) {
HighlightingFeature feature;
if (parent instanceof PsiParameter && ((PsiParameter)parent).getDeclarationScope() instanceof PsiLambdaExpression) {
feature = HighlightingFeature.VAR_LAMBDA_PARAMETER;
}
else {
feature = HighlightingFeature.LVTI;
}
HighlightUtil.registerIncreaseLanguageLevelFixes(registrar, ref, feature);
}
@NotNull
@Override
public Class<PsiJavaCodeReferenceElement> getReferenceClass() {
return PsiJavaCodeReferenceElement.class;
}
}

View File

@@ -1,53 +0,0 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInsight.daemon.impl.analysis;
import com.intellij.codeInsight.daemon.QuickFixActionRegistrar;
import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider;
import com.intellij.pom.java.AcceptedLanguageLevelsSettings;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
public class LocalVariableTypeInferenceUnresolvedFixProvider extends UnresolvedReferenceQuickFixProvider<PsiJavaCodeReferenceElement> {
@Override
public void registerFixes(@NotNull PsiJavaCodeReferenceElement ref, @NotNull QuickFixActionRegistrar registrar) {
PsiElement typeElement = ref.getParent();
PsiElement parent = typeElement instanceof PsiTypeElement ? typeElement.getParent() : null;
boolean increaseLanguageLevel = true;
LanguageLevel targetLanguageLevel;
if (parent instanceof PsiParameter && ((PsiParameter)parent).getDeclarationScope() instanceof PsiLambdaExpression) {
//early-draft specification support to be enabled after release
if (LanguageLevel.HIGHEST.isAtLeast(LanguageLevel.JDK_11)) {
targetLanguageLevel = LanguageLevel.JDK_11;
}
else if (AcceptedLanguageLevelsSettings.isLanguageLevelAccepted(LanguageLevel.JDK_11)) {
targetLanguageLevel = LanguageLevel.JDK_11;
//show module options with ability to explicitly agree with legal notice
increaseLanguageLevel = false;
}
else {
return;
}
}
else {
targetLanguageLevel = LanguageLevel.JDK_10;
}
if (PsiUtil.getLanguageLevel(ref).isAtLeast(targetLanguageLevel)) return;
if (!PsiKeyword.VAR.equals(ref.getReferenceName())) return;
if (increaseLanguageLevel) {
registrar.register(QuickFixFactory.getInstance().createIncreaseLanguageLevelFix(targetLanguageLevel));
}
registrar.register(QuickFixFactory.getInstance().createShowModulePropertiesFix(ref));
}
@NotNull
@Override
public Class<PsiJavaCodeReferenceElement> getReferenceClass() {
return PsiJavaCodeReferenceElement.class;
}
}

View File

@@ -0,0 +1,3 @@
class X {
r<caret>ecord R() {}
}

View File

@@ -0,0 +1,5 @@
class X {
void test() {
r<caret>ecord R() {}
}
}

View File

@@ -0,0 +1,9 @@
class X {
interface Fn {
void test(String s);
}
void test() {
Fn fn = (v<caret>ar s) -> System.out.println(s);
}
}

View File

@@ -0,0 +1,5 @@
class X {
void test() {
v<caret>ar x = 5;
}
}

View File

@@ -0,0 +1,72 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.codeInsight.daemon;
import com.intellij.JavaTestUtil;
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.java.JavaBundle;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl;
import com.intellij.util.lang.JavaVersion;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.stream.Stream;
public class IncreaseLanguageLevelFixTest extends LightDaemonAnalyzerTestCase {
@Override
protected @NotNull String getTestDataPath() {
return JavaTestUtil.getJavaTestDataPath() + "/codeInsight/daemonCodeAnalyzer/increaseLanguageLevel/";
}
@Override
protected Sdk getProjectJDK() {
return IdeaTestUtil.getMockJdk(JavaVersion.compose(14));
}
@Override
protected LanguageLevel getLanguageLevel() {
return LanguageLevel.JDK_1_8;
}
public void testVarLocal() {
doTest(LanguageLevel.JDK_10);
}
public void testVarLambda() {
doTest(LanguageLevel.JDK_11);
}
public void testRecordTopLevel() {
doTest(LanguageLevel.JDK_14_PREVIEW);
}
public void testRecordInClass() {
doTest(LanguageLevel.JDK_14_PREVIEW);
}
public void testRecordInMethod() {
doTest(LanguageLevel.JDK_14_PREVIEW);
}
private void doTest(LanguageLevel level) {
configureByFile(getTestName(false) + ".java");
doHighlighting();
List<IntentionAction> actions = CodeInsightTestFixtureImpl.getAvailableIntentions(getEditor(), getFile());
String message = JavaBundle.message("set.language.level.to.0", level.getPresentableText());
boolean found = actions.stream().anyMatch(act -> act.getText().equals(message));
if (!found) {
LanguageLevel foundLevel = Stream.of(LanguageLevel.values())
.filter(l -> actions.stream().anyMatch(
act -> act.getText().equals(JavaBundle.message("set.language.level.to.0", l.getPresentableText()))))
.findFirst().orElse(null);
if (foundLevel != null) {
fail("Expected level: "+level+"; actual: "+foundLevel);
} else {
fail("Action " + message + " not found");
}
}
}
}

View File

@@ -2808,7 +2808,7 @@
bundle="messages.InspectionGadgetsBundle" key="inspection.constant.expression.display.name"
groupBundle="messages.InspectionsBundle" groupKey="group.names.code.style.issues"
implementationClass="com.siyeh.ig.style.ConstantExpressionInspection"/>
<codeInsight.unresolvedReferenceQuickFixProvider implementation="com.intellij.codeInsight.daemon.impl.analysis.LocalVariableTypeInferenceUnresolvedFixProvider"/>
<codeInsight.unresolvedReferenceQuickFixProvider implementation="com.intellij.codeInsight.daemon.impl.analysis.JavaFutureKeywordUseFixProvider"/>
</extensions>