private void addProperty(ClassNode cNode, PropertyNode pNode) {
   final FieldNode fn = pNode.getField();
   cNode.getFields().remove(fn);
   cNode.addProperty(
       pNode.getName(),
       pNode.getModifiers() | ACC_FINAL,
       pNode.getType(),
       pNode.getInitialExpression(),
       pNode.getGetterBlock(),
       pNode.getSetterBlock());
   final FieldNode newfn = cNode.getField(fn.getName());
   cNode.getFields().remove(newfn);
   cNode.addField(fn);
 }
  private void assertMembersNamesAreUnique() {
    Map<String, FieldNode> allDslCollectionFieldNodesOfHierarchy = new HashMap<String, FieldNode>();

    for (ClassNode level : ASTHelper.getHierarchyOfDSLObjectAncestors(annotatedClass)) {
      for (FieldNode field : level.getFields()) {
        if (!ASTHelper.isListOrMap(field.getType())) continue;

        String memberName = getElementNameForCollectionField(field);

        FieldNode conflictingField = allDslCollectionFieldNodesOfHierarchy.get(memberName);

        if (conflictingField != null) {
          addCompileError(
              String.format(
                  "Member name %s is used more than once: %s:%s and %s:%s",
                  memberName,
                  field.getOwner().getName(),
                  field.getName(),
                  conflictingField.getOwner().getName(),
                  conflictingField.getName()),
              field);
          return;
        }

        allDslCollectionFieldNodesOfHierarchy.put(memberName, field);
      }
    }
  }
  private List<FieldNode> getAnnotatedFieldOfClass(ClassNode target, ClassNode annotation) {
    List<FieldNode> result = new ArrayList<FieldNode>();

    for (FieldNode fieldNode : target.getFields())
      if (!fieldNode.getAnnotations(annotation).isEmpty()) result.add(fieldNode);

    return result;
  }
 public static List<FieldNode> getInstanceNonPropertyFields(ClassNode cNode) {
   final List<FieldNode> result = new ArrayList<FieldNode>();
   for (FieldNode fNode : cNode.getFields()) {
     if (!fNode.isStatic() && cNode.getProperty(fNode.getName()) == null) {
       result.add(fNode);
     }
   }
   return result;
 }
 public static List<FieldNode> getSuperNonPropertyFields(ClassNode cNode) {
   final List<FieldNode> result;
   if (cNode == ClassHelper.OBJECT_TYPE) {
     result = new ArrayList<FieldNode>();
   } else {
     result = getSuperNonPropertyFields(cNode.getSuperClass());
   }
   for (FieldNode fNode : cNode.getFields()) {
     if (!fNode.isStatic() && cNode.getProperty(fNode.getName()) == null) {
       result.add(fNode);
     }
   }
   return result;
 }
  /**
   * If we are in a constructor, that is static compiled, but in a class, that is not, it may happen
   * that init code from object initializers, fields or properties is added into the constructor
   * code. The backend assumes a purely static contructor, so it may fail if it encounters dynamic
   * code here. Thus we make this kind of code fail
   */
  private void checkForConstructorWithCSButClassWithout(MethodNode node) {
    if (!(node instanceof ConstructorNode)) return;
    Object meta = node.getNodeMetaData(STATIC_COMPILE_NODE);
    if (!Boolean.TRUE.equals(meta)) return;
    ClassNode clz = typeCheckingContext.getEnclosingClassNode();
    meta = clz.getNodeMetaData(STATIC_COMPILE_NODE);
    if (Boolean.TRUE.equals(meta)) return;
    if (clz.getObjectInitializerStatements().isEmpty()
        && clz.getFields().isEmpty()
        && clz.getProperties().isEmpty()) {
      return;
    }

    addStaticTypeError(
        "Cannot statically compile constructor implicitly including non static elements from object initializers, properties or fields.",
        node);
  }
 private void visitClassNode(ClassNode cNode, List<PackageScopeTarget> value) {
   String cName = cNode.getName();
   if (cNode.isInterface() && value.size() != 1 && value.get(0) != PackageScopeTarget.CLASS) {
     throw new RuntimeException(
         "Error processing interface '"
             + cName
             + "'. "
             + MY_TYPE_NAME
             + " not allowed for interfaces except when targeting Class level.");
   }
   if (value.contains(groovy.transform.PackageScopeTarget.CLASS)) {
     if (cNode.isSyntheticPublic()) revertVisibility(cNode);
     else
       throw new RuntimeException(
           "Can't use "
               + MY_TYPE_NAME
               + " for class '"
               + cNode.getName()
               + "' which has explicit visibility.");
   }
   if (value.contains(groovy.transform.PackageScopeTarget.METHODS)) {
     final List<MethodNode> mList = cNode.getMethods();
     for (MethodNode mNode : mList) {
       if (mNode.isSyntheticPublic()) revertVisibility(mNode);
     }
   }
   if (value.contains(PackageScopeTarget.FIELDS)) {
     final List<PropertyNode> pList = cNode.getProperties();
     List<PropertyNode> foundProps = new ArrayList<PropertyNode>();
     List<String> foundNames = new ArrayList<String>();
     for (PropertyNode pNode : pList) {
       foundProps.add(pNode);
       foundNames.add(pNode.getName());
     }
     for (PropertyNode pNode : foundProps) {
       pList.remove(pNode);
     }
     final List<FieldNode> fList = cNode.getFields();
     for (FieldNode fNode : fList) {
       if (foundNames.contains(fNode.getName())) {
         revertVisibility(fNode);
       }
     }
   }
 }
  private void validateFieldAnnotations() {
    for (FieldNode fieldNode : annotatedClass.getFields()) {
      if (shouldFieldBeIgnored(fieldNode)) continue;

      AnnotationNode annotation = getAnnotation(fieldNode, DSL_FIELD_ANNOTATION);

      if (annotation == null) continue;

      if (ASTHelper.isListOrMap(fieldNode.getType())) return;

      if (annotation.getMember("members") != null) {
        addCompileError(
            String.format(
                "@Field.members is only valid for List or Map fields, but field %s is of type %s",
                fieldNode.getName(), fieldNode.getType().getName()),
            annotation);
      }
    }
  }
 private void printFields(PrintWriter out, ClassNode classNode) {
   boolean isInterface = classNode.isInterface();
   List<FieldNode> fields = classNode.getFields();
   if (fields == null) return;
   List<FieldNode> enumFields = new ArrayList<FieldNode>(fields.size());
   List<FieldNode> normalFields = new ArrayList<FieldNode>(fields.size());
   for (FieldNode field : fields) {
     boolean isSynthetic = (field.getModifiers() & Opcodes.ACC_SYNTHETIC) != 0;
     if (field.isEnum()) {
       enumFields.add(field);
     } else if (!isSynthetic) {
       normalFields.add(field);
     }
   }
   printEnumFields(out, enumFields);
   for (FieldNode normalField : normalFields) {
     printField(out, normalField, isInterface);
   }
 }
  private void validateFields(BlockStatement block) {
    Validation.Option mode =
        getEnumMemberValue(
            getAnnotation(annotatedClass, VALIDATION_ANNOTATION),
            "option",
            Validation.Option.class,
            Validation.Option.IGNORE_UNMARKED);
    for (FieldNode fieldNode : annotatedClass.getFields()) {
      if (shouldFieldBeIgnoredForValidation(fieldNode)) continue;

      ClosureExpression validationClosure =
          createGroovyTruthClosureExpression(block.getVariableScope());
      String message = null;

      AnnotationNode validateAnnotation = getAnnotation(fieldNode, VALIDATE_ANNOTATION);
      if (validateAnnotation != null) {
        message =
            getMemberStringValue(
                validateAnnotation, "message", "'" + fieldNode.getName() + "' must be set!");
        Expression member = validateAnnotation.getMember("value");
        if (member instanceof ClassExpression) {
          ClassNode memberType = member.getType();
          if (memberType.equals(ClassHelper.make(Validate.Ignore.class))) continue;
          else if (!memberType.equals(ClassHelper.make(Validate.GroovyTruth.class))) {
            addError(
                "value of Validate must be either Validate.GroovyTruth, Validate.Ignore or a closure.",
                fieldNode);
          }
        } else if (member instanceof ClosureExpression) {
          validationClosure = (ClosureExpression) member;
        }
      }

      if (validateAnnotation != null || mode == Validation.Option.VALIDATE_UNMARKED) {
        block.addStatement(
            new AssertStatement(
                new BooleanExpression(
                    callX(validationClosure, "call", args(varX(fieldNode.getName())))),
                message == null ? ConstantExpression.NULL : new ConstantExpression(message)));
      }
    }
  }
 private void createConstructorMapCommon(ClassNode cNode, BlockStatement body) {
   final List<FieldNode> fList = cNode.getFields();
   for (FieldNode fNode : fList) {
     if (fNode.isPublic()) continue; // public fields will be rejected elsewhere
     if (cNode.getProperty(fNode.getName()) != null) continue; // a property
     if (fNode.isFinal() && fNode.isStatic()) continue;
     if (fNode.getName().contains("$")) continue; // internal field
     if (fNode.isFinal() && fNode.getInitialExpression() != null)
       body.addStatement(checkFinalArgNotOverridden(cNode, fNode));
     body.addStatement(createConstructorStatementDefault(fNode));
   }
   final Parameter[] params = new Parameter[] {new Parameter(HASHMAP_TYPE, "args")};
   doAddConstructor(
       cNode,
       new ConstructorNode(
           ACC_PUBLIC,
           params,
           ClassNode.EMPTY_ARRAY,
           new IfStatement(
               equalsNullExpr(new VariableExpression("args")), new EmptyStatement(), body)));
 }
  public void visit(ASTNode[] nodes, SourceUnit source) {
    init(nodes, source);
    AnnotatedNode parent = (AnnotatedNode) nodes[1];
    AnnotationNode node = (AnnotationNode) nodes[0];
    // temporarily have weaker check which allows for old Deprecated Annotation
    //        if (!MY_TYPE.equals(node.getClassNode())) return;
    if (!node.getClassNode().getName().endsWith(".Immutable")) return;
    List<PropertyNode> newProperties = new ArrayList<PropertyNode>();

    if (parent instanceof ClassNode) {
      final List<String> knownImmutableClasses = getKnownImmutableClasses(node);
      final List<String> knownImmutables = getKnownImmutables(node);

      ClassNode cNode = (ClassNode) parent;
      String cName = cNode.getName();
      checkNotInterface(cNode, MY_TYPE_NAME);
      makeClassFinal(cNode);

      final List<PropertyNode> pList = getInstanceProperties(cNode);
      for (PropertyNode pNode : pList) {
        adjustPropertyForImmutability(pNode, newProperties);
      }
      for (PropertyNode pNode : newProperties) {
        cNode.getProperties().remove(pNode);
        addProperty(cNode, pNode);
      }
      final List<FieldNode> fList = cNode.getFields();
      for (FieldNode fNode : fList) {
        ensureNotPublic(cName, fNode);
      }
      createConstructors(cNode, knownImmutableClasses, knownImmutables);
      if (!hasAnnotation(cNode, EqualsAndHashCodeASTTransformation.MY_TYPE)) {
        createHashCode(cNode, true, false, false, null, null);
        createEquals(cNode, false, false, false, null, null);
      }
      if (!hasAnnotation(cNode, ToStringASTTransformation.MY_TYPE)) {
        createToString(cNode, false, false, null, null, false, true);
      }
    }
  }
  private Variable findClassMember(ClassNode cn, String name) {
    if (cn == null) return null;
    if (cn.isScript()) {
      return new DynamicVariable(name, false);
    }

    for (FieldNode fn : cn.getFields()) {
      if (fn.getName().equals(name)) return fn;
    }

    for (MethodNode mn : cn.getMethods()) {
      String pName = getPropertyName(mn);
      // GRECLIPSE: start
      // must set the declaringClass
      /*old{
      if (pName != null && pName.equals(name))
          return new PropertyNode(pName, mn.getModifiers(), getPropertyType(mn), cn, null, null, null);
          */
      // newcode
      if (pName != null && pName.equals(name)) {
        PropertyNode property =
            new PropertyNode(pName, mn.getModifiers(), getPropertyType(mn), cn, null, null, null);
        property.setDeclaringClass(cn);
        property.getField().setDeclaringClass(cn);
        return property;
      }
      // GRECLIPSE: end
    }

    for (PropertyNode pn : cn.getProperties()) {
      if (pn.getName().equals(name)) return pn;
    }

    Variable ret = findClassMember(cn.getSuperClass(), name);
    if (ret != null) return ret;
    return findClassMember(cn.getOuterClass(), name);
  }
  /** Adds special accessors for private constants so that inner classes can retrieve them. */
  @SuppressWarnings("unchecked")
  private void addPrivateFieldsAccessors(ClassNode node) {
    Set<ASTNode> accessedFields =
        (Set<ASTNode>) node.getNodeMetaData(StaticTypesMarker.PV_FIELDS_ACCESS);
    if (accessedFields == null) return;
    Map<String, MethodNode> privateConstantAccessors =
        (Map<String, MethodNode>) node.getNodeMetaData(PRIVATE_FIELDS_ACCESSORS);
    if (privateConstantAccessors != null) {
      // already added
      return;
    }
    int acc = -1;
    privateConstantAccessors = new HashMap<String, MethodNode>();
    final int access = Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC;
    for (FieldNode fieldNode : node.getFields()) {
      if (accessedFields.contains(fieldNode)) {

        acc++;
        Parameter param = new Parameter(node.getPlainNodeReference(), "$that");
        Expression receiver =
            fieldNode.isStatic() ? new ClassExpression(node) : new VariableExpression(param);
        Statement stmt =
            new ExpressionStatement(new PropertyExpression(receiver, fieldNode.getName()));
        MethodNode accessor =
            node.addMethod(
                "pfaccess$" + acc,
                access,
                fieldNode.getOriginType(),
                new Parameter[] {param},
                ClassNode.EMPTY_ARRAY,
                stmt);
        privateConstantAccessors.put(fieldNode.getName(), accessor);
      }
    }
    node.setNodeMetaData(PRIVATE_FIELDS_ACCESSORS, privateConstantAccessors);
  }
  private Set<String> getPropertyNamesToIncludeInWhiteList(
      final SourceUnit sourceUnit, final ClassNode classNode) {
    if (CLASS_NAME_TO_WHITE_LIST_PROPERTY_NAMES.containsKey(classNode)) {
      return CLASS_NAME_TO_WHITE_LIST_PROPERTY_NAMES.get(classNode);
    }
    final Set<String> propertyNamesToIncludeInWhiteList = new HashSet<String>();
    final Set<String> unbindablePropertyNames = new HashSet<String>();
    final Set<String> bindablePropertyNames = new HashSet<String>();
    if (!classNode.getSuperClass().equals(new ClassNode(Object.class))) {
      final Set<String> parentClassPropertyNames =
          getPropertyNamesToIncludeInWhiteList(sourceUnit, classNode.getSuperClass());
      bindablePropertyNames.addAll(parentClassPropertyNames);
    }

    final FieldNode constraintsFieldNode = classNode.getDeclaredField(CONSTRAINTS_FIELD_NAME);
    if (constraintsFieldNode != null && constraintsFieldNode.hasInitialExpression()) {
      final Expression constraintsInitialExpression = constraintsFieldNode.getInitialExpression();
      if (constraintsInitialExpression instanceof ClosureExpression) {

        final Map<String, Map<String, Expression>> constraintsInfo =
            GrailsASTUtils.getConstraintMetadata((ClosureExpression) constraintsInitialExpression);

        for (Entry<String, Map<String, Expression>> constraintConfig : constraintsInfo.entrySet()) {
          final String propertyName = constraintConfig.getKey();
          final Map<String, Expression> mapEntryExpressions = constraintConfig.getValue();
          for (Entry<String, Expression> entry : mapEntryExpressions.entrySet()) {
            final String constraintName = entry.getKey();
            if (BINDABLE_CONSTRAINT_NAME.equals(constraintName)) {
              final Expression valueExpression = entry.getValue();
              Boolean bindableValue = null;
              if (valueExpression instanceof ConstantExpression) {
                final Object constantValue = ((ConstantExpression) valueExpression).getValue();
                if (constantValue instanceof Boolean) {
                  bindableValue = (Boolean) constantValue;
                }
              }
              if (bindableValue != null) {
                if (Boolean.TRUE.equals(bindableValue)) {
                  unbindablePropertyNames.remove(propertyName);
                  bindablePropertyNames.add(propertyName);
                } else {
                  bindablePropertyNames.remove(propertyName);
                  unbindablePropertyNames.add(propertyName);
                }
              } else {
                final String message =
                    "The bindable constraint for property ["
                        + propertyName
                        + "] in class ["
                        + classNode.getName()
                        + "] has a value which is not a boolean literal and will be ignored.";
                GrailsASTUtils.warning(sourceUnit, valueExpression, message);
              }
            }
          }
        }
      }
    }

    final Set<String> fieldsInTransientsList = getPropertyNamesExpressedInTransientsList(classNode);

    propertyNamesToIncludeInWhiteList.addAll(bindablePropertyNames);
    final List<FieldNode> fields = classNode.getFields();
    for (FieldNode fieldNode : fields) {
      final String fieldName = fieldNode.getName();
      if ((!unbindablePropertyNames.contains(fieldName))
          && (bindablePropertyNames.contains(fieldName)
              || shouldFieldBeInWhiteList(fieldNode, fieldsInTransientsList))) {
        propertyNamesToIncludeInWhiteList.add(fieldName);
      }
    }

    final Map<String, MethodNode> declaredMethodsMap = classNode.getDeclaredMethodsMap();
    for (Entry<String, MethodNode> methodEntry : declaredMethodsMap.entrySet()) {
      final MethodNode value = methodEntry.getValue();
      if (value.getDeclaringClass() == classNode) {
        Parameter[] parameters = value.getParameters();
        if (parameters != null && parameters.length == 1) {
          final String methodName = value.getName();
          if (methodName.startsWith("set")) {
            final Parameter parameter = parameters[0];
            final ClassNode paramType = parameter.getType();
            if (!paramType.equals(new ClassNode(Object.class))) {
              final String restOfMethodName = methodName.substring(3);
              final String propertyName = GrailsNameUtils.getPropertyName(restOfMethodName);
              if (!unbindablePropertyNames.contains(propertyName)) {
                propertyNamesToIncludeInWhiteList.add(propertyName);
              }
            }
          }
        }
      }
    }
    CLASS_NAME_TO_WHITE_LIST_PROPERTY_NAMES.put(classNode, propertyNamesToIncludeInWhiteList);
    Map<String, ClassNode> allAssociationMap = GrailsASTUtils.getAllAssociationMap(classNode);
    for (String associationName : allAssociationMap.keySet()) {
      if (!propertyNamesToIncludeInWhiteList.contains(associationName)) {
        propertyNamesToIncludeInWhiteList.add(associationName);
      }
    }
    return propertyNamesToIncludeInWhiteList;
  }
 private void createFieldMethods() {
   for (FieldNode fieldNode : annotatedClass.getFields()) createMethodsForSingleField(fieldNode);
 }