mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-core] JavaPsiReferenceUtil moved to codeserver.core
GitOrigin-RevId: acad9e3fddb54a91d678aead628c2124128e93f0
This commit is contained in:
committed by
intellij-monorepo-bot
parent
f659d57b70
commit
47ea843d98
@@ -0,0 +1,116 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.java.codeserver.core;
|
||||
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.ThreeState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Utility methods related to references in Java sources
|
||||
*/
|
||||
public final class JavaPsiReferenceUtil {
|
||||
private JavaPsiReferenceUtil() { }
|
||||
|
||||
/**
|
||||
* @param expression reference that potentially references the field
|
||||
* @param referencedField the field referenced
|
||||
* @param acceptQualified true if qualified references are accepted
|
||||
* @return {@link ThreeState#UNSURE} if
|
||||
*/
|
||||
public static @NotNull ForwardReferenceProblem checkForwardReference(@NotNull PsiReferenceExpression expression,
|
||||
@NotNull PsiField referencedField,
|
||||
boolean acceptQualified) {
|
||||
PsiClass containingClass = referencedField.getContainingClass();
|
||||
if (containingClass == null) return ForwardReferenceProblem.LEGAL;
|
||||
if (expression.getContainingFile() != referencedField.getContainingFile()) return ForwardReferenceProblem.LEGAL;
|
||||
TextRange fieldRange = referencedField.getTextRange();
|
||||
if (fieldRange == null || expression.getTextRange().getStartOffset() >= fieldRange.getEndOffset()) return ForwardReferenceProblem.LEGAL;
|
||||
if (!acceptQualified) {
|
||||
if (containingClass.isEnum()) {
|
||||
if (isLegalForwardReferenceInEnum(expression, referencedField, containingClass)) return ForwardReferenceProblem.LEGAL;
|
||||
}
|
||||
// simple reference can be illegal (JLS 8.3.3)
|
||||
else if (expression.getQualifierExpression() != null) return ForwardReferenceProblem.LEGAL;
|
||||
}
|
||||
PsiField initField = findEnclosingFieldInitializer(expression);
|
||||
PsiClassInitializer classInitializer = findParentClassInitializer(expression);
|
||||
if (initField == null && classInitializer == null) return ForwardReferenceProblem.LEGAL;
|
||||
// instance initializers may access static fields
|
||||
boolean isStaticClassInitializer = classInitializer != null && classInitializer.hasModifierProperty(PsiModifier.STATIC);
|
||||
boolean isStaticInitField = initField != null && initField.hasModifierProperty(PsiModifier.STATIC);
|
||||
boolean inStaticContext = isStaticInitField || isStaticClassInitializer;
|
||||
if (!inStaticContext && referencedField.hasModifierProperty(PsiModifier.STATIC)) return ForwardReferenceProblem.LEGAL;
|
||||
if (PsiUtil.isOnAssignmentLeftHand(expression) && !PsiUtil.isAccessedForReading(expression)) return ForwardReferenceProblem.LEGAL;
|
||||
if (!containingClass.getManager().areElementsEquivalent(containingClass, PsiTreeUtil.getParentOfType(expression, PsiClass.class))) {
|
||||
return ForwardReferenceProblem.LEGAL;
|
||||
}
|
||||
return initField == referencedField
|
||||
? ForwardReferenceProblem.ILLEGAL_SELF_REFERENCE
|
||||
: ForwardReferenceProblem.ILLEGAL_FORWARD_REFERENCE;
|
||||
}
|
||||
|
||||
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 (!(qualifierExpr instanceof PsiReferenceExpression)) return true;
|
||||
|
||||
PsiElement qualifiedReference = ((PsiReferenceExpression)qualifierExpr).resolve();
|
||||
if (containingClass.equals(qualifiedReference)) {
|
||||
// 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.
|
||||
return PsiUtil.isCompileTimeConstant(referencedField);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return field that has initializer with this element as subexpression or null if not found
|
||||
*/
|
||||
private static PsiField findEnclosingFieldInitializer(@NotNull PsiElement entry) {
|
||||
PsiElement element = entry;
|
||||
while (element != null) {
|
||||
PsiElement parent = element.getParent();
|
||||
if (parent instanceof PsiField) {
|
||||
if (element == ((PsiField)parent).getInitializer()) return (PsiField)parent;
|
||||
if (parent instanceof PsiEnumConstant && element == ((PsiEnumConstant)parent).getArgumentList()) return (PsiField)parent;
|
||||
}
|
||||
if (element instanceof PsiClass || element instanceof PsiMethod) return null;
|
||||
element = parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PsiClassInitializer findParentClassInitializer(@NotNull PsiElement root) {
|
||||
PsiElement element = root;
|
||||
while (element != null) {
|
||||
if (element instanceof PsiClassInitializer initializer) return initializer;
|
||||
if (element instanceof PsiClass || element instanceof PsiMethod) return null;
|
||||
element = element.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A kind of problem with forward reference
|
||||
*/
|
||||
public enum ForwardReferenceProblem {
|
||||
/**
|
||||
* The reference has no problem in terms of forward kind
|
||||
*/
|
||||
LEGAL,
|
||||
/**
|
||||
* The reference refers to an object being initialized (e.g., field initializer refers to a field itself)
|
||||
*/
|
||||
ILLEGAL_SELF_REFERENCE,
|
||||
/**
|
||||
* The reference is an illegal reference to an object declared later
|
||||
*/
|
||||
ILLEGAL_FORWARD_REFERENCE
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user