Search in sources :

Example 56 with InnerClassNode

use of org.codehaus.groovy.ast.InnerClassNode in project groovy-core by groovy.

the class TraitASTTransformation method createHelperClass.

private void createHelperClass(final ClassNode cNode) {
    ClassNode helper = new InnerClassNode(cNode, Traits.helperClassName(cNode), ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE, ClassNode.EMPTY_ARRAY, null);
    cNode.setModifiers(ACC_PUBLIC | ACC_INTERFACE | ACC_ABSTRACT);
    checkInnerClasses(cNode);
    MethodNode initializer = createInitMethod(false, cNode, helper);
    MethodNode staticInitializer = createInitMethod(true, cNode, helper);
    // apply the verifier to have the property nodes generated
    generatePropertyMethods(cNode);
    // prepare fields
    List<FieldNode> fields = new ArrayList<FieldNode>();
    Set<String> fieldNames = new HashSet<String>();
    for (FieldNode field : cNode.getFields()) {
        if (!"metaClass".equals(field.getName()) && (!field.isSynthetic() || field.getName().indexOf('$') < 0)) {
            fields.add(field);
            fieldNames.add(field.getName());
        }
    }
    ClassNode fieldHelper = null;
    if (!fields.isEmpty()) {
        fieldHelper = new InnerClassNode(cNode, Traits.fieldHelperClassName(cNode), ACC_STATIC | ACC_PUBLIC | ACC_INTERFACE | ACC_ABSTRACT, ClassHelper.OBJECT_TYPE);
    }
    // add methods
    List<MethodNode> methods = new ArrayList<MethodNode>(cNode.getMethods());
    List<MethodNode> nonPublicAPIMethods = new LinkedList<MethodNode>();
    for (final MethodNode methodNode : methods) {
        boolean declared = methodNode.getDeclaringClass() == cNode;
        if (declared) {
            if (!methodNode.isSynthetic() && (methodNode.isProtected() || methodNode.getModifiers() == 0)) {
                unit.addError(new SyntaxException("Cannot have protected/package private method in a trait (" + cNode.getName() + "#" + methodNode.getTypeDescriptor() + ")", methodNode.getLineNumber(), methodNode.getColumnNumber()));
                return;
            }
            helper.addMethod(processMethod(cNode, methodNode, fieldHelper, fieldNames));
            if (methodNode.isPrivate() || methodNode.isStatic()) {
                nonPublicAPIMethods.add(methodNode);
            }
        }
    }
    // remove methods which should not appear in the trait interface
    for (MethodNode privateMethod : nonPublicAPIMethods) {
        cNode.removeMethod(privateMethod);
    }
    // add fields
    for (FieldNode field : fields) {
        processField(field, initializer, staticInitializer, fieldHelper, cNode, fieldNames);
    }
    // clear properties to avoid generation of methods
    cNode.getProperties().clear();
    // copy annotations
    copyClassAnnotations(cNode, helper);
    // reuse the full list of fields
    fields = new ArrayList<FieldNode>(cNode.getFields());
    for (FieldNode field : fields) {
        cNode.removeField(field.getName());
    }
    // visit AST xforms
    registerASTTranformations(helper);
    unit.getAST().addClass(helper);
    if (fieldHelper != null) {
        unit.getAST().addClass(fieldHelper);
    }
    // resolve scope (for closures)
    resolveScope(helper);
    if (fieldHelper != null) {
        resolveScope(fieldHelper);
    }
}
Also used : InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) FieldNode(org.codehaus.groovy.ast.FieldNode) ArrayList(java.util.ArrayList) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) LinkedList(java.util.LinkedList) MethodNode(org.codehaus.groovy.ast.MethodNode) SyntaxException(org.codehaus.groovy.syntax.SyntaxException) HashSet(java.util.HashSet)

Example 57 with InnerClassNode

use of org.codehaus.groovy.ast.InnerClassNode in project groovy-core by groovy.

the class EnumHelper method makeEnumNode.

public static ClassNode makeEnumNode(String name, int modifiers, ClassNode[] interfaces, ClassNode outerClass) {
    modifiers = modifiers | Opcodes.ACC_FINAL | Opcodes.ACC_ENUM;
    ClassNode enumClass;
    if (outerClass == null) {
        enumClass = new ClassNode(name, modifiers, null, interfaces, MixinNode.EMPTY_ARRAY);
    } else {
        name = outerClass.getName() + "$" + name;
        enumClass = new InnerClassNode(outerClass, name, modifiers, null, interfaces, MixinNode.EMPTY_ARRAY);
    }
    // set super class and generics info
    // "enum X" -> class X extends Enum<X>
    GenericsType gt = new GenericsType(enumClass);
    ClassNode superClass = ClassHelper.makeWithoutCaching("java.lang.Enum");
    superClass.setGenericsTypes(new GenericsType[] { gt });
    enumClass.setSuperClass(superClass);
    superClass.setRedirect(ClassHelper.Enum_Type);
    return enumClass;
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) GenericsType(org.codehaus.groovy.ast.GenericsType) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode)

Example 58 with InnerClassNode

use of org.codehaus.groovy.ast.InnerClassNode in project groovy-core by groovy.

the class EnumVisitor method addInit.

private void addInit(ClassNode enumClass, FieldNode minValue, FieldNode maxValue, FieldNode values, boolean isAic) {
    // constructor helper
    // This method is used instead of calling the constructor as
    // calling the constructor may require a table with MetaClass
    // selecting the constructor for each enum value. So instead we
    // use this method to have a central point for constructor selection
    // and only one table. The whole construction is needed because
    // Reflection forbids access to the enum constructor.
    // code:
    // def $INIT(Object[] para) {
    // return this(*para)
    // }
    ClassNode enumRef = enumClass.getPlainNodeReference();
    Parameter[] parameter = new Parameter[] { new Parameter(ClassHelper.OBJECT_TYPE.makeArray(), "para") };
    MethodNode initMethod = new MethodNode("$INIT", PUBLIC_FS | Opcodes.ACC_SYNTHETIC, enumRef, parameter, ClassNode.EMPTY_ARRAY, null);
    initMethod.setSynthetic(true);
    ConstructorCallExpression cce = new ConstructorCallExpression(ClassNode.THIS, new ArgumentListExpression(new SpreadExpression(new VariableExpression("para"))));
    BlockStatement code = new BlockStatement();
    code.addStatement(new ReturnStatement(cce));
    initMethod.setCode(code);
    enumClass.addMethod(initMethod);
    // static init
    List<FieldNode> fields = enumClass.getFields();
    List<Expression> arrayInit = new ArrayList<Expression>();
    int value = -1;
    Token assign = Token.newSymbol(Types.ASSIGN, -1, -1);
    List<Statement> block = new ArrayList<Statement>();
    FieldNode tempMin = null;
    FieldNode tempMax = null;
    for (FieldNode field : fields) {
        if ((field.getModifiers() & Opcodes.ACC_ENUM) == 0)
            continue;
        value++;
        if (tempMin == null)
            tempMin = field;
        tempMax = field;
        ClassNode enumBase = enumClass;
        ArgumentListExpression args = new ArgumentListExpression();
        args.addExpression(new ConstantExpression(field.getName()));
        args.addExpression(new ConstantExpression(value));
        if (field.getInitialExpression() == null) {
            if ((enumClass.getModifiers() & Opcodes.ACC_ABSTRACT) != 0) {
                addError(field, "The enum constant " + field.getName() + " must override abstract methods from " + enumBase.getName() + ".");
                continue;
            }
        } else {
            ListExpression oldArgs = (ListExpression) field.getInitialExpression();
            List<MapEntryExpression> savedMapEntries = new ArrayList<MapEntryExpression>();
            for (Expression exp : oldArgs.getExpressions()) {
                if (exp instanceof MapEntryExpression) {
                    savedMapEntries.add((MapEntryExpression) exp);
                    continue;
                }
                InnerClassNode inner = null;
                if (exp instanceof ClassExpression) {
                    ClassExpression clazzExp = (ClassExpression) exp;
                    ClassNode ref = clazzExp.getType();
                    if (ref instanceof EnumConstantClassNode) {
                        inner = (InnerClassNode) ref;
                    }
                }
                if (inner != null) {
                    List<MethodNode> baseMethods = enumBase.getMethods();
                    for (MethodNode methodNode : baseMethods) {
                        if (!methodNode.isAbstract())
                            continue;
                        MethodNode enumConstMethod = inner.getMethod(methodNode.getName(), methodNode.getParameters());
                        if (enumConstMethod == null || (enumConstMethod.getModifiers() & Opcodes.ACC_ABSTRACT) != 0) {
                            addError(field, "Can't have an abstract method in enum constant " + field.getName() + ". Implement method '" + methodNode.getTypeDescriptor() + "'.");
                        }
                    }
                    if (inner.getVariableScope() == null) {
                        enumBase = inner;
                        /*
                             * GROOVY-3985: Remove the final modifier from $INIT method in this case
                             * so that subclasses of enum generated for enum constants (aic) can provide
                             * their own $INIT method
                             */
                        initMethod.setModifiers(initMethod.getModifiers() & ~Opcodes.ACC_FINAL);
                        continue;
                    }
                }
                args.addExpression(exp);
            }
            if (savedMapEntries.size() > 0) {
                args.getExpressions().add(2, new MapExpression(savedMapEntries));
            }
        }
        field.setInitialValueExpression(null);
        block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(field), assign, new StaticMethodCallExpression(enumBase, "$INIT", args))));
        arrayInit.add(new FieldExpression(field));
    }
    if (!isAic) {
        if (tempMin != null) {
            block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(minValue), assign, new FieldExpression(tempMin))));
            block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(maxValue), assign, new FieldExpression(tempMax))));
            enumClass.addField(minValue);
            enumClass.addField(maxValue);
        }
        block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(values), assign, new ArrayExpression(enumClass, arrayInit))));
        enumClass.addField(values);
    }
    enumClass.addStaticInitializerStatements(block, true);
}
Also used : EnumConstantClassNode(org.codehaus.groovy.ast.EnumConstantClassNode) ArrayList(java.util.ArrayList) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) Token(org.codehaus.groovy.syntax.Token) MethodNode(org.codehaus.groovy.ast.MethodNode) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) EnumConstantClassNode(org.codehaus.groovy.ast.EnumConstantClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) FieldNode(org.codehaus.groovy.ast.FieldNode) Statement(org.codehaus.groovy.ast.stmt.Statement) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) EmptyStatement(org.codehaus.groovy.ast.stmt.EmptyStatement) IfStatement(org.codehaus.groovy.ast.stmt.IfStatement) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) Parameter(org.codehaus.groovy.ast.Parameter)

Example 59 with InnerClassNode

use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.

the class StaticTypesCallSiteWriter method makeGetPropertyWithGetter.

private boolean makeGetPropertyWithGetter(final Expression receiver, final ClassNode receiverType, final String propertyName, final boolean safe, final boolean implicitThis) {
    // check for an accessor method
    String getterName = "is" + capitalize(propertyName);
    MethodNode getterNode = receiverType.getGetterMethod(getterName);
    if (getterNode == null) {
        getterName = "get" + capitalize(propertyName);
        getterNode = receiverType.getGetterMethod(getterName);
    }
    if (getterNode != null && receiver instanceof ClassExpression && !isClassType(receiverType) && !getterNode.isStatic()) {
        return false;
    }
    // GROOVY-5561: if two files are compiled in the same source unit and
    // one references the other, the getters for properties have not been
    // generated by the compiler yet (generated by the Verifier)
    PropertyNode propertyNode = receiverType.getProperty(propertyName);
    if (getterNode == null && propertyNode != null) {
        // it is possible to use an accessor method
        String prefix = isPrimitiveBoolean(propertyNode.getOriginType()) ? "is" : "get";
        getterName = prefix + capitalize(propertyName);
        getterNode = new MethodNode(getterName, ACC_PUBLIC | (propertyNode.isStatic() ? ACC_STATIC : 0), propertyNode.getOriginType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
        getterNode.setDeclaringClass(receiverType);
    }
    if (getterNode != null) {
        if (!AsmClassGenerator.isMemberDirectlyAccessible(getterNode.getModifiers(), getterNode.getDeclaringClass(), controller.getClassNode())) {
            // GROOVY-6277
            return false;
        }
        MethodCallExpression call = callX(receiver, getterName);
        call.setImplicitThis(implicitThis);
        call.setMethodTarget(getterNode);
        call.setSafe(safe);
        call.setSourcePosition(receiver);
        call.visit(controller.getAcg());
        return true;
    }
    if (receiverType instanceof InnerClassNode && !receiverType.isStaticClass()) {
        if (makeGetPropertyWithGetter(receiver, receiverType.getOuterClass(), propertyName, safe, implicitThis)) {
            return true;
        }
    }
    // GROOVY-7149: check direct interfaces
    for (ClassNode node : receiverType.getInterfaces()) {
        if (makeGetPropertyWithGetter(receiver, node, propertyName, safe, implicitThis)) {
            return true;
        }
    }
    // go upper level
    ClassNode superClass = receiverType.getSuperClass();
    if (superClass != null) {
        return makeGetPropertyWithGetter(receiver, superClass, propertyName, safe, implicitThis);
    }
    return false;
}
Also used : InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) MethodNode(org.codehaus.groovy.ast.MethodNode) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) PropertyNode(org.codehaus.groovy.ast.PropertyNode) ClassExpression(org.codehaus.groovy.ast.expr.ClassExpression) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode)

Example 60 with InnerClassNode

use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.

the class StaticTypeCheckingVisitor method findMethod.

protected List<MethodNode> findMethod(ClassNode receiver, final String name, final ClassNode... args) {
    if (isPrimitiveType(receiver))
        receiver = getWrapper(receiver);
    List<MethodNode> methods;
    if ("<init>".equals(name) && !receiver.isInterface()) {
        methods = addGeneratedMethods(receiver, new ArrayList<>(receiver.getDeclaredConstructors()));
        if (methods.isEmpty()) {
            MethodNode node = new ConstructorNode(Opcodes.ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
            node.setDeclaringClass(receiver);
            methods.add(node);
            if (receiver.isArray()) {
                // arbitrary number of parameters.
                return methods;
            }
        }
    } else {
        methods = findMethodsWithGenerated(receiver, name);
        if ("call".equals(name) && receiver.isInterface()) {
            MethodNode sam = findSAM(receiver);
            if (sam != null) {
                MethodNode callMethod = new MethodNode("call", sam.getModifiers(), sam.getReturnType(), sam.getParameters(), sam.getExceptions(), sam.getCode());
                callMethod.setDeclaringClass(sam.getDeclaringClass());
                callMethod.setSourcePosition(sam);
                methods.add(callMethod);
            }
        }
        if (!receiver.isStaticClass() && receiver.getOuterClass() != null && typeCheckingContext.getEnclosingClassNodes().contains(receiver)) {
            ClassNode outer = receiver.getOuterClass();
            do {
                methods.addAll(findMethodsWithGenerated(outer, name));
            } while (!outer.isStaticClass() && (outer = outer.getOuterClass()) != null);
        }
        if (methods.isEmpty()) {
            addArrayMethods(methods, receiver, name, args);
        }
        if (methods.isEmpty() && (args == null || args.length == 0)) {
            // check if it's a property
            String pname = extractPropertyNameFromMethodName("get", name);
            if (pname == null) {
                pname = extractPropertyNameFromMethodName("is", name);
            }
            PropertyNode property = null;
            if (pname != null) {
                property = findProperty(receiver, pname);
            } else {
                out: for (ClassNode cn = receiver; cn != null; cn = cn.getSuperClass()) {
                    for (PropertyNode pn : cn.getProperties()) {
                        if (name.equals(pn.getGetterName())) {
                            property = pn;
                            break out;
                        }
                    }
                }
            }
            if (property != null) {
                int mods = Opcodes.ACC_PUBLIC | (property.isStatic() ? Opcodes.ACC_STATIC : 0);
                MethodNode node = new MethodNode(name, mods, property.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
                node.setDeclaringClass(property.getDeclaringClass());
                return Collections.singletonList(node);
            }
        } else if (methods.isEmpty() && args != null && args.length == 1) {
            // maybe we are looking for a setter ?
            String pname = extractPropertyNameFromMethodName("set", name);
            if (pname != null) {
                PropertyNode property = findProperty(receiver, pname);
                if (property != null && !Modifier.isFinal(property.getModifiers())) {
                    ClassNode type = property.getOriginType();
                    if (implementsInterfaceOrIsSubclassOf(wrapTypeIfNecessary(args[0]), wrapTypeIfNecessary(type))) {
                        int mods = Opcodes.ACC_PUBLIC | (property.isStatic() ? Opcodes.ACC_STATIC : 0);
                        MethodNode node = new MethodNode(name, mods, VOID_TYPE, new Parameter[] { new Parameter(type, name) }, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
                        node.setDeclaringClass(property.getDeclaringClass());
                        return Collections.singletonList(node);
                    }
                }
            }
        }
    }
    if (!"<init>".equals(name) && !"<clinit>".equals(name)) {
        // lookup in DGM methods too
        findDGMMethodsByNameAndArguments(getSourceUnit().getClassLoader(), receiver, name, args, methods);
    }
    methods = filterMethodsByVisibility(methods, typeCheckingContext.getEnclosingClassNode());
    List<MethodNode> chosen = chooseBestMethod(receiver, methods, args);
    if (!chosen.isEmpty())
        return chosen;
    // GROOVY-5566
    if (receiver instanceof InnerClassNode && ((InnerClassNode) receiver).isAnonymous() && methods.size() == 1 && args != null && "<init>".equals(name)) {
        MethodNode constructor = methods.get(0);
        if (constructor.getParameters().length == args.length) {
            return methods;
        }
    }
    if (isClassClassNodeWrappingConcreteType(receiver)) {
        // GROOVY-6802, GROOVY-6803
        List<MethodNode> result = findMethod(receiver.getGenericsTypes()[0].getType(), name, args);
        if (!result.isEmpty())
            return result;
    }
    if (isGStringType(receiver)) {
        return findMethod(STRING_TYPE, name, args);
    }
    if (isBeingCompiled(receiver)) {
        return findMethod(GROOVY_OBJECT_TYPE, name, args);
    }
    return EMPTY_METHODNODE_LIST;
}
Also used : StaticTypeCheckingSupport.findDGMMethodsForClassNode(org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findDGMMethodsForClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) MethodNode(org.codehaus.groovy.ast.MethodNode) ConstructorNode(org.codehaus.groovy.ast.ConstructorNode) PropertyNode(org.codehaus.groovy.ast.PropertyNode) ArrayList(java.util.ArrayList) ClosureUtils.hasImplicitParameter(org.codehaus.groovy.ast.tools.ClosureUtils.hasImplicitParameter) Parameter(org.codehaus.groovy.ast.Parameter) StaticTypeCheckingSupport.toMethodParametersString(org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.toMethodParametersString) StaticTypeCheckingSupport.isParameterizedWithString(org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.isParameterizedWithString) StaticTypeCheckingSupport.isParameterizedWithGStringOrGStringString(org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.isParameterizedWithGStringOrGStringString) ClosureSignatureHint(groovy.transform.stc.ClosureSignatureHint) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode)

Aggregations

InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)78 ClassNode (org.codehaus.groovy.ast.ClassNode)67 MethodNode (org.codehaus.groovy.ast.MethodNode)33 FieldNode (org.codehaus.groovy.ast.FieldNode)20 Parameter (org.codehaus.groovy.ast.Parameter)20 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)20 ArrayList (java.util.ArrayList)17 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)16 ClassExpression (org.codehaus.groovy.ast.expr.ClassExpression)15 ConstructorCallExpression (org.codehaus.groovy.ast.expr.ConstructorCallExpression)15 Expression (org.codehaus.groovy.ast.expr.Expression)15 ExpressionStatement (org.codehaus.groovy.ast.stmt.ExpressionStatement)14 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)13 Statement (org.codehaus.groovy.ast.stmt.Statement)13 ConstructorNode (org.codehaus.groovy.ast.ConstructorNode)12 ClosureExpression (org.codehaus.groovy.ast.expr.ClosureExpression)12 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)11 EnumConstantClassNode (org.codehaus.groovy.ast.EnumConstantClassNode)10 GenericsType (org.codehaus.groovy.ast.GenericsType)10 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)9