KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > apt > core > internal > util > Visitors


1 /*******************************************************************************
2  * Copyright (c) 2005, 2007 BEA Systems, Inc.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * tyeung@bea.com - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.apt.core.internal.util;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.List JavaDoc;
16 import java.util.Map JavaDoc;
17
18 import org.eclipse.jdt.core.dom.ASTNode;
19 import org.eclipse.jdt.core.dom.ASTVisitor;
20 import org.eclipse.jdt.core.dom.Annotation;
21 import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
22 import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration;
23 import org.eclipse.jdt.core.dom.Block;
24 import org.eclipse.jdt.core.dom.BodyDeclaration;
25 import org.eclipse.jdt.core.dom.DoStatement;
26 import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
27 import org.eclipse.jdt.core.dom.EnumDeclaration;
28 import org.eclipse.jdt.core.dom.FieldDeclaration;
29 import org.eclipse.jdt.core.dom.ForStatement;
30 import org.eclipse.jdt.core.dom.IExtendedModifier;
31 import org.eclipse.jdt.core.dom.IfStatement;
32 import org.eclipse.jdt.core.dom.MarkerAnnotation;
33 import org.eclipse.jdt.core.dom.MethodDeclaration;
34 import org.eclipse.jdt.core.dom.NormalAnnotation;
35 import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
36 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
37 import org.eclipse.jdt.core.dom.TryStatement;
38 import org.eclipse.jdt.core.dom.TypeDeclaration;
39
40 /**
41  * Home for ast visitors of various flavors.
42  */

43 @SuppressWarnings JavaDoc("unchecked") // JDT DOM AST API returns raw collections
44
public class Visitors {
45     
46     /**
47      * Traverse the ast looking for annotations at the declaration level.
48      * This visitor only operates at the declaration level. Method body
49      * and field initializers and static block will be ignored.
50      */

51     public static final class AnnotationVisitor extends ASTVisitor
52     {
53         private final List JavaDoc<Annotation> _annotations;
54         /**
55          * @param annotations to be populated by this visitor
56          */

57         public AnnotationVisitor(final List JavaDoc<Annotation> annotations)
58         { _annotations = annotations; }
59
60         public boolean visit(MarkerAnnotation annotation)
61         {
62             _annotations.add(annotation);
63             return false;
64         }
65
66         public boolean visit(SingleMemberAnnotation annotation)
67         {
68             _annotations.add(annotation);
69             return false;
70         }
71
72         public boolean visit(NormalAnnotation annotation)
73         {
74             _annotations.add(annotation);
75             return false;
76         }
77
78         // make sure we don't hit Arguments other than formal parameters.
79
public boolean visit(Block blk){ return false; }
80         public boolean visit(DoStatement doStatement){ return false; }
81         public boolean visit(ForStatement forStatement){ return false; }
82         public boolean visit(IfStatement ifStatement){ return false; }
83         public boolean visit(TryStatement tryStatement){ return false; }
84         
85         public void reset(){ _annotations.clear(); }
86     }
87     
88     /**
89      * Locate all the annotations and the declaration that they annotate.
90      * This visitor only operates at the declaration level. Method body
91      * and field initializers and static block will be ignored.
92      */

93     public static final class AnnotatedNodeVisitor extends ASTVisitor
94     {
95         private final Map JavaDoc<ASTNode, List JavaDoc<Annotation>> _result;
96         
97         /**
98          * @param map to be populated by this visitor.
99          * Key is the declaration ast node and the value is the list
100          * of annotation ast nodes that annotate the declaration.
101          */

102         public AnnotatedNodeVisitor(Map JavaDoc<ASTNode, List JavaDoc<Annotation>> map)
103         {
104             _result = map;
105         }
106
107         /**
108          * visit package declaration
109          */

110         public boolean visit(org.eclipse.jdt.core.dom.PackageDeclaration node)
111         {
112             final List JavaDoc<Annotation> annotations = node.annotations();
113             if( !annotations.isEmpty() )
114                 _result.put(node, annotations);
115
116             return false;
117         }
118
119         /**
120          * visit class and interface declaration
121          */

122         public boolean visit(org.eclipse.jdt.core.dom.TypeDeclaration node)
123         {
124             visitBodyDeclaration(node);
125             return true;
126         }
127
128         /**
129          * visit annotation type declaration
130          */

131         public boolean visit(org.eclipse.jdt.core.dom.AnnotationTypeDeclaration node)
132         {
133             visitBodyDeclaration(node);
134             return true;
135         }
136
137         /**
138          * visit enum type declaration
139          */

140         public boolean visit(org.eclipse.jdt.core.dom.EnumDeclaration node)
141         {
142             visitBodyDeclaration(node);
143             return true;
144         }
145
146         /**
147          * visit field declaration
148          */

149         public boolean visit(org.eclipse.jdt.core.dom.FieldDeclaration node)
150         {
151             visitBodyDeclaration(node);
152             return true;
153         }
154
155         /**
156          * visit enum constant declaration
157          */

158         public boolean visit(org.eclipse.jdt.core.dom.EnumConstantDeclaration node)
159         {
160             visitBodyDeclaration(node);
161             return true;
162         }
163
164         /**
165          * visit method declaration
166          */

167         public boolean visit(MethodDeclaration node)
168         {
169             visitBodyDeclaration(node);
170             return true;
171         }
172
173         /**
174          * visit annotation type member
175          */

176         public boolean visit(AnnotationTypeMemberDeclaration node)
177         {
178             visitBodyDeclaration(node);
179             return true;
180         }
181
182         private void visitBodyDeclaration(final BodyDeclaration node)
183         {
184             final List JavaDoc<IExtendedModifier> extMods = node.modifiers();
185             List JavaDoc<Annotation> annos = null;
186             for( IExtendedModifier extMod : extMods ){
187                 if( extMod.isAnnotation() ){
188                     if( annos == null ){
189                         annos = new ArrayList JavaDoc<Annotation>(2);
190                         _result.put(node, annos);
191                     }
192                     annos.add((Annotation)extMod);
193                 }
194             }
195         }
196
197         /**
198          * visiting formal parameter declaration.
199          */

200         public boolean visit(SingleVariableDeclaration node)
201         {
202             final List JavaDoc<IExtendedModifier> extMods = node.modifiers();
203             List JavaDoc<Annotation> annos = null;
204             for( IExtendedModifier extMod : extMods ){
205                 if( extMod.isAnnotation() ){
206                     if( annos == null ){
207                         annos = new ArrayList JavaDoc<Annotation>(2);
208                         _result.put(node, annos);
209                     }
210                     annos.add((Annotation)extMod);
211                 }
212             }
213             return false;
214         }
215
216         /**
217          * @return false so we skip everything beyond declaration level.
218          */

219         public boolean visit(Block node)
220         { // so we don't look into anything beyond declaration level.
221
return false;
222         }
223         public boolean visit(MarkerAnnotation node){ return false; }
224         public boolean visit(NormalAnnotation node){ return false; }
225         public boolean visit(SingleMemberAnnotation node){ return false; }
226     }
227     
228     /**
229      * Given an annotation locate the declaration that its annotates.
230      * This visitor only operates at the declaration level. Method body
231      * and field initializers and static block will be ignored.
232      *
233      */

234     public static final class DeclarationFinder extends ASTVisitor
235     {
236         private final Annotation _anno;
237         // The declaration, could be a body declaration or a parameter
238
// could also remain null if the annotation doesn't actually
239
// annotates anything.
240
private ASTNode _result = null;
241         public DeclarationFinder(final Annotation annotation)
242         {
243             _anno = annotation;
244         }
245         
246         /**
247          * @return back the result of the search.
248          */

249         public ASTNode getAnnotatedNode(){return _result;}
250         
251         /**
252          * We only visit nodes that can have annotations on them
253          */

254         public boolean visit(AnnotationTypeDeclaration node) {
255             return internalVisit(node);
256         }
257         
258         public boolean visit(AnnotationTypeMemberDeclaration node) {
259             return internalVisit(node);
260         }
261         
262         public boolean visit(EnumDeclaration node) {
263             return internalVisit(node);
264         }
265         
266         public boolean visit(EnumConstantDeclaration node) {
267             return internalVisit(node);
268         }
269         
270         public boolean visit(FieldDeclaration node) {
271             return internalVisit(node);
272         }
273         
274         public boolean visit(MethodDeclaration node) {
275             return internalVisit(node);
276         }
277         
278         public boolean visit(TypeDeclaration node) {
279             return internalVisit(node);
280         }
281         
282         public boolean visit(SingleVariableDeclaration node) {
283             return internalVisit(node);
284         }
285         
286         private boolean internalVisit(ASTNode node) {
287             // terminate the search.
288
if( _result != null ) return false;
289             int nodeStart = node.getStartPosition();
290             int nodeEnd = nodeStart + node.getLength();
291             int annoStart = _anno.getStartPosition();
292             int annoEnd = annoStart + _anno.getLength();
293             
294             if (nodeStart > annoEnd) {
295                 // We've passed our position. No need to search any further
296
return false;
297             }
298             if (nodeEnd > annoStart) { // nodeStart <= annoEnd && nodeEnd > annoStart
299
// This annotation declaration surrounds the offset
300
List JavaDoc<IExtendedModifier> extendedModifiers;
301                 if (node.getNodeType() == ASTNode.SINGLE_VARIABLE_DECLARATION) {
302                     SingleVariableDeclaration declaration = (SingleVariableDeclaration)node;
303                     extendedModifiers = declaration.modifiers();
304                 }
305                 else {
306                     BodyDeclaration declaration = (BodyDeclaration)node;
307                     extendedModifiers = declaration.modifiers();
308                 }
309                 for (IExtendedModifier modifier : extendedModifiers) {
310                     // found what we came to look for.
311
if( modifier == _anno ){
312                         _result = node;
313                         return false;
314                     }
315                 }
316             }
317             
318             // Keep searching
319
return true;
320         }
321         
322         /**
323          * @return false so we skip everything beyond declaration level.
324          */

325         public boolean visit(Block node)
326         { // so we don't look into anything beyond declaration level.
327
return false;
328         }
329         public boolean visit(MarkerAnnotation node){ return false; }
330         public boolean visit(NormalAnnotation node){ return false; }
331         public boolean visit(SingleMemberAnnotation node){ return false; }
332     }
333     /**
334      * Responsible for finding the ending offset of the tighest ast node match that starts
335      * at a given offset. This ast visitor can operator on an array of offsets in one pass.
336      * @author tyeung
337      */

338     public static class EndingOffsetFinder extends ASTVisitor
339     {
340         private final int[] _sortedStartingOffset;
341         /**
342          * parallel to <code>_sortedOffsets</code> and contains
343          * the ending offset of the ast node that has the tightest match for the
344          * corresponding starting offset.
345          */

346         private final int[] _endingOffsets;
347         
348         /**
349          * @param offsets the array of offsets which will be sorted.
350          * @throws IllegalArgumentException if <code>offsets</code> is <code>null</code>.
351          */

352         public EndingOffsetFinder(int[] offsets)
353         {
354             if(offsets == null)
355                 throw new IllegalArgumentException JavaDoc("argument cannot be null."); //$NON-NLS-1$
356
// sort the array first
357
Arrays.sort(offsets);
358         
359             // look for duplicates.
360
int count = 0;
361             for( int i=1, len=offsets.length; i<len; i++){
362                 if( offsets[i-1] == offsets[i] )
363                     continue;
364                 count ++;
365             }
366         
367             if( count != offsets.length ){
368                 _sortedStartingOffset = new int[count];
369         
370                 int index = 0;
371                 for( int i=0, len=offsets.length; i<len; i++){
372                     if( i != 0 && offsets[i-1] == offsets[i] )
373                         continue;
374                     _sortedStartingOffset[index++] = offsets[i];
375                 }
376             }
377             else{
378                 _sortedStartingOffset = offsets;
379             }
380             
381             _endingOffsets = new int[count];
382             for( int i=0; i<count; i++ )
383                 _endingOffsets[i] = 0;
384         }
385         
386         public void preVisit(ASTNode node)
387         {
388             final int startingOffset = node.getStartPosition();
389             final int endingOffset = startingOffset + node.getLength();
390             // starting offset is inclusive
391
int startIndex = Arrays.binarySearch(_sortedStartingOffset, startingOffset);
392             // ending offset is exclusive
393
int endIndex = Arrays.binarySearch(_sortedStartingOffset, endingOffset);
394             if( startIndex < 0 )
395                 startIndex = - startIndex - 1;
396             if( endIndex < 0 )
397                 endIndex = - endIndex - 1;
398             else
399                 // endIndex needs to be exclusive and we want to
400
// include the 'endIndex'th entry in our computation.
401
endIndex ++;
402             if( startIndex >= _sortedStartingOffset.length )
403                 return;
404             
405             for( int i=startIndex; i<endIndex; i++ ){
406                 if( _endingOffsets[i] == 0 )
407                     _endingOffsets[i] = endingOffset;
408                 else if( endingOffset < _endingOffsets[i] )
409                     _endingOffsets[i] = endingOffset;
410             }
411         }
412         
413         
414         public int getEndingOffset(final int startingOffset)
415         {
416             int index = Arrays.binarySearch(_sortedStartingOffset, startingOffset);
417             if( index == -1 ) return 0;
418             return _endingOffsets[index];
419         }
420     }
421 }
422
Popular Tags