private static FieldNode createFieldCopy(ClassNode buildee, Parameter param) {
   Map<String, ClassNode> genericsSpec = createGenericsSpec(buildee);
   extractSuperClassGenerics(param.getType(), buildee, genericsSpec);
   ClassNode correctedParamType = correctToGenericsSpecRecurse(genericsSpec, param.getType());
   return new FieldNode(
       param.getName(), ACC_PRIVATE, correctedParamType, buildee, param.getInitialExpression());
 }
 public static String makeDescriptorWithoutReturnType(MethodNode mn) {
   StringBuilder sb = new StringBuilder();
   sb.append(mn.getName()).append(':');
   for (Parameter p : mn.getParameters()) {
     sb.append(p.getType()).append(',');
   }
   return sb.toString();
 }
 private ClassNode getConstructorArgumentType(Expression arg, ConstructorNode node) {
   if (!(arg instanceof VariableExpression)) return arg.getType();
   VariableExpression vexp = (VariableExpression) arg;
   String name = vexp.getName();
   for (Parameter param : node.getParameters()) {
     if (param.getName().equals(name)) {
       return param.getType();
     }
   }
   return vexp.getType();
 }
Exemple #4
0
 private static Parameter[] copyParameters(Parameter[] parameterTypes) {
   Parameter[] newParameterTypes = new Parameter[parameterTypes.length];
   for (int i = 0; i < parameterTypes.length; i++) {
     Parameter parameterType = parameterTypes[i];
     Parameter newParameter =
         new Parameter(
             nonGeneric(parameterType.getType()),
             parameterType.getName(),
             parameterType.getInitialExpression());
     newParameter.addAnnotations(parameterType.getAnnotations());
     newParameterTypes[i] = newParameter;
   }
   return newParameterTypes;
 }
 private List<FieldNode> convertParamsToFields(ClassNode builder, Parameter[] parameters) {
   List<FieldNode> fieldNodes = new ArrayList<FieldNode>();
   for (Parameter parameter : parameters) {
     Map<String, ClassNode> genericsSpec = createGenericsSpec(builder);
     ClassNode correctedType = correctToGenericsSpecRecurse(genericsSpec, parameter.getType());
     FieldNode fieldNode =
         new FieldNode(
             parameter.getName(),
             parameter.getModifiers(),
             correctedType,
             builder,
             DEFAULT_INITIAL_VALUE);
     fieldNodes.add(fieldNode);
     builder.addField(fieldNode);
   }
   return fieldNodes;
 }
 private void addInvalidUseOfFinalError(
     MethodNode method, Parameter[] parameters, ClassNode superCN) {
   StringBuilder msg = new StringBuilder();
   msg.append("You are not allowed to override the final method ").append(method.getName());
   msg.append("(");
   boolean needsComma = false;
   for (Parameter parameter : parameters) {
     if (needsComma) {
       msg.append(",");
     } else {
       needsComma = true;
     }
     msg.append(parameter.getType());
   }
   msg.append(") from ").append(getDescription(superCN));
   msg.append(".");
   addError(msg.toString(), method);
 }
 public void buildMethod(
     BuilderASTTransformation transform, MethodNode mNode, AnnotationNode anno) {
   if (transform.getMemberValue(anno, "includes") != null
       || transform.getMemberValue(anno, "includes") != null) {
     transform.addError(
         "Error during "
             + BuilderASTTransformation.MY_TYPE_NAME
             + " processing: includes/excludes only allowed on classes",
         anno);
   }
   ClassNode buildee = mNode.getDeclaringClass();
   ClassNode builder = createBuilder(anno, buildee);
   createBuilderFactoryMethod(anno, buildee, builder);
   for (Parameter parameter : mNode.getParameters()) {
     builder.addField(createFieldCopy(buildee, parameter));
     builder.addMethod(
         createBuilderMethodForProp(
             builder,
             new PropertyInfo(parameter.getName(), parameter.getType()),
             getPrefix(anno)));
   }
   builder.addMethod(createBuildMethodForMethod(anno, buildee, mNode, mNode.getParameters()));
 }
 private void addWeakerAccessError(
     ClassNode cn, MethodNode method, Parameter[] parameters, MethodNode superMethod) {
   StringBuilder msg = new StringBuilder();
   msg.append(method.getName());
   msg.append("(");
   boolean needsComma = false;
   for (Parameter parameter : parameters) {
     if (needsComma) {
       msg.append(",");
     } else {
       needsComma = true;
     }
     msg.append(parameter.getType());
   }
   msg.append(") in ");
   msg.append(cn.getName());
   msg.append(" cannot override ");
   msg.append(superMethod.getName());
   msg.append(" in ");
   msg.append(superMethod.getDeclaringClass().getName());
   msg.append("; attempting to assign weaker access privileges; was ");
   msg.append(superMethod.isPublic() ? "public" : "protected");
   addError(msg.toString(), method);
 }
  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;
  }
  protected ClassNode createClosureClass(ClosureExpression expression, int mods) {
    ClassNode classNode = controller.getClassNode();
    ClassNode outerClass = controller.getOutermostClass();
    MethodNode methodNode = controller.getMethodNode();
    String name =
        classNode.getName()
            + "$"
            + controller
                .getContext()
                .getNextClosureInnerName(
                    outerClass, classNode, methodNode); // add a more informative name
    boolean staticMethodOrInStaticClass = controller.isStaticMethod() || classNode.isStaticClass();

    Parameter[] parameters = expression.getParameters();
    if (parameters == null) {
      parameters = Parameter.EMPTY_ARRAY;
    } else if (parameters.length == 0) {
      // let's create a default 'it' parameter
      Parameter it = new Parameter(ClassHelper.OBJECT_TYPE, "it", ConstantExpression.NULL);
      parameters = new Parameter[] {it};
      Variable ref = expression.getVariableScope().getDeclaredVariable("it");
      if (ref != null) it.setClosureSharedVariable(ref.isClosureSharedVariable());
    }

    Parameter[] localVariableParams = getClosureSharedVariables(expression);
    removeInitialValues(localVariableParams);

    InnerClassNode answer =
        new InnerClassNode(classNode, name, mods, ClassHelper.CLOSURE_TYPE.getPlainNodeReference());
    answer.setEnclosingMethod(controller.getMethodNode());
    answer.setSynthetic(true);
    answer.setUsingGenerics(outerClass.isUsingGenerics());
    answer.setSourcePosition(expression);

    if (staticMethodOrInStaticClass) {
      answer.setStaticClass(true);
    }
    if (controller.isInScriptBody()) {
      answer.setScriptBody(true);
    }
    MethodNode method =
        answer.addMethod(
            "doCall",
            ACC_PUBLIC,
            ClassHelper.OBJECT_TYPE,
            parameters,
            ClassNode.EMPTY_ARRAY,
            expression.getCode());
    method.setSourcePosition(expression);

    VariableScope varScope = expression.getVariableScope();
    if (varScope == null) {
      throw new RuntimeException(
          "Must have a VariableScope by now! for expression: " + expression + " class: " + name);
    } else {
      method.setVariableScope(varScope.copy());
    }
    if (parameters.length > 1
        || (parameters.length == 1
            && parameters[0].getType() != null
            && parameters[0].getType() != ClassHelper.OBJECT_TYPE
            && !ClassHelper.OBJECT_TYPE.equals(parameters[0].getType().getComponentType()))) {

      // let's add a typesafe call method
      MethodNode call =
          answer.addMethod(
              "call",
              ACC_PUBLIC,
              ClassHelper.OBJECT_TYPE,
              parameters,
              ClassNode.EMPTY_ARRAY,
              new ReturnStatement(
                  new MethodCallExpression(
                      VariableExpression.THIS_EXPRESSION,
                      "doCall",
                      new ArgumentListExpression(parameters))));
      call.setSourcePosition(expression);
    }

    // let's make the constructor
    BlockStatement block = new BlockStatement();
    // this block does not get a source position, because we don't
    // want this synthetic constructor to show up in corbertura reports
    VariableExpression outer = new VariableExpression("_outerInstance");
    outer.setSourcePosition(expression);
    block.getVariableScope().putReferencedLocalVariable(outer);
    VariableExpression thisObject = new VariableExpression("_thisObject");
    thisObject.setSourcePosition(expression);
    block.getVariableScope().putReferencedLocalVariable(thisObject);
    TupleExpression conArgs = new TupleExpression(outer, thisObject);
    block.addStatement(
        new ExpressionStatement(new ConstructorCallExpression(ClassNode.SUPER, conArgs)));

    // let's assign all the parameter fields from the outer context
    for (Parameter param : localVariableParams) {
      String paramName = param.getName();
      ClassNode type = param.getType();
      if (true) {
        VariableExpression initialValue = new VariableExpression(paramName);
        initialValue.setAccessedVariable(param);
        initialValue.setUseReferenceDirectly(true);
        ClassNode realType = type;
        type = ClassHelper.makeReference();
        param.setType(ClassHelper.makeReference());
        FieldNode paramField =
            answer.addField(paramName, ACC_PRIVATE | ACC_SYNTHETIC, type, initialValue);
        paramField.setOriginType(ClassHelper.getWrapper(param.getOriginType()));
        paramField.setHolder(true);
        String methodName = Verifier.capitalize(paramName);

        // let's add a getter & setter
        Expression fieldExp = new FieldExpression(paramField);
        answer.addMethod(
            "get" + methodName,
            ACC_PUBLIC,
            realType.getPlainNodeReference(),
            Parameter.EMPTY_ARRAY,
            ClassNode.EMPTY_ARRAY,
            new ReturnStatement(fieldExp));
      }
    }

    Parameter[] params = new Parameter[2 + localVariableParams.length];
    params[0] = new Parameter(ClassHelper.OBJECT_TYPE, "_outerInstance");
    params[1] = new Parameter(ClassHelper.OBJECT_TYPE, "_thisObject");
    System.arraycopy(localVariableParams, 0, params, 2, localVariableParams.length);

    ASTNode sn = answer.addConstructor(ACC_PUBLIC, params, ClassNode.EMPTY_ARRAY, block);
    sn.setSourcePosition(expression);

    correctAccessedVariable(answer, expression);

    return answer;
  }
 private void checkGenericsUsage(ASTNode ref, Parameter[] params) {
   for (Parameter p : params) {
     checkGenericsUsage(ref, p.getType());
   }
 }
  public static void apply(ClassNode declaringClass) {
    injectInterface(declaringClass, MYBATIS_CONTRIBUTION_HANDLER_CNODE);

    // add field:
    // protected MybatisProvider this$MybatisProvider = DefaultMybatisProvider.instance
    FieldNode providerField =
        declaringClass.addField(
            MYBATIS_PROVIDER_FIELD_NAME,
            ACC_PRIVATE | ACC_SYNTHETIC,
            MYBATIS_PROVIDER_CNODE,
            defaultMybatisProviderInstance());

    // add method:
    // MybatisProvider getMybatisProvider() {
    //     return this$MybatisProvider
    // }
    injectMethod(
        declaringClass,
        new MethodNode(
            METHOD_GET_MYBATIS_PROVIDER,
            ACC_PUBLIC,
            MYBATIS_PROVIDER_CNODE,
            Parameter.EMPTY_ARRAY,
            NO_EXCEPTIONS,
            returns(field(providerField))));

    // add method:
    // void setMybatisProvider(MybatisProvider provider) {
    //     this$MybatisProvider = provider ?: DefaultMybatisProvider.instance
    // }
    injectMethod(
        declaringClass,
        new MethodNode(
            METHOD_SET_MYBATIS_PROVIDER,
            ACC_PUBLIC,
            ClassHelper.VOID_TYPE,
            params(param(MYBATIS_PROVIDER_CNODE, PROVIDER)),
            NO_EXCEPTIONS,
            block(
                ifs_no_return(
                    cmp(var(PROVIDER), ConstantExpression.NULL),
                    assigns(field(providerField), defaultMybatisProviderInstance()),
                    assigns(field(providerField), var(PROVIDER))))));

    for (MethodNode method : MYBATIS_CONTRIBUTION_HANDLER_CNODE.getMethods()) {
      if (Arrays.binarySearch(DELEGATING_METHODS, method.getName()) < 0) continue;
      List<Expression> variables = new ArrayList<Expression>();
      Parameter[] parameters = new Parameter[method.getParameters().length];
      for (int i = 0; i < method.getParameters().length; i++) {
        Parameter p = method.getParameters()[i];
        parameters[i] = new Parameter(makeClassSafe(p.getType()), p.getName());
        parameters[i].getType().setGenericsTypes(p.getType().getGenericsTypes());
        variables.add(var(p.getName()));
      }
      ClassNode returnType = makeClassSafe(method.getReturnType());
      returnType.setGenericsTypes(method.getReturnType().getGenericsTypes());
      returnType.setGenericsPlaceHolder(method.getReturnType().isGenericsPlaceHolder());

      MethodNode newMethod =
          new MethodNode(
              method.getName(),
              ACC_PUBLIC,
              returnType,
              parameters,
              NO_EXCEPTIONS,
              returns(call(field(providerField), method.getName(), args(variables))));
      newMethod.setGenericsTypes(method.getGenericsTypes());
      injectMethod(declaringClass, newMethod);
    }
  }