/**
   * Wrap the given expression with a logging method call. Some kinds of expressions don't like
   * being wrapped in a simple fashion and so we have to handle them specially. The
   * ExpressionTransformer doesn't have methods for each type so we check for each one here.
   *
   * <p>TODO: There are potentially other expressions which need special handling (like indexing and
   * variables). This code may be working because those types have their parent being wrapped and we
   * don't transform their children.
   *
   * @param lineNumber line number to report for this value
   * @param expression the expression whose value we want to report
   * @return an expression that computes the value and also reports it somewheres
   */
  private Expression loggingExpression(Integer lineNumber, Expression expression) {
    if (expression instanceof DeclarationExpression) {
      DeclarationExpression declarationExpression = (DeclarationExpression) expression;

      return new DeclarationExpression(
          declarationExpression.getLeftExpression(),
          declarationExpression.getOperation(),
          loggingExpression(lineNumber, declarationExpression.getRightExpression()));
    }

    if (expression instanceof BooleanExpression) {
      BooleanExpression booleanExpression = (BooleanExpression) expression;
      return new BooleanExpression(
          new MethodCallExpression(
              new VariableExpression("this"),
              "_log",
              new ArgumentListExpression(
                  new ConstantExpression(lineNumber), booleanExpression.getExpression())));
    }

    return new MethodCallExpression(
        new VariableExpression("this"),
        "_log",
        new ArgumentListExpression(new ConstantExpression(lineNumber), expression));
  }
  private void changeBaseScriptTypeFromDeclaration(
      final DeclarationExpression de, final AnnotationNode node) {
    if (de.isMultipleAssignmentDeclaration()) {
      addError(
          "Annotation " + MY_TYPE_NAME + " not supported with multiple assignment notation.", de);
      return;
    }

    if (!(de.getRightExpression() instanceof EmptyExpression)) {
      addError("Annotation " + MY_TYPE_NAME + " not supported with variable assignment.", de);
      return;
    }
    Expression value = node.getMember("value");
    if (value != null) {
      addError(
          "Annotation " + MY_TYPE_NAME + " cannot have member 'value' if used on a declaration.",
          value);
      return;
    }

    ClassNode cNode = de.getDeclaringClass();
    ClassNode baseScriptType = de.getVariableExpression().getType().getPlainNodeReference();
    de.setRightExpression(new VariableExpression("this"));

    changeBaseScriptType(de, cNode, baseScriptType);
  }
  public void visitDeclarationExpression(DeclarationExpression expression) {
    // visit right side first to avoid the usage of a
    // variable before its declaration
    expression.getRightExpression().visit(this);

    if (expression.isMultipleAssignmentDeclaration()) {
      TupleExpression list = expression.getTupleExpression();
      for (Expression e : list.getExpressions()) {
        declare((VariableExpression) e);
      }
    } else {
      declare(expression.getVariableExpression());
    }
  }
 private DeclarationExpression optimizeConstantInitialization(
     final BinaryExpression originalDeclaration,
     final Token operation,
     final ConstantExpression constant,
     final Expression leftExpression,
     final ClassNode declarationType) {
   ConstantExpression cexp =
       new ConstantExpression(
           convertConstant((Number) constant.getValue(), ClassHelper.getWrapper(declarationType)),
           true);
   cexp.setType(declarationType);
   cexp.setSourcePosition(constant);
   DeclarationExpression result = new DeclarationExpression(leftExpression, operation, cexp);
   result.setSourcePosition(originalDeclaration);
   result.copyNodeMetaData(originalDeclaration);
   return result;
 }
  protected void addError(String msg, ASTNode expr) {
    int line = expr.getLineNumber();
    int col = expr.getColumnNumber();
    // GRECLIPSE
    int start = expr.getStart();
    int end = expr.getEnd() - 1;
    if (expr instanceof ClassNode) {
      // assume we have a class declaration
      ClassNode cn = (ClassNode) expr;
      if (cn.getNameEnd() > 0) {
        start = cn.getNameStart();
        end = cn.getNameEnd();
      } else if (cn.getComponentType() != null) {
        // avoid extra whitespace after closing ]
        end--;
      }

    } else if (expr instanceof DeclarationExpression) {
      // assume that we just want to underline the variable declaration
      DeclarationExpression decl = (DeclarationExpression) expr;
      Expression lhs = decl.getLeftExpression();
      start = lhs.getStart();
      // avoid extra space before = if a variable
      end =
          lhs instanceof VariableExpression ? start + lhs.getText().length() - 1 : lhs.getEnd() - 1;
    }
    // end

    SourceUnit source = getSourceUnit();
    source
        .getErrorCollector()
        .addErrorAndContinue(
            // GRECLIPSE: start
            new SyntaxErrorMessage(
                new PreciseSyntaxException(msg + '\n', line, col, start, end), source)
            // end
            );
  }
  private void setScriptURIOnDeclaration(
      final DeclarationExpression de, final AnnotationNode node) {
    if (de.isMultipleAssignmentDeclaration()) {
      addError(
          "Annotation " + MY_TYPE_NAME + " not supported with multiple assignment notation.", de);
      return;
    }

    if (!(de.getRightExpression() instanceof EmptyExpression)) {
      addError("Annotation " + MY_TYPE_NAME + " not supported with variable assignment.", de);
      return;
    }

    URI uri = getSourceURI(node);

    if (uri == null) {
      addError("Unable to get the URI for the source of this script!", de);
    } else {
      // Set the RHS to '= URI.create("string for this URI")'.
      // That may throw an IllegalArgumentExpression wrapping the URISyntaxException.
      de.setRightExpression(getExpression(uri));
    }
  }
  @Test
  public void transformationOfAnnotationOnLocalVariable() {
    ClassNode classNode = new ClassNode("Test", 0, new ClassNode(Object.class));
    this.moduleNode.addClass(classNode);

    DeclarationExpression declarationExpression =
        new DeclarationExpression(
            new VariableExpression("test"), null, new ConstantExpression("test"));
    declarationExpression.addAnnotation(this.grabAnnotation);

    BlockStatement code =
        new BlockStatement(
            Arrays.asList((Statement) new ExpressionStatement(declarationExpression)),
            new VariableScope());

    MethodNode methodNode =
        new MethodNode(
            "test", 0, new ClassNode(Void.class), new Parameter[0], new ClassNode[0], code);

    classNode.addMethod(methodNode);

    assertGrabAnnotationHasBeenTransformed();
  }
 @Override
 public void visitDeclarationExpression(DeclarationExpression expression) {
   super.visitDeclarationExpression(expression);
   if (expression.isMultipleAssignmentDeclaration()) return;
   checkInvalidDeclarationModifier(expression, ACC_ABSTRACT, "abstract");
   checkInvalidDeclarationModifier(expression, ACC_NATIVE, "native");
   checkInvalidDeclarationModifier(expression, ACC_PRIVATE, "private");
   checkInvalidDeclarationModifier(expression, ACC_PROTECTED, "protected");
   checkInvalidDeclarationModifier(expression, ACC_PUBLIC, "public");
   checkInvalidDeclarationModifier(expression, ACC_STATIC, "static");
   checkInvalidDeclarationModifier(expression, ACC_STRICT, "strictfp");
   checkInvalidDeclarationModifier(expression, ACC_SYNCHRONIZED, "synchronized");
   checkInvalidDeclarationModifier(expression, ACC_TRANSIENT, "transient");
   checkInvalidDeclarationModifier(expression, ACC_VOLATILE, "volatile");
 }
    @Override
    public void visitDeclarationExpression(DeclarationExpression expression) {
      // LOG.debug "Transforming expression '${expression}':"

      if (expression.getLineNumber() >= 0 && expression.getLineNumber() < lineNumbers.length) {
        // LOG.debug "   start from ${expression.lineNumber} to ${lineNumbers[expression.lineNumber
        // - 1]}"
        expression.setLineNumber(lineNumbers[expression.getLineNumber() - 1]);
      }

      if (expression.getLastLineNumber() > 0
          && expression.getLastLineNumber() < lineNumbers.length) {
        // LOG.debug "   end from ${expression.lastLineNumber} to
        // ${lineNumbers[expression.lastLineNumber - 1]}"
        expression.setLastLineNumber(lineNumbers[expression.getLastLineNumber() - 1]);
      }
      super.visitDeclarationExpression(expression);
    }
 /**
  * Don't treat the LHS of a declaration as something we can wrap, just the RHS.
  *
  * @param expression
  */
 @Override
 public void visitDeclarationExpression(DeclarationExpression expression) {
   expression.getRightExpression().visit(this);
 }
 private void checkInvalidDeclarationModifier(
     DeclarationExpression expression, int modifier, String modName) {
   if ((expression.getVariableExpression().getModifiers() & modifier) != 0) {
     addError("Modifier '" + modName + "' not allowed here.", expression);
   }
 }