@Override
 public void visit(Function obj) {
   preVisitVisitor(obj);
   Expression[] args = obj.getArgs();
   if (args != null) {
     for (int i = 0; i < args.length; i++) {
       visitNode(args[i]);
     }
   }
   postVisitVisitor(obj);
 }
  private void modifyLanguageObject(
      Object theObject, LanguageObject theNewValue, boolean retainSelection) {
    CoreArgCheck.isNotNull(theNewValue); // should not be null when modifying

    //
    // set the parent object to reflect the change in it's child. parent's can't be undefined
    //

    Object newSelection = StructuredSelection.EMPTY;
    LanguageObject parent = (LanguageObject) contentProvider.getParent(theObject);

    Object newValue = theNewValue;

    if (parent == null) {
      // root language object
      setLanguageObject((LanguageObject) newValue);
      refresh(true);
      newSelection = contentProvider.getRoot();
      expandToLevel(newSelection, ALL_LEVELS);

      if (newSelection instanceof Function) {
        Function function = (Function) newSelection;

        if (function.getArgs().length > 0) {
          newSelection = contentProvider.getChildAt(0, function);
        }
      }
    } else if (parent instanceof Function) {
      // set the arg to new value in parent
      int index = contentProvider.getChildIndex(theObject);

      Expression[] args = ((Function) parent).getArgs();
      args[index] = (Expression) newValue;

      refresh(true);
      expandToLevel(parent, ALL_LEVELS);

      newSelection = contentProvider.getChildAt(index, parent);

      if (!retainSelection) {
        if (newSelection instanceof Function) {
          // if function arg change to be a function, select first function arg
          if (contentProvider.getChildCount(newSelection) > 0) {
            newSelection = contentProvider.getChildAt(0, newSelection);
          }
        } else {
          // select next sibling function arg if exists
          if ((args.length - 1) > index) {
            newSelection = contentProvider.getChildAt(index + 1, parent);
          } else if (index > 0) {
            newSelection = contentProvider.getChildAt(0, parent);
          } else {
            newSelection = contentProvider.getChildAt(index, parent);
          }
        }
      }
    } else if (parent instanceof Criteria) {
      // theLangObj must also be a Criteria
      // since NotCriteria aren't really edited in the editor (their contained criteria is). Need to
      // save the state in order to restore it when modifying
      Criteria newCriteria = (Criteria) newValue;
      int index = contentProvider.getChildIndex(theObject);

      if ((parent instanceof CompoundCriteria) || (parent instanceof NotCriteria)) {
        CompoundCriteria compoundCriteria = null;

        if (parent instanceof CompoundCriteria) {
          compoundCriteria = (CompoundCriteria) parent;
        } else {
          compoundCriteria = (CompoundCriteria) ((NotCriteria) parent).getCriteria();
        }

        List criteriaCollection = compoundCriteria.getCriteria();
        criteriaCollection.set(index, newCriteria);
        refresh(true);

        if (retainSelection) {
          newSelection = criteriaCollection.get(index);
        } else {
          // set selection to next sibling criteria or to the first sibling
          if ((criteriaCollection.size() - 1) > index) {
            newSelection = criteriaCollection.get(index + 1);
          } else if (index > 0) {
            newSelection = criteriaCollection.get(0);
          } else {
            newSelection = contentProvider.getChildAt(index + 1, parent);
          }
        }
      } else {
        CoreArgCheck.isTrue(
            false,
            Util.getString(
                PREFIX + "unexpectedType", // $NON-NLS-1$
                new Object[] {
                  "modifyLanguageObject", //$NON-NLS-1$
                  parent.getClass().getName()
                }));
      }

      expandToLevel(parent, ALL_LEVELS);
    }

    // select next node
    setSelection(
        (newSelection == null) ? StructuredSelection.EMPTY : new StructuredSelection(newSelection));
  }