--- /dev/null
+package org.jetbrains.concurrency;
+
+public interface ObsolescentAsyncFunction<PARAM, RESULT> extends AsyncFunction<PARAM, RESULT>, Obsolescent {
+}
\ No newline at end of file
import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.concurrency.Obsolescent;
import org.jetbrains.concurrency.Promise;
+import org.jetbrains.debugger.EvaluateContext;
import org.jetbrains.debugger.Variable;
import org.jetbrains.debugger.VariablesHost;
@NotNull
Promise<List<Variable>> getProperties();
+ @NotNull
+ Promise<List<Variable>> getProperties(@NotNull List<String> names, @NotNull EvaluateContext evaluateContext, @NotNull Obsolescent obsolescent);
+
@NotNull
VariablesHost getVariablesHost();
package org.jetbrains.debugger.values;
+import com.intellij.util.SmartList;
import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.concurrency.Obsolescent;
+import org.jetbrains.concurrency.ObsolescentAsyncFunction;
import org.jetbrains.concurrency.Promise;
+import org.jetbrains.debugger.EvaluateContext;
+import org.jetbrains.debugger.ValueModifier;
import org.jetbrains.debugger.Variable;
import org.jetbrains.debugger.VariablesHost;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
public abstract class ObjectValueBase<VALUE_LOADER extends ValueManager> extends ValueBase implements ObjectValue {
return childrenManager.get();
}
+ abstract class MyObsolescentAsyncFunction<PARAM, RESULT> implements ObsolescentAsyncFunction<PARAM, RESULT> {
+ private final Obsolescent obsolescent;
+
+ MyObsolescentAsyncFunction(@NotNull Obsolescent obsolescent) {
+ this.obsolescent = obsolescent;
+ }
+
+ @Override
+ public boolean isObsolete() {
+ return obsolescent.isObsolete() || childrenManager.valueManager.isObsolete();
+ }
+ }
+
+ @NotNull
+ @Override
+ public Promise<List<Variable>> getProperties(@NotNull final List<String> names, @NotNull final EvaluateContext evaluateContext, @NotNull final Obsolescent obsolescent) {
+ return getProperties()
+ .then(new MyObsolescentAsyncFunction<List<Variable>, List<Variable>>(obsolescent) {
+ @NotNull
+ @Override
+ public Promise<List<Variable>> fun(List<Variable> variables) {
+ final List<Variable> properties = new SmartList<Variable>();
+ int getterCount = 0;
+ for (Variable property : variables) {
+ if (!property.isReadable() || !names.contains(property.getName())) {
+ continue;
+ }
+
+ if (!properties.isEmpty()) {
+ Collections.sort(properties, new Comparator<Variable>() {
+ @Override
+ public int compare(@NotNull Variable o1, @NotNull Variable o2) {
+ return names.indexOf(o1.getName()) - names.indexOf(o2.getName());
+ }
+ });
+ }
+
+ properties.add(property);
+ if (property.getValue() == null) {
+ getterCount++;
+ }
+ }
+
+ if (getterCount == 0) {
+ return Promise.resolve(properties);
+ }
+ else {
+ List<Promise<?>> promises = new SmartList<Promise<?>>();
+ for (Variable variable : properties) {
+ if (variable.getValue() == null) {
+ ValueModifier valueModifier = variable.getValueModifier();
+ assert valueModifier != null;
+ promises.add(valueModifier.evaluateGet(variable, evaluateContext));
+ }
+ }
+ return Promise.all(promises, properties);
+ }
+ }
+ });
+ }
+
@Nullable
@Override
public String getValueString() {
promise.done(new ValueNodeConsumer<Void>(node) {
@Override
public void consume(Void ignored) {
- callFrame.getReceiverVariable().done(new Consumer<Variable>() {
- @Override
- public void consume(Variable variable) {
- if (!node.isObsolete()) {
+ callFrame.getReceiverVariable()
+ .done(new Consumer<Variable>() {
+ @Override
+ public void consume(Variable variable) {
node.addChildren(variable == null ? XValueChildrenList.EMPTY : XValueChildrenList.singleton(new VariableView(variable, context)), true);
}
- }
- }).rejected(new Consumer<Throwable>() {
- @Override
- public void consume(@Nullable Throwable error) {
- if (!node.isObsolete()) {
- node.addChildren(XValueChildrenList.EMPTY, true);
+ })
+ .rejected(new Consumer<Throwable>() {
+ @Override
+ public void consume(@Nullable Throwable error) {
+ if (!node.isObsolete()) {
+ node.addChildren(XValueChildrenList.EMPTY, true);
+ }
}
- }
- });
+ });
}
});
}
import org.jetbrains.annotations.NotNull;
import org.jetbrains.concurrency.AsyncFunction;
+import org.jetbrains.concurrency.Obsolescent;
public abstract class ValueNodeAsyncFunction<PARAM, RESULT> implements AsyncFunction<PARAM, RESULT>, org.jetbrains.concurrency.Obsolescent {
- private final com.intellij.xdebugger.Obsolescent node;
+ private final Obsolescent node;
- protected ValueNodeAsyncFunction(@NotNull com.intellij.xdebugger.Obsolescent node) {
+ protected ValueNodeAsyncFunction(@NotNull Obsolescent node) {
this.node = node;
}
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.util.Consumer;
+import com.intellij.util.PairConsumer;
import com.intellij.util.SmartList;
import com.intellij.util.ThreeState;
import com.intellij.xdebugger.XSourcePositionWrapper;
@NotNull
private Promise<Void> computeNamedProperties(@NotNull final ObjectValue value, @NotNull final XCompositeNode node, final boolean isLastChildren) {
- // start properties loading to achieve, possibly, parallel execution (properties loading & member filter computation)
- final Promise<List<Variable>> properties = value.getProperties();
- return getMemberFilter()
- .then(new ValueNodeAsyncFunction<MemberFilter, Void>(node) {
- @NotNull
- @Override
- public Promise<Void> fun(MemberFilter memberFilter) {
- VariableView.this.memberFilter = memberFilter;
- return properties.then(new ValueNodeAsyncFunction<List<Variable>, Void>(node) {
- @NotNull
- @Override
- public Promise<Void> fun(List<Variable> variables) {
- if (value.getType() == ValueType.ARRAY && !(value instanceof ArrayValue)) {
- computeArrayRanges(variables, node);
- return Promise.DONE;
- }
-
- FunctionValue functionValue = value instanceof FunctionValue ? (FunctionValue)value : null;
- if (functionValue != null && functionValue.hasScopes() == ThreeState.NO) {
- functionValue = null;
- }
-
- remainingChildren = Variables.processNamedObjectProperties(variables, node, VariableView.this, VariableView.this.memberFilter, XCompositeNode.MAX_CHILDREN_TO_SHOW,
- isLastChildren && functionValue == null);
- if (remainingChildren != null) {
- remainingChildrenOffset = XCompositeNode.MAX_CHILDREN_TO_SHOW;
- }
-
- if (functionValue != null) {
- // we pass context as variable context instead of this variable value - we cannot watch function scopes variables, so, this variable name doesn't matter
- node.addChildren(XValueChildrenList.bottomGroup(new FunctionScopesValueGroup(functionValue, context)), isLastChildren);
- }
- return Promise.DONE;
- }
- });
+ return Variables.processVariables(this, value.getProperties(), node, new PairConsumer<MemberFilter, List<Variable>>() {
+ @Override
+ public void consume(MemberFilter memberFilter, List<Variable> variables) {
+ if (value.getType() == ValueType.ARRAY && !(value instanceof ArrayValue)) {
+ computeArrayRanges(variables, node);
+ return;
}
- });
+
+ FunctionValue functionValue = value instanceof FunctionValue ? (FunctionValue)value : null;
+ if (functionValue != null && functionValue.hasScopes() == ThreeState.NO) {
+ functionValue = null;
+ }
+
+ remainingChildren = Variables.processNamedObjectProperties(variables, node, VariableView.this, VariableView.this.memberFilter, XCompositeNode.MAX_CHILDREN_TO_SHOW,
+ isLastChildren && functionValue == null);
+ if (remainingChildren != null) {
+ remainingChildrenOffset = XCompositeNode.MAX_CHILDREN_TO_SHOW;
+ }
+
+ if (functionValue != null) {
+ // we pass context as variable context instead of this variable value - we cannot watch function scopes variables, so, this variable name doesn't matter
+ node.addChildren(XValueChildrenList.bottomGroup(new FunctionScopesValueGroup(functionValue, context)), isLastChildren);
+ }
+ }
+ });
}
private void computeArrayRanges(@NotNull List<Variable> properties, @NotNull XCompositeNode node) {
package org.jetbrains.debugger;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.PairConsumer;
import com.intellij.util.SmartList;
import com.intellij.xdebugger.frame.XCompositeNode;
import com.intellij.xdebugger.frame.XValueChildrenList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.concurrency.Obsolescent;
+import org.jetbrains.concurrency.ObsolescentFunction;
import org.jetbrains.concurrency.Promise;
import org.jetbrains.debugger.values.Value;
import org.jetbrains.debugger.values.ValueType;
};
@NotNull
- public static Promise<Void> processScopeVariables(@NotNull final Scope scope,
- @NotNull final XCompositeNode node,
- @NotNull final VariableContext context,
- final boolean isLast) {
+ public static Promise<Void> processVariables(@NotNull final VariableContext context,
+ @NotNull final Promise<List<Variable>> variables,
+ @NotNull final Obsolescent obsolescent,
+ @NotNull final PairConsumer<MemberFilter, List<Variable>> consumer) {
+ // start properties loading to achieve, possibly, parallel execution (properties loading & member filter computation)
return context.getMemberFilter()
- .then(new ValueNodeAsyncFunction<MemberFilter, Void>(node) {
+ .then(new ValueNodeAsyncFunction<MemberFilter, Void>(obsolescent) {
@NotNull
@Override
public Promise<Void> fun(final MemberFilter memberFilter) {
- return scope.getVariablesHost().get()
- .then(new ValueNodeAsyncFunction<List<Variable>, Void>(node) {
- @NotNull
- @Override
- public Promise<Void> fun(List<Variable> variables) {
- Collection<Variable> additionalVariables = memberFilter.getAdditionalVariables();
- List<Variable> properties = new ArrayList<Variable>(variables.size() + additionalVariables.size());
- List<Variable> functions = new SmartList<Variable>();
- for (Variable variable : variables) {
- if (memberFilter.isMemberVisible(variable, false)) {
- Value value = variable.getValue();
- if (value != null &&
- value.getType() == ValueType.FUNCTION &&
- value.getValueString() != null &&
- !UNNAMED_FUNCTION_PATTERN.matcher(value.getValueString()).lookingAt()) {
- functions.add(variable);
- }
- else {
- properties.add(variable);
- }
- }
- }
+ return variables.then(new ObsolescentFunction<List<Variable>, Void>() {
+ @Override
+ public boolean isObsolete() {
+ return obsolescent.isObsolete();
+ }
+
+ @Override
+ public Void fun(List<Variable> variables) {
+ consumer.consume(memberFilter, variables);
+ return null;
+ }
+ });
+ }
+ });
+ }
- Comparator<Variable> comparator = memberFilter.hasNameMappings() ? new Comparator<Variable>() {
- @Override
- public int compare(@NotNull Variable o1, @NotNull Variable o2) {
- return naturalCompare(memberFilter.getName(o1), memberFilter.getName(o2));
- }
- } : NATURAL_NAME_COMPARATOR;
+ @NotNull
+ public static Promise<Void> processScopeVariables(@NotNull final Scope scope,
+ @NotNull final XCompositeNode node,
+ @NotNull final VariableContext context,
+ final boolean isLast) {
+ return processVariables(context, scope.getVariablesHost().get(), node, new PairConsumer<MemberFilter, List<Variable>>() {
+ @Override
+ public void consume(final MemberFilter memberFilter, List<Variable> variables) {
+ Collection<Variable> additionalVariables = memberFilter.getAdditionalVariables();
+ List<Variable> properties = new ArrayList<Variable>(variables.size() + additionalVariables.size());
+ List<Variable> functions = new SmartList<Variable>();
+ for (Variable variable : variables) {
+ if (memberFilter.isMemberVisible(variable, false)) {
+ Value value = variable.getValue();
+ if (value != null &&
+ value.getType() == ValueType.FUNCTION &&
+ value.getValueString() != null &&
+ !UNNAMED_FUNCTION_PATTERN.matcher(value.getValueString()).lookingAt()) {
+ functions.add(variable);
+ }
+ else {
+ properties.add(variable);
+ }
+ }
+ }
- Collections.sort(properties, comparator);
- Collections.sort(functions, comparator);
+ Comparator<Variable> comparator = memberFilter.hasNameMappings() ? new Comparator<Variable>() {
+ @Override
+ public int compare(@NotNull Variable o1, @NotNull Variable o2) {
+ return naturalCompare(memberFilter.getName(o1), memberFilter.getName(o2));
+ }
+ } : NATURAL_NAME_COMPARATOR;
- addAditionalVariables(variables, additionalVariables, properties, memberFilter);
+ Collections.sort(properties, comparator);
+ Collections.sort(functions, comparator);
- if (!properties.isEmpty()) {
- node.addChildren(createVariablesList(properties, context, memberFilter), functions.isEmpty() && isLast);
- }
+ addAditionalVariables(variables, additionalVariables, properties, memberFilter);
- if (!functions.isEmpty()) {
- node.addChildren(XValueChildrenList.bottomGroup(new VariablesGroup("Functions", functions, context)), isLast);
- }
- else if (isLast && properties.isEmpty()) {
- node.addChildren(XValueChildrenList.EMPTY, true);
- }
+ if (!properties.isEmpty()) {
+ node.addChildren(createVariablesList(properties, context, memberFilter), functions.isEmpty() && isLast);
+ }
- return Promise.DONE;
- }
- });
+ if (!functions.isEmpty()) {
+ node.addChildren(XValueChildrenList.bottomGroup(new VariablesGroup("Functions", functions, context)), isLast);
}
- });
+ else if (isLast && properties.isEmpty()) {
+ node.addChildren(XValueChildrenList.EMPTY, true);
+ }
+ }
+ });
}
@Nullable
--- /dev/null
+package org.jetbrains.jsonProtocol;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.io.JsonReaderEx;
+
+import java.util.Map;
+
+public final class MapFactory<T> extends ObjectFactory<Map<String, T>> {
+ private final ObjectFactory<T> valueFactory;
+
+ public MapFactory(@NotNull ObjectFactory<T> valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ @Override
+ public Map<String, T> read(JsonReaderEx reader) {
+ return JsonReaders.readMap(reader, valueFactory);
+ }
+}
}
out.append(')');
}
+
+ @Override
+ void writeArrayReadCode(@NotNull ClassScope scope, boolean subtyping, @NotNull TextOutput out) {
+ beginReadCall("ObjectArray", subtyping, out);
+ out.comma().append("new org.jetbrains.jsonProtocol.MapFactory(");
+ assert componentParser != null;
+ ((ObjectValueReader)componentParser).writeFactoryNewExpression(scope, out);
+ out.append("))");
+ }
}
}
void writeFactoryArgument(@NotNull ClassScope scope, @NotNull TextOutput out) {
- out.comma().append("new ").append(scope.requireFactoryGenerationAndGetName(refToType.type)).append(Util.TYPE_FACTORY_NAME_POSTFIX).append("()");
+ out.comma();
+ writeFactoryNewExpression(scope, out);
+ }
+
+ void writeFactoryNewExpression(@NotNull ClassScope scope, @NotNull TextOutput out) {
+ out.append("new ").append(scope.requireFactoryGenerationAndGetName(refToType.type)).append(Util.TYPE_FACTORY_NAME_POSTFIX).append("()");
}
}
else {
out.append("if (name == null)").openBlock();
{
- out.append("if (reader.beginObject().hasNext())").openBlock();
+ out.append("if (reader.hasNext() && reader.beginObject().hasNext())").openBlock();
{
out.append("name = reader.nextName()").semi();
}