示例#1
0
 static List<Extension> getApplicableExtensionMethods(
     EclipseNode typeNode, Annotation ann, TypeBinding receiverType) {
   List<Extension> extensions = new ArrayList<Extension>();
   if ((typeNode != null) && (ann != null) && (receiverType != null)) {
     BlockScope blockScope = ((TypeDeclaration) typeNode.get()).initializerScope;
     EclipseNode annotationNode = typeNode.getNodeFor(ann);
     AnnotationValues<ExtensionMethod> annotation =
         createAnnotation(ExtensionMethod.class, annotationNode);
     boolean suppressBaseMethods = false;
     try {
       suppressBaseMethods = annotation.getInstance().suppressBaseMethods();
     } catch (AnnotationValueDecodeFail fail) {
       fail.owner.setError(fail.getMessage(), fail.idx);
     }
     for (Object extensionMethodProvider : annotation.getActualExpressions("value")) {
       if (extensionMethodProvider instanceof ClassLiteralAccess) {
         TypeBinding binding =
             ((ClassLiteralAccess) extensionMethodProvider).type.resolveType(blockScope);
         if (binding == null) continue;
         if (!binding.isClass() && !binding.isEnum()) continue;
         Extension e = new Extension();
         e.extensionMethods =
             getApplicableExtensionMethodsDefinedInProvider(
                 typeNode, (ReferenceBinding) binding, receiverType);
         e.suppressBaseMethods = suppressBaseMethods;
         extensions.add(e);
       }
     }
   }
   return extensions;
 }
示例#2
0
  @Override
  public void handle(
      AnnotationValues<EqualsAndHashCode> annotation, JCAnnotation ast, JavacNode annotationNode) {
    deleteAnnotationIfNeccessary(annotationNode, EqualsAndHashCode.class);
    EqualsAndHashCode ann = annotation.getInstance();
    List<String> excludes = List.from(ann.exclude());
    List<String> includes = List.from(ann.of());
    JavacNode typeNode = annotationNode.up();

    checkForBogusFieldNames(typeNode, annotation);

    Boolean callSuper = ann.callSuper();
    if (!annotation.isExplicit("callSuper")) callSuper = null;
    if (!annotation.isExplicit("exclude")) excludes = null;
    if (!annotation.isExplicit("of")) includes = null;

    if (excludes != null && includes != null) {
      excludes = null;
      annotation.setWarning(
          "exclude",
          "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored.");
    }

    FieldAccess fieldAccess = ann.doNotUseGetters() ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;

    generateMethods(typeNode, annotationNode, excludes, includes, callSuper, true, fieldAccess);
  }
示例#3
0
  public boolean handle(
      AnnotationValues<ToString> annotation, Annotation ast, EclipseNode annotationNode) {
    ToString ann = annotation.getInstance();
    List<String> excludes = Arrays.asList(ann.exclude());
    List<String> includes = Arrays.asList(ann.of());
    EclipseNode typeNode = annotationNode.up();
    Boolean callSuper = ann.callSuper();

    if (!annotation.isExplicit("callSuper")) callSuper = null;
    if (!annotation.isExplicit("exclude")) excludes = null;
    if (!annotation.isExplicit("of")) includes = null;

    if (excludes != null && includes != null) {
      excludes = null;
      annotation.setWarning(
          "exclude",
          "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored.");
    }

    checkForBogusFieldNames(typeNode, annotation);

    FieldAccess fieldAccess = ann.doNotUseGetters() ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;

    return generateToString(
        typeNode,
        annotationNode,
        excludes,
        includes,
        ann.includeFieldNames(),
        callSuper,
        true,
        fieldAccess);
  }
示例#4
0
  /**
   * When generating a setter, the setter either returns void (beanspec) or Self (fluent). This
   * method scans for the {@code Accessors} annotation to figure that out.
   */
  public static boolean shouldReturnThis(JavacNode field) {
    if ((((JCVariableDecl) field.get()).mods.flags & Flags.STATIC) != 0) return false;

    AnnotationValues<Accessors> accessors = JavacHandlerUtil.getAccessorsForField(field);

    boolean forced = (accessors.getActualExpression("chain") != null);
    Accessors instance = accessors.getInstance();
    return instance.chain() || (instance.fluent() && !forced);
  }
示例#5
0
  private static GetterMethod findGetter(JavacNode field) {
    JCVariableDecl decl = (JCVariableDecl) field.get();
    JavacNode typeNode = field.up();
    for (String potentialGetterName : toAllGetterNames(field)) {
      for (JavacNode potentialGetter : typeNode.down()) {
        if (potentialGetter.getKind() != Kind.METHOD) continue;
        JCMethodDecl method = (JCMethodDecl) potentialGetter.get();
        if (!method.name.toString().equalsIgnoreCase(potentialGetterName)) continue;
        /** static getX() methods don't count. */
        if ((method.mods.flags & Flags.STATIC) != 0) continue;
        /** Nor do getters with a non-empty parameter list. */
        if (method.params != null && method.params.size() > 0) continue;
        return new GetterMethod(method.name, method.restype);
      }
    }

    // Check if the field has a @Getter annotation.

    boolean hasGetterAnnotation = false;

    for (JavacNode child : field.down()) {
      if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Getter.class, child)) {
        AnnotationValues<Getter> ann = createAnnotation(Getter.class, child);
        if (ann.getInstance().value() == AccessLevel.NONE)
          return null; // Definitely WONT have a getter.
        hasGetterAnnotation = true;
      }
    }

    // Check if the class has a @Getter annotation.

    if (!hasGetterAnnotation && new HandleGetter().fieldQualifiesForGetterGeneration(field)) {
      // Check if the class has @Getter or @Data annotation.

      JavacNode containingType = field.up();
      if (containingType != null)
        for (JavacNode child : containingType.down()) {
          if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Data.class, child))
            hasGetterAnnotation = true;
          if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Getter.class, child)) {
            AnnotationValues<Getter> ann = createAnnotation(Getter.class, child);
            if (ann.getInstance().value() == AccessLevel.NONE)
              return null; // Definitely WONT have a getter.
            hasGetterAnnotation = true;
          }
        }
    }

    if (hasGetterAnnotation) {
      String getterName = toGetterName(field);
      if (getterName == null) return null;
      return new GetterMethod(field.toName(getterName), decl.vartype);
    }

    return null;
  }
示例#6
0
  static boolean lookForGetter(JavacNode field, FieldAccess fieldAccess) {
    if (fieldAccess == FieldAccess.GETTER) return true;
    if (fieldAccess == FieldAccess.ALWAYS_FIELD) return false;

    // If @Getter(lazy = true) is used, then using it is mandatory.
    for (JavacNode child : field.down()) {
      if (child.getKind() != Kind.ANNOTATION) continue;
      if (annotationTypeMatches(Getter.class, child)) {
        AnnotationValues<Getter> ann = createAnnotation(Getter.class, child);
        if (ann.getInstance().lazy()) return true;
      }
    }
    return false;
  }
  @Override
  public void handle(
      final AnnotationValues<ListenerSupport> annotation,
      final JCAnnotation source,
      final JavacNode annotationNode) {
    deleteAnnotationIfNeccessary(annotationNode, ListenerSupport.class);

    JavacType type = JavacType.typeOf(annotationNode, source);
    if (type.isAnnotation() || type.isInterface()) {
      annotationNode.addError(canBeUsedOnClassAndEnumOnly(ListenerSupport.class));
      return;
    }

    List<Object> listenerInterfaces = annotation.getActualExpressions("value");
    if (listenerInterfaces.isEmpty()) {
      annotationNode.addError(
          String.format(
              "@%s has no effect since no interface types were specified.",
              ListenerSupport.class.getName()));
      return;
    }
    List<TypeSymbol> resolvedInterfaces =
        resolveInterfaces(annotationNode, ListenerSupport.class, listenerInterfaces);
    for (TypeSymbol interfaze : resolvedInterfaces) {
      handler.addListenerField(type, interfaze);
      handler.addAddListenerMethod(type, interfaze);
      handler.addRemoveListenerMethod(type, interfaze);
      addFireListenerMethods(type, interfaze);
    }

    type.editor().rebuild();
  }
示例#8
0
 public <A extends java.lang.annotation.Annotation> AnnotationValues<A> getAnnotationValue(
     final Class<A> expectedType) {
   final EclipseNode node = getAnnotation(expectedType);
   return node == null
       ? AnnotationValues.of(expectedType, node())
       : createAnnotation(expectedType, node);
 }
示例#9
0
  @Override
  public boolean handle(
      AnnotationValues<Synchronized> annotation, JCAnnotation ast, Node annotationNode) {
    Node methodNode = annotationNode.up();

    if (methodNode == null
        || methodNode.getKind() != Kind.METHOD
        || !(methodNode.get() instanceof JCMethodDecl)) {
      annotationNode.addError("@Synchronized is legal only on methods.");
      return true;
    }

    JCMethodDecl method = (JCMethodDecl) methodNode.get();

    if ((method.mods.flags & Flags.ABSTRACT) != 0) {
      annotationNode.addError("@Synchronized is legal only on concrete methods.");
      return true;
    }
    boolean isStatic = (method.mods.flags & Flags.STATIC) != 0;
    String lockName = annotation.getInstance().value();
    boolean autoMake = false;
    if (lockName.length() == 0) {
      autoMake = true;
      lockName = isStatic ? STATIC_LOCK_NAME : INSTANCE_LOCK_NAME;
    }

    TreeMaker maker = methodNode.getTreeMaker();

    if (fieldExists(lockName, methodNode) == MemberExistsResult.NOT_EXISTS) {
      if (!autoMake) {
        annotationNode.addError("The field " + new String(lockName) + " does not exist.");
        return true;
      }
      JCExpression objectType = chainDots(maker, methodNode, "java", "lang", "Object");
      // We use 'new Object[0];' because quite unlike 'new Object();', empty arrays *ARE*
      // serializable!
      JCNewArray newObjectArray =
          maker.NewArray(
              chainDots(maker, methodNode, "java", "lang", "Object"),
              List.<JCExpression>of(maker.Literal(TypeTags.INT, 0)),
              null);
      JCVariableDecl fieldDecl =
          maker.VarDef(
              maker.Modifiers(Flags.FINAL | (isStatic ? Flags.STATIC : 0)),
              methodNode.toName(lockName),
              objectType,
              newObjectArray);
      injectField(methodNode.up(), fieldDecl);
    }

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

    JCExpression lockNode = maker.Ident(methodNode.toName(lockName));

    method.body = maker.Block(0, List.<JCStatement>of(maker.Synchronized(lockNode, method.body)));

    methodNode.rebuild();

    return true;
  }
示例#10
0
  public static AnnotationValues<Accessors> getAccessorsForField(JavacNode field) {
    for (JavacNode node : field.down()) {
      if (annotationTypeMatches(Accessors.class, node)) {
        return createAnnotation(Accessors.class, node);
      }
    }

    JavacNode current = field.up();
    while (current != null) {
      for (JavacNode node : current.down()) {
        if (annotationTypeMatches(Accessors.class, node)) {
          return createAnnotation(Accessors.class, node);
        }
      }
      current = current.up();
    }

    return AnnotationValues.of(Accessors.class, field);
  }
示例#11
0
  public boolean handle(
      AnnotationValues<Data> annotation, Annotation ast, EclipseNode annotationNode) {
    Data ann = annotation.getInstance();
    EclipseNode typeNode = annotationNode.up();

    TypeDeclaration typeDecl = null;
    if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
    int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
    boolean notAClass =
        (modifiers
                & (ClassFileConstants.AccInterface
                    | ClassFileConstants.AccAnnotation
                    | ClassFileConstants.AccEnum))
            != 0;

    if (typeDecl == null || notAClass) {
      annotationNode.addError("@Data is only supported on a class.");
      return false;
    }

    // Careful: Generate the public static constructor (if there is one) LAST, so that any attempt
    // to
    // 'find callers' on the annotation node will find callers of the constructor, which is by far
    // the
    // most useful of the many methods built by @Data. This trick won't work for the non-static
    // constructor,
    // for whatever reason, though you can find callers of that one by focusing on the class name
    // itself
    // and hitting 'find callers'.

    new HandleGetter().generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
    new HandleSetter().generateSetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
    new HandleEqualsAndHashCode().generateEqualsAndHashCodeForType(typeNode, annotationNode);
    new HandleToString().generateToStringForType(typeNode, annotationNode);
    new HandleConstructor()
        .generateRequiredArgsConstructor(
            typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), true, ast);

    return false;
  }
示例#12
0
 private void checkForBogusFieldNames(EclipseNode type, AnnotationValues<ToString> annotation) {
   if (annotation.isExplicit("exclude")) {
     for (int i :
         createListOfNonExistentFields(
             Arrays.asList(annotation.getInstance().exclude()), type, true, false)) {
       annotation.setWarning(
           "exclude", "This field does not exist, or would have been excluded anyway.", i);
     }
   }
   if (annotation.isExplicit("of")) {
     for (int i :
         createListOfNonExistentFields(
             Arrays.asList(annotation.getInstance().of()), type, false, false)) {
       annotation.setWarning("of", "This field does not exist.", i);
     }
   }
 }
示例#13
0
  @Override
  public void handle(
      AnnotationValues<Data> annotation, JCAnnotation ast, JavacNode annotationNode) {
    deleteAnnotationIfNeccessary(annotationNode, Data.class);
    JavacNode typeNode = annotationNode.up();
    boolean notAClass = !isClass(typeNode);

    if (notAClass) {
      annotationNode.addError("@Data is only supported on a class.");
      return;
    }

    String staticConstructorName = annotation.getInstance().staticConstructor();

    // TODO move this to the end OR move it to the top in eclipse.
    new HandleConstructor()
        .generateRequiredArgsConstructor(
            typeNode, AccessLevel.PUBLIC, staticConstructorName, true, annotationNode);
    new HandleGetter().generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
    new HandleSetter().generateSetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
    new HandleEqualsAndHashCode().generateEqualsAndHashCodeForType(typeNode, annotationNode);
    new HandleToString().generateToStringForType(typeNode, annotationNode);
  }
示例#14
0
 public void checkForBogusFieldNames(
     JavacNode type, AnnotationValues<EqualsAndHashCode> annotation) {
   if (annotation.isExplicit("exclude")) {
     for (int i :
         createListOfNonExistentFields(
             List.from(annotation.getInstance().exclude()), type, true, true)) {
       annotation.setWarning(
           "exclude", "This field does not exist, or would have been excluded anyway.", i);
     }
   }
   if (annotation.isExplicit("of")) {
     for (int i :
         createListOfNonExistentFields(
             List.from(annotation.getInstance().of()), type, false, false)) {
       annotation.setWarning("of", "This field does not exist.", i);
     }
   }
 }
示例#15
0
  @Override
  public boolean handle(
      AnnotationValues<SneakyThrows> annotation, JCAnnotation ast, JavacNode annotationNode) {
    markAnnotationAsProcessed(annotationNode, SneakyThrows.class);
    Collection<String> exceptionNames = annotation.getRawExpressions("value");
    if (exceptionNames.isEmpty()) {
      exceptionNames = Collections.singleton("java.lang.Throwable");
    }

    java.util.List<String> exceptions = new ArrayList<String>();
    for (String exception : exceptionNames) {
      if (exception.endsWith(".class")) exception = exception.substring(0, exception.length() - 6);
      exceptions.add(exception);
    }

    JavacNode owner = annotationNode.up();
    switch (owner.getKind()) {
      case METHOD:
        return handleMethod(annotationNode, (JCMethodDecl) owner.get(), exceptions);
      default:
        annotationNode.addError("@SneakyThrows is legal only on methods and constructors.");
        return true;
    }
  }
示例#16
0
  @Override
  public void handle(
      AnnotationValues<Builder> annotation, JCAnnotation ast, JavacNode annotationNode) {
    handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder");

    Builder builderInstance = annotation.getInstance();
    String builderMethodName = builderInstance.builderMethodName();
    String buildMethodName = builderInstance.buildMethodName();
    String builderClassName = builderInstance.builderClassName();

    if (builderMethodName == null) builderMethodName = "builder";
    if (buildMethodName == null) buildMethodName = "build";
    if (builderClassName == null) builderClassName = "";

    if (!checkName("builderMethodName", builderMethodName, annotationNode)) return;
    if (!checkName("buildMethodName", buildMethodName, annotationNode)) return;
    if (!builderClassName.isEmpty()) {
      if (!checkName("builderClassName", builderClassName, annotationNode)) return;
    }

    deleteAnnotationIfNeccessary(annotationNode, Builder.class);
    deleteImportFromCompilationUnit(annotationNode, "lombok.experimental.Builder");

    JavacNode parent = annotationNode.up();

    java.util.List<JCExpression> typesOfParameters = new ArrayList<JCExpression>();
    java.util.List<Name> namesOfParameters = new ArrayList<Name>();
    JCExpression returnType;
    List<JCTypeParameter> typeParams = List.nil();
    List<JCExpression> thrownExceptions = List.nil();
    Name nameOfStaticBuilderMethod;
    JavacNode tdParent;

    JCMethodDecl fillParametersFrom =
        parent.get() instanceof JCMethodDecl ? ((JCMethodDecl) parent.get()) : null;

    if (parent.get() instanceof JCClassDecl) {
      tdParent = parent;
      JCClassDecl td = (JCClassDecl) tdParent.get();
      ListBuffer<JavacNode> allFields = new ListBuffer<JavacNode>();
      @SuppressWarnings("deprecation")
      boolean valuePresent =
          (hasAnnotation(lombok.Value.class, parent)
              || hasAnnotation(lombok.experimental.Value.class, parent));
      for (JavacNode fieldNode : HandleConstructor.findAllFields(tdParent)) {
        JCVariableDecl fd = (JCVariableDecl) fieldNode.get();
        // final fields with an initializer cannot be written to, so they can't be 'builderized'.
        // Unfortunately presence of @Value makes
        // non-final fields final, but @Value's handler hasn't done this yet, so we have to do this
        // math ourselves.
        // Value will only skip making a field final if it has an explicit @NonFinal annotation, so
        // we check for that.
        if (fd.init != null && valuePresent && !hasAnnotation(NonFinal.class, fieldNode)) continue;
        namesOfParameters.add(removePrefixFromField(fieldNode));
        typesOfParameters.add(fd.vartype);
        allFields.append(fieldNode);
      }

      new HandleConstructor()
          .generateConstructor(
              tdParent,
              AccessLevel.PACKAGE,
              List.<JCAnnotation>nil(),
              allFields.toList(),
              null,
              SkipIfConstructorExists.I_AM_BUILDER,
              null,
              annotationNode);

      returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), td.name, td.typarams);
      typeParams = td.typarams;
      thrownExceptions = List.nil();
      nameOfStaticBuilderMethod = null;
      if (builderClassName.isEmpty()) builderClassName = td.name.toString() + "Builder";
    } else if (fillParametersFrom != null
        && fillParametersFrom.getName().toString().equals("<init>")) {
      if (!fillParametersFrom.typarams.isEmpty()) {
        annotationNode.addError(
            "@Builder is not supported on constructors with constructor type parameters.");
        return;
      }
      tdParent = parent.up();
      JCClassDecl td = (JCClassDecl) tdParent.get();
      returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), td.name, td.typarams);
      typeParams = td.typarams;
      thrownExceptions = fillParametersFrom.thrown;
      nameOfStaticBuilderMethod = null;
      if (builderClassName.isEmpty()) builderClassName = td.name.toString() + "Builder";
    } else if (fillParametersFrom != null) {
      tdParent = parent.up();
      JCClassDecl td = (JCClassDecl) tdParent.get();
      if ((fillParametersFrom.mods.flags & Flags.STATIC) == 0) {
        annotationNode.addError(
            "@Builder is only supported on types, constructors, and static methods.");
        return;
      }
      returnType = fillParametersFrom.restype;
      typeParams = fillParametersFrom.typarams;
      thrownExceptions = fillParametersFrom.thrown;
      nameOfStaticBuilderMethod = fillParametersFrom.name;
      if (builderClassName.isEmpty()) {
        if (returnType instanceof JCTypeApply) {
          returnType = ((JCTypeApply) returnType).clazz;
        }
        if (returnType instanceof JCFieldAccess) {
          builderClassName = ((JCFieldAccess) returnType).name.toString() + "Builder";
        } else if (returnType instanceof JCIdent) {
          Name n = ((JCIdent) returnType).name;

          for (JCTypeParameter tp : typeParams) {
            if (tp.name.equals(n)) {
              annotationNode.addError(
                  "@Builder requires specifying 'builderClassName' if used on methods with a type parameter as return type.");
              return;
            }
          }
          builderClassName = n.toString() + "Builder";
        } else if (returnType instanceof JCPrimitiveTypeTree) {
          builderClassName = returnType.toString() + "Builder";
          if (Character.isLowerCase(builderClassName.charAt(0))) {
            builderClassName =
                Character.toTitleCase(builderClassName.charAt(0)) + builderClassName.substring(1);
          }

        } else {
          // This shouldn't happen.
          System.err.println(
              "Lombok bug ID#20140614-1651: javac HandleBuilder: return type to name conversion failed: "
                  + returnType.getClass());
          builderClassName = td.name.toString() + "Builder";
        }
      }
    } else {
      annotationNode.addError(
          "@Builder is only supported on types, constructors, and static methods.");
      return;
    }

    if (fillParametersFrom != null) {
      for (JCVariableDecl param : fillParametersFrom.params) {
        namesOfParameters.add(param.name);
        typesOfParameters.add(param.vartype);
      }
    }

    JavacNode builderType = findInnerClass(tdParent, builderClassName);
    if (builderType == null) {
      builderType = makeBuilderClass(tdParent, builderClassName, typeParams, ast);
    } else {
      sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode);
    }
    java.util.List<JavacNode> fieldNodes =
        addFieldsToBuilder(builderType, namesOfParameters, typesOfParameters, ast);
    java.util.List<JCMethodDecl> newMethods = new ArrayList<JCMethodDecl>();
    for (JavacNode fieldNode : fieldNodes) {
      JCMethodDecl newMethod =
          makeSetterMethodForBuilder(
              builderType,
              fieldNode,
              annotationNode,
              builderInstance.fluent(),
              builderInstance.chain());
      if (newMethod != null) newMethods.add(newMethod);
    }

    if (constructorExists(builderType) == MemberExistsResult.NOT_EXISTS) {
      JCMethodDecl cd =
          HandleConstructor.createConstructor(
              AccessLevel.PACKAGE,
              List.<JCAnnotation>nil(),
              builderType,
              List.<JavacNode>nil(),
              null,
              annotationNode);
      if (cd != null) injectMethod(builderType, cd);
    }

    for (JCMethodDecl newMethod : newMethods) injectMethod(builderType, newMethod);

    if (methodExists(buildMethodName, builderType, -1) == MemberExistsResult.NOT_EXISTS) {
      JCMethodDecl md =
          generateBuildMethod(
              buildMethodName,
              nameOfStaticBuilderMethod,
              returnType,
              namesOfParameters,
              builderType,
              thrownExceptions);
      if (md != null) injectMethod(builderType, md);
    }

    if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) {
      JCMethodDecl md =
          HandleToString.createToString(
              builderType, fieldNodes, true, false, FieldAccess.ALWAYS_FIELD, ast);
      if (md != null) injectMethod(builderType, md);
    }

    if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) {
      JCMethodDecl md =
          generateBuilderMethod(builderMethodName, builderClassName, tdParent, typeParams);
      if (md != null) injectMethod(tdParent, md);
    }
  }
示例#17
0
  public boolean handle(
      AnnotationValues<Data> annotation, Annotation ast, EclipseNode annotationNode) {
    Data ann = annotation.getInstance();
    EclipseNode typeNode = annotationNode.up();

    TypeDeclaration typeDecl = null;
    if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
    int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
    boolean notAClass =
        (modifiers
                & (ClassFileConstants.AccInterface
                    | ClassFileConstants.AccAnnotation
                    | ClassFileConstants.AccEnum))
            != 0;

    if (typeDecl == null || notAClass) {
      annotationNode.addError("@Data is only supported on a class.");
      return false;
    }

    FieldNameMangler fieldNameMangler = null;
    try {
      Class<? extends FieldNameMangler> clazz = annotation.getInstance().fieldNameMangler();
      if (clazz != null) {
        fieldNameMangler = clazz.newInstance();
      }
    } catch (InstantiationException ie) {
      // Ignore this Exception (would log if there were a logger instance)
    } catch (IllegalAccessException iae) {
      // Ignore this Exception (would log if there were a logger instance)
    }
    boolean chainable = annotation.getInstance().chainableSetters();

    List<EclipseNode> nodesForConstructor = new ArrayList<EclipseNode>();
    for (EclipseNode child : typeNode.down()) {
      if (child.getKind() != Kind.FIELD) continue;
      FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
      // Skip fields that start with $
      if (fieldDecl.name.length > 0 && fieldDecl.name[0] == '$') continue;
      // Skip static fields.
      if ((fieldDecl.modifiers & ClassFileConstants.AccStatic) != 0) continue;
      boolean isFinal = (fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0;
      boolean isNonNull =
          findAnnotations(fieldDecl, TransformationsUtil.NON_NULL_PATTERN).length != 0;
      if ((isFinal || isNonNull) && fieldDecl.initialization == null)
        nodesForConstructor.add(child);
      new HandleGetter().generateGetterForField(child, annotationNode.get(), fieldNameMangler);
      if (!isFinal)
        new HandleSetter()
            .generateSetterForField(child, annotationNode.get(), chainable, fieldNameMangler);
    }

    new HandleToString().generateToStringForType(typeNode, annotationNode);
    new HandleEqualsAndHashCode().generateEqualsAndHashCodeForType(typeNode, annotationNode);

    // Careful: Generate the public static constructor (if there is one) LAST, so that any attempt
    // to
    // 'find callers' on the annotation node will find callers of the constructor, which is by far
    // the
    // most useful of the many methods built by @Data. This trick won't work for the non-static
    // constructor,
    // for whatever reason, though you can find callers of that one by focusing on the class name
    // itself
    // and hitting 'find callers'.

    if (constructorExists(typeNode) == MemberExistsResult.NOT_EXISTS) {
      ConstructorDeclaration constructor =
          createConstructor(
              ann.staticConstructor().length() == 0, typeNode, nodesForConstructor, ast);
      injectMethod(typeNode, constructor);
    }

    if (ann.staticConstructor().length() > 0) {
      if (methodExists("of", typeNode) == MemberExistsResult.NOT_EXISTS) {
        MethodDeclaration staticConstructor =
            createStaticConstructor(ann.staticConstructor(), typeNode, nodesForConstructor, ast);
        injectMethod(typeNode, staticConstructor);
      }
    }

    return false;
  }
示例#18
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;
  }