IDEA-242390 - fixed illegal forward reference error inside enums

GitOrigin-RevId: e322e6c1daa46bf5df6314177c8be06ca54377df
This commit is contained in:
Ilyas Selimov
2020-07-10 13:40:17 +07:00
committed by intellij-monorepo-bot
parent 29a49ce121
commit d9a6306659
3 changed files with 79 additions and 16 deletions

View File

@@ -62,6 +62,7 @@ import com.intellij.util.containers.MultiMap;
import com.intellij.util.ui.UIUtil;
import com.intellij.xml.util.XmlStringUtil;
import com.siyeh.ig.psiutils.ControlFlowUtils;
import com.siyeh.ig.psiutils.TypeUtils;
import gnu.trove.THashMap;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
@@ -2242,7 +2243,7 @@ public final class HighlightUtil {
}
/**
* See JLS 8.3.2.3.
* See JLS 8.3.3.
*/
static HighlightInfo checkIllegalForwardReferenceToField(@NotNull PsiReferenceExpression expression, @NotNull PsiField referencedField) {
Boolean isIllegalForwardReference = isIllegalForwardReferenceToField(expression, referencedField, false);
@@ -2259,8 +2260,13 @@ public final class HighlightUtil {
if (expression.getContainingFile() != referencedField.getContainingFile()) return null;
TextRange fieldRange = referencedField.getTextRange();
if (fieldRange == null || expression.getTextRange().getStartOffset() >= fieldRange.getEndOffset()) return null;
// only simple reference can be illegal
if (!acceptQualified && expression.getQualifierExpression() != null) return null;
if (!acceptQualified) {
if (containingClass.isEnum()) {
if (isLegalForwardReferenceInEnum(expression, referencedField, containingClass)) return null;
}
// simple reference can be illegal (JLS 8.3.3)
else if (expression.getQualifierExpression() != null) return null;
}
PsiField initField = findEnclosingFieldInitializer(expression);
PsiClassInitializer classInitializer = findParentClassInitializer(expression);
if (initField == null && classInitializer == null) return null;
@@ -2276,6 +2282,25 @@ public final class HighlightUtil {
return initField != referencedField;
}
private static boolean isLegalForwardReferenceInEnum(@NotNull PsiReferenceExpression expression,
@NotNull PsiField referencedField,
@NotNull PsiClass containingClass) {
PsiExpression qualifierExpr = expression.getQualifierExpression();
// simple reference can be illegal (JLS 8.3.3)
if (qualifierExpr == null) return false;
if (Objects.equals(qualifierExpr.getText(), containingClass.getName())) {
PsiClassType enumType = TypeUtils.getType(CommonClassNames.JAVA_LANG_ENUM, referencedField);
// static fields that are constant variables (4.12.4) are initialized before other static fields (12.4.2),
// so a qualified reference to the constant variable is possible.
// And we have to ignore a reference to the enum constant which is not a constant variable (4.12.4, 15.29).
if (!enumType.isAssignableFrom(referencedField.getType()) && referencedField.computeConstantValue() != null) {
return true;
}
return false;
}
return true;
}
/**
* @return field that has initializer with this element as subexpression or null if not found
*/

View File

@@ -1,21 +1,58 @@
enum Enum242390 {
TYPE1(<error descr="Illegal forward reference">Enum242390.TYPE2</error>),
TYPE2(TYPE1);
import java.util.ArrayList;
import java.util.List;
static final String C1 = Enum242390.D;
static final String C2 = <error descr="Illegal forward reference">D</error>;
static final String D = "";
private final Enum242390 next;
Enum242390(Enum242390 next) {
this.next = next;
enum Enum1 {
A(<error descr="Illegal forward reference">B</error>.var),
B(A.var),
C(<error descr="Illegal forward reference">constant</error>),
D(Enum1.constant),
E(<error descr="Illegal forward reference">staticVar</error>),
F(<error descr="Illegal forward reference">Enum1.staticVar</error>)
;
Enum1(String str) {
}
static final String constant = "const";
static String staticVar = "staticVar";
String var = "var";
}
enum Enum242390_2 {
A(Enum242390_2.D);
enum Enum2 {
A(<error descr="Illegal forward reference">B</error>.var),
B(A.var),
C(<error descr="Illegal forward reference">constant</error>),
D(<error descr="Illegal forward reference">Enum2.constant</error>)
;
Enum2(List<String> str) {
}
Enum242390_2(String s) { }
static final List<String> constant = new ArrayList<>();
List<String> var = new ArrayList<>();
}
enum Enum3 {
A(<error descr="Illegal forward reference">B</error>),
B(<error descr="Illegal forward reference">Enum3.C</error>),
C(A),
D(Enum3.B),
E(<error descr="Illegal forward reference">constant</error>),
F(<error descr="Illegal forward reference">Enum3.constant</error>),
G(A.var),
H(<error descr="Illegal forward reference">staticVar</error>),
I(<error descr="Illegal forward reference">Enum3.staticVar</error>)
;
Enum3(Enum3 str) {
}
static final Enum3 constant = Enum3.A;
static Enum3 staticVar = Enum3.B;
Enum3 var;
}
enum Enum4 {
A
;
static final String C1 = Enum4.D;
static final String C2 = <error descr="Illegal forward reference">D</error>;
static final String C3 = A.D;
static final String D = "";
}

View File

@@ -84,6 +84,7 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testEnumImplementsInterface() { doTest7(false); }
public void testEnum() { doTest5(false); }
public void testEnum56239() { doTest6(false); }
public void testEnum242390() { doTest7(false); }
public void testSameErasure() { doTest5(false); }
public void testPairsWithSameErasure() { doTest5(false); }
public void testMethods() { doTest5(false); }