private MethodDeclaration createCanEqual(EclipseNode type, ASTNode source) {
    /* public boolean canEqual(final java.lang.Object other) {
     *     return other instanceof MyType;
     * }
     */
    int pS = source.sourceStart;
    int pE = source.sourceEnd;
    long p = (long) pS << 32 | pE;

    char[] otherName = "other".toCharArray();

    MethodDeclaration method =
        new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
    Eclipse.setGeneratedBy(method, source);
    method.modifiers = EclipseHandlerUtil.toEclipseModifier(AccessLevel.PUBLIC);
    method.returnType = TypeReference.baseTypeReference(TypeIds.T_boolean, 0);
    method.returnType.sourceStart = pS;
    method.returnType.sourceEnd = pE;
    Eclipse.setGeneratedBy(method.returnType, source);
    method.selector = "canEqual".toCharArray();
    method.thrownExceptions = null;
    method.typeParameters = null;
    method.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
    method.bodyStart = method.declarationSourceStart = method.sourceStart = source.sourceStart;
    method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = source.sourceEnd;
    TypeReference objectRef =
        new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] {p, p, p});
    Eclipse.setGeneratedBy(objectRef, source);
    method.arguments = new Argument[] {new Argument(otherName, 0, objectRef, Modifier.FINAL)};
    method.arguments[0].sourceStart = pS;
    method.arguments[0].sourceEnd = pE;
    Eclipse.setGeneratedBy(method.arguments[0], source);

    SingleNameReference otherRef = new SingleNameReference(otherName, p);
    Eclipse.setGeneratedBy(otherRef, source);

    SingleTypeReference typeReference =
        new SingleTypeReference(((TypeDeclaration) type.get()).name, p);
    Eclipse.setGeneratedBy(typeReference, source);

    InstanceOfExpression instanceOf = new InstanceOfExpression(otherRef, typeReference);
    instanceOf.sourceStart = pS;
    instanceOf.sourceEnd = pE;
    Eclipse.setGeneratedBy(instanceOf, source);

    ReturnStatement returnStatement = new ReturnStatement(instanceOf, pS, pE);
    Eclipse.setGeneratedBy(returnStatement, source);

    method.statements = new Statement[] {returnStatement};
    return method;
  }
Example #2
0
  /**
   * In case emulating local variables, wrap the (recovered) statements inside a try statement so as
   * to achieve local state commiting (copy local vars back to fields). The CSToCuMapper could not
   * be used, since it could have interfered with the syntax recovery specific to code snippets.
   */
  protected void consumeMethodDeclaration(boolean isNotAbstract) {
    // MethodDeclaration ::= MethodHeader MethodBody
    // AbstractMethodDeclaration ::= MethodHeader ';'

    super.consumeMethodDeclaration(isNotAbstract);

    // now we know that we have a method declaration at the top of the ast stack
    MethodDeclaration methodDecl = (MethodDeclaration) this.astStack[this.astPtr];

    // automatically wrap the last statement inside a return statement, if it is an expression
    // support have to be defined at toplevel only
    if (this.isTopLevelType()) {
      int last = methodDecl.statements == null ? -1 : methodDecl.statements.length - 1;
      if (last >= 0 && methodDecl.statements[last] instanceof Expression) {
        Expression lastExpression = (Expression) methodDecl.statements[last];
        methodDecl.statements[last] =
            new CodeSnippetReturnStatement(
                lastExpression, lastExpression.sourceStart, lastExpression.sourceEnd);
      }
    }

    int start = methodDecl.bodyStart - 1, end = start;
    long position = ((long) start << 32) + end;
    long[] positions = new long[] {position};
    if (this.evaluationContext.localVariableNames != null) {

      int varCount =
          this.evaluationContext.localVariableNames.length; // n local decls+ try statement

      // generate n local variable declarations: [type] [name] = val$[name];
      Statement[] newStatements = new Statement[varCount + 1];
      for (int i = 0; i < varCount; i++) {
        char[] trimmedTypeName = this.evaluationContext.localVariableTypeNames[i];
        int nameEnd = CharOperation.indexOf('[', trimmedTypeName);
        if (nameEnd >= 0) {
          trimmedTypeName = CharOperation.subarray(trimmedTypeName, 0, nameEnd);
        }
        nameEnd = CharOperation.indexOf(' ', trimmedTypeName);
        if (nameEnd >= 0) {
          trimmedTypeName = CharOperation.subarray(trimmedTypeName, 0, nameEnd);
        }
        TypeReference typeReference =
            new QualifiedTypeReference(CharOperation.splitOn('.', trimmedTypeName), positions);
        int dimCount =
            CharOperation.occurencesOf('[', this.evaluationContext.localVariableTypeNames[i]);
        if (dimCount > 0) {
          typeReference = this.copyDims(typeReference, dimCount);
        }
        NameReference init =
            new SingleNameReference(
                CharOperation.concat(
                    LOCAL_VAR_PREFIX, this.evaluationContext.localVariableNames[i]),
                position);
        LocalDeclaration declaration =
            new LocalDeclaration(this.evaluationContext.localVariableNames[i], start, end);
        declaration.initialization = init;
        declaration.type = typeReference;
        declaration.modifiers = this.evaluationContext.localVariableModifiers[i];
        newStatements[i] = declaration;
      }

      // generate try { [snippet] } finally { [save locals to fields] }
      // try block
      TryStatement tryStatement = new TryStatement();
      Block tryBlock = new Block(methodDecl.explicitDeclarations);
      tryBlock.sourceStart = start;
      tryBlock.sourceEnd = end;
      tryBlock.statements = methodDecl.statements; // snippet statements
      tryStatement.tryBlock = tryBlock;
      // finally block
      Block finallyBlock = new Block(0);
      finallyBlock.sourceStart = start;
      finallyBlock.sourceEnd = end;
      finallyBlock.statements = new Statement[varCount];
      for (int i = 0; i < varCount; i++) {
        finallyBlock.statements[i] =
            new Assignment(
                new SingleNameReference(
                    CharOperation.concat(
                        LOCAL_VAR_PREFIX, this.evaluationContext.localVariableNames[i]),
                    position),
                new SingleNameReference(this.evaluationContext.localVariableNames[i], position),
                (int) position);
      }
      tryStatement.finallyBlock = finallyBlock;

      newStatements[varCount] = tryStatement;
      methodDecl.statements = newStatements;
    }
  }
Example #3
0
  private MethodDeclaration createStaticConstructor(
      String name, EclipseNode type, Collection<EclipseNode> fields, ASTNode source) {
    int pS = source.sourceStart, pE = source.sourceEnd;
    long p = (long) pS << 32 | pE;

    MethodDeclaration constructor =
        new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
    Eclipse.setGeneratedBy(constructor, source);

    constructor.modifiers = PKG.toModifier(AccessLevel.PUBLIC) | Modifier.STATIC;
    TypeDeclaration typeDecl = (TypeDeclaration) type.get();
    if (typeDecl.typeParameters != null && typeDecl.typeParameters.length > 0) {
      TypeReference[] refs = new TypeReference[typeDecl.typeParameters.length];
      int idx = 0;
      for (TypeParameter param : typeDecl.typeParameters) {
        TypeReference typeRef =
            new SingleTypeReference(param.name, (long) param.sourceStart << 32 | param.sourceEnd);
        Eclipse.setGeneratedBy(typeRef, source);
        refs[idx++] = typeRef;
      }
      constructor.returnType = new ParameterizedSingleTypeReference(typeDecl.name, refs, 0, p);
    } else constructor.returnType = new SingleTypeReference(((TypeDeclaration) type.get()).name, p);
    Eclipse.setGeneratedBy(constructor.returnType, source);
    constructor.annotations = null;
    constructor.selector = name.toCharArray();
    constructor.thrownExceptions = null;
    constructor.typeParameters =
        copyTypeParams(((TypeDeclaration) type.get()).typeParameters, source);
    constructor.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
    constructor.bodyStart =
        constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart;
    constructor.bodyEnd =
        constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd;

    List<Argument> args = new ArrayList<Argument>();
    List<Expression> assigns = new ArrayList<Expression>();
    AllocationExpression statement = new AllocationExpression();
    statement.sourceStart = pS;
    statement.sourceEnd = pE;
    Eclipse.setGeneratedBy(statement, source);
    statement.type = copyType(constructor.returnType, source);

    for (EclipseNode fieldNode : fields) {
      FieldDeclaration field = (FieldDeclaration) fieldNode.get();
      long fieldPos = (((long) field.sourceStart) << 32) | field.sourceEnd;
      SingleNameReference nameRef = new SingleNameReference(field.name, fieldPos);
      Eclipse.setGeneratedBy(nameRef, source);
      assigns.add(nameRef);

      Argument argument = new Argument(field.name, fieldPos, copyType(field.type, source), 0);
      Eclipse.setGeneratedBy(argument, source);

      Annotation[] copiedAnnotations =
          copyAnnotations(
              findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN),
              findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN),
              source);
      if (copiedAnnotations.length != 0) argument.annotations = copiedAnnotations;
      args.add(new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL));
    }

    statement.arguments =
        assigns.isEmpty() ? null : assigns.toArray(new Expression[assigns.size()]);
    constructor.arguments = args.isEmpty() ? null : args.toArray(new Argument[args.size()]);
    constructor.statements =
        new Statement[] {new ReturnStatement(statement, (int) (p >> 32), (int) p)};
    Eclipse.setGeneratedBy(constructor.statements[0], source);
    return constructor;
  }
Example #4
0
  @Override
  public boolean handle(
      AnnotationValues<Synchronized> annotation, Annotation source, EclipseNode annotationNode) {
    int p1 = source.sourceStart - 1;
    int p2 = source.sourceStart - 2;
    long pos = (((long) p1) << 32) | p2;
    EclipseNode methodNode = annotationNode.up();
    if (methodNode == null
        || methodNode.getKind() != Kind.METHOD
        || !(methodNode.get() instanceof MethodDeclaration)) {
      annotationNode.addError("@Synchronized is legal only on methods.");
      return true;
    }

    MethodDeclaration method = (MethodDeclaration) methodNode.get();
    if (method.isAbstract()) {
      annotationNode.addError("@Synchronized is legal only on concrete methods.");
      return true;
    }

    char[] lockName = annotation.getInstance().value().toCharArray();
    boolean autoMake = false;
    if (lockName.length == 0) {
      autoMake = true;
      lockName = method.isStatic() ? STATIC_LOCK_NAME : INSTANCE_LOCK_NAME;
    }

    if (fieldExists(new String(lockName), methodNode) == MemberExistsResult.NOT_EXISTS) {
      if (!autoMake) {
        annotationNode.addError("The field " + new String(lockName) + " does not exist.");
        return true;
      }
      FieldDeclaration fieldDecl = new FieldDeclaration(lockName, 0, -1);
      Eclipse.setGeneratedBy(fieldDecl, source);
      fieldDecl.declarationSourceEnd = -1;

      fieldDecl.modifiers =
          (method.isStatic() ? Modifier.STATIC : 0) | Modifier.FINAL | Modifier.PRIVATE;

      // We use 'new Object[0];' because quite unlike 'new Object();', empty arrays *ARE*
      // serializable!
      ArrayAllocationExpression arrayAlloc = new ArrayAllocationExpression();
      Eclipse.setGeneratedBy(arrayAlloc, source);
      arrayAlloc.dimensions = new Expression[] {new IntLiteral(new char[] {'0'}, 0, 0)};
      Eclipse.setGeneratedBy(arrayAlloc.dimensions[0], source);
      arrayAlloc.type =
          new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] {0, 0, 0});
      Eclipse.setGeneratedBy(arrayAlloc.type, source);
      fieldDecl.type =
          new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] {0, 0, 0});
      Eclipse.setGeneratedBy(fieldDecl.type, source);
      fieldDecl.initialization = arrayAlloc;
      injectFieldSuppressWarnings(annotationNode.up().up(), fieldDecl);
    }

    if (method.statements == null) return false;

    Block block = new Block(0);
    Eclipse.setGeneratedBy(block, source);
    block.statements = method.statements;
    Expression lockVariable;
    if (method.isStatic())
      lockVariable =
          new QualifiedNameReference(
              new char[][] {methodNode.up().getName().toCharArray(), lockName},
              new long[] {pos, pos},
              p1,
              p2);
    else {
      lockVariable = new FieldReference(lockName, pos);
      ThisReference thisReference = new ThisReference(p1, p2);
      Eclipse.setGeneratedBy(thisReference, source);
      ((FieldReference) lockVariable).receiver = thisReference;
    }
    Eclipse.setGeneratedBy(lockVariable, source);

    method.statements = new Statement[] {new SynchronizedStatement(lockVariable, block, 0, 0)};
    Eclipse.setGeneratedBy(method.statements[0], source);

    methodNode.rebuild();

    return true;
  }
  private MethodDeclaration createEquals(
      EclipseNode type,
      Collection<EclipseNode> fields,
      boolean callSuper,
      ASTNode source,
      FieldAccess fieldAccess,
      boolean needsCanEqual) {
    int pS = source.sourceStart;
    int pE = source.sourceEnd;
    long p = (long) pS << 32 | pE;
    TypeDeclaration typeDecl = (TypeDeclaration) type.get();

    MethodDeclaration method =
        new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
    Eclipse.setGeneratedBy(method, source);
    method.modifiers = EclipseHandlerUtil.toEclipseModifier(AccessLevel.PUBLIC);
    method.returnType = TypeReference.baseTypeReference(TypeIds.T_boolean, 0);
    method.returnType.sourceStart = pS;
    method.returnType.sourceEnd = pE;
    Eclipse.setGeneratedBy(method.returnType, source);
    method.annotations =
        new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source)};
    method.selector = "equals".toCharArray();
    method.thrownExceptions = null;
    method.typeParameters = null;
    method.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
    method.bodyStart = method.declarationSourceStart = method.sourceStart = source.sourceStart;
    method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = source.sourceEnd;
    TypeReference objectRef =
        new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] {p, p, p});
    Eclipse.setGeneratedBy(objectRef, source);
    method.arguments =
        new Argument[] {new Argument(new char[] {'o'}, 0, objectRef, Modifier.FINAL)};
    method.arguments[0].sourceStart = pS;
    method.arguments[0].sourceEnd = pE;
    Eclipse.setGeneratedBy(method.arguments[0], source);

    List<Statement> statements = new ArrayList<Statement>();

    /* if (o == this) return true; */ {
      SingleNameReference oRef = new SingleNameReference(new char[] {'o'}, p);
      Eclipse.setGeneratedBy(oRef, source);
      ThisReference thisRef = new ThisReference(pS, pE);
      Eclipse.setGeneratedBy(thisRef, source);
      EqualExpression otherEqualsThis = new EqualExpression(oRef, thisRef, OperatorIds.EQUAL_EQUAL);
      Eclipse.setGeneratedBy(otherEqualsThis, source);

      TrueLiteral trueLiteral = new TrueLiteral(pS, pE);
      Eclipse.setGeneratedBy(trueLiteral, source);
      ReturnStatement returnTrue = new ReturnStatement(trueLiteral, pS, pE);
      Eclipse.setGeneratedBy(returnTrue, source);
      IfStatement ifOtherEqualsThis = new IfStatement(otherEqualsThis, returnTrue, pS, pE);
      Eclipse.setGeneratedBy(ifOtherEqualsThis, source);
      statements.add(ifOtherEqualsThis);
    }

    /* if (!(o instanceof MyType) return false; */ {
      SingleNameReference oRef = new SingleNameReference(new char[] {'o'}, p);
      Eclipse.setGeneratedBy(oRef, source);

      SingleTypeReference typeReference = new SingleTypeReference(typeDecl.name, p);
      Eclipse.setGeneratedBy(typeReference, source);

      InstanceOfExpression instanceOf = new InstanceOfExpression(oRef, typeReference);
      instanceOf.sourceStart = pS;
      instanceOf.sourceEnd = pE;
      Eclipse.setGeneratedBy(instanceOf, source);

      Expression notInstanceOf = new UnaryExpression(instanceOf, OperatorIds.NOT);
      Eclipse.setGeneratedBy(notInstanceOf, source);

      FalseLiteral falseLiteral = new FalseLiteral(pS, pE);
      Eclipse.setGeneratedBy(falseLiteral, source);

      ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE);
      Eclipse.setGeneratedBy(returnFalse, source);

      IfStatement ifNotInstanceOf = new IfStatement(notInstanceOf, returnFalse, pS, pE);
      Eclipse.setGeneratedBy(ifNotInstanceOf, source);
      statements.add(ifNotInstanceOf);
    }

    char[] otherName = "other".toCharArray();

    /* MyType<?> other = (MyType<?>) o; */ {
      if (!fields.isEmpty() || needsCanEqual) {
        LocalDeclaration other = new LocalDeclaration(otherName, pS, pE);
        other.modifiers |= ClassFileConstants.AccFinal;
        Eclipse.setGeneratedBy(other, source);
        char[] typeName = typeDecl.name;
        Expression targetType;
        if (typeDecl.typeParameters == null || typeDecl.typeParameters.length == 0) {
          targetType = new SingleNameReference(((TypeDeclaration) type.get()).name, p);
          Eclipse.setGeneratedBy(targetType, source);
          other.type = new SingleTypeReference(typeName, p);
          Eclipse.setGeneratedBy(other.type, source);
        } else {
          TypeReference[] typeArgs = new TypeReference[typeDecl.typeParameters.length];
          for (int i = 0; i < typeArgs.length; i++) {
            typeArgs[i] = new Wildcard(Wildcard.UNBOUND);
            typeArgs[i].sourceStart = pS;
            typeArgs[i].sourceEnd = pE;
            Eclipse.setGeneratedBy(typeArgs[i], source);
          }
          targetType = new ParameterizedSingleTypeReference(typeName, typeArgs, 0, p);
          Eclipse.setGeneratedBy(targetType, source);
          other.type =
              new ParameterizedSingleTypeReference(typeName, copyTypes(typeArgs, source), 0, p);
          Eclipse.setGeneratedBy(other.type, source);
        }
        NameReference oRef = new SingleNameReference(new char[] {'o'}, p);
        Eclipse.setGeneratedBy(oRef, source);
        other.initialization = new CastExpression(oRef, targetType);
        Eclipse.setGeneratedBy(other.initialization, source);
        statements.add(other);
      }
    }

    /* if (!other.canEqual((java.lang.Object) this)) return false; */ {
      if (needsCanEqual) {
        MessageSend otherCanEqual = new MessageSend();
        otherCanEqual.sourceStart = pS;
        otherCanEqual.sourceEnd = pE;
        Eclipse.setGeneratedBy(otherCanEqual, source);
        otherCanEqual.receiver = new SingleNameReference(otherName, p);
        Eclipse.setGeneratedBy(otherCanEqual.receiver, source);
        otherCanEqual.selector = "canEqual".toCharArray();

        ThisReference thisReference = new ThisReference(pS, pE);
        Eclipse.setGeneratedBy(thisReference, source);
        CastExpression castThisRef =
            new CastExpression(
                thisReference, generateQualifiedNameRef(source, TypeConstants.JAVA_LANG_OBJECT));
        Eclipse.setGeneratedBy(castThisRef, source);
        castThisRef.sourceStart = pS;
        castThisRef.sourceEnd = pE;

        otherCanEqual.arguments = new Expression[] {castThisRef};

        Expression notOtherCanEqual = new UnaryExpression(otherCanEqual, OperatorIds.NOT);
        Eclipse.setGeneratedBy(notOtherCanEqual, source);

        FalseLiteral falseLiteral = new FalseLiteral(pS, pE);
        Eclipse.setGeneratedBy(falseLiteral, source);

        ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE);
        Eclipse.setGeneratedBy(returnFalse, source);

        IfStatement ifNotCanEqual = new IfStatement(notOtherCanEqual, returnFalse, pS, pE);
        Eclipse.setGeneratedBy(ifNotCanEqual, source);

        statements.add(ifNotCanEqual);
      }
    }

    /* if (!super.equals(o)) return false; */
    if (callSuper) {
      MessageSend callToSuper = new MessageSend();
      callToSuper.sourceStart = pS;
      callToSuper.sourceEnd = pE;
      Eclipse.setGeneratedBy(callToSuper, source);
      callToSuper.receiver = new SuperReference(pS, pE);
      Eclipse.setGeneratedBy(callToSuper.receiver, source);
      callToSuper.selector = "equals".toCharArray();
      SingleNameReference oRef = new SingleNameReference(new char[] {'o'}, p);
      Eclipse.setGeneratedBy(oRef, source);
      callToSuper.arguments = new Expression[] {oRef};
      Expression superNotEqual = new UnaryExpression(callToSuper, OperatorIds.NOT);
      Eclipse.setGeneratedBy(superNotEqual, source);
      FalseLiteral falseLiteral = new FalseLiteral(pS, pE);
      Eclipse.setGeneratedBy(falseLiteral, source);
      ReturnStatement returnFalse = new ReturnStatement(falseLiteral, pS, pE);
      Eclipse.setGeneratedBy(returnFalse, source);
      IfStatement ifSuperEquals = new IfStatement(superNotEqual, returnFalse, pS, pE);
      Eclipse.setGeneratedBy(ifSuperEquals, source);
      statements.add(ifSuperEquals);
    }

    for (EclipseNode field : fields) {
      TypeReference fType = getFieldType(field, fieldAccess);
      char[] token = fType.getLastToken();
      Expression thisFieldAccessor = createFieldAccessor(field, fieldAccess, source);
      Expression otherFieldAccessor = createFieldAccessor(field, fieldAccess, source, otherName);

      if (fType.dimensions() == 0 && token != null) {
        if (Arrays.equals(TypeConstants.FLOAT, token)) {
          statements.add(
              generateCompareFloatOrDouble(
                  thisFieldAccessor, otherFieldAccessor, "Float".toCharArray(), source));
        } else if (Arrays.equals(TypeConstants.DOUBLE, token)) {
          statements.add(
              generateCompareFloatOrDouble(
                  thisFieldAccessor, otherFieldAccessor, "Double".toCharArray(), source));
        } else if (BUILT_IN_TYPES.contains(new String(token))) {
          EqualExpression fieldsNotEqual =
              new EqualExpression(thisFieldAccessor, otherFieldAccessor, OperatorIds.NOT_EQUAL);
          Eclipse.setGeneratedBy(fieldsNotEqual, source);
          FalseLiteral falseLiteral = new FalseLiteral(pS, pE);
          Eclipse.setGeneratedBy(falseLiteral, source);
          ReturnStatement returnStatement = new ReturnStatement(falseLiteral, pS, pE);
          Eclipse.setGeneratedBy(returnStatement, source);
          IfStatement ifStatement = new IfStatement(fieldsNotEqual, returnStatement, pS, pE);
          Eclipse.setGeneratedBy(ifStatement, source);
          statements.add(ifStatement);
        } else /* objects */ {
          NullLiteral nullLiteral = new NullLiteral(pS, pE);
          Eclipse.setGeneratedBy(nullLiteral, source);
          EqualExpression fieldIsNull =
              new EqualExpression(thisFieldAccessor, nullLiteral, OperatorIds.EQUAL_EQUAL);
          nullLiteral = new NullLiteral(pS, pE);
          Eclipse.setGeneratedBy(nullLiteral, source);
          EqualExpression otherFieldIsntNull =
              new EqualExpression(otherFieldAccessor, nullLiteral, OperatorIds.NOT_EQUAL);
          MessageSend equalsCall = new MessageSend();
          equalsCall.sourceStart = pS;
          equalsCall.sourceEnd = pE;
          Eclipse.setGeneratedBy(equalsCall, source);
          equalsCall.receiver = createFieldAccessor(field, fieldAccess, source);
          equalsCall.selector = "equals".toCharArray();
          Expression equalsArg = createFieldAccessor(field, fieldAccess, source, otherName);
          CastExpression castEqualsArg =
              new CastExpression(
                  equalsArg, generateQualifiedNameRef(source, TypeConstants.JAVA_LANG_OBJECT));
          Eclipse.setGeneratedBy(castEqualsArg, source);
          castEqualsArg.sourceStart = pS;
          castEqualsArg.sourceEnd = pE;
          equalsCall.arguments = new Expression[] {castEqualsArg};
          UnaryExpression fieldsNotEqual = new UnaryExpression(equalsCall, OperatorIds.NOT);
          fieldsNotEqual.sourceStart = pS;
          fieldsNotEqual.sourceEnd = pE;
          Eclipse.setGeneratedBy(fieldsNotEqual, source);
          ConditionalExpression fullEquals =
              new ConditionalExpression(fieldIsNull, otherFieldIsntNull, fieldsNotEqual);
          fullEquals.sourceStart = pS;
          fullEquals.sourceEnd = pE;
          Eclipse.setGeneratedBy(fullEquals, source);
          FalseLiteral falseLiteral = new FalseLiteral(pS, pE);
          Eclipse.setGeneratedBy(falseLiteral, source);
          ReturnStatement returnStatement = new ReturnStatement(falseLiteral, pS, pE);
          Eclipse.setGeneratedBy(returnStatement, source);
          IfStatement ifStatement = new IfStatement(fullEquals, returnStatement, pS, pE);
          Eclipse.setGeneratedBy(ifStatement, source);
          statements.add(ifStatement);
        }
      } else if (fType.dimensions() > 0 && token != null) {
        MessageSend arraysEqualCall = new MessageSend();
        arraysEqualCall.sourceStart = pS;
        arraysEqualCall.sourceEnd = pE;
        Eclipse.setGeneratedBy(arraysEqualCall, source);
        arraysEqualCall.receiver =
            generateQualifiedNameRef(
                source, TypeConstants.JAVA, TypeConstants.UTIL, "Arrays".toCharArray());
        if (fType.dimensions() > 1 || !BUILT_IN_TYPES.contains(new String(token))) {
          arraysEqualCall.selector = "deepEquals".toCharArray();
        } else {
          arraysEqualCall.selector = "equals".toCharArray();
        }
        arraysEqualCall.arguments = new Expression[] {thisFieldAccessor, otherFieldAccessor};
        UnaryExpression arraysNotEqual = new UnaryExpression(arraysEqualCall, OperatorIds.NOT);
        arraysNotEqual.sourceStart = pS;
        arraysNotEqual.sourceEnd = pE;
        Eclipse.setGeneratedBy(arraysNotEqual, source);
        FalseLiteral falseLiteral = new FalseLiteral(pS, pE);
        Eclipse.setGeneratedBy(falseLiteral, source);
        ReturnStatement returnStatement = new ReturnStatement(falseLiteral, pS, pE);
        Eclipse.setGeneratedBy(returnStatement, source);
        IfStatement ifStatement = new IfStatement(arraysNotEqual, returnStatement, pS, pE);
        Eclipse.setGeneratedBy(ifStatement, source);
        statements.add(ifStatement);
      }
    }

    /* return true; */ {
      TrueLiteral trueLiteral = new TrueLiteral(pS, pE);
      Eclipse.setGeneratedBy(trueLiteral, source);
      ReturnStatement returnStatement = new ReturnStatement(trueLiteral, pS, pE);
      Eclipse.setGeneratedBy(returnStatement, source);
      statements.add(returnStatement);
    }
    method.statements = statements.toArray(new Statement[statements.size()]);
    return method;
  }
  private MethodDeclaration createHashCode(
      EclipseNode type,
      Collection<EclipseNode> fields,
      boolean callSuper,
      ASTNode source,
      FieldAccess fieldAccess) {
    int pS = source.sourceStart, pE = source.sourceEnd;
    long p = (long) pS << 32 | pE;

    MethodDeclaration method =
        new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
    Eclipse.setGeneratedBy(method, source);

    method.modifiers = EclipseHandlerUtil.toEclipseModifier(AccessLevel.PUBLIC);
    method.returnType = TypeReference.baseTypeReference(TypeIds.T_int, 0);
    Eclipse.setGeneratedBy(method.returnType, source);
    method.annotations =
        new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source)};
    method.selector = "hashCode".toCharArray();
    method.thrownExceptions = null;
    method.typeParameters = null;
    method.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
    method.bodyStart = method.declarationSourceStart = method.sourceStart = source.sourceStart;
    method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = source.sourceEnd;
    method.arguments = null;

    List<Statement> statements = new ArrayList<Statement>();
    List<Expression> intoResult = new ArrayList<Expression>();

    final char[] PRIME = "PRIME".toCharArray();
    final char[] RESULT = "result".toCharArray();
    final boolean isEmpty = fields.isEmpty();

    /* final int PRIME = 31; */ {
      /* Without fields, PRIME isn't used, and that would trigger a 'local variable not used' warning. */
      if (!isEmpty || callSuper) {
        LocalDeclaration primeDecl = new LocalDeclaration(PRIME, pS, pE);
        Eclipse.setGeneratedBy(primeDecl, source);
        primeDecl.modifiers |= Modifier.FINAL;
        primeDecl.type = TypeReference.baseTypeReference(TypeIds.T_int, 0);
        primeDecl.type.sourceStart = pS;
        primeDecl.type.sourceEnd = pE;
        Eclipse.setGeneratedBy(primeDecl.type, source);
        primeDecl.initialization = new IntLiteral("31".toCharArray(), pS, pE);
        Eclipse.setGeneratedBy(primeDecl.initialization, source);
        statements.add(primeDecl);
      }
    }

    /* int result = 1; */ {
      LocalDeclaration resultDecl = new LocalDeclaration(RESULT, pS, pE);
      Eclipse.setGeneratedBy(resultDecl, source);
      resultDecl.initialization = new IntLiteral("1".toCharArray(), pS, pE);
      Eclipse.setGeneratedBy(resultDecl.initialization, source);
      resultDecl.type = TypeReference.baseTypeReference(TypeIds.T_int, 0);
      resultDecl.type.sourceStart = pS;
      resultDecl.type.sourceEnd = pE;
      Eclipse.setGeneratedBy(resultDecl.type, source);
      statements.add(resultDecl);
    }

    if (callSuper) {
      MessageSend callToSuper = new MessageSend();
      Eclipse.setGeneratedBy(callToSuper, source);
      callToSuper.sourceStart = pS;
      callToSuper.sourceEnd = pE;
      callToSuper.receiver = new SuperReference(pS, pE);
      Eclipse.setGeneratedBy(callToSuper.receiver, source);
      callToSuper.selector = "hashCode".toCharArray();
      intoResult.add(callToSuper);
    }

    int tempCounter = 0;
    for (EclipseNode field : fields) {
      TypeReference fType = getFieldType(field, fieldAccess);
      char[] token = fType.getLastToken();
      Expression fieldAccessor = createFieldAccessor(field, fieldAccess, source);
      if (fType.dimensions() == 0 && token != null) {
        if (Arrays.equals(TypeConstants.FLOAT, token)) {
          /* Float.floatToIntBits(fieldName) */
          MessageSend floatToIntBits = new MessageSend();
          floatToIntBits.sourceStart = pS;
          floatToIntBits.sourceEnd = pE;
          Eclipse.setGeneratedBy(floatToIntBits, source);
          floatToIntBits.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA_LANG_FLOAT);
          floatToIntBits.selector = "floatToIntBits".toCharArray();
          floatToIntBits.arguments = new Expression[] {fieldAccessor};
          intoResult.add(floatToIntBits);
        } else if (Arrays.equals(TypeConstants.DOUBLE, token)) {
          /* longToIntForHashCode(Double.doubleToLongBits(fieldName)) */
          MessageSend doubleToLongBits = new MessageSend();
          doubleToLongBits.sourceStart = pS;
          doubleToLongBits.sourceEnd = pE;
          Eclipse.setGeneratedBy(doubleToLongBits, source);
          doubleToLongBits.receiver =
              generateQualifiedNameRef(source, TypeConstants.JAVA_LANG_DOUBLE);
          doubleToLongBits.selector = "doubleToLongBits".toCharArray();
          doubleToLongBits.arguments = new Expression[] {fieldAccessor};
          final char[] tempName = ("temp" + ++tempCounter).toCharArray();
          LocalDeclaration tempVar = new LocalDeclaration(tempName, pS, pE);
          Eclipse.setGeneratedBy(tempVar, source);
          tempVar.initialization = doubleToLongBits;
          tempVar.type = TypeReference.baseTypeReference(TypeIds.T_long, 0);
          tempVar.type.sourceStart = pS;
          tempVar.type.sourceEnd = pE;
          Eclipse.setGeneratedBy(tempVar.type, source);
          tempVar.modifiers = Modifier.FINAL;
          statements.add(tempVar);
          SingleNameReference copy1 = new SingleNameReference(tempName, p);
          Eclipse.setGeneratedBy(copy1, source);
          SingleNameReference copy2 = new SingleNameReference(tempName, p);
          Eclipse.setGeneratedBy(copy2, source);
          intoResult.add(longToIntForHashCode(copy1, copy2, source));
        } else if (Arrays.equals(TypeConstants.BOOLEAN, token)) {
          /* booleanField ? 1231 : 1237 */
          IntLiteral int1231 = new IntLiteral("1231".toCharArray(), pS, pE);
          Eclipse.setGeneratedBy(int1231, source);
          IntLiteral int1237 = new IntLiteral("1237".toCharArray(), pS, pE);
          Eclipse.setGeneratedBy(int1237, source);
          ConditionalExpression int1231or1237 =
              new ConditionalExpression(fieldAccessor, int1231, int1237);
          Eclipse.setGeneratedBy(int1231or1237, source);
          intoResult.add(int1231or1237);
        } else if (Arrays.equals(TypeConstants.LONG, token)) {
          intoResult.add(
              longToIntForHashCode(
                  fieldAccessor, createFieldAccessor(field, fieldAccess, source), source));
        } else if (BUILT_IN_TYPES.contains(new String(token))) {
          intoResult.add(fieldAccessor);
        } else /* objects */ {
          /* this.fieldName == null ? 0 : this.fieldName.hashCode() */
          MessageSend hashCodeCall = new MessageSend();
          hashCodeCall.sourceStart = pS;
          hashCodeCall.sourceEnd = pE;
          Eclipse.setGeneratedBy(hashCodeCall, source);
          hashCodeCall.receiver = createFieldAccessor(field, fieldAccess, source);
          hashCodeCall.selector = "hashCode".toCharArray();
          NullLiteral nullLiteral = new NullLiteral(pS, pE);
          Eclipse.setGeneratedBy(nullLiteral, source);
          EqualExpression objIsNull =
              new EqualExpression(fieldAccessor, nullLiteral, OperatorIds.EQUAL_EQUAL);
          Eclipse.setGeneratedBy(objIsNull, source);
          IntLiteral int0 = new IntLiteral("0".toCharArray(), pS, pE);
          Eclipse.setGeneratedBy(int0, source);
          ConditionalExpression nullOrHashCode =
              new ConditionalExpression(objIsNull, int0, hashCodeCall);
          nullOrHashCode.sourceStart = pS;
          nullOrHashCode.sourceEnd = pE;
          Eclipse.setGeneratedBy(nullOrHashCode, source);
          intoResult.add(nullOrHashCode);
        }
      } else if (fType.dimensions() > 0 && token != null) {
        /* Arrays.deepHashCode(array)  //just hashCode for simple arrays */
        MessageSend arraysHashCodeCall = new MessageSend();
        arraysHashCodeCall.sourceStart = pS;
        arraysHashCodeCall.sourceEnd = pE;
        Eclipse.setGeneratedBy(arraysHashCodeCall, source);
        arraysHashCodeCall.receiver =
            generateQualifiedNameRef(
                source, TypeConstants.JAVA, TypeConstants.UTIL, "Arrays".toCharArray());
        if (fType.dimensions() > 1 || !BUILT_IN_TYPES.contains(new String(token))) {
          arraysHashCodeCall.selector = "deepHashCode".toCharArray();
        } else {
          arraysHashCodeCall.selector = "hashCode".toCharArray();
        }
        arraysHashCodeCall.arguments = new Expression[] {fieldAccessor};
        intoResult.add(arraysHashCodeCall);
      }
    }

    /* fold each intoResult entry into:
    result = result * PRIME + (item); */ {
      for (Expression ex : intoResult) {
        SingleNameReference resultRef = new SingleNameReference(RESULT, p);
        Eclipse.setGeneratedBy(resultRef, source);
        SingleNameReference primeRef = new SingleNameReference(PRIME, p);
        Eclipse.setGeneratedBy(primeRef, source);
        BinaryExpression multiplyByPrime =
            new BinaryExpression(resultRef, primeRef, OperatorIds.MULTIPLY);
        multiplyByPrime.sourceStart = pS;
        multiplyByPrime.sourceEnd = pE;
        Eclipse.setGeneratedBy(multiplyByPrime, source);
        BinaryExpression addItem = new BinaryExpression(multiplyByPrime, ex, OperatorIds.PLUS);
        addItem.sourceStart = pS;
        addItem.sourceEnd = pE;
        Eclipse.setGeneratedBy(addItem, source);
        resultRef = new SingleNameReference(RESULT, p);
        Eclipse.setGeneratedBy(resultRef, source);
        Assignment assignment = new Assignment(resultRef, addItem, pE);
        assignment.sourceStart = pS;
        assignment.sourceEnd = pE;
        Eclipse.setGeneratedBy(assignment, source);
        statements.add(assignment);
      }
    }

    /* return result; */ {
      SingleNameReference resultRef = new SingleNameReference(RESULT, p);
      Eclipse.setGeneratedBy(resultRef, source);
      ReturnStatement returnStatement = new ReturnStatement(resultRef, pS, pE);
      Eclipse.setGeneratedBy(returnStatement, source);
      statements.add(returnStatement);
    }
    method.statements = statements.toArray(new Statement[statements.size()]);
    return method;
  }
Example #7
0
  private MethodDeclaration createToString(
      EclipseNode type,
      Collection<EclipseNode> fields,
      boolean includeFieldNames,
      boolean callSuper,
      ASTNode source,
      FieldAccess fieldAccess) {
    String typeName = getTypeName(type);
    char[] suffix = ")".toCharArray();
    String infixS = ", ";
    char[] infix = infixS.toCharArray();
    int pS = source.sourceStart, pE = source.sourceEnd;
    long p = (long) pS << 32 | pE;
    final int PLUS = OperatorIds.PLUS;

    char[] prefix;

    if (callSuper) {
      prefix = (typeName + "(super=").toCharArray();
    } else if (fields.isEmpty()) {
      prefix = (typeName + "()").toCharArray();
    } else if (includeFieldNames) {
      prefix =
          (typeName
                  + "("
                  + new String(((FieldDeclaration) fields.iterator().next().get()).name)
                  + "=")
              .toCharArray();
    } else {
      prefix = (typeName + "(").toCharArray();
    }

    boolean first = true;
    Expression current = new StringLiteral(prefix, pS, pE, 0);
    Eclipse.setGeneratedBy(current, source);

    if (callSuper) {
      MessageSend callToSuper = new MessageSend();
      callToSuper.sourceStart = pS;
      callToSuper.sourceEnd = pE;
      Eclipse.setGeneratedBy(callToSuper, source);
      callToSuper.receiver = new SuperReference(pS, pE);
      Eclipse.setGeneratedBy(callToSuper, source);
      callToSuper.selector = "toString".toCharArray();
      current = new BinaryExpression(current, callToSuper, PLUS);
      Eclipse.setGeneratedBy(current, source);
      first = false;
    }

    for (EclipseNode field : fields) {
      TypeReference fType = getFieldType(field, fieldAccess);
      Expression fieldAccessor = createFieldAccessor(field, fieldAccess, source);

      Expression ex;
      if (fType.dimensions() > 0) {
        MessageSend arrayToString = new MessageSend();
        arrayToString.sourceStart = pS;
        arrayToString.sourceEnd = pE;
        arrayToString.receiver =
            generateQualifiedNameRef(
                source, TypeConstants.JAVA, TypeConstants.UTIL, "Arrays".toCharArray());
        arrayToString.arguments = new Expression[] {fieldAccessor};
        Eclipse.setGeneratedBy(arrayToString.arguments[0], source);
        if (fType.dimensions() > 1 || !BUILT_IN_TYPES.contains(new String(fType.getLastToken()))) {
          arrayToString.selector = "deepToString".toCharArray();
        } else {
          arrayToString.selector = "toString".toCharArray();
        }
        ex = arrayToString;
      } else {
        ex = fieldAccessor;
      }
      Eclipse.setGeneratedBy(ex, source);

      if (first) {
        current = new BinaryExpression(current, ex, PLUS);
        current.sourceStart = pS;
        current.sourceEnd = pE;
        Eclipse.setGeneratedBy(current, source);
        first = false;
        continue;
      }

      StringLiteral fieldNameLiteral;
      if (includeFieldNames) {
        char[] namePlusEqualsSign = (infixS + field.getName() + "=").toCharArray();
        fieldNameLiteral = new StringLiteral(namePlusEqualsSign, pS, pE, 0);
      } else {
        fieldNameLiteral = new StringLiteral(infix, pS, pE, 0);
      }
      Eclipse.setGeneratedBy(fieldNameLiteral, source);
      current = new BinaryExpression(current, fieldNameLiteral, PLUS);
      Eclipse.setGeneratedBy(current, source);
      current = new BinaryExpression(current, ex, PLUS);
      Eclipse.setGeneratedBy(current, source);
    }
    if (!first) {
      StringLiteral suffixLiteral = new StringLiteral(suffix, pS, pE, 0);
      Eclipse.setGeneratedBy(suffixLiteral, source);
      current = new BinaryExpression(current, suffixLiteral, PLUS);
      Eclipse.setGeneratedBy(current, source);
    }

    ReturnStatement returnStatement = new ReturnStatement(current, pS, pE);
    Eclipse.setGeneratedBy(returnStatement, source);

    MethodDeclaration method =
        new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
    Eclipse.setGeneratedBy(method, source);
    method.modifiers = toEclipseModifier(AccessLevel.PUBLIC);
    method.returnType =
        new QualifiedTypeReference(TypeConstants.JAVA_LANG_STRING, new long[] {p, p, p});
    Eclipse.setGeneratedBy(method.returnType, source);
    method.annotations =
        new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source)};
    method.arguments = null;
    method.selector = "toString".toCharArray();
    method.thrownExceptions = null;
    method.typeParameters = null;
    method.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
    method.bodyStart = method.declarationSourceStart = method.sourceStart = source.sourceStart;
    method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = source.sourceEnd;
    method.statements = new Statement[] {returnStatement};
    return method;
  }