diff options
author | Reinier Zwitserloot <reinier@tipit.to> | 2009-06-08 22:26:30 +0200 |
---|---|---|
committer | Reinier Zwitserloot <reinier@tipit.to> | 2009-06-08 22:26:30 +0200 |
commit | 1677c4a52a0aea1b955f7c2c7d096903d4a8c5ce (patch) | |
tree | 29de8d12d774f026c0f317e229532befaeb2d096 /original_panno/com/hanhuy/panno/processing/ASTTreeToSource.java | |
download | lombok-1677c4a52a0aea1b955f7c2c7d096903d4a8c5ce.tar.gz lombok-1677c4a52a0aea1b955f7c2c7d096903d4a8c5ce.tar.bz2 lombok-1677c4a52a0aea1b955f7c2c7d096903d4a8c5ce.zip |
Initial commit. As a proof of concept, it already works in javac and eclipse!
Diffstat (limited to 'original_panno/com/hanhuy/panno/processing/ASTTreeToSource.java')
-rw-r--r-- | original_panno/com/hanhuy/panno/processing/ASTTreeToSource.java | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/original_panno/com/hanhuy/panno/processing/ASTTreeToSource.java b/original_panno/com/hanhuy/panno/processing/ASTTreeToSource.java new file mode 100644 index 00000000..2e7dc641 --- /dev/null +++ b/original_panno/com/hanhuy/panno/processing/ASTTreeToSource.java @@ -0,0 +1,320 @@ +/* + * Copyright 2007 Perry Nguyen <pfnguyen@hanhuy.com> Licensed under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.hanhuy.panno.processing; + +import java.util.Map; +import java.util.Stack; + +import javax.annotation.processing.Messager; +import javax.lang.model.element.Modifier; +import javax.tools.Diagnostic; + +import com.hanhuy.panno.Property; +import com.sun.source.tree.AnnotationTree; +import com.sun.source.tree.BlockTree; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.IdentifierTree; +import com.sun.source.tree.ImportTree; +import com.sun.source.tree.MethodTree; +import com.sun.source.tree.StatementTree; +import com.sun.source.tree.VariableTree; +import com.sun.source.util.TreeScanner; + +/** + * Old attempt to get the annotation working, have a better approach now. + */ +@Deprecated +class ASTTreeToSource extends TreeScanner<Void, StringBuilder> { + public final static String PROPERTY_ANNOTATION_FULL = "com.hanhuy.panno.Property"; + public final static String PROPERTY_ANNOTATION = "Property"; + + private final Stack<String> currentClassNameStack = new Stack<String>(); + private final Messager messager; + private final Map<String, Property> fieldMap; + private String currentClassName; + private String currentField; + private String currentType; + + ASTTreeToSource(Map<String, Property> fieldMap, Messager messager) { + this.fieldMap = fieldMap; + this.messager = messager; + } + + /** + * Handle initializer blocks, both static and non. + */ + @Override + public Void visitBlock(BlockTree node, StringBuilder p) { + p.append("\n"); + if ( node.isStatic() ) p.append("static "); + p.append("{\n"); + for ( StatementTree st : node.getStatements() ) { + p.append(st); + p.append(";"); + } + p.append("\n}\n"); + return null; + } + + /** + * Detect our annotation and add accessors if necessary. + */ + @Override + public Void visitAnnotation(AnnotationTree node, StringBuilder p) { + String anno = ((IdentifierTree)node.getAnnotationType()).getName().toString(); + if ( anno != null && PROPERTY_ANNOTATION.equals(anno.trim()) ) { + Property pAnno = fieldMap.get(currentClassName + "." + currentField); + + String propName = currentField; + if ( !"".equals(pAnno.name()) ) propName = pAnno.name(); + propName = PropertyProcessor.ucfirst(propName); + + if ( pAnno.writeOnly() && pAnno.readOnly() ) { + messager.printMessage(Diagnostic.Kind.ERROR, "@Property's writeOnly and readOnly may not both be true"); + } + + if ( !"boolean".equals(currentType) && pAnno.useGet() ) { + messager.printMessage(Diagnostic.Kind.WARNING, "@Property's useGet is only for booleans"); + } + + if ( !pAnno.writeOnly() ) { + // generate a getter + p.append("\n"); + p.append("public "); + p.append(currentType); + if ( !"boolean".equals(currentType) || pAnno.useGet() ) p.append(" get"); + else p.append(" is"); + p.append(propName); + p.append("() { return "); + p.append(currentField); + p.append("; }"); + } + if ( !pAnno.readOnly() ) { + // generate a setter + p.append("\n"); + p.append("public void set"); + p.append(propName); + p.append("("); + p.append(currentType); + p.append(" "); + p.append(currentField); + p.append(") { this."); + p.append(currentField); + p.append(" = "); + p.append(currentField); + p.append("; }"); + } + } + return null; + } + + /** + * Gather file information. Then continue to visit classes. + */ + @Override + public Void visitCompilationUnit(CompilationUnitTree node, StringBuilder p) { + new Exception("Visit CUT: " + node.getSourceFile()).printStackTrace(); + p.append("// Generated from: "); + p.append(node.getSourceFile()); + p.append("\n\npackage "); + p.append(node.getPackageName()); + p.append(";\n\n"); + + for ( ImportTree it : node.getImports() ) { + if ( PROPERTY_ANNOTATION_FULL.equals(it.getQualifiedIdentifier().toString().trim()) ) { + continue; + } + p.append("import "); + if ( it.isStatic() ) p.append("static "); + p.append(it.getQualifiedIdentifier()); + p.append(";\n"); + } + super.visitCompilationUnit(node, p); + return null; + } + + private void pushClass(String className) { + currentClassName = className; + currentClassNameStack.push(currentClassName); + } + + private void popClass() { + currentClassNameStack.pop(); + if ( currentClassNameStack.size() > 0 ) currentClassName = currentClassNameStack.peek(); + } + + /** + * Reproduce class declarations, and go on to handle methods, blocks and + * variables. + */ + @Override + public Void visitClass(ClassTree node, StringBuilder p) { + pushClass(node.getSimpleName().toString()); + + // Check to see if this is an enum + // I have no idea what will happen if we encounter an AST + // implementation that is not Sun's (or if this has changed in java7) + if ( node instanceof com.sun.tools.javac.tree.JCTree.JCClassDecl ) { + com.sun.tools.javac.tree.JCTree.JCClassDecl jcd = (com.sun.tools.javac.tree.JCTree.JCClassDecl)node; + if ( (jcd.mods.flags & 16384L) != 0L ) { + p.append(node.getModifiers()); + p.append(" enum "); + p.append(currentClassName); + appendEnumBody(jcd.defs, p); + + popClass(); + + return null; + } + } + + p.append("\n"); + p.append(node.getModifiers()); + p.append(" class "); + p.append(currentClassName); + if ( node.getTypeParameters().size() > 0 ) { + p.append("<"); + p.append(node.getTypeParameters()); + p.append(">"); + } + if ( node.getExtendsClause() != null ) { + p.append("\nextends "); + p.append(node.getExtendsClause()); + } + if ( node.getImplementsClause().size() > 0 ) { + p.append("\nimplements "); + p.append(node.getImplementsClause()); + } + + p.append("\n{"); + super.visitClass(node, p); + p.append("\n}\n"); + + popClass(); + + return null; + } + + /** + * Enums appear to be a special case. We must reconstitute its source in a + * different manner from the rest. Need to remove any 'super()' statements + * and print the lines appropriately. + */ + public void appendEnumBody(com.sun.tools.javac.util.List<com.sun.tools.javac.tree.JCTree> list, StringBuilder p) { + p.append("{\n"); + boolean flag = true; + + for ( com.sun.tools.javac.util.List<com.sun.tools.javac.tree.JCTree> list1 = list; list1.nonEmpty(); list1 = list1.tail ) { + + if ( !isEnumerator(list1.head) ) continue; + + if ( !flag ) p.append(",\n"); + + p.append(list1.head); + flag = false; + } + + p.append(";\n"); + for ( com.sun.tools.javac.util.List<com.sun.tools.javac.tree.JCTree> list2 = list; list2.nonEmpty(); list2 = list2.tail ) { + if ( !isEnumerator(list2.head) ) { + if ( list2.head instanceof MethodTree ) visitMethod((MethodTree)list2.head, p); + else p.append(list2.head); + p.append("\n"); + } + } + + p.append("}"); + } + + private boolean isEnumerator(com.sun.tools.javac.tree.JCTree jctree) { + return jctree.tag == 5 && (((com.sun.tools.javac.tree.JCTree.JCVariableDecl)jctree).mods.flags & 16384L) != 0L; + } + + /** + * Reconstitute methods. We could just do node.toString() here, but + * constructors need to be renamed from <init> to the class name, so + * handle all methods. + */ + @Override + public Void visitMethod(MethodTree node, StringBuilder p) { + p.append("\n"); + p.append(node.getModifiers()); + p.append(" "); + if ( node.getReturnType() != null ) p.append(node.getReturnType()); + if ( node.getTypeParameters().size() > 0 ) { + p.append(" <"); + p.append(node.getTypeParameters()); + p.append(">"); + } + p.append(" "); + if ( node.getName() != null && "<init>".equals(node.getName().toString().trim()) ) p.append(currentClassName); + else p.append(node.getName()); + + p.append("("); + p.append(node.getParameters()); + p.append(")"); + if ( node.getThrows().size() > 0 ) { + p.append("\nthrows "); + p.append(node.getThrows()); + } + + p.append(" {\n"); + // this needs to be done for enums, otherwise we'll get a compile error + // if we didn't need this case, we'd just do p.append(node.getBody()) + for ( StatementTree st : node.getBody().getStatements() ) { + if ( "super()".equals(st.toString().trim()) ) continue; + p.append(st); + if ( p.charAt(p.length() - 1) != ';' ) p.append(";\n"); + } + p.append("\n}\n"); + return null; + } + + /** + * Reconstitute class fields. While doing so, search for our annotation to + * perform processing. + */ + @Override + public Void visitVariable(VariableTree node, StringBuilder p) { + currentField = node.getName().toString(); + currentType = node.getType().toString(); + p.append("\n"); + + for ( AnnotationTree a : node.getModifiers().getAnnotations() ) { + String anno = ((IdentifierTree)a.getAnnotationType()).getName().toString(); + if ( !PROPERTY_ANNOTATION.equals(anno) ) { + p.append(a); + p.append("\n"); + } + } + + for ( Modifier m : node.getModifiers().getFlags() ) { + p.append(m.toString()); + p.append(" "); + } + p.append(" "); + p.append(currentType); + p.append(" "); + p.append(currentField); + + if ( node.getInitializer() != null ) { + p.append(" = "); + p.append(node.getInitializer()); + } + p.append(";"); + super.visitVariable(node, p); + return null; + } +} |