KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > apt > core > internal > env > EnvUtil


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.env;
12
13 import java.util.Arrays JavaDoc;
14 import java.util.List JavaDoc;
15
16 import org.eclipse.jdt.core.compiler.IProblem;
17 import org.eclipse.jdt.core.dom.ASTNode;
18 import org.eclipse.jdt.core.dom.ASTVisitor;
19 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
20 import org.eclipse.jdt.core.dom.CompilationUnit;
21 import org.eclipse.jdt.core.dom.SimpleName;
22
23 /*package*/ class EnvUtil {
24     /**
25      * Handling the following 2 cases
26      * 1) For IProblems that does not have a starting and ending offset,
27      * place the problem at the class name.
28      *
29      * 2) For IProblems that does not have an ending offset, place the ending
30      * offset at the end of the tightest ast node.
31      * We will only walk the ast once to determine the ending
32      * offsets of all the problems that do not have the information set.
33      */

34     static void updateProblemLength(List JavaDoc<APTProblem> problems, CompilationUnit astUnit)
35     {
36         // for those problems that doesn't have an ending offset, figure it out by
37
// traversing the ast.
38
// we do it once just before we post the marker so we only have to walk the ast
39
// once.
40
int count = 0;
41         int[] classNameRange = null;
42         for(IProblem problem : problems ){
43             if( problem.getSourceStart() < 0 ){
44                 if( classNameRange == null )
45                     classNameRange = getClassNameRange(astUnit);
46                 problem.setSourceStart(classNameRange[0]);
47                 problem.setSourceEnd(classNameRange[1]);
48                 problem.setSourceLineNumber(classNameRange[2]);
49             }
50             if( problem.getSourceEnd() < 0 ){
51                 count ++;
52             }
53         }
54             
55         if( count > 0 ){
56             if( astUnit != null ){
57                 final int[] startingOffsets = new int[count];
58                 int index = 0;
59                 for( IProblem problem : problems ){
60                     if( problem.getSourceEnd() < 0 )
61                         startingOffsets[index++] = problem.getSourceStart();
62                 }
63                 
64                 final EndingOffsetFinder lfinder = new EndingOffsetFinder(startingOffsets);
65                 
66                 astUnit.accept( lfinder );
67                 
68                 for(IProblem problem : problems ){
69                     if( problem.getSourceEnd() < 0 ){
70                         int startingOffset = problem.getSourceStart();
71                         int endingOffset = lfinder.getEndingOffset(startingOffset);
72                         if( endingOffset == 0 )
73                             endingOffset = startingOffset;
74                         problem.setSourceEnd(endingOffset-1);
75                     }
76                 }
77             }
78             else{
79                 for(IProblem problem : problems){
80                     // set the -1 source end to be the same as the source start.
81
if( problem.getSourceEnd() < problem.getSourceStart() )
82                         problem.setSourceEnd(problem.getSourceStart());
83                 }
84             }
85         }
86     }
87     
88     /**
89      * @param file
90      * @return length 3 int array with the following information.
91      * at index 0: contains the starting offset, always >= 0
92      * at index 1: contains the ending offset, may be a negative number.
93      * at index 2: the line number
94      *
95      */

96     private static int[] getClassNameRange(final CompilationUnit astUnit){
97         int[] startAndEnd = null;
98         if( astUnit != null){
99             @SuppressWarnings JavaDoc({"unchecked", "nls"})
100             final List JavaDoc<AbstractTypeDeclaration> topTypes = astUnit.types();
101             if( topTypes != null && topTypes.size() > 0 ){
102                 final AbstractTypeDeclaration topType = topTypes.get(0);
103                 startAndEnd = new int[3];
104                 final SimpleName typename = topType.getName();
105                 if( typename != null ){
106                     startAndEnd[0] = typename.getStartPosition();
107                     // ending offsets need to be exclusive.
108
startAndEnd[1] = startAndEnd[0] + typename.getLength() - 1;
109                     startAndEnd[2] = astUnit.getLineNumber(typename.getStartPosition());
110                     if( startAndEnd[2] < 1 )
111                         startAndEnd[2] = 1;
112                 }
113                 else{
114                     startAndEnd[0] = topType.getStartPosition();
115                     // let case 2 in updateProblemLength() kicks in.
116
startAndEnd[1] = -2;
117                     startAndEnd[2] = astUnit.getLineNumber(topType.getStartPosition());
118                     if( startAndEnd[2] < 1 )
119                         startAndEnd[2] = 1;
120                 }
121             }
122         }
123         if( startAndEnd == null )
124             // let case 2 in updateProblemLength() kicks in.
125
return new int[]{0, -2, 1};
126     
127         return startAndEnd;
128     }
129     
130     /**
131      * Responsible for finding the ending offset of the ast node that has the tightest match
132      * for a given offset. This ast visitor can operator on an array of offsets in one pass.
133      * @author tyeung
134      */

135     private static class EndingOffsetFinder extends ASTVisitor
136     {
137         private final int[] _sortedStartingOffset;
138         /**
139          * parallel to <code>_sortedOffsets</code> and contains
140          * the ending offset of the ast node that has the tightest match for the
141          * corresponding starting offset.
142          */

143         private final int[] _endingOffsets;
144         
145         /**
146          * @param offsets the array of offsets which will be sorted.
147          * @throws IllegalArgumentException if <code>offsets</code> is <code>null</code>.
148          */

149         private EndingOffsetFinder(int[] offsets)
150         {
151             if(offsets == null)
152                 throw new IllegalArgumentException JavaDoc("argument cannot be null."); //$NON-NLS-1$
153
// sort the array first
154
Arrays.sort(offsets);
155         
156             // look for duplicates.
157
int count = 0;
158             for( int i=0, len=offsets.length; i<len; i++){
159                 if( i > 0 && offsets[i-1] == offsets[i] )
160                     continue;
161                 count ++;
162             }
163         
164             if( count != offsets.length ){
165                 _sortedStartingOffset = new int[count];
166         
167                 int index = 0;
168                 for( int i=0, len=offsets.length; i<len; i++){
169                     if( i > 0 && offsets[i-1] == offsets[i] )
170                         continue;
171                     _sortedStartingOffset[index++] = offsets[i];
172                 }
173             }
174             else{
175                 _sortedStartingOffset = offsets;
176             }
177             
178             _endingOffsets = new int[count];
179             for( int i=0; i<count; i++ )
180                 _endingOffsets[i] = 0;
181         }
182         
183         public void preVisit(ASTNode node)
184         {
185             final int startingOffset = node.getStartPosition();
186             final int endingOffset = startingOffset + node.getLength();
187             // starting offset is inclusive
188
int startIndex = Arrays.binarySearch(_sortedStartingOffset, startingOffset);
189             // ending offset is exclusive
190
int endIndex = Arrays.binarySearch(_sortedStartingOffset, endingOffset);
191             if( startIndex < 0 )
192                 startIndex = - startIndex - 1;
193             if( endIndex < 0 )
194                 endIndex = - endIndex - 1;
195             else
196                 // endIndex needs to be exclusive and we want to
197
// include the 'endIndex'th entry in our computation.
198
endIndex ++;
199             if( startIndex >= _sortedStartingOffset.length )
200                 return;
201             
202             for( int i=startIndex; i<endIndex; i++ ){
203                 if( _endingOffsets[i] == 0 )
204                     _endingOffsets[i] = endingOffset;
205                 else if( endingOffset < _endingOffsets[i] )
206                     _endingOffsets[i] = endingOffset;
207             }
208         }
209         
210         
211         public int getEndingOffset(final int startingOffset)
212         {
213             int index = Arrays.binarySearch(_sortedStartingOffset, startingOffset);
214             if( index == -1 ) return 0;
215             return _endingOffsets[index];
216         }
217     }
218 }
219
Popular Tags