From a365288a1fe0742badb7dac80b570eccf9540bf3 Mon Sep 17 00:00:00 2001 From: Egor Ushakov Date: Wed, 4 Feb 2026 18:26:43 +0100 Subject: [PATCH] IDEA-366793 Remove non-final fields from debugger evaluators GitOrigin-RevId: b216bce9c8110f03fdd09c2072fae85c9ec5b1e1 --- .../expression/ArrayAccessEvaluator.java | 18 +-- .../expression/AssignmentEvaluator.java | 5 - .../expression/BlockStatementEvaluator.java | 5 - .../evaluation/expression/DisableGC.java | 5 - .../evaluation/expression/Evaluator.java | 6 +- .../expression/EvaluatorBuilderImpl.java | 11 +- .../expression/ExpressionEvaluatorImpl.java | 16 ++- .../evaluation/expression/FieldEvaluator.java | 20 +-- .../expression/LocalVariableEvaluator.java | 135 +++++++----------- .../expression/PostfixOperationEvaluator.java | 11 +- .../SyntheticVariableEvaluator.java | 12 +- 11 files changed, 74 insertions(+), 170 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayAccessEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayAccessEvaluator.java index 7a55f0147c51..579abd7c6aef 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayAccessEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayAccessEvaluator.java @@ -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; diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/AssignmentEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/AssignmentEvaluator.java index 43a3ebb8db4f..ec3054f98005 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/AssignmentEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/AssignmentEvaluator.java @@ -65,11 +65,6 @@ public class AssignmentEvaluator implements ModifiableEvaluator { } } - @Override - public Modifier getModifier() { - return myLeftEvaluator.getModifier(); - } - @Override public String toString() { return myLeftEvaluator + " = " + myRightEvaluator; diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BlockStatementEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BlockStatementEvaluator.java index 98611ce69f93..38e2b4a5a283 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BlockStatementEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BlockStatementEvaluator.java @@ -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; - } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DisableGC.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DisableGC.java index ff64a21315b0..13afa391999d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DisableGC.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DisableGC.java @@ -44,11 +44,6 @@ public final class DisableGC implements ModifiableEvaluator { } } - @Override - public Modifier getModifier() { - return myDelegate.getModifier(); - } - @Override public String toString() { return "NoGC -> " + myDelegate; diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/Evaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/Evaluator.java index 5c77c29bd537..fbf59c32361e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/Evaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/Evaluator.java @@ -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; } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java index 2e8f78af6f32..0cc209b6df20 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java @@ -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(); - } }; } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ExpressionEvaluatorImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ExpressionEvaluatorImpl.java index 135d6bb57f0c..94d21e96366c 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ExpressionEvaluatorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ExpressionEvaluatorImpl.java @@ -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) { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/FieldEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/FieldEvaluator.java index a70081f387f7..086eb1b5805e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/FieldEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/FieldEvaluator.java @@ -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; diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/LocalVariableEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/LocalVariableEvaluator.java index c46b05a6796d..5b987e31d434 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/LocalVariableEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/LocalVariableEvaluator.java @@ -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 vars = LocalVariablesUtil.fetchValues(frameProxy, process, true); - for (Map.Entry 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 vars = LocalVariablesUtil.fetchValues(frameProxy, process, true); + for (Map.Entry 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, diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/PostfixOperationEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/PostfixOperationEvaluator.java index ad43e62cf0c0..b30ca11be63f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/PostfixOperationEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/PostfixOperationEvaluator.java @@ -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; - } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/SyntheticVariableEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/SyntheticVariableEvaluator.java index 1d63b3cc4eeb..f2cee771a765 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/SyntheticVariableEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/SyntheticVariableEvaluator.java @@ -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;