IDEA-366793 Remove non-final fields from debugger evaluators

GitOrigin-RevId: b216bce9c8110f03fdd09c2072fae85c9ec5b1e1
This commit is contained in:
Egor Ushakov
2026-02-05 12:59:59 +00:00
committed by intellij-monorepo-bot
parent 58000004ea
commit a365288a1f
11 changed files with 74 additions and 170 deletions
@@ -27,19 +27,13 @@ class ArrayAccessEvaluator implements ModifiableEvaluator {
private final Evaluator myArrayReferenceEvaluator;
private final Evaluator myIndexEvaluator;
// TODO remove non-final fields, see IDEA-366793
@Deprecated
private ArrayReference myEvaluatedArrayReference;
@Deprecated
private int myEvaluatedIndex;
ArrayAccessEvaluator(Evaluator arrayReferenceEvaluator, Evaluator indexEvaluator) {
myArrayReferenceEvaluator = arrayReferenceEvaluator;
myIndexEvaluator = indexEvaluator;
}
@Override
public @NotNull ModifiableValue evaluateModifiable(EvaluationContextImpl context) throws EvaluateException {
public @NotNull ModifiableValue evaluateModifiable(@NotNull EvaluationContextImpl context) throws EvaluateException {
if (!(myArrayReferenceEvaluator.evaluate(context) instanceof ArrayReference evaluatedArrayReference)) {
throw EvaluateExceptionUtil.createEvaluateException(JavaDebuggerBundle.message("evaluation.error.array.reference.expected"));
}
@@ -51,8 +45,6 @@ class ArrayAccessEvaluator implements ModifiableEvaluator {
try {
Value value = evaluatedArrayReference.getValue(evaluatedIndex);
myEvaluatedArrayReference = evaluatedArrayReference;
myEvaluatedIndex = evaluatedIndex;
return new ModifiableValue(value, new MyModifier(evaluatedArrayReference, evaluatedIndex));
}
catch (Exception e) {
@@ -60,14 +52,6 @@ class ArrayAccessEvaluator implements ModifiableEvaluator {
}
}
@Override
public Modifier getModifier() {
if (myEvaluatedArrayReference != null) {
return new MyModifier(myEvaluatedArrayReference, myEvaluatedIndex);
}
return null;
}
private static class MyModifier implements Modifier {
private final ArrayReference myEvaluatedArrayReference;
private final int myEvaluatedIndex;
@@ -65,11 +65,6 @@ public class AssignmentEvaluator implements ModifiableEvaluator {
}
}
@Override
public Modifier getModifier() {
return myLeftEvaluator.getModifier();
}
@Override
public String toString() {
return myLeftEvaluator + " = " + myRightEvaluator;
@@ -20,9 +20,4 @@ public class BlockStatementEvaluator implements ModifiableEvaluator {
}
return result;
}
@Override
public Modifier getModifier() {
return myStatements.length > 0 ? myStatements[myStatements.length - 1].getModifier() : null;
}
}
@@ -44,11 +44,6 @@ public final class DisableGC implements ModifiableEvaluator {
}
}
@Override
public Modifier getModifier() {
return myDelegate.getModifier();
}
@Override
public String toString() {
return "NoGC -> " + myDelegate;
@@ -8,16 +8,18 @@ package com.intellij.debugger.engine.evaluation.expression;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import org.jetbrains.annotations.NotNull;
public interface Evaluator {
default Object evaluate(EvaluationContextImpl context) throws EvaluateException {
throw new AbstractMethodError("evaluate or evaluateModifiable must be implemented");
}
/**
* Implement if the value may be modified (like local variable or a field)
*/
default ModifiableValue evaluateModifiable(EvaluationContextImpl context) throws EvaluateException {
default @NotNull ModifiableValue evaluateModifiable(EvaluationContextImpl context) throws EvaluateException {
return new ModifiableValue(evaluate(context), getModifier());
}
@@ -30,7 +32,7 @@ public interface Evaluator {
* @deprecated implement {@link #evaluateModifiable(EvaluationContextImpl)} instead
* @see ModifiableEvaluator
*/
@Deprecated
@Deprecated(forRemoval = true)
default Modifier getModifier() {
return null;
}
@@ -1055,8 +1055,6 @@ public final class EvaluatorBuilderImpl implements EvaluatorBuilder {
private static Evaluator createFallbackEvaluator(final Evaluator primary, final Evaluator fallback) {
return new ModifiableEvaluator() {
private boolean myIsFallback;
@Override
public @NotNull ModifiableValue evaluateModifiable(@NotNull EvaluationContextImpl context) throws EvaluateException {
try {
@@ -1064,20 +1062,13 @@ public final class EvaluatorBuilderImpl implements EvaluatorBuilder {
}
catch (EvaluateException e) {
try {
ModifiableValue res = fallback.evaluateModifiable(context);
myIsFallback = true;
return res;
return fallback.evaluateModifiable(context);
}
catch (EvaluateException e1) {
throw e;
}
}
}
@Override
public Modifier getModifier() {
return myIsFallback ? fallback.getModifier() : primary.getModifier();
}
};
}
@@ -27,6 +27,7 @@ import com.sun.jdi.Value;
public class ExpressionEvaluatorImpl implements ExpressionEvaluator {
private static final Logger LOG = Logger.getInstance(ExpressionEvaluator.class);
private final Evaluator myEvaluator;
private Modifier myModifier;
public ExpressionEvaluatorImpl(Evaluator evaluator) {
myEvaluator = evaluator;
@@ -35,7 +36,7 @@ public class ExpressionEvaluatorImpl implements ExpressionEvaluator {
//call evaluate before
@Override
public Modifier getModifier() {
return myEvaluator.getModifier();
return myModifier;
}
// EvaluationContextImpl should be at the same stackFrame as it was in the call to EvaluatorBuilderImpl.build
@@ -51,12 +52,12 @@ public class ExpressionEvaluatorImpl implements ExpressionEvaluator {
EvaluationContextImpl evaluationContextImpl = (EvaluationContextImpl)context;
final Object value;
final ModifiableValue modifiableValue;
if (evaluationContextImpl.isMayRetryEvaluation()) {
value = DebuggerUtils.getInstance().processCollectibleValue(
() -> myEvaluator.evaluate(evaluationContextImpl),
modifiableValue = DebuggerUtils.getInstance().processCollectibleValue(
() -> myEvaluator.evaluateModifiable(evaluationContextImpl),
r -> {
if (r instanceof Value v) {
if (r.getValue() instanceof Value v) {
evaluationContextImpl.keep(v);
}
return r;
@@ -65,14 +66,17 @@ public class ExpressionEvaluatorImpl implements ExpressionEvaluator {
);
}
else {
value = myEvaluator.evaluate(evaluationContextImpl);
modifiableValue = myEvaluator.evaluateModifiable(evaluationContextImpl);
}
Object value = modifiableValue.getValue();
if (value != null && !(value instanceof Value)) {
throw EvaluateExceptionUtil
.createEvaluateException(JavaDebuggerBundle.message("evaluation.error.invalid.expression", ""));
}
myModifier = modifiableValue.getModifier();
return (Value)value;
}
catch (ReturnEvaluator.ReturnException r) {
@@ -40,12 +40,6 @@ public class FieldEvaluator implements ModifiableEvaluator {
private final TargetClassFilter myTargetClassFilter;
private final String myFieldName;
// TODO remove non-final fields, see IDEA-366793
@Deprecated
private Object myEvaluatedQualifier;
@Deprecated
private Field myEvaluatedField;
public interface TargetClassFilter {
TargetClassFilter ALL = refType -> true;
@@ -108,7 +102,7 @@ public class FieldEvaluator implements ModifiableEvaluator {
}
@Override
public @NotNull ModifiableValue evaluateModifiable(EvaluationContextImpl context) throws EvaluateException {
public @NotNull ModifiableValue evaluateModifiable(@NotNull EvaluationContextImpl context) throws EvaluateException {
Object object = myObjectEvaluator.evaluate(context);
if (object instanceof ReferenceType refType) {
@@ -120,8 +114,6 @@ public class FieldEvaluator implements ModifiableEvaluator {
throw EvaluateExceptionUtil.createEvaluateException(JavaDebuggerBundle.message("evaluation.error.no.static.field", myFieldName));
}
MyModifier modifier = new MyModifier(refType, field);
myEvaluatedField = field;
myEvaluatedQualifier = refType;
return new ModifiableValue(refType.getValue(field), modifier);
}
@@ -147,8 +139,6 @@ public class FieldEvaluator implements ModifiableEvaluator {
}
Object qualifier = field.isStatic() ? refType : objRef;
MyModifier modifier = new MyModifier(qualifier, field);
myEvaluatedQualifier = qualifier;
myEvaluatedField = field;
return new ModifiableValue(field.isStatic() ? refType.getValue(field) : objRef.getValue(field), modifier);
}
@@ -159,14 +149,6 @@ public class FieldEvaluator implements ModifiableEvaluator {
throw EvaluateExceptionUtil.createEvaluateException(JavaDebuggerBundle.message("evaluation.error.evaluating.field", myFieldName));
}
@Override
public Modifier getModifier() {
if (myEvaluatedField != null && (myEvaluatedQualifier instanceof ClassType || myEvaluatedQualifier instanceof ObjectReference)) {
return new MyModifier(myEvaluatedQualifier, myEvaluatedField);
}
return null;
}
@Override
public String toString() {
return "field " + myFieldName;
@@ -44,105 +44,78 @@ class LocalVariableEvaluator implements ModifiableEvaluator {
private final String myLocalVariableName;
private final boolean myCanScanFrames;
// TODO remove non-final fields, see IDEA-366793
@Deprecated
private EvaluationContextImpl myContext;
@Deprecated
private LocalVariableProxyImpl myEvaluatedVariable;
@Deprecated
private DecompiledLocalVariable myEvaluatedDecompiledVariable;
LocalVariableEvaluator(String localVariableName, boolean canScanFrames) {
myLocalVariableName = localVariableName;
myCanScanFrames = canScanFrames;
}
@Override
public @NotNull ModifiableValue evaluateModifiable(EvaluationContextImpl context) throws EvaluateException {
public @NotNull ModifiableValue evaluateModifiable(@NotNull EvaluationContextImpl context) throws EvaluateException {
StackFrameProxyImpl frameProxy = context.getFrameProxy();
if (frameProxy == null) {
throw EvaluateExceptionUtil.createEvaluateException(JavaDebuggerBundle.message("evaluation.error.no.stackframe"));
}
try {
ThreadReferenceProxyImpl threadProxy = null;
int lastFrameIndex = -1;
PsiVariable variable = null;
DebugProcessImpl process = context.getDebugProcess();
ThreadReferenceProxyImpl threadProxy = null;
int lastFrameIndex = -1;
PsiVariable variable = null;
DebugProcessImpl process = context.getDebugProcess();
boolean topFrame = true;
boolean topFrame = true;
while (true) {
try {
LocalVariableProxyImpl local = frameProxy.visibleVariableByName(myLocalVariableName);
if (local != null) {
if (topFrame ||
variable.equals(resolveVariable(frameProxy, myLocalVariableName, context.getProject(), process))) {
myEvaluatedVariable = local;
myContext = context;
return new ModifiableValue(frameProxy.getValue(local), new MyModifier(context, local, null));
}
while (true) {
try {
LocalVariableProxyImpl local = frameProxy.visibleVariableByName(myLocalVariableName);
if (local != null) {
if (topFrame ||
variable.equals(resolveVariable(frameProxy, myLocalVariableName, context.getProject(), process))) {
return new ModifiableValue(frameProxy.getValue(local), new MyModifier(context, local, null));
}
}
catch (EvaluateException e) {
if (!(e.getCause() instanceof AbsentInformationException)) {
throw e;
}
// try to look in slots
try {
Map<DecompiledLocalVariable, Value> vars = LocalVariablesUtil.fetchValues(frameProxy, process, true);
for (Map.Entry<DecompiledLocalVariable, Value> entry : vars.entrySet()) {
DecompiledLocalVariable var = entry.getKey();
if (var.getMatchedNames().contains(myLocalVariableName) || var.getDefaultName().equals(myLocalVariableName)) {
myEvaluatedDecompiledVariable = var;
myContext = context;
return new ModifiableValue(entry.getValue(), new MyModifier(context, null, var));
}
}
}
catch (Exception e1) {
LOG.info(e1);
}
}
if (myCanScanFrames) {
if (topFrame) {
variable = resolveVariable(frameProxy, myLocalVariableName, context.getProject(), process);
if (variable == null) break;
}
if (threadProxy == null /* initialize it lazily */) {
threadProxy = frameProxy.threadProxy();
lastFrameIndex = threadProxy.frameCount() - 1;
}
int currentFrameIndex = frameProxy.getFrameIndex();
if (currentFrameIndex < lastFrameIndex) {
frameProxy = threadProxy.frame(currentFrameIndex + 1);
if (frameProxy != null) {
topFrame = false;
continue;
}
}
}
break;
}
throw EvaluateExceptionUtil.createEvaluateException(
JavaDebuggerBundle.message("evaluation.error.local.variable.missing", myLocalVariableName));
}
catch (EvaluateException e) {
myEvaluatedVariable = null;
myContext = null;
throw e;
}
}
catch (EvaluateException e) {
if (!(e.getCause() instanceof AbsentInformationException)) {
throw e;
}
@Override
public Modifier getModifier() {
if ((myEvaluatedVariable != null || myEvaluatedDecompiledVariable != null) && myContext != null) {
return new MyModifier(myContext, myEvaluatedVariable, myEvaluatedDecompiledVariable);
// try to look in slots
try {
Map<DecompiledLocalVariable, Value> vars = LocalVariablesUtil.fetchValues(frameProxy, process, true);
for (Map.Entry<DecompiledLocalVariable, Value> entry : vars.entrySet()) {
DecompiledLocalVariable var = entry.getKey();
if (var.getMatchedNames().contains(myLocalVariableName) || var.getDefaultName().equals(myLocalVariableName)) {
return new ModifiableValue(entry.getValue(), new MyModifier(context, null, var));
}
}
}
catch (Exception e1) {
LOG.info(e1);
}
}
if (myCanScanFrames) {
if (topFrame) {
variable = resolveVariable(frameProxy, myLocalVariableName, context.getProject(), process);
if (variable == null) break;
}
if (threadProxy == null /* initialize it lazily */) {
threadProxy = frameProxy.threadProxy();
lastFrameIndex = threadProxy.frameCount() - 1;
}
int currentFrameIndex = frameProxy.getFrameIndex();
if (currentFrameIndex < lastFrameIndex) {
frameProxy = threadProxy.frame(currentFrameIndex + 1);
if (frameProxy != null) {
topFrame = false;
continue;
}
}
}
break;
}
return null;
throw EvaluateExceptionUtil.createEvaluateException(
JavaDebuggerBundle.message("evaluation.error.local.variable.missing", myLocalVariableName));
}
private static @Nullable PsiVariable resolveVariable(final StackFrameProxy frame,
@@ -10,8 +10,6 @@ public class PostfixOperationEvaluator implements ModifiableEvaluator {
private final Evaluator myIncrementImpl;
private Modifier myModifier;
public PostfixOperationEvaluator(Evaluator operandEvaluator, Evaluator incrementImpl) {
myOperandEvaluator = DisableGC.create(operandEvaluator);
myIncrementImpl = DisableGC.create(incrementImpl);
@@ -20,14 +18,9 @@ public class PostfixOperationEvaluator implements ModifiableEvaluator {
@Override
public @NotNull ModifiableValue evaluateModifiable(@NotNull EvaluationContextImpl context) throws EvaluateException {
ModifiableValue modifiableValue = myOperandEvaluator.evaluateModifiable(context);
myModifier = modifiableValue.getModifier();
Modifier modifier = modifiableValue.getModifier();
Object operationResult = myIncrementImpl.evaluate(context);
AssignmentEvaluator.assign(myModifier, operationResult, context);
AssignmentEvaluator.assign(modifier, operationResult, context);
return modifiableValue;
}
@Override
public Modifier getModifier() {
return myModifier;
}
}
@@ -22,10 +22,6 @@ public class SyntheticVariableEvaluator implements ModifiableEvaluator {
private final String myLocalName;
private final JVMName myTypeName;
// TODO remove non-final fields, see IDEA-366793
@Deprecated
private String myTypeNameString = null;
public SyntheticVariableEvaluator(CodeFragmentEvaluator codeFragmentEvaluator, String localName, @Nullable JVMName typeName) {
myCodeFragmentEvaluator = codeFragmentEvaluator;
myLocalName = localName;
@@ -33,17 +29,11 @@ public class SyntheticVariableEvaluator implements ModifiableEvaluator {
}
@Override
public @NotNull ModifiableValue evaluateModifiable(EvaluationContextImpl context) throws EvaluateException {
public @NotNull ModifiableValue evaluateModifiable(@NotNull EvaluationContextImpl context) throws EvaluateException {
String typeNameString = myTypeName != null ? myTypeName.getName(context.getDebugProcess()) : null;
myTypeNameString = typeNameString;
return new ModifiableValue(myCodeFragmentEvaluator.getValue(myLocalName, context), new MyModifier(typeNameString));
}
@Override
public Modifier getModifier() {
return new MyModifier(myTypeNameString);
}
@Override
public String toString() {
return myLocalName;