private void checkClassForOtherModifiers(ClassNode node) { checkClassForModifier(node, isTransient(node.getModifiers()), "transient"); checkClassForModifier(node, isVolatile(node.getModifiers()), "volatile"); checkClassForModifier(node, isNative(node.getModifiers()), "native"); if (!(node instanceof InnerClassNode)) { checkClassForModifier(node, isStatic(node.getModifiers()), "static"); } // don't check synchronized here as it overlaps with ACC_SUPER }
private void checkClassForAbstractAndFinal(ClassNode node) { if (!isAbstract(node.getModifiers())) return; if (!isFinal(node.getModifiers())) return; if (node.isInterface()) { addError( "The " + getDescription(node) + " must not be final. It is by definition abstract.", node); } else { addError("The " + getDescription(node) + " must not be both final and abstract.", node); } }
/** * Tells if a class node is candidate for class literal bytecode optimization. If so, bytecode may * use LDC instructions instead of static constant Class fields to retrieve class literals. * * @param classNode the classnode for which we want to know if bytecode optimization is possible * @return true if the bytecode can be optimized */ public static boolean isClassLiteralPossible(ClassNode classNode) { // the current implementation only checks for public modifier, because Groovy used to allow // handles on classes even if they are package protected and not in the same package. // There are situations where we could make more fine grained checks, but be careful of // potential breakage of existing code. return Modifier.isPublic(classNode.getModifiers()); }
private void checkClassForOverwritingFinal(ClassNode cn) { ClassNode superCN = cn.getSuperClass(); if (superCN == null) return; if (!isFinal(superCN.getModifiers())) return; StringBuilder msg = new StringBuilder(); msg.append("You are not allowed to overwrite the final "); msg.append(getDescription(superCN)); msg.append("."); addError(msg.toString(), cn); }
// GroovyClassVisitor interface // ------------------------------------------------------------------------- public void visitClass(ClassNode classNode) { try { this.classNode = classNode; this.internalClassName = BytecodeHelper.getClassInternalName(classNode); // System.out.println("Generating class: " + classNode.getName()); this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass()); cv.visit( Opcodes.V1_3, classNode.getModifiers(), internalClassName, (String) null, internalBaseClassName, BytecodeHelper.getClassInternalNames(classNode.getInterfaces())); classNode.visitContents(this); for (Iterator iter = innerClasses.iterator(); iter.hasNext(); ) { ClassNode innerClass = (ClassNode) iter.next(); ClassNode innerClassType = innerClass; String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassType); String outerClassName = internalClassName; // default for inner classes MethodNode enclosingMethod = innerClass.getEnclosingMethod(); if (enclosingMethod != null) { // local inner classes do not specify the outer class name outerClassName = null; } cv.visitInnerClass( innerClassInternalName, outerClassName, innerClassType.getName(), innerClass.getModifiers()); } cv.visitEnd(); } catch (GroovyRuntimeException e) { e.setModule(classNode.getModule()); throw e; } }
@Override public void call( final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException { if ((classNode.getModifiers() & Opcodes.ACC_INTERFACE) > 0) { // does not apply on interfaces return; } if (!(classNode instanceof InnerClassNode)) { addTimeStamp(classNode); } }
public static ClassNode getFurthestUnresolvedParent(ClassNode classNode) { ClassNode parent = classNode.getSuperClass(); while (parent != null && !getFullName(parent).equals("java.lang.Object") && !parent.isResolved() && !Modifier.isAbstract(parent.getModifiers())) { classNode = parent; parent = parent.getSuperClass(); } return classNode; }
private void checkAbstractDeclaration(MethodNode methodNode) { if (!methodNode.isAbstract()) return; if (isAbstract(currentClass.getModifiers())) return; addError( "Can't have an abstract method in a non-abstract class." + " The " + getDescription(currentClass) + " must be declared abstract or the method '" + methodNode.getTypeDescriptor() + "' must not be abstract.", methodNode); }
private void visitDeprecation(AnnotatedNode node, AnnotationNode visited) { if (visited.getClassNode().isResolved() && visited.getClassNode().getName().equals("java.lang.Deprecated")) { if (node instanceof MethodNode) { MethodNode mn = (MethodNode) node; mn.setModifiers(mn.getModifiers() | Opcodes.ACC_DEPRECATED); } else if (node instanceof FieldNode) { FieldNode fn = (FieldNode) node; fn.setModifiers(fn.getModifiers() | Opcodes.ACC_DEPRECATED); } else if (node instanceof ClassNode) { ClassNode cn = (ClassNode) node; cn.setModifiers(cn.getModifiers() | Opcodes.ACC_DEPRECATED); } } }
private void checkNoAbstractMethodsNonabstractClass(ClassNode node) { if (isAbstract(node.getModifiers())) return; List<MethodNode> abstractMethods = node.getAbstractMethods(); if (abstractMethods == null) return; for (MethodNode method : abstractMethods) { addError( "Can't have an abstract method in a non-abstract class." + " The " + getDescription(node) + " must be declared abstract or" + " the " + getDescription(method) + " must be implemented.", node); } }
public void generateClass(ClassNode classNode) throws FileNotFoundException { // Only attempt to render our self if our super-class is resolved, else wait for it if (requireSuperResolved && !classNode.getSuperClass().isResolved()) { return; } // owner should take care for us if (classNode instanceof InnerClassNode) return; // don't generate stubs for private classes, as they are only visible in the same file if ((classNode.getModifiers() & Opcodes.ACC_PRIVATE) != 0) return; String fileName = classNode.getName().replace('.', '/'); mkdirs(outputPath, fileName); toCompile.add(fileName); File file = new File(outputPath, fileName + ".java"); FileOutputStream fos = new FileOutputStream(file); PrintWriter out = new PrintWriter(fos); try { String packageName = classNode.getPackageName(); if (packageName != null) { out.println("package " + packageName + ";\n"); } printImports(out, classNode); printClassContents(out, classNode); } finally { try { out.close(); } catch (Exception e) { // ignore } try { fos.close(); } catch (IOException e) { // ignore } } }
private void makeClassFinal(ClassNode cNode) { if ((cNode.getModifiers() & ACC_FINAL) == 0) { cNode.setModifiers(cNode.getModifiers() | ACC_FINAL); } }
@Override public void visit(ASTNode[] astNodes, SourceUnit source) { if (!(astNodes[0] instanceof AnnotationNode) || !(astNodes[1] instanceof AnnotatedNode)) { throw new RuntimeException("Internal error: wrong types: $node.class / $parent.class"); } AnnotatedNode parent = (AnnotatedNode) astNodes[1]; AnnotationNode node = (AnnotationNode) astNodes[0]; if (!MY_TYPE.equals(node.getClassNode()) || !(parent instanceof ClassNode)) { return; } ClassNode classNode = (ClassNode) parent; if (classNode.isInterface() || Modifier.isAbstract(classNode.getModifiers())) { return; } boolean junit3Test = isJunit3Test(classNode); boolean spockTest = isSpockTest(classNode); boolean isJunit = classNode.getName().endsWith("Tests"); if (!junit3Test && !spockTest && !isJunit) return; Expression value = node.getMember("value"); ClassExpression ce; if (value instanceof ClassExpression) { ce = (ClassExpression) value; testFor(classNode, ce); } else { if (!junit3Test) { List<AnnotationNode> annotations = classNode.getAnnotations(MY_TYPE); if (annotations.size() > 0) return; // bail out, in this case it was already applied as a local transform // no explicit class specified try by convention String fileName = source.getName(); String className = GrailsResourceUtils.getClassName(new FileSystemResource(fileName)); if (className != null) { boolean isSpock = className.endsWith("Spec"); String targetClassName = null; if (isJunit) { targetClassName = className.substring(0, className.indexOf("Tests")); } else if (isSpock) { targetClassName = className.substring(0, className.indexOf("Spec")); } if (targetClassName != null) { Resource targetResource = getResourceLocator().findResourceForClassName(targetClassName); if (targetResource != null) { try { if (GrailsResourceUtils.isDomainClass(targetResource.getURL())) { testFor( classNode, new ClassExpression( new ClassNode(targetClassName, 0, ClassHelper.OBJECT_TYPE))); } else { for (String artefactType : artefactTypeToTestMap.keySet()) { if (targetClassName.endsWith(artefactType)) { testFor( classNode, new ClassExpression( new ClassNode(targetClassName, 0, ClassHelper.OBJECT_TYPE))); break; } } } } catch (IOException e) { // ignore } } } } } } }
private void revertVisibility(ClassNode cNode) { cNode.setModifiers(cNode.getModifiers() & ~ACC_PUBLIC); }
@SuppressWarnings("BooleanMethodIsAlwaysInverted") private boolean isFinal(ClassNode classNode) { return (classNode.getModifiers() & ACC_FINAL) != 0; }
private void printClassContents(PrintWriter out, ClassNode classNode) throws FileNotFoundException { if (classNode instanceof InnerClassNode && ((InnerClassNode) classNode).isAnonymous()) { // if it is an anonymous inner class, don't generate the stub code for it. return; } try { Verifier verifier = new Verifier() { public void addCovariantMethods(ClassNode cn) {} protected void addTimeStamp(ClassNode node) {} protected void addInitialization(ClassNode node) {} protected void addPropertyMethod(MethodNode method) { doAddMethod(method); } protected void addReturnIfNeeded(MethodNode node) {} protected void addMethod( ClassNode node, boolean shouldBeSynthetic, String name, int modifiers, ClassNode returnType, Parameter[] parameters, ClassNode[] exceptions, Statement code) { doAddMethod( new MethodNode(name, modifiers, returnType, parameters, exceptions, code)); } protected void addConstructor( Parameter[] newParams, ConstructorNode ctor, Statement code, ClassNode node) { if (code instanceof ExpressionStatement) { // GROOVY-4508 Statement temp = code; code = new BlockStatement(); ((BlockStatement) code).addStatement(temp); } ConstructorNode ctrNode = new ConstructorNode(ctor.getModifiers(), newParams, ctor.getExceptions(), code); ctrNode.setDeclaringClass(node); constructors.add(ctrNode); } protected void addDefaultParameters(DefaultArgsAction action, MethodNode method) { final Parameter[] parameters = method.getParameters(); final Expression[] saved = new Expression[parameters.length]; for (int i = 0; i < parameters.length; i++) { if (parameters[i].hasInitialExpression()) saved[i] = parameters[i].getInitialExpression(); } super.addDefaultParameters(action, method); for (int i = 0; i < parameters.length; i++) { if (saved[i] != null) parameters[i].setInitialExpression(saved[i]); } } private void doAddMethod(MethodNode method) { String sig = method.getTypeDescriptor(); if (propertyMethodsWithSigs.containsKey(sig)) return; propertyMethods.add(method); propertyMethodsWithSigs.put(sig, method); } @Override protected void addDefaultConstructor(ClassNode node) { // not required for stub generation } }; verifier.visitClass(classNode); currentModule = classNode.getModule(); boolean isInterface = classNode.isInterface(); boolean isEnum = (classNode.getModifiers() & Opcodes.ACC_ENUM) != 0; boolean isAnnotationDefinition = classNode.isAnnotationDefinition(); printAnnotations(out, classNode); printModifiers( out, classNode.getModifiers() & ~(isInterface ? Opcodes.ACC_ABSTRACT : 0) & ~(isEnum ? Opcodes.ACC_FINAL : 0)); if (isInterface) { if (isAnnotationDefinition) { out.print("@"); } out.print("interface "); } else if (isEnum) { out.print("enum "); } else { out.print("class "); } String className = classNode.getNameWithoutPackage(); if (classNode instanceof InnerClassNode) className = className.substring(className.lastIndexOf("$") + 1); out.println(className); printGenericsBounds(out, classNode, true); ClassNode superClass = classNode.getUnresolvedSuperClass(false); if (!isInterface && !isEnum) { out.print(" extends "); printType(out, superClass); } ClassNode[] interfaces = classNode.getInterfaces(); if (interfaces != null && interfaces.length > 0 && !isAnnotationDefinition) { if (isInterface) { out.println(" extends"); } else { out.println(" implements"); } for (int i = 0; i < interfaces.length - 1; ++i) { out.print(" "); printType(out, interfaces[i]); out.print(","); } out.print(" "); printType(out, interfaces[interfaces.length - 1]); } out.println(" {"); printFields(out, classNode); printMethods(out, classNode, isEnum); for (Iterator<InnerClassNode> inner = classNode.getInnerClasses(); inner.hasNext(); ) { // GROOVY-4004: Clear the methods from the outer class so that they don't get duplicated in // inner ones propertyMethods.clear(); propertyMethodsWithSigs.clear(); constructors.clear(); printClassContents(out, inner.next()); } out.println("}"); } finally { propertyMethods.clear(); propertyMethodsWithSigs.clear(); constructors.clear(); currentModule = null; } }