IDEA-125805 (language level increase quickfix for switch on enum/string)

This commit is contained in:
Roman Shevchenko
2014-06-02 20:14:07 +04:00
parent 75a492a4e0
commit b8be4e29d9
7 changed files with 73 additions and 67 deletions
@@ -1314,48 +1314,62 @@ public class HighlightUtil extends HighlightUtilBase {
@Nullable
public static HighlightInfo checkSwitchSelectorType(@NotNull PsiSwitchStatement statement) {
final PsiExpression expression = statement.getExpression();
PsiType type = expression == null ? null : expression.getType();
if (type == null) {
return null;
}
HighlightInfo errorResult = null;
final boolean atLeastJava7 = PsiUtil.isLanguageLevel7OrHigher(expression);
if (!isValidTypeForSwitchSelector(type, atLeastJava7)) {
final String switchSelectorMessage = atLeastJava7 ? JavaErrorMessages.message("valid.switch.17.selector.types")
: JavaErrorMessages.message("valid.switch.selector.types");
String message =
JavaErrorMessages.message("incompatible.types", switchSelectorMessage, JavaHighlightUtil.formatType(type));
errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create();
QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createConvertSwitchToIfIntention(statement));
public static HighlightInfo checkSwitchSelectorType(@NotNull PsiSwitchStatement statement, @NotNull LanguageLevel level) {
PsiExpression expression = statement.getExpression();
if (expression == null) return null;
PsiType type = expression.getType();
if (type == null) return null;
SelectorKind kind = getSwitchSelectorKind(type);
if (kind == SelectorKind.INT) return null;
LanguageLevel requiredLevel = null;
if (kind == SelectorKind.ENUM) requiredLevel = LanguageLevel.JDK_1_5;
if (kind == SelectorKind.STRING) requiredLevel = LanguageLevel.JDK_1_7;
if (kind == null || requiredLevel != null && !level.isAtLeast(requiredLevel)) {
boolean is7 = level.isAtLeast(LanguageLevel.JDK_1_7);
String expected = JavaErrorMessages.message(is7 ? "valid.switch.17.selector.types" : "valid.switch.selector.types");
String message = JavaErrorMessages.message("incompatible.types", expected, JavaHighlightUtil.formatType(type));
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create();
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createConvertSwitchToIfIntention(statement));
if (PsiType.LONG.equals(type) || PsiType.FLOAT.equals(type) || PsiType.DOUBLE.equals(type)) {
QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createAddTypeCastFix(PsiType.INT, expression));
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createAddTypeCastFix(PsiType.INT, expression));
}
}
else {
final PsiClass member = PsiUtil.resolveClassInClassTypeOnly(type);
if (member != null && !PsiUtil.isAccessible(member.getProject(), member, expression, null)) {
String message = PsiFormatUtil.formatClass(member, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_FQ_NAME) + " is inaccessible here";
errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create();
if (requiredLevel != null) {
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createIncreaseLanguageLevelFix(requiredLevel));
}
return info;
}
return errorResult;
PsiClass member = PsiUtil.resolveClassInClassTypeOnly(type);
if (member != null && !PsiUtil.isAccessible(member.getProject(), member, expression, null)) {
String className = PsiFormatUtil.formatClass(member, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_FQ_NAME);
String message = JavaErrorMessages.message("inaccessible.type", className);
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create();
}
return null;
}
public static boolean isValidTypeForSwitchSelector(@NotNull PsiType type, final boolean languageLevel7OrHigher) {
if (TypeConversionUtil.getTypeRank(type) <= TypeConversionUtil.INT_RANK) return true;
if (type instanceof PsiClassType) {
PsiClass psiClass = ((PsiClassType)type).resolve();
if (psiClass == null) return false;
private enum SelectorKind { INT, ENUM, STRING }
private static SelectorKind getSwitchSelectorKind(@NotNull PsiType type) {
if (TypeConversionUtil.getTypeRank(type) <= TypeConversionUtil.INT_RANK) {
return SelectorKind.INT;
}
PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(type);
if (psiClass != null) {
if (psiClass.isEnum()) {
return true;
return SelectorKind.ENUM;
}
if (languageLevel7OrHigher) {
return Comparing.strEqual(psiClass.getQualifiedName(), CommonClassNames.JAVA_LANG_STRING);
if (Comparing.strEqual(psiClass.getQualifiedName(), CommonClassNames.JAVA_LANG_STRING)) {
return SelectorKind.STRING;
}
}
return false;
return null;
}
@Nullable
@@ -1391,7 +1391,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
@Override
public void visitSwitchStatement(PsiSwitchStatement statement) {
super.visitSwitchStatement(statement);
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkSwitchSelectorType(statement));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkSwitchSelectorType(statement, myLanguageLevel));
}
@Override
@@ -219,6 +219,7 @@ exception.already.caught.warn=Unreachable section: {1, choice, 0#exception|2#exc
not.a.statement=Not a statement
invalid.statement=Invalid statement
incompatible.types=Incompatible types. Found: ''{1}'', required: ''{0}''
inaccessible.type=''{0}'' is inaccessible here
incompatible.call.types=Wrong {0, choice, 1#1st|2#2nd|3#3rd|4#{0,number}th} argument type. Found: ''{2}'', required: ''{1}''
valid.switch.selector.types=byte, char, short or int
valid.switch.17.selector.types=char, byte, short, int, Character, Byte, Short, Integer, String, or an enum
@@ -1,19 +1,3 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.*;
import java.util.*;
@@ -34,16 +18,7 @@ class UnsupportedFeatures {
<error descr="Incompatible types. Found: 'boolean', required: 'java.lang.Boolean'">Boolean b = true;</error>
<error descr="Incompatible types. Found: 'java.lang.Boolean', required: 'boolean'">boolean b1 = Boolean.TRUE;</error>
try { Reader r = new FileReader("/dev/null"); }
catch (<error descr="Multi-catches are not supported at this language level">FileNotFoundException | IOException e</error>) { e.printStackTrace(); }
try <error descr="Try-with-resources are not supported at this language level">(Reader r = new FileReader("/dev/null"))</error> { }
I i1 = <error descr="Method references are not supported at this language level">UnsupportedFeatures::m</error>;
I i2 = <error descr="Lambda expressions are not supported at this language level">() -> { }</error>;
}
interface I {
<error descr="Extension methods are not supported at this language level">default void m() { }</error>
java.lang.annotation.ElementType t = null;
switch (<error descr="Incompatible types. Found: 'java.lang.annotation.ElementType', required: 'byte, char, short or int'">t</error>) { }
}
}
@@ -41,6 +41,10 @@ class UnsupportedFeatures {
I i1 = <error descr="Method references are not supported at this language level">UnsupportedFeatures::m</error>;
I i2 = <error descr="Lambda expressions are not supported at this language level">() -> { }</error>;
switch (<error descr="Incompatible types. Found: 'java.lang.String', required: 'byte, char, short or int'">list.get(0)</error>) {
case "foo": break;
}
}
interface I {
@@ -13,7 +13,7 @@ interface A {
class D {
public static void f(A a) {
A.B b = a.getB();
switch (<error descr="A.B.C is inaccessible here">b.c</error>) {
switch (<error descr="'A.B.C' is inaccessible here">b.c</error>) {
case SOME:
break;
}
@@ -15,8 +15,10 @@
*/
package org.jetbrains.plugins.groovy.refactoring.convertToJava;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiType;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -39,10 +41,7 @@ import org.jetbrains.plugins.groovy.lang.psi.util.GroovyConstantExpressionEvalua
*/
public class SwitchStatementGenerator {
private static final boolean LANGUAGE_LEVEL_7_OR_HIGHER = false;
private SwitchStatementGenerator() {
}
private SwitchStatementGenerator() { }
public static void generate(@NotNull StringBuilder builder,
@NotNull ExpressionContext context,
@@ -51,7 +50,7 @@ public class SwitchStatementGenerator {
final GrCaseSection[] caseSections = switchStatement.getCaseSections();
final PsiType type = condition == null ? null : TypesUtil.unboxPrimitiveTypeWrapper(condition.getType());
if (type == null || HighlightUtil.isValidTypeForSwitchSelector(type, LANGUAGE_LEVEL_7_OR_HIGHER)) {
if (type == null || isValidTypeForSwitchSelector(type)) {
generateSwitch(builder, context, condition, caseSections);
}
else {
@@ -59,6 +58,19 @@ public class SwitchStatementGenerator {
}
}
private static boolean isValidTypeForSwitchSelector(@NotNull PsiType type) {
if (TypeConversionUtil.getTypeRank(type) <= TypeConversionUtil.INT_RANK) {
return true;
}
PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(type);
if (aClass != null && aClass.isEnum()) {
return true;
}
return false;
}
private static void generateIfs(@NotNull StringBuilder builder,
@NotNull ExpressionContext context,
@NotNull GrExpression condition,