private void checkRepetitiveMethod(MethodNode node) { if (isConstructor(node)) return; for (MethodNode method : currentClass.getMethods(node.getName())) { if (method == node) continue; if (!method.getDeclaringClass().equals(node.getDeclaringClass())) continue; Parameter[] p1 = node.getParameters(); Parameter[] p2 = method.getParameters(); if (p1.length != p2.length) continue; addErrorIfParamsAndReturnTypeEqual(p2, p1, node, method); } }
private MethodNode createBuildMethodForMethod( AnnotationNode anno, ClassNode buildee, MethodNode mNode, Parameter[] params) { String buildMethodName = getMemberStringValue(anno, "buildMethodName", "build"); final BlockStatement body = new BlockStatement(); ClassNode returnType; if (mNode instanceof ConstructorNode) { returnType = newClass(buildee); body.addStatement(returnS(ctorX(newClass(mNode.getDeclaringClass()), args(params)))); } else { body.addStatement( returnS(callX(newClass(mNode.getDeclaringClass()), mNode.getName(), args(params)))); returnType = newClass(mNode.getReturnType()); } return new MethodNode(buildMethodName, ACC_PUBLIC, returnType, NO_PARAMS, NO_EXCEPTIONS, body); }
private void createBuilderForAnnotatedMethod( 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); } if (mNode instanceof ConstructorNode) { mNode.setModifiers(ACC_PRIVATE | ACC_SYNTHETIC); } else { if ((mNode.getModifiers() & ACC_STATIC) == 0) { transform.addError( "Error during " + BuilderASTTransformation.MY_TYPE_NAME + " processing: method builders only allowed on static methods", anno); } mNode.setModifiers(ACC_PRIVATE | ACC_SYNTHETIC | ACC_STATIC); } ClassNode buildee = mNode.getDeclaringClass(); Parameter[] parameters = mNode.getParameters(); ClassNode builder = createInnerHelperClass(buildee, getBuilderClassName(buildee, anno), parameters.length); List<FieldNode> convertedFields = convertParamsToFields(builder, parameters); buildCommon(buildee, anno, convertedFields, builder); if (mNode instanceof ConstructorNode) { createBuildeeConstructors(transform, buildee, builder, convertedFields, false); } else { createBuildeeMethods(buildee, mNode, builder, convertedFields); } }
private void checkOverloadingPrivateAndPublic(MethodNode node) { if (isConstructor(node)) return; boolean hasPrivate = false; boolean hasPublic = false; for (MethodNode method : currentClass.getMethods(node.getName())) { if (method == node) continue; if (!method.getDeclaringClass().equals(node.getDeclaringClass())) continue; if (method.isPublic() || method.isProtected()) { hasPublic = true; } else { hasPrivate = true; } } if (hasPrivate && hasPublic) { addError( "Mixing private and public/protected methods of the same name causes multimethods to be disabled and is forbidden to avoid surprising behaviour. Renaming the private methods will solve the problem.", node); } }
private void checkMethodsForOverridingFinal(ClassNode cn) { for (MethodNode method : cn.getMethods()) { Parameter[] params = method.getParameters(); for (MethodNode superMethod : cn.getSuperClass().getMethods(method.getName())) { Parameter[] superParams = superMethod.getParameters(); if (!hasEqualParameterTypes(params, superParams)) continue; if (!superMethod.isFinal()) break; addInvalidUseOfFinalError(method, params, superMethod.getDeclaringClass()); return; } } }
private String createMethodLabel(MethodNode node) { StringBuilder sb = new StringBuilder(); sb.append(createClassLabel(node.getReturnType())); sb.append(" "); sb.append(createClassLabel(node.getDeclaringClass())); sb.append("."); sb.append(node.getName()); sb.append("("); Parameter[] params = node.getParameters(); if (params != null) { for (int i = 0; i < params.length; i++) { sb.append(createClassLabel(params[i].getType())); sb.append(" " + params[i].getName()); if (i < params.length - 1) { sb.append(", "); } } } sb.append(")"); return sb.toString(); }
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 boolean isCustomScriptBodyMethod(MethodNode node) { return node != null && !(node.getDeclaringClass().equals(ClassHelper.SCRIPT_TYPE) && "run".equals(node.getName()) && node.getParameters().length == 0); }
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; }
/** * Adds or modifies an existing constructor to delegate to the given static constructor method for * initialization logic. * * @param classNode The class node * @param constructorMethod The constructor static method */ public static void addDelegateConstructor(ClassNode classNode, MethodNode constructorMethod) { BlockStatement constructorBody = new BlockStatement(); Parameter[] constructorParams = getRemainingParameterTypes(constructorMethod.getParameters()); ArgumentListExpression arguments = createArgumentListFromParameters(constructorParams, true); MethodCallExpression constructCallExpression = new MethodCallExpression( new ClassExpression(constructorMethod.getDeclaringClass()), "initialize", arguments); constructCallExpression.setMethodTarget(constructorMethod); ExpressionStatement constructorInitExpression = new ExpressionStatement(constructCallExpression); if (constructorParams.length > 0) { constructorBody.addStatement( new ExpressionStatement( new ConstructorCallExpression( ClassNode.THIS, GrailsArtefactClassInjector.ZERO_ARGS))); } constructorBody.addStatement(constructorInitExpression); if (constructorParams.length == 0) { // handle default constructor ConstructorNode constructorNode = getDefaultConstructor(classNode); if (constructorNode != null) { List<AnnotationNode> annotations = constructorNode.getAnnotations(new ClassNode(GrailsDelegatingConstructor.class)); if (annotations.size() == 0) { Statement existingBodyCode = constructorNode.getCode(); if (existingBodyCode instanceof BlockStatement) { ((BlockStatement) existingBodyCode).addStatement(constructorInitExpression); } else { constructorNode.setCode(constructorBody); } } } else { constructorNode = new ConstructorNode(Modifier.PUBLIC, constructorBody); classNode.addConstructor(constructorNode); } constructorNode.addAnnotation( new AnnotationNode(new ClassNode(GrailsDelegatingConstructor.class))); } else { // create new constructor, restoring default constructor if there is none ConstructorNode cn = findConstructor(classNode, constructorParams); if (cn == null) { cn = new ConstructorNode( Modifier.PUBLIC, copyParameters(constructorParams), null, constructorBody); classNode.addConstructor(cn); } else { List<AnnotationNode> annotations = cn.getAnnotations(new ClassNode(GrailsDelegatingConstructor.class)); if (annotations.size() == 0) { Statement code = cn.getCode(); constructorBody.addStatement(code); cn.setCode(constructorBody); } } ConstructorNode defaultConstructor = getDefaultConstructor(classNode); if (defaultConstructor == null) { // add empty classNode.addConstructor(new ConstructorNode(Modifier.PUBLIC, new BlockStatement())); } cn.addAnnotation(new AnnotationNode(new ClassNode(GrailsDelegatingConstructor.class))); } }
/** * Adds a static method call to given class node that delegates to the given method * * @param classNode The class node * @param delegateMethod The delegate method * @return The added method node or null if it couldn't be added */ public static MethodNode addDelegateStaticMethod(ClassNode classNode, MethodNode delegateMethod) { ClassExpression classExpression = new ClassExpression(delegateMethod.getDeclaringClass()); return addDelegateStaticMethod(classExpression, classNode, delegateMethod); }