예제 #1
0
  @Override
  public void buildChildren(
      final Value value, final ChildrenBuilder builder, final EvaluationContext evaluationContext) {
    DebuggerManagerThreadImpl.assertIsManagerThread();
    final ValueDescriptorImpl parentDescriptor =
        (ValueDescriptorImpl) builder.getParentDescriptor();
    final NodeManager nodeManager = builder.getNodeManager();
    final NodeDescriptorFactory nodeDescriptorFactory = builder.getDescriptorManager();

    List<DebuggerTreeNode> children = new ArrayList<>();
    if (value instanceof ObjectReference) {
      final ObjectReference objRef = (ObjectReference) value;
      final ReferenceType refType = objRef.referenceType();
      // default ObjectReference processing
      List<Field> fields = refType.allFields();
      if (!fields.isEmpty()) {
        Set<String> names = new HashSet<>();
        for (Field field : fields) {
          if (shouldDisplay(evaluationContext, objRef, field)) {
            FieldDescriptor fieldDescriptor =
                createFieldDescriptor(
                    parentDescriptor, nodeDescriptorFactory, objRef, field, evaluationContext);
            String name = fieldDescriptor.getName();
            if (names.contains(name)) {
              fieldDescriptor.putUserData(FieldDescriptor.SHOW_DECLARING_TYPE, Boolean.TRUE);
            } else {
              names.add(name);
            }
            children.add(nodeManager.createNode(fieldDescriptor, evaluationContext));
          }
        }

        if (children.isEmpty()) {
          children.add(
              nodeManager.createMessageNode(
                  DebuggerBundle.message("message.node.class.no.fields.to.display")));
        } else if (XDebuggerSettingsManager.getInstance().getDataViewSettings().isSortValues()) {
          children.sort(NodeManagerImpl.getNodeComparator());
        }
      } else {
        children.add(
            nodeManager.createMessageNode(MessageDescriptor.CLASS_HAS_NO_FIELDS.getLabel()));
      }
    }
    builder.setChildren(children);
  }
  private static class VariablesCollector extends JavaRecursiveElementVisitor {
    private final Set<String> myVisibleLocals;
    private final TextRange myLineRange;
    private final Set<TextWithImports> myExpressions = new HashSet<TextWithImports>();
    private final Set<String> myVars = new HashSet<String>();
    private final boolean myCollectExpressions =
        XDebuggerSettingsManager.getInstance().getDataViewSettings().isAutoExpressions();

    public VariablesCollector(Set<String> visibleLocals, TextRange lineRange) {
      myVisibleLocals = visibleLocals;
      myLineRange = lineRange;
    }

    public Set<String> getVars() {
      return myVars;
    }

    public Set<TextWithImports> getExpressions() {
      return myExpressions;
    }

    @Override
    public void visitElement(final PsiElement element) {
      if (myLineRange.intersects(element.getTextRange())) {
        super.visitElement(element);
      }
    }

    @Override
    public void visitMethodCallExpression(final PsiMethodCallExpression expression) {
      if (myCollectExpressions) {
        final PsiMethod psiMethod = expression.resolveMethod();
        if (psiMethod != null
            && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(expression, myVisibleLocals)) {
          myExpressions.add(new TextWithImportsImpl(expression));
        }
      }
      super.visitMethodCallExpression(expression);
    }

    @Override
    public void visitReferenceExpression(final PsiReferenceExpression reference) {
      if (myLineRange.intersects(reference.getTextRange())) {
        final PsiElement psiElement = reference.resolve();
        if (psiElement instanceof PsiVariable) {
          final PsiVariable var = (PsiVariable) psiElement;
          if (var instanceof PsiField) {
            if (myCollectExpressions
                && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(
                    reference, myVisibleLocals)) {
              /*
              if (var instanceof PsiEnumConstant && reference.getQualifier() == null) {
                final PsiClass enumClass = ((PsiEnumConstant)var).getContainingClass();
                if (enumClass != null) {
                  final PsiExpression expression = JavaPsiFacade.getInstance(var.getProject()).getParserFacade().createExpressionFromText(enumClass.getName() + "." + var.getName(), var);
                  final PsiReference ref = expression.getReference();
                  if (ref != null) {
                    ref.bindToElement(var);
                    myExpressions.add(new TextWithImportsImpl(expression));
                  }
                }
              }
              else {
                myExpressions.add(new TextWithImportsImpl(reference));
              }
              */
              final PsiModifierList modifierList = var.getModifierList();
              boolean isConstant =
                  (var instanceof PsiEnumConstant)
                      || (modifierList != null
                          && modifierList.hasModifierProperty(PsiModifier.STATIC)
                          && modifierList.hasModifierProperty(PsiModifier.FINAL));
              if (!isConstant) {
                myExpressions.add(new TextWithImportsImpl(reference));
              }
            }
          } else {
            if (myVisibleLocals.contains(var.getName())) {
              myVars.add(var.getName());
            } else {
              // fix for variables used in inner classes
              if (!Comparing.equal(
                  PsiTreeUtil.getParentOfType(reference, PsiClass.class),
                  PsiTreeUtil.getParentOfType(var, PsiClass.class))) {
                myExpressions.add(new TextWithImportsImpl(reference));
              }
            }
          }
        }
      }
      super.visitReferenceExpression(reference);
    }

    @Override
    public void visitArrayAccessExpression(final PsiArrayAccessExpression expression) {
      if (myCollectExpressions
          && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(expression, myVisibleLocals)) {
        myExpressions.add(new TextWithImportsImpl(expression));
      }
      super.visitArrayAccessExpression(expression);
    }

    @Override
    public void visitParameter(final PsiParameter parameter) {
      processVariable(parameter);
      super.visitParameter(parameter);
    }

    @Override
    public void visitLocalVariable(final PsiLocalVariable variable) {
      processVariable(variable);
      super.visitLocalVariable(variable);
    }

    private void processVariable(final PsiVariable variable) {
      if (myLineRange.intersects(variable.getTextRange())
          && myVisibleLocals.contains(variable.getName())) {
        myVars.add(variable.getName());
      }
    }

    @Override
    public void visitClass(final PsiClass aClass) {
      // Do not step in to local and anonymous classes...
    }
  }
  // copied from FrameVariablesTree
  private void buildVariables(
      DebuggerContextImpl debuggerContext,
      final EvaluationContextImpl evaluationContext,
      @NotNull DebugProcessImpl debugProcess,
      XValueChildrenList children,
      ObjectReference thisObjectReference,
      Location location)
      throws EvaluateException {
    final Set<String> visibleLocals = new HashSet<String>();
    if (NodeRendererSettings.getInstance().getClassRenderer().SHOW_VAL_FIELDS_AS_LOCAL_VARIABLES) {
      if (thisObjectReference != null
          && debugProcess.getVirtualMachineProxy().canGetSyntheticAttribute()) {
        final ReferenceType thisRefType = thisObjectReference.referenceType();
        if (thisRefType instanceof ClassType
            && location != null
            && thisRefType.equals(location.declaringType())
            && thisRefType.name().contains("$")) { // makes sense for nested classes only
          for (Field field : thisRefType.fields()) {
            if (DebuggerUtils.isSynthetic(field)
                && StringUtil.startsWith(
                    field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) {
              final FieldDescriptorImpl fieldDescriptor =
                  myNodeManager.getFieldDescriptor(myDescriptor, thisObjectReference, field);
              children.add(JavaValue.create(fieldDescriptor, evaluationContext, myNodeManager));
              visibleLocals.add(fieldDescriptor.calcValueName());
            }
          }
        }
      }
    }

    boolean myAutoWatchMode = DebuggerSettings.getInstance().AUTO_VARIABLES_MODE;
    if (evaluationContext == null) {
      return;
    }
    final SourcePosition sourcePosition = debuggerContext.getSourcePosition();
    if (sourcePosition == null) {
      return;
    }

    try {
      if (!XDebuggerSettingsManager.getInstance().getDataViewSettings().isAutoExpressions()
          && !myAutoWatchMode) {
        // optimization
        superBuildVariables(evaluationContext, children);
      } else {
        final Map<String, LocalVariableProxyImpl> visibleVariables =
            getVisibleVariables(getStackFrameProxy());
        final Pair<Set<String>, Set<TextWithImports>> usedVars =
            ApplicationManager.getApplication()
                .runReadAction(
                    new Computable<Pair<Set<String>, Set<TextWithImports>>>() {
                      @Override
                      public Pair<Set<String>, Set<TextWithImports>> compute() {
                        return findReferencedVars(
                            ContainerUtil.union(visibleVariables.keySet(), visibleLocals),
                            sourcePosition);
                      }
                    });
        // add locals
        if (myAutoWatchMode) {
          for (String var : usedVars.first) {
            LocalVariableProxyImpl local = visibleVariables.get(var);
            if (local != null) {
              children.add(
                  JavaValue.create(
                      myNodeManager.getLocalVariableDescriptor(null, local),
                      evaluationContext,
                      myNodeManager));
            }
          }
        } else {
          superBuildVariables(evaluationContext, children);
        }
        final EvaluationContextImpl evalContextCopy =
            evaluationContext.createEvaluationContext(evaluationContext.getThisObject());
        evalContextCopy.setAutoLoadClasses(false);

        final Set<TextWithImports> extraVars =
            computeExtraVars(usedVars, sourcePosition, evaluationContext);

        // add extra vars
        addToChildrenFrom(extraVars, children, evaluationContext);

        // add expressions
        addToChildrenFrom(usedVars.second, children, evalContextCopy);
      }
    } catch (EvaluateException e) {
      if (e.getCause() instanceof AbsentInformationException) {
        children.add(
            new DummyMessageValueNode(
                MessageDescriptor.LOCAL_VARIABLES_INFO_UNAVAILABLE.getLabel(),
                XDebuggerUIConstants.INFORMATION_MESSAGE_ICON));
        // trying to collect values from variable slots
        try {
          for (Map.Entry<DecompiledLocalVariable, Value> entry :
              LocalVariablesUtil.fetchValues(getStackFrameProxy(), debugProcess).entrySet()) {
            children.add(
                JavaValue.create(
                    myNodeManager.getArgumentValueDescriptor(
                        null, entry.getKey(), entry.getValue()),
                    evaluationContext,
                    myNodeManager));
          }
        } catch (Exception ex) {
          LOG.info(ex);
        }
      } else {
        throw e;
      }
    }
  }