001    /*
002     * Copyright 2004-2006 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.apt.comp;
027    
028    import com.sun.mirror.declaration.*;
029    import static com.sun.mirror.declaration.Modifier.*;
030    import com.sun.mirror.type.*;
031    import com.sun.mirror.apt.*;
032    
033    import java.util.*;
034    import com.sun.mirror.util.*;
035    
036    /**
037     * Class used to implement "-print" option.
038     */
039    public class PrintAP implements AnnotationProcessor {
040    
041    
042        static class PrintingVisitors {
043            int indentation = 0; // Indentation level;
044            AnnotationProcessorEnvironment env;
045            Messager out;
046            Declaration java_lang_Object;
047            Declaration java_lang_annotation_Annotation;
048    
049            static Set<Modifier> EMPTY_ELIDES = Collections.emptySet();
050            static Set<Modifier> INTERFACE_ELIDES = EnumSet.of(ABSTRACT);
051            static Set<Modifier> ENUM_ELIDES = EnumSet.of(FINAL, ABSTRACT);
052            static Set<Modifier> INTERFACE_MEMBER_ELIDES = EnumSet.of(ABSTRACT, PUBLIC, STATIC, FINAL);
053    
054            PrintingVisitors(AnnotationProcessorEnvironment env) {
055                this.env = env;
056                this.out = env.getMessager();
057                this.java_lang_Object = env.getTypeDeclaration("java.lang.Object");
058                this.java_lang_annotation_Annotation = env.getTypeDeclaration("java.lang.annotation.Annotation");
059            }
060    
061    
062            static String [] spaces = {
063                "",
064                "  ",
065                "    ",
066                "      ",
067                "        ",
068                "          ",
069                "            ",
070                "              ",
071                "                ",
072                "                  ",
073                "                    "
074            };
075    
076    
077            String indent(){
078                int indentation = this.indentation;
079                if (indentation < 0)
080                    return "";
081                else if (indentation <= 10)
082                    return spaces[indentation];
083                else {
084                    StringBuilder sb = new StringBuilder();
085                    while (indentation > 10) {
086                        sb.append(spaces[indentation]);
087                        indentation -= 10;
088                    }
089                    sb.append(spaces[indentation]);
090                return sb.toString();
091                }
092            }
093    
094    
095            class PrePrinting extends SimpleDeclarationVisitor {
096                Map<EnumDeclaration, Integer> enumCardinality  = new HashMap<EnumDeclaration, Integer>();
097                Map<EnumDeclaration, Integer> enumConstVisited = new HashMap<EnumDeclaration, Integer>();
098    
099                PrePrinting(){}
100    
101                public void visitClassDeclaration(ClassDeclaration d) {
102                    System.out.println();
103                    printDocComment(d);
104                    printModifiers(d, EMPTY_ELIDES);
105                    System.out.print("class " + d.getSimpleName());
106                    printFormalTypeParameters(d);
107    
108                    // Elide "extends Object"
109                    ClassType Super = d.getSuperclass();
110                    if (Super != null && !java_lang_Object.equals(Super.getDeclaration()) )
111                        System.out.print(" extends " + Super.toString());
112    
113                    printInterfaces(d);
114    
115                    System.out.println(" {");
116    
117                    PrintingVisitors.this.indentation++;
118                }
119    
120                public void visitEnumDeclaration(EnumDeclaration d) {
121                    enumCardinality.put(d, d.getEnumConstants().size());
122                    enumConstVisited.put(d, 1);
123    
124                    System.out.println();
125                    printDocComment(d);
126                    printModifiers(d, ENUM_ELIDES);
127    
128                    System.out.print("enum " + d.getSimpleName());
129                    printFormalTypeParameters(d);
130                    printInterfaces(d);
131    
132                    System.out.println(" {");
133    
134                    PrintingVisitors.this.indentation++;
135                }
136    
137    
138                public void visitInterfaceDeclaration(InterfaceDeclaration d) {
139                    System.out.println();
140                    printDocComment(d);
141                    printModifiers(d, INTERFACE_ELIDES);
142                    System.out.print("interface " + d.getSimpleName());
143    
144                    printFormalTypeParameters(d);
145                    printInterfaces(d);
146    
147                    System.out.println(" {");
148    
149                    PrintingVisitors.this.indentation++;
150                }
151    
152                public void visitAnnotationTypeDeclaration(AnnotationTypeDeclaration d) {
153                    System.out.println();
154                    printDocComment(d);
155                    printModifiers(d, INTERFACE_ELIDES);
156                    System.out.print("@interface " + d.getSimpleName());
157                    printFormalTypeParameters(d);
158    
159                    printInterfaces(d);
160    
161                    System.out.println(" {");
162    
163                    PrintingVisitors.this.indentation++;
164                }
165    
166                public void visitFieldDeclaration(FieldDeclaration d) {
167                    System.out.println();
168                    printDocComment(d);
169                    printModifiers(d,
170                                   (d.getDeclaringType() instanceof InterfaceDeclaration)?
171                                   INTERFACE_MEMBER_ELIDES : EMPTY_ELIDES);
172                    System.out.print(d.getType().toString() + " " +
173                                       d.getSimpleName() );
174                    String constantExpr = d.getConstantExpression();
175                    if (constantExpr != null) {
176                        System.out.print(" = " + constantExpr);
177                    }
178                    System.out.println(";" );
179                }
180    
181                public void visitEnumConstantDeclaration(EnumConstantDeclaration d) {
182                    EnumDeclaration ed = d.getDeclaringType();
183                    int enumCard = enumCardinality.get(ed);
184                    int enumVisit = enumConstVisited.get(ed);
185    
186                    System.out.println();
187                    printDocComment(d);
188                    System.out.print(PrintingVisitors.this.indent());
189                    System.out.print(d.getSimpleName() );
190                    System.out.println((enumVisit < enumCard )? ",":";" );
191    
192                    enumConstVisited.put(ed, enumVisit+1);
193                }
194    
195                public void visitMethodDeclaration(MethodDeclaration d) {
196                    System.out.println();
197                    printDocComment(d);
198                    printModifiers(d,
199                                   (d.getDeclaringType() instanceof InterfaceDeclaration)?
200                                   INTERFACE_MEMBER_ELIDES : EMPTY_ELIDES);
201                    printFormalTypeParameters(d);
202                    System.out.print(d.getReturnType().toString() + " ");
203                    System.out.print(d.getSimpleName() + "(");
204                    printParameters(d);
205                    System.out.print(")");
206                    printThrows(d);
207                    System.out.println(";");
208                }
209    
210                public void visitConstructorDeclaration(ConstructorDeclaration d) {
211                    System.out.println();
212                    printDocComment(d);
213                    printModifiers(d, EMPTY_ELIDES);
214                    printFormalTypeParameters(d);
215                    System.out.print(d.getSimpleName() + "(");
216                    printParameters(d);
217                    System.out.print(")");
218                    printThrows(d);
219                    System.out.println(";");
220                }
221    
222    
223            }
224    
225            class PostPrinting extends SimpleDeclarationVisitor {
226                PostPrinting(){}
227    
228                public void visitTypeDeclaration(TypeDeclaration d) {
229                    PrintingVisitors.this.indentation--;
230    
231                    System.out.print(PrintingVisitors.this.indent());
232                    System.out.println("}");
233                }
234            }
235    
236            private void printAnnotations(Collection<AnnotationMirror> annots) {
237    
238                for(AnnotationMirror annot: annots) {
239                    System.out.print(this.indent());
240                    System.out.print(annot.toString());
241                    System.out.println();
242                }
243            }
244    
245            private void printAnnotationsInline(Collection<AnnotationMirror> annots) {
246    
247                for(AnnotationMirror annot: annots) {
248                    System.out.print(annot);
249                    System.out.print(" ");
250                }
251            }
252    
253    
254            private void printParameters(ExecutableDeclaration ex) {
255    
256                Collection<ParameterDeclaration> parameters = ex.getParameters();
257                int size = parameters.size();
258    
259                switch (size) {
260                case 0:
261                    break;
262    
263                case 1:
264                    for(ParameterDeclaration parameter: parameters) {
265                        printModifiers(parameter, EMPTY_ELIDES);
266    
267                        if (ex.isVarArgs() ) {
268                            System.out.print(((ArrayType)parameter.getType()).getComponentType() );
269                            System.out.print("...");
270                        } else
271                            System.out.print(parameter.getType());
272                        System.out.print(" " + parameter.getSimpleName());
273                    }
274                    break;
275    
276                default:
277                    {
278                        int i = 1;
279                        for(ParameterDeclaration parameter: parameters) {
280                            if (i == 2)
281                                PrintingVisitors.this.indentation++;
282    
283                            if (i > 1)
284                                System.out.print(PrintingVisitors.this.indent());
285    
286                            printModifiers(parameter, EMPTY_ELIDES);
287    
288                            if (i == size && ex.isVarArgs() ) {
289                                System.out.print(((ArrayType)parameter.getType()).getComponentType() );
290                                System.out.print("...");
291                            } else
292                                System.out.print(parameter.getType());
293                            System.out.print(" " + parameter.getSimpleName());
294    
295                            if (i < size)
296                                System.out.println(",");
297    
298                            i++;
299                        }
300    
301                        if (parameters.size() >= 2)
302                            PrintingVisitors.this.indentation--;
303                    }
304                    break;
305                }
306            }
307    
308            private void printDocComment(Declaration d) {
309                String docComment = d.getDocComment();
310    
311                if (docComment != null) {
312                    // Break comment into lines
313                    java.util.StringTokenizer st = new StringTokenizer(docComment,
314                                                                      "\n\r");
315                    System.out.print(PrintingVisitors.this.indent());
316                    System.out.println("/**");
317    
318                    while(st.hasMoreTokens()) {
319                        System.out.print(PrintingVisitors.this.indent());
320                        System.out.print(" *");
321                        System.out.println(st.nextToken());
322                    }
323    
324                    System.out.print(PrintingVisitors.this.indent());
325                    System.out.println(" */");
326                }
327            }
328    
329            private void printModifiers(Declaration d, Collection<Modifier> elides) {
330                printAnnotations(d.getAnnotationMirrors());
331    
332                System.out.print(PrintingVisitors.this.indent());
333    
334                for(Modifier m: adjustModifiers(d.getModifiers(), elides) ){
335                    System.out.print(m.toString() + " ");
336                }
337            }
338    
339            private void printModifiers(ParameterDeclaration d, Collection<Modifier> elides) {
340                printAnnotationsInline(d.getAnnotationMirrors());
341    
342                for(Modifier m: adjustModifiers(d.getModifiers(), elides) ) {
343                    System.out.print(m.toString() + " ");
344                }
345            }
346    
347            private Collection<Modifier> adjustModifiers(Collection<Modifier> mods,
348                                                         Collection<Modifier> elides) {
349                if (elides.isEmpty())
350                    return mods;
351                else {
352                    Collection<Modifier> newMods = new LinkedHashSet<Modifier>();
353                    newMods.addAll(mods);
354                    newMods.removeAll(elides);
355                    return newMods;
356                }
357            }
358    
359            private void printFormalTypeParameters(ExecutableDeclaration e) {
360                printFormalTypeParameterSet(e.getFormalTypeParameters(), true);
361            }
362    
363            private void printFormalTypeParameters(TypeDeclaration d) {
364                printFormalTypeParameterSet(d.getFormalTypeParameters(), false);
365            }
366    
367            private void printFormalTypeParameterSet(Collection<TypeParameterDeclaration> typeParams, boolean pad) {
368                if (typeParams.size() != 0) {
369                    System.out.print("<");
370    
371                    boolean first = true;
372                    for(TypeParameterDeclaration tpd: typeParams) {
373                        if (!first)
374                            System.out.print(", ");
375                        System.out.print(tpd.toString());
376                    }
377    
378                    System.out.print(">");
379                    if (pad)
380                        System.out.print(" ");
381    
382                }
383            }
384    
385            private void printInterfaceSet(Collection<InterfaceType> interfaces,
386                                           boolean classNotInterface) {
387                if (interfaces.size() != 0) {
388                    System.out.print((classNotInterface?" implements" : " extends"));
389    
390                    boolean first = true;
391                    for(InterfaceType interType: interfaces) {
392                        if (!first)
393                            System.out.print(",");
394                        System.out.print(" ");
395                        System.out.print(interType.toString());
396                        first = false;
397                    }
398                }
399            }
400    
401            private void printInterfaces(TypeDeclaration d) {
402                printInterfaceSet(d.getSuperinterfaces(), d instanceof ClassDeclaration);
403            }
404    
405            private void printInterfaces(AnnotationTypeDeclaration d) {
406                Collection<InterfaceType> interfaces = new HashSet<InterfaceType>(d.getSuperinterfaces());
407    
408                for(InterfaceType interType: interfaces) {
409                    if (java_lang_annotation_Annotation.equals(interType.getDeclaration()) )
410                        interfaces.remove(interType);
411                }
412    
413                printInterfaceSet(interfaces, d instanceof ClassDeclaration);
414            }
415    
416            private void printThrows(ExecutableDeclaration d) {
417                Collection<ReferenceType> thrownTypes = d.getThrownTypes();
418                final int size = thrownTypes.size();
419                if (size != 0) {
420                    System.out.print(" throws");
421    
422                    int i = 1;
423                    for(ReferenceType thrownType: thrownTypes) {
424                        if (i == 1) {
425                            System.out.print(" ");
426                        }
427    
428                        if (i == 2)
429                            PrintingVisitors.this.indentation++;
430    
431                        if (i >= 2)
432                            System.out.print(PrintingVisitors.this.indent());
433    
434                        System.out.print(thrownType.toString());
435    
436    
437                        if (i != size) {
438                            System.out.println(", ");
439                        }
440                        i++;
441                    }
442    
443                    if (size >= 2)
444                        PrintingVisitors.this.indentation--;
445                }
446            }
447    
448            DeclarationVisitor getPrintingVisitor() {
449                return DeclarationVisitors.getSourceOrderDeclarationScanner(new PrePrinting(),
450                                                                            new PostPrinting());
451            }
452        }
453    
454        AnnotationProcessorEnvironment env;
455        PrintAP(AnnotationProcessorEnvironment env) {
456            this.env = env;
457        }
458    
459    
460        public void process() {
461            Collection<TypeDeclaration> typedecls = env.getSpecifiedTypeDeclarations();
462    
463            for (TypeDeclaration td: typedecls)
464                td.accept((new PrintingVisitors(env)).getPrintingVisitor());
465        }
466    }