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 a649423de1b2..849f7e4cf0da 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 @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2015 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. - */ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. /* * Class ArrayAccessEvaluator @@ -29,11 +15,16 @@ import com.intellij.debugger.ui.impl.watch.ArrayElementDescriptorImpl; import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl; import com.intellij.openapi.project.Project; import com.sun.jdi.*; +import org.jetbrains.annotations.NotNull; -class ArrayAccessEvaluator implements Evaluator { +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) { @@ -42,21 +33,21 @@ class ArrayAccessEvaluator implements Evaluator { } @Override - public Object evaluate(EvaluationContextImpl context) throws EvaluateException { - myEvaluatedIndex = 0; - myEvaluatedArrayReference = null; - Value indexValue = (Value)myIndexEvaluator.evaluate(context); - Value arrayValue = (Value)myArrayReferenceEvaluator.evaluate(context); - if (!(arrayValue instanceof ArrayReference)) { + public @NotNull ModifiableValue evaluateModifiable(EvaluationContextImpl context) throws EvaluateException { + if (!(myArrayReferenceEvaluator.evaluate(context) instanceof ArrayReference evaluatedArrayReference)) { throw EvaluateExceptionUtil.createEvaluateException(JavaDebuggerBundle.message("evaluation.error.array.reference.expected")); } - myEvaluatedArrayReference = (ArrayReference)arrayValue; + Value indexValue = (Value)myIndexEvaluator.evaluate(context); if (!DebuggerUtils.isInteger(indexValue)) { throw EvaluateExceptionUtil.createEvaluateException(JavaDebuggerBundle.message("evaluation.error.invalid.index.expression")); } - myEvaluatedIndex = ((PrimitiveValue)indexValue).intValue(); + int evaluatedIndex = ((PrimitiveValue)indexValue).intValue(); + try { - return myEvaluatedArrayReference.getValue(myEvaluatedIndex); + Value value = evaluatedArrayReference.getValue(evaluatedIndex); + myEvaluatedArrayReference = evaluatedArrayReference; + myEvaluatedIndex = evaluatedIndex; + return new ModifiableValue(value, new MyModifier(evaluatedArrayReference, evaluatedIndex)); } catch (Exception e) { throw EvaluateExceptionUtil.createEvaluateException(e); @@ -65,41 +56,50 @@ class ArrayAccessEvaluator implements Evaluator { @Override public Modifier getModifier() { - Modifier modifier = null; if (myEvaluatedArrayReference != null) { - modifier = new Modifier() { - @Override - public boolean canInspect() { - return true; - } + return new MyModifier(myEvaluatedArrayReference, myEvaluatedIndex); + } + return null; + } - @Override - public boolean canSetValue() { - return true; - } + private static class MyModifier implements Modifier { + private final ArrayReference myEvaluatedArrayReference; + private final int myEvaluatedIndex; - @Override - public void setValue(Value value) throws ClassNotLoadedException, InvalidTypeException { - myEvaluatedArrayReference.setValue(myEvaluatedIndex, value); - } + private MyModifier(ArrayReference evaluatedArrayReference, int evaluatedIndex) { + myEvaluatedArrayReference = evaluatedArrayReference; + myEvaluatedIndex = evaluatedIndex; + } - @Override - public Type getExpectedType() throws EvaluateException { - try { - ArrayType type = (ArrayType)myEvaluatedArrayReference.referenceType(); - return type.componentType(); - } - catch (ClassNotLoadedException e) { - throw EvaluateExceptionUtil.createEvaluateException(e); - } - } + @Override + public boolean canInspect() { + return true; + } - @Override - public NodeDescriptorImpl getInspectItem(Project project) { - return new ArrayElementDescriptorImpl(project, myEvaluatedArrayReference, myEvaluatedIndex); - } - }; + @Override + public boolean canSetValue() { + return true; + } + + @Override + public void setValue(Value value) throws ClassNotLoadedException, InvalidTypeException { + myEvaluatedArrayReference.setValue(myEvaluatedIndex, value); + } + + @Override + public Type getExpectedType() throws EvaluateException { + try { + ArrayType type = (ArrayType)myEvaluatedArrayReference.referenceType(); + return type.componentType(); + } + catch (ClassNotLoadedException e) { + throw EvaluateExceptionUtil.createEvaluateException(e); + } + } + + @Override + public NodeDescriptorImpl getInspectItem(Project project) { + return new ArrayElementDescriptorImpl(project, myEvaluatedArrayReference, myEvaluatedIndex); } - return modifier; } } 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 db69e60802c6..b5343bfdd9a3 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 @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// 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.debugger.engine.evaluation.expression; import com.intellij.debugger.JavaDebuggerBundle; @@ -8,7 +8,7 @@ import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.sun.jdi.*; import org.jetbrains.annotations.NotNull; -public class AssignmentEvaluator implements Evaluator { +public class AssignmentEvaluator implements ModifiableEvaluator { private final Evaluator myLeftEvaluator; private final Evaluator myRightEvaluator; @@ -18,9 +18,8 @@ public class AssignmentEvaluator implements Evaluator { } @Override - public Object evaluate(EvaluationContextImpl context) throws EvaluateException { - myLeftEvaluator.evaluate(context); - final Modifier modifier = myLeftEvaluator.getModifier(); + public @NotNull ModifiableValue evaluateModifiable(@NotNull EvaluationContextImpl context) throws EvaluateException { + Modifier modifier = myLeftEvaluator.evaluateModifiable(context).getModifier(); final Object right = myRightEvaluator.evaluate(context); if (right != null && !(right instanceof Value)) { @@ -29,7 +28,7 @@ public class AssignmentEvaluator implements Evaluator { assign(modifier, right, context); - return right; + return new ModifiableValue(right, modifier); } static void assign(Modifier modifier, Object right, EvaluationContextImpl context) throws EvaluateException { 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 3e18e34e65dc..98611ce69f93 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 @@ -1,10 +1,11 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// 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.debugger.engine.evaluation.expression; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; +import org.jetbrains.annotations.NotNull; -public class BlockStatementEvaluator implements Evaluator { +public class BlockStatementEvaluator implements ModifiableEvaluator { protected Evaluator[] myStatements; public BlockStatementEvaluator(Evaluator[] statements) { @@ -12,10 +13,10 @@ public class BlockStatementEvaluator implements Evaluator { } @Override - public Object evaluate(EvaluationContextImpl context) throws EvaluateException { - Object result = context.getVirtualMachineProxy().mirrorOfVoid(); + public @NotNull ModifiableValue evaluateModifiable(@NotNull EvaluationContextImpl context) throws EvaluateException { + ModifiableValue result = new ModifiableValue(context.getVirtualMachineProxy().mirrorOfVoid(), null); for (Evaluator statement : myStatements) { - result = statement.evaluate(context); + result = statement.evaluateModifiable(context); } return result; } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DeconstructionPatternEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DeconstructionPatternEvaluator.java index c95bdde2e8a7..970124168ef7 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DeconstructionPatternEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DeconstructionPatternEvaluator.java @@ -40,7 +40,7 @@ public class DeconstructionPatternEvaluator extends PatternEvaluator { res = componentEvaluator.match(objRef.getValue(field), context); } if (res && myVariableEvaluator != null) { - AssignmentEvaluator.assign(myVariableEvaluator.getModifier(), value, context); + AssignmentEvaluator.assign(myVariableEvaluator.evaluateModifiable(context).getModifier(), value, context); } return res; } 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 e78f6e865bd8..ff64a21315b0 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 @@ -1,4 +1,4 @@ -// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// 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.debugger.engine.evaluation.expression; import com.intellij.debugger.engine.evaluation.EvaluateException; @@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull; /** * @author Eugene Zhuravlev */ -public final class DisableGC implements Evaluator { +public final class DisableGC implements ModifiableEvaluator { private final Evaluator myDelegate; private DisableGC(@NotNull Evaluator delegate) { @@ -24,12 +24,24 @@ public final class DisableGC implements Evaluator { } @Override - public Object evaluate(EvaluationContextImpl context) throws EvaluateException { - final Object result = myDelegate.evaluate(context); - if (result instanceof ObjectReference) { - context.getSuspendContext().keep((ObjectReference)result); + public @NotNull ModifiableValue evaluateModifiable(EvaluationContextImpl context) throws EvaluateException { + if (myDelegate instanceof ModifiableEvaluator modifiableEvaluator) { + ModifiableValue result = modifiableEvaluator.evaluateModifiable(context); + Object value = result.getValue(); + keep(context, value); + return result; + } + else { + Object value = myDelegate.evaluate(context); + keep(context, value); + return new ModifiableValue(value, null); + } + } + + private static void keep(EvaluationContextImpl context, Object value) { + if (value instanceof ObjectReference reference) { + context.keep(reference); } - return result; } @Override diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DoWhileStatementEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DoWhileStatementEvaluator.java index 5c9aa8e661a0..9afb81a4d712 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DoWhileStatementEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DoWhileStatementEvaluator.java @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// 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.debugger.engine.evaluation.expression; import com.intellij.debugger.engine.evaluation.EvaluateException; @@ -15,11 +15,6 @@ public class DoWhileStatementEvaluator extends LoopEvaluator { myConditionEvaluator = DisableGC.create(conditionEvaluator); } - @Override - public Modifier getModifier() { - return myConditionEvaluator.getModifier(); - } - @Override public Object evaluate(EvaluationContextImpl context) throws EvaluateException { Object value = context.getVirtualMachineProxy().mirrorOfVoid(); 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 e1146ea6903b..5c77c29bd537 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 @@ -1,4 +1,4 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. /* * Interface Evaluator @@ -10,14 +10,27 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; public interface Evaluator { - Object evaluate(EvaluationContextImpl context) throws EvaluateException; + 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 { + return new ModifiableValue(evaluate(context), getModifier()); + } /** * In order to obtain a modifier the expression must be evaluated first * * @return a modifier object allowing to set a value in case the expression is lvalue, * otherwise null is returned + * + * @deprecated implement {@link #evaluateModifiable(EvaluationContextImpl)} instead + * @see ModifiableEvaluator */ + @Deprecated 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 a8c7ccfd3616..758aad916f40 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 @@ -936,17 +936,17 @@ public final class EvaluatorBuilderImpl implements EvaluatorBuilder { } private static Evaluator createFallbackEvaluator(final Evaluator primary, final Evaluator fallback) { - return new Evaluator() { + return new ModifiableEvaluator() { private boolean myIsFallback; @Override - public Object evaluate(EvaluationContextImpl context) throws EvaluateException { + public @NotNull ModifiableValue evaluateModifiable(@NotNull EvaluationContextImpl context) throws EvaluateException { try { - return primary.evaluate(context); + return primary.evaluateModifiable(context); } catch (EvaluateException e) { try { - Object res = fallback.evaluate(context); + ModifiableValue res = fallback.evaluateModifiable(context); myIsFallback = true; return res; } 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 53dbf35c6f6a..a9c10e653e22 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 @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. /* * Class FieldEvaluator @@ -25,11 +25,15 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class FieldEvaluator implements Evaluator { +public class FieldEvaluator implements ModifiableEvaluator { private final Evaluator myObjectEvaluator; 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 { @@ -94,15 +98,9 @@ public class FieldEvaluator implements Evaluator { } @Override - public Object evaluate(EvaluationContextImpl context) throws EvaluateException { - myEvaluatedField = null; - myEvaluatedQualifier = null; + public @NotNull ModifiableValue evaluateModifiable(EvaluationContextImpl context) throws EvaluateException { Object object = myObjectEvaluator.evaluate(context); - return evaluateField(object, context); - } - - private Object evaluateField(Object object, EvaluationContextImpl context) throws EvaluateException { if (object instanceof ReferenceType refType) { Field field = findField(refType); if (field == null || !field.isStatic()) { @@ -111,9 +109,10 @@ public class FieldEvaluator implements Evaluator { if (field == null || !field.isStatic()) { throw EvaluateExceptionUtil.createEvaluateException(JavaDebuggerBundle.message("evaluation.error.no.static.field", myFieldName)); } + MyModifier modifier = new MyModifier(refType, field); myEvaluatedField = field; myEvaluatedQualifier = refType; - return refType.getValue(field); + return new ModifiableValue(refType.getValue(field), modifier); } if (object instanceof ObjectReference objRef) { @@ -125,7 +124,7 @@ public class FieldEvaluator implements Evaluator { // expressions like 'array.length' must be treated separately if (objRef instanceof ArrayReference && "length".equals(myFieldName)) { - return context.getVirtualMachineProxy().mirrorOf(((ArrayReference)objRef).length()); + return new ModifiableValue(context.getVirtualMachineProxy().mirrorOf(((ArrayReference)objRef).length()), null); } Field field = findField(refType); @@ -136,9 +135,11 @@ public class FieldEvaluator implements Evaluator { if (field == null) { throw EvaluateExceptionUtil.createEvaluateException(JavaDebuggerBundle.message("evaluation.error.no.instance.field", myFieldName)); } - myEvaluatedQualifier = field.isStatic() ? refType : objRef; + Object qualifier = field.isStatic() ? refType : objRef; + MyModifier modifier = new MyModifier(qualifier, field); + myEvaluatedQualifier = qualifier; myEvaluatedField = field; - return field.isStatic() ? refType.getValue(field) : objRef.getValue(field); + return new ModifiableValue(field.isStatic() ? refType.getValue(field) : objRef.getValue(field), modifier); } if (object == null) { @@ -150,48 +151,10 @@ public class FieldEvaluator implements Evaluator { @Override public Modifier getModifier() { - Modifier modifier = null; if (myEvaluatedField != null && (myEvaluatedQualifier instanceof ClassType || myEvaluatedQualifier instanceof ObjectReference)) { - modifier = new Modifier() { - @Override - public boolean canInspect() { - return myEvaluatedQualifier instanceof ObjectReference; - } - - @Override - public boolean canSetValue() { - return true; - } - - @Override - public void setValue(Value value) throws ClassNotLoadedException, InvalidTypeException { - if (myEvaluatedQualifier instanceof ReferenceType) { - ClassType classType = (ClassType)myEvaluatedQualifier; - classType.setValue(myEvaluatedField, value); - } - else { - ObjectReference objRef = (ObjectReference)myEvaluatedQualifier; - objRef.setValue(myEvaluatedField, value); - } - } - - @Override - public Type getExpectedType() throws ClassNotLoadedException { - return myEvaluatedField.type(); - } - - @Override - public NodeDescriptorImpl getInspectItem(Project project) { - if (myEvaluatedQualifier instanceof ObjectReference) { - return new FieldDescriptorImpl(project, (ObjectReference)myEvaluatedQualifier, myEvaluatedField); - } - else { - return null; - } - } - }; + return new MyModifier(myEvaluatedQualifier, myEvaluatedField); } - return modifier; + return null; } @Override @@ -238,4 +201,50 @@ public class FieldEvaluator implements Evaluator { return false; } } + + private static class MyModifier implements Modifier { + private final Object myEvaluatedQualifier; + private final Field myEvaluatedField; + + private MyModifier(Object qualifier, Field field) { + myEvaluatedQualifier = qualifier; + myEvaluatedField = field; } + + @Override + public boolean canInspect() { + return myEvaluatedQualifier instanceof ObjectReference; + } + + @Override + public boolean canSetValue() { + return true; + } + + @Override + public void setValue(Value value) throws ClassNotLoadedException, InvalidTypeException { + if (myEvaluatedQualifier instanceof ReferenceType) { + ClassType classType = (ClassType)myEvaluatedQualifier; + classType.setValue(myEvaluatedField, value); + } + else { + ObjectReference objRef = (ObjectReference)myEvaluatedQualifier; + objRef.setValue(myEvaluatedField, value); + } + } + + @Override + public Type getExpectedType() throws ClassNotLoadedException { + return myEvaluatedField.type(); + } + + @Override + public NodeDescriptorImpl getInspectItem(Project project) { + if (myEvaluatedQualifier instanceof ObjectReference) { + return new FieldDescriptorImpl(project, (ObjectReference)myEvaluatedQualifier, myEvaluatedField); + } + else { + return null; + } + } + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ForStatementEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ForStatementEvaluator.java index fb1fbffe2f29..22d378bdca09 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ForStatementEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ForStatementEvaluator.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 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. - */ +// 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.debugger.engine.evaluation.expression; import com.intellij.debugger.engine.evaluation.EvaluateException; @@ -23,8 +9,6 @@ public class ForStatementEvaluator extends ForStatementEvaluatorBase { private final Evaluator myConditionEvaluator; private final Evaluator myUpdateEvaluator; - private Modifier myModifier; - public ForStatementEvaluator(Evaluator initializationEvaluator, Evaluator conditionEvaluator, Evaluator updateEvaluator, @@ -36,16 +20,10 @@ public class ForStatementEvaluator extends ForStatementEvaluatorBase { myUpdateEvaluator = updateEvaluator != null ? DisableGC.create(updateEvaluator) : null; } - @Override - public Modifier getModifier() { - return myModifier; - } - @Override protected Object evaluateInitialization(EvaluationContextImpl context, Object value) throws EvaluateException { if (myInitializationEvaluator != null) { - value = myInitializationEvaluator.evaluate(context); - myModifier = myInitializationEvaluator.getModifier(); + return myInitializationEvaluator.evaluate(context); } return value; } @@ -53,9 +31,7 @@ public class ForStatementEvaluator extends ForStatementEvaluatorBase { @Override protected Object evaluateCondition(EvaluationContextImpl context) throws EvaluateException { if (myConditionEvaluator != null) { - Object value = myConditionEvaluator.evaluate(context); - myModifier = myConditionEvaluator.getModifier(); - return value; + return myConditionEvaluator.evaluate(context); } return true; } @@ -63,8 +39,7 @@ public class ForStatementEvaluator extends ForStatementEvaluatorBase { @Override protected Object evaluateUpdate(EvaluationContextImpl context, Object value) throws EvaluateException { if (myUpdateEvaluator != null) { - value = myUpdateEvaluator.evaluate(context); - myModifier = myUpdateEvaluator.getModifier(); + return myUpdateEvaluator.evaluate(context); } return value; } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ForeachStatementEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ForeachStatementEvaluator.java index b97c9aafb29e..abfe4ca95064 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ForeachStatementEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ForeachStatementEvaluator.java @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// 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.debugger.engine.evaluation.expression; import com.intellij.debugger.engine.JVMNameUtil; @@ -9,85 +9,95 @@ import com.sun.jdi.ArrayReference; import com.sun.jdi.ObjectReference; import com.sun.jdi.Value; -public class ForeachStatementEvaluator extends ForStatementEvaluatorBase { +public class ForeachStatementEvaluator implements Evaluator { private final Evaluator myIterationParameterEvaluator; private final Evaluator myIterableEvaluator; - - private Evaluator myConditionEvaluator; - private Evaluator myNextEvaluator; - - private int myArrayLength = -1; - private int myCurrentIndex = 0; - - private Modifier myModifier; + private final Evaluator myBodyEvaluator; + private final String myLabelName; public ForeachStatementEvaluator(Evaluator iterationParameterEvaluator, Evaluator iterableEvaluator, Evaluator bodyEvaluator, String labelName) { - super(labelName, bodyEvaluator); myIterationParameterEvaluator = iterationParameterEvaluator; myIterableEvaluator = DisableGC.create(iterableEvaluator); + myBodyEvaluator = bodyEvaluator; + myLabelName = labelName; } @Override - public Modifier getModifier() { - return myModifier; - } - - @Override - protected Object evaluateInitialization(EvaluationContextImpl context, Object value) throws EvaluateException { + public Object evaluate(EvaluationContextImpl context) throws EvaluateException { final Object iterable = myIterableEvaluator.evaluate(context); if (!(iterable instanceof ObjectReference)) { throw new EvaluateException("Unable to do foreach for" + iterable); } - IdentityEvaluator iterableEvaluator = new IdentityEvaluator((Value)iterable); + if (iterable instanceof ArrayReference) { - myCurrentIndex = 0; - myArrayLength = ((ArrayReference)iterable).length(); - myNextEvaluator = new AssignmentEvaluator(myIterationParameterEvaluator, - new Evaluator() { - @Override - public Object evaluate(EvaluationContextImpl context) throws EvaluateException { - return ((ArrayReference)iterable).getValue(myCurrentIndex++); - } - }); + return new ForStatementEvaluatorBase(myLabelName, myBodyEvaluator) { + private int myCurrentIndex = 0; + private int myArrayLength = -1; + private Evaluator myNextEvaluator; + + @Override + protected Object evaluateInitialization(EvaluationContextImpl context, Object value) throws EvaluateException { + myArrayLength = ((ArrayReference)iterable).length(); + myNextEvaluator = new AssignmentEvaluator(myIterationParameterEvaluator, + new Evaluator() { + @Override + public Object evaluate(EvaluationContextImpl context) { + return ((ArrayReference)iterable).getValue(myCurrentIndex++); + } + }); + return value; + } + + @Override + protected Object evaluateCondition(EvaluationContextImpl context) { + return myCurrentIndex < myArrayLength; + } + + @Override + protected void evaluateBody(EvaluationContextImpl context) throws EvaluateException { + myNextEvaluator.evaluate(context); + super.evaluateBody(context); + } + }.evaluate(context); } else { - Object iterator = - new MethodEvaluator(iterableEvaluator, JVMNameUtil.getJVMRawText(CommonClassNames.JAVA_LANG_ITERABLE), "iterator", null, - new Evaluator[0]).evaluate(context); - IdentityEvaluator iteratorEvaluator = new IdentityEvaluator((Value)iterator); - myConditionEvaluator = - new MethodEvaluator(iteratorEvaluator, JVMNameUtil.getJVMRawText(CommonClassNames.JAVA_UTIL_ITERATOR), "hasNext", null, - new Evaluator[0]); - myNextEvaluator = new AssignmentEvaluator(myIterationParameterEvaluator, new MethodEvaluator(iteratorEvaluator, - JVMNameUtil.getJVMRawText( - CommonClassNames.JAVA_UTIL_ITERATOR), - "next", null, new Evaluator[0])); - } - return value; - } + return new ForStatementEvaluatorBase(myLabelName, myBodyEvaluator) { + private MethodEvaluator myConditionEvaluator; + private AssignmentEvaluator myNextEvaluator; - private boolean isArray() { - return myArrayLength > -1; - } + @Override + protected Object evaluateInitialization(EvaluationContextImpl context, Object value) throws EvaluateException { + Object iterator = new MethodEvaluator(new IdentityEvaluator((Value)iterable), + JVMNameUtil.getJVMRawText(CommonClassNames.JAVA_LANG_ITERABLE), + "iterator", null, + new Evaluator[0]).evaluate(context); + IdentityEvaluator iteratorEvaluator = new IdentityEvaluator((Value)iterator); + myConditionEvaluator = new MethodEvaluator(iteratorEvaluator, + JVMNameUtil.getJVMRawText(CommonClassNames.JAVA_UTIL_ITERATOR), + "hasNext", null, + new Evaluator[0]); + myNextEvaluator = new AssignmentEvaluator(myIterationParameterEvaluator, + new MethodEvaluator(iteratorEvaluator, + JVMNameUtil.getJVMRawText(CommonClassNames.JAVA_UTIL_ITERATOR), + "next", null, + new Evaluator[0])); + return value; + } - @Override - protected Object evaluateCondition(EvaluationContextImpl context) throws EvaluateException { - if (isArray()) { - return myCurrentIndex < myArrayLength; - } - else { - Object res = myConditionEvaluator.evaluate(context); - myModifier = myConditionEvaluator.getModifier(); - return res; - } - } + @Override + protected Object evaluateCondition(EvaluationContextImpl context) throws EvaluateException { + return myConditionEvaluator.evaluate(context); + } - @Override - protected void evaluateBody(EvaluationContextImpl context) throws EvaluateException { - myNextEvaluator.evaluate(context); - super.evaluateBody(context); + @Override + protected void evaluateBody(EvaluationContextImpl context) throws EvaluateException { + myNextEvaluator.evaluate(context); + super.evaluateBody(context); + } + }.evaluate(context); + } } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IfStatementEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IfStatementEvaluator.java index 61b9b727cb1e..903f15618fa4 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IfStatementEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IfStatementEvaluator.java @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// 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.debugger.engine.evaluation.expression; import com.intellij.debugger.engine.evaluation.EvaluateException; @@ -11,19 +11,12 @@ public class IfStatementEvaluator implements Evaluator { private final Evaluator myThenEvaluator; private final Evaluator myElseEvaluator; - private Modifier myModifier; - public IfStatementEvaluator(Evaluator conditionEvaluator, Evaluator thenEvaluator, Evaluator elseEvaluator) { myConditionEvaluator = DisableGC.create(conditionEvaluator); myThenEvaluator = DisableGC.create(thenEvaluator); myElseEvaluator = elseEvaluator == null ? null : DisableGC.create(elseEvaluator); } - @Override - public Modifier getModifier() { - return myModifier; - } - @Override public Object evaluate(EvaluationContextImpl context) throws EvaluateException { Object value = myConditionEvaluator.evaluate(context); @@ -33,16 +26,13 @@ public class IfStatementEvaluator implements Evaluator { else { if (((BooleanValue)value).booleanValue()) { value = myThenEvaluator.evaluate(context); - myModifier = myThenEvaluator.getModifier(); } else { if (myElseEvaluator != null) { value = myElseEvaluator.evaluate(context); - myModifier = myElseEvaluator.getModifier(); } else { value = context.getVirtualMachineProxy().mirrorOfVoid(); - myModifier = null; } } } 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 6ec0b45c5dbd..6038b4a8da9c 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 @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. /* * Class LocalVariableEvaluator @@ -25,26 +25,32 @@ import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiVariable; import com.sun.jdi.*; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Map; -class LocalVariableEvaluator implements Evaluator { +class LocalVariableEvaluator implements ModifiableEvaluator { private static final Logger LOG = Logger.getInstance(LocalVariableEvaluator.class); private final String myLocalVariableName; - private EvaluationContextImpl myContext; - private LocalVariableProxyImpl myEvaluatedVariable; - private DecompiledLocalVariable myEvaluatedDecompiledVariable; 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 Object evaluate(EvaluationContextImpl context) throws EvaluateException { + public @NotNull ModifiableValue evaluateModifiable(EvaluationContextImpl context) throws EvaluateException { StackFrameProxyImpl frameProxy = context.getFrameProxy(); if (frameProxy == null) { throw EvaluateExceptionUtil.createEvaluateException(JavaDebuggerBundle.message("evaluation.error.no.stackframe")); @@ -66,7 +72,7 @@ class LocalVariableEvaluator implements Evaluator { variable.equals(resolveVariable(frameProxy, myLocalVariableName, context.getProject(), process))) { myEvaluatedVariable = local; myContext = context; - return frameProxy.getValue(local); + return new ModifiableValue(frameProxy.getValue(local), new MyModifier(context, local, null)); } } } @@ -83,7 +89,7 @@ class LocalVariableEvaluator implements Evaluator { if (var.getMatchedNames().contains(myLocalVariableName) || var.getDefaultName().equals(myLocalVariableName)) { myEvaluatedDecompiledVariable = var; myContext = context; - return entry.getValue(); + return new ModifiableValue(entry.getValue(), new MyModifier(context, null, var)); } } } @@ -125,54 +131,10 @@ class LocalVariableEvaluator implements Evaluator { @Override public Modifier getModifier() { - Modifier modifier = null; if ((myEvaluatedVariable != null || myEvaluatedDecompiledVariable != null) && myContext != null) { - modifier = new Modifier() { - @Override - public boolean canInspect() { - return true; - } - - @Override - public boolean canSetValue() { - return true; - } - - @Override - public void setValue(Value value) throws ClassNotLoadedException, InvalidTypeException { - StackFrameProxyImpl frameProxy = myContext.getFrameProxy(); - try { - assert frameProxy != null; - if (myEvaluatedVariable != null) { - frameProxy.setValue(myEvaluatedVariable, value); - } - else { // no debug info - LocalVariablesUtil.setValue(frameProxy.getStackFrame(), myEvaluatedDecompiledVariable, value); - } - } - catch (EvaluateException e) { - LOG.error(e); - } - } - - @Override - public Type getExpectedType() throws ClassNotLoadedException { - try { - return myEvaluatedVariable.getType(); - } - catch (EvaluateException e) { - LOG.error(e); - return null; - } - } - - @Override - public NodeDescriptorImpl getInspectItem(Project project) { - return new LocalVariableDescriptorImpl(project, myEvaluatedVariable); - } - }; + return new MyModifier(myContext, myEvaluatedVariable, myEvaluatedDecompiledVariable); } - return modifier; + return null; } private static @Nullable PsiVariable resolveVariable(final StackFrameProxy frame, @@ -191,4 +153,61 @@ class LocalVariableEvaluator implements Evaluator { public String toString() { return myLocalVariableName; } + + private static class MyModifier implements Modifier { + private final EvaluationContextImpl myContext; + private final LocalVariableProxyImpl myEvaluatedVariable; + private final DecompiledLocalVariable myEvaluatedDecompiledVariable; + + private MyModifier(EvaluationContextImpl context, + LocalVariableProxyImpl evaluatedVariable, + DecompiledLocalVariable evaluatedDecompiledVariable) { + this.myContext = context; + this.myEvaluatedVariable = evaluatedVariable; + this.myEvaluatedDecompiledVariable = evaluatedDecompiledVariable; + } + + @Override + public boolean canInspect() { + return true; + } + + @Override + public boolean canSetValue() { + return true; + } + + @Override + public void setValue(Value value) throws ClassNotLoadedException, InvalidTypeException { + StackFrameProxyImpl frameProxy = myContext.getFrameProxy(); + try { + assert frameProxy != null; + if (myEvaluatedVariable != null) { + frameProxy.setValue(myEvaluatedVariable, value); + } + else { // no debug info + LocalVariablesUtil.setValue(frameProxy.getStackFrame(), myEvaluatedDecompiledVariable, value); + } + } + catch (EvaluateException e) { + LOG.error(e); + } + } + + @Override + public Type getExpectedType() throws ClassNotLoadedException { + try { + return myEvaluatedVariable.getType(); + } + catch (EvaluateException e) { + LOG.error(e); + return null; + } + } + + @Override + public NodeDescriptorImpl getInspectItem(Project project) { + return new LocalVariableDescriptorImpl(project, myEvaluatedVariable); + } + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ModifiableEvaluator.kt b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ModifiableEvaluator.kt new file mode 100644 index 000000000000..d7e3c88fe092 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ModifiableEvaluator.kt @@ -0,0 +1,22 @@ +// 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.debugger.engine.evaluation.expression + +import com.intellij.debugger.engine.evaluation.EvaluateException +import com.intellij.debugger.engine.evaluation.EvaluationContextImpl + +interface ModifiableEvaluator : Evaluator { + @Throws(EvaluateException::class) + override fun evaluate(context: EvaluationContextImpl): Any? = evaluateModifiable(context).value + + @Throws(EvaluateException::class) + override fun evaluateModifiable(context: EvaluationContextImpl): ModifiableValue +} + +/** + * Represents a value that can be modified. This class encapsulates a value and an optional modifier + * that allows modifications to the value. + * + * @property value The value being encapsulated, which can be of any type or null. + * @property modifier The modifier associated with the value, which provides functionality for modifying the value. + */ +class ModifiableValue(val value: Any?, val modifier: Modifier?) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/PatternEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/PatternEvaluator.java index 7bcf23832dbb..087797a5d3c3 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/PatternEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/PatternEvaluator.java @@ -40,7 +40,7 @@ public class PatternEvaluator implements Evaluator { res = primitiveType.name().equals(myPrimitiveType); } if (res && myVariableEvaluator != null) { - AssignmentEvaluator.assign(myVariableEvaluator.getModifier(), value, context); + AssignmentEvaluator.assign(myVariableEvaluator.evaluateModifiable(context).getModifier(), value, context); } return res; } 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 e1e9da0f7034..ad43e62cf0c0 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 @@ -1,10 +1,11 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// 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.debugger.engine.evaluation.expression; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; +import org.jetbrains.annotations.NotNull; -public class PostfixOperationEvaluator implements Evaluator { +public class PostfixOperationEvaluator implements ModifiableEvaluator { private final Evaluator myOperandEvaluator; private final Evaluator myIncrementImpl; @@ -17,12 +18,12 @@ public class PostfixOperationEvaluator implements Evaluator { } @Override - public Object evaluate(EvaluationContextImpl context) throws EvaluateException { - final Object value = myOperandEvaluator.evaluate(context); - myModifier = myOperandEvaluator.getModifier(); + public @NotNull ModifiableValue evaluateModifiable(@NotNull EvaluationContextImpl context) throws EvaluateException { + ModifiableValue modifiableValue = myOperandEvaluator.evaluateModifiable(context); + myModifier = modifiableValue.getModifier(); Object operationResult = myIncrementImpl.evaluate(context); AssignmentEvaluator.assign(myModifier, operationResult, context); - return value; + return modifiableValue; } @Override 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 71d70952d044..f90d370d530e 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 @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// 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.debugger.engine.evaluation.expression; import com.intellij.debugger.JavaDebuggerBundle; @@ -12,14 +12,18 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.sun.jdi.Type; import com.sun.jdi.Value; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class SyntheticVariableEvaluator implements Evaluator { +public class SyntheticVariableEvaluator implements ModifiableEvaluator { private static final Logger LOG = Logger.getInstance(SyntheticVariableEvaluator.class); private final CodeFragmentEvaluator myCodeFragmentEvaluator; 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) { @@ -29,59 +33,65 @@ public class SyntheticVariableEvaluator implements Evaluator { } @Override - public Object evaluate(EvaluationContextImpl context) throws EvaluateException { - if (myTypeNameString == null && myTypeName != null) { - myTypeNameString = myTypeName.getName(context.getDebugProcess()); - } - return myCodeFragmentEvaluator.getValue(myLocalName, context.getVirtualMachineProxy()); + public @NotNull ModifiableValue evaluateModifiable(EvaluationContextImpl context) throws EvaluateException { + String typeNameString = myTypeName != null ? myTypeName.getName(context.getDebugProcess()) : null; + myTypeNameString = typeNameString; + return new ModifiableValue(myCodeFragmentEvaluator.getValue(myLocalName, context.getVirtualMachineProxy()), + new MyModifier(typeNameString)); } @Override public Modifier getModifier() { - return new Modifier() { - @Override - public boolean canInspect() { - return false; - } - - @Override - public boolean canSetValue() { - return false; - } - - @Override - public void setValue(Value value) throws EvaluateException { - if (value == null) { - if (myTypeNameString != null && DebuggerUtils.isPrimitiveType(myTypeNameString)) { - throw EvaluateExceptionUtil.createEvaluateException( - JavaDebuggerBundle.message("evaluation.error.cannot.set.primitive.to.null")); - } - } - else { - Type type = value.type(); - if (myTypeNameString != null && !DebuggerUtils.instanceOf(type, myTypeNameString)) { - throw EvaluateExceptionUtil.createEvaluateException( - JavaDebuggerBundle.message("evaluation.error.cannot.cast.object", type.name(), myTypeNameString)); - } - } - myCodeFragmentEvaluator.setValue(myLocalName, value); - } - - @Override - public Type getExpectedType() { - LOG.assertTrue(false); - return null; - } - - @Override - public NodeDescriptorImpl getInspectItem(Project project) { - return null; - } - }; + return new MyModifier(myTypeNameString); } @Override public String toString() { return myLocalName; } + + private class MyModifier implements Modifier { + private final String myTypeNameString; + + private MyModifier(String typeNameString) { this.myTypeNameString = typeNameString; } + + @Override + public boolean canInspect() { + return false; + } + + @Override + public boolean canSetValue() { + return false; + } + + @Override + public void setValue(Value value) throws EvaluateException { + if (value == null) { + if (myTypeNameString != null && DebuggerUtils.isPrimitiveType(myTypeNameString)) { + throw EvaluateExceptionUtil.createEvaluateException( + JavaDebuggerBundle.message("evaluation.error.cannot.set.primitive.to.null")); + } + } + else { + Type type = value.type(); + if (myTypeNameString != null && !DebuggerUtils.instanceOf(type, myTypeNameString)) { + throw EvaluateExceptionUtil.createEvaluateException( + JavaDebuggerBundle.message("evaluation.error.cannot.cast.object", type.name(), myTypeNameString)); + } + } + myCodeFragmentEvaluator.setValue(myLocalName, value); + } + + @Override + public Type getExpectedType() { + LOG.assertTrue(false); + return null; + } + + @Override + public NodeDescriptorImpl getInspectItem(Project project) { + return null; + } + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/TypeEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/TypeEvaluator.java index 22c3a9deb9f7..a6d936b378e1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/TypeEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/TypeEvaluator.java @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. /* * Class TypeEvaluator @@ -13,13 +13,10 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.reference.SoftReference; import com.sun.jdi.ClassLoaderReference; import com.sun.jdi.ReferenceType; import org.jetbrains.annotations.NotNull; -import java.lang.ref.WeakReference; - import static com.intellij.util.containers.ContainerUtil.filter; import static com.intellij.util.containers.ContainerUtil.getOnlyItem; @@ -28,9 +25,6 @@ public class TypeEvaluator implements Evaluator { private final JVMName myTypeName; - private WeakReference myLastResult; - private WeakReference myLastClassLoader; - public TypeEvaluator(@NotNull JVMName typeName) { myTypeName = typeName; } @@ -41,13 +35,6 @@ public class TypeEvaluator implements Evaluator { @Override public @NotNull ReferenceType evaluate(EvaluationContextImpl context) throws EvaluateException { ClassLoaderReference classLoader = context.getClassLoader(); - ReferenceType lastRes = SoftReference.dereference(myLastResult); - if (lastRes != null && classLoader == SoftReference.dereference(myLastClassLoader)) { - // if class loader is null, check that vms match - if (classLoader != null || lastRes.virtualMachine().equals(context.getVirtualMachineProxy().getVirtualMachine())) { - return lastRes; - } - } DebugProcessImpl debugProcess = context.getDebugProcess(); String typeName = myTypeName.getName(debugProcess); ReferenceType type; @@ -69,8 +56,6 @@ public class TypeEvaluator implements Evaluator { if (type == null) { throw EvaluateExceptionUtil.createEvaluateException(JavaDebuggerBundle.message("error.class.not.loaded", typeName)); } - myLastClassLoader = new WeakReference<>(classLoader); - myLastResult = new WeakReference<>(type); return type; } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/WhileStatementEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/WhileStatementEvaluator.java index 42cf333d9457..e8b534acea53 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/WhileStatementEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/WhileStatementEvaluator.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 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. - */ +// 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.debugger.engine.evaluation.expression; import com.intellij.debugger.engine.evaluation.EvaluateException; @@ -29,11 +15,6 @@ public class WhileStatementEvaluator extends LoopEvaluator { myConditionEvaluator = DisableGC.create(conditionEvaluator); } - @Override - public Modifier getModifier() { - return myConditionEvaluator.getModifier(); - } - @Override public Object evaluate(EvaluationContextImpl context) throws EvaluateException { Object value; diff --git a/plugins/kotlin/jvm-debugger/evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluatorBuilder.kt b/plugins/kotlin/jvm-debugger/evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluatorBuilder.kt index f50bb6f93426..510ed701e824 100644 --- a/plugins/kotlin/jvm-debugger/evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluatorBuilder.kt +++ b/plugins/kotlin/jvm-debugger/evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluatorBuilder.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.idea.debugger.evaluate @@ -489,8 +489,6 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, private val sourcePositi } } - override fun getModifier() = null - companion object { @get:TestOnly @get:ApiStatus.Internal