001    /*
002     * Copyright 2004-2005 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.mirror.util;
027    
028    import com.sun.mirror.declaration.*;
029    
030    import java.util.SortedSet;
031    import java.util.TreeSet;
032    
033    /**
034     * A visitor for declarations that scans declarations contained within
035     * the given declaration in source code order.  For example, when
036     * visiting a class, the methods, fields, constructors, and nested
037     * types of the class are also visited.
038     *
039     * To control the processing done on a declaration, users of this
040     * class pass in their own visitors for pre and post processing.  The
041     * preprocessing visitor is called before the contained declarations
042     * are scanned; the postprocessing visitor is called after the
043     * contained declarations are scanned.
044     *
045     * @author Joseph D. Darcy
046     * @author Scott Seligman
047     * @since 1.5
048     */
049    class SourceOrderDeclScanner extends DeclarationScanner {
050        static class SourceOrderComparator implements java.util.Comparator<Declaration> {
051            SourceOrderComparator(){}
052    
053    
054            static boolean equals(Declaration d1, Declaration d2) {
055                return d1 == d2 || (d1 != null && d1.equals(d2));
056            }
057    
058            private static class DeclPartialOrder extends com.sun.mirror.util.SimpleDeclarationVisitor {
059                private int value = 1000;
060                private static int staticAdjust(Declaration d) {
061                    return d.getModifiers().contains(Modifier.STATIC)?0:1;
062                }
063    
064                DeclPartialOrder() {}
065    
066                public int getValue() { return value; }
067    
068                @Override
069                public void visitTypeParameterDeclaration(TypeParameterDeclaration d) {value = 0;}
070    
071                @Override
072                public void visitEnumConstantDeclaration(EnumConstantDeclaration d) {value = 1;}
073    
074                @Override
075                public void visitClassDeclaration(ClassDeclaration d) {value = 2 + staticAdjust(d);}
076    
077                @Override
078                public void visitInterfaceDeclaration(InterfaceDeclaration d) {value = 4;}
079    
080                @Override
081                public void visitEnumDeclaration(EnumDeclaration d) {value = 6;}
082    
083                @Override
084                public void visitAnnotationTypeDeclaration(AnnotationTypeDeclaration d) {value = 8;}
085    
086                @Override
087                public void visitFieldDeclaration(FieldDeclaration d) {value = 10 + staticAdjust(d);}
088    
089                @Override
090                public void visitConstructorDeclaration(ConstructorDeclaration d) {value = 12;}
091    
092                @Override
093                public void visitMethodDeclaration(MethodDeclaration d) {value = 14 + staticAdjust(d);}
094            }
095            @SuppressWarnings("cast")
096            private int compareEqualPosition(Declaration d1, Declaration d2) {
097                assert d1.getPosition() == d2.getPosition();
098    
099                DeclPartialOrder dpo1 = new DeclPartialOrder();
100                DeclPartialOrder dpo2 = new DeclPartialOrder();
101    
102                d1.accept(dpo1);
103                d2.accept(dpo2);
104    
105                int difference = dpo1.getValue() - dpo2.getValue();
106                if (difference != 0)
107                    return difference;
108                else {
109                    int result = d1.getSimpleName().compareTo(d2.getSimpleName());
110                    if (result != 0)
111                        return result;
112                    return (int)( Long.signum((long)System.identityHashCode(d1) -
113                                              (long)System.identityHashCode(d2)));
114                }
115            }
116    
117            public int compare(Declaration d1, Declaration d2) {
118                if (equals(d1, d2))
119                    return 0;
120    
121                SourcePosition p1 = d1.getPosition();
122                SourcePosition p2 = d2.getPosition();
123    
124                if (p1 == null && p2 != null)
125                    return 1;
126                else if (p1 != null && p2 == null)
127                    return -1;
128                else if(p1 == null && p2 == null)
129                    return compareEqualPosition(d1, d2);
130                else {
131                    assert p1 != null && p2 != null;
132                    int fileComp = p1.file().compareTo(p2.file()) ;
133                    if (fileComp == 0) {
134                        long diff = (long)p1.line() - (long)p2.line();
135                        if (diff == 0) {
136                            diff = Long.signum((long)p1.column() - (long)p2.column());
137                            if (diff != 0)
138                                return (int)diff;
139                            else {
140                                // declarations may be two
141                                // compiler-generated members with the
142                                // same source position
143                                return compareEqualPosition(d1, d2);
144                            }
145                        } else
146                            return (diff<0)? -1:1;
147                    } else
148                        return fileComp;
149                }
150            }
151        }
152    
153        final static java.util.Comparator<Declaration> comparator = new SourceOrderComparator();
154    
155        SourceOrderDeclScanner(DeclarationVisitor pre, DeclarationVisitor post) {
156            super(pre, post);
157        }
158    
159        /**
160         * Visits a type declaration.
161         *
162         * @param d the declaration to visit
163         */
164        public void visitTypeDeclaration(TypeDeclaration d) {
165            d.accept(pre);
166    
167            SortedSet<Declaration> decls = new
168                TreeSet<Declaration>(SourceOrderDeclScanner.comparator) ;
169    
170            for(TypeParameterDeclaration tpDecl: d.getFormalTypeParameters()) {
171                decls.add(tpDecl);
172            }
173    
174            for(FieldDeclaration fieldDecl: d.getFields()) {
175                decls.add(fieldDecl);
176            }
177    
178            for(MethodDeclaration methodDecl: d.getMethods()) {
179                decls.add(methodDecl);
180            }
181    
182            for(TypeDeclaration typeDecl: d.getNestedTypes()) {
183                decls.add(typeDecl);
184            }
185    
186            for(Declaration decl: decls )
187                decl.accept(this);
188    
189            d.accept(post);
190        }
191    
192        /**
193         * Visits a class declaration.
194         *
195         * @param d the declaration to visit
196         */
197        public void visitClassDeclaration(ClassDeclaration d) {
198            d.accept(pre);
199    
200            SortedSet<Declaration> decls = new
201                TreeSet<Declaration>(SourceOrderDeclScanner.comparator) ;
202    
203            for(TypeParameterDeclaration tpDecl: d.getFormalTypeParameters()) {
204                decls.add(tpDecl);
205            }
206    
207            for(FieldDeclaration fieldDecl: d.getFields()) {
208                decls.add(fieldDecl);
209            }
210    
211            for(MethodDeclaration methodDecl: d.getMethods()) {
212                decls.add(methodDecl);
213            }
214    
215            for(TypeDeclaration typeDecl: d.getNestedTypes()) {
216                decls.add(typeDecl);
217            }
218    
219            for(ConstructorDeclaration ctorDecl: d.getConstructors()) {
220                decls.add(ctorDecl);
221            }
222    
223            for(Declaration decl: decls )
224                decl.accept(this);
225    
226            d.accept(post);
227        }
228    
229        public void visitExecutableDeclaration(ExecutableDeclaration d) {
230            d.accept(pre);
231    
232            SortedSet<Declaration> decls = new
233                TreeSet<Declaration>(SourceOrderDeclScanner.comparator) ;
234    
235            for(TypeParameterDeclaration tpDecl: d.getFormalTypeParameters())
236                decls.add(tpDecl);
237    
238            for(ParameterDeclaration pDecl: d.getParameters())
239                decls.add(pDecl);
240    
241            for(Declaration decl: decls )
242                decl.accept(this);
243    
244            d.accept(post);
245        }
246    
247    }