KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > javacore > internalapi > JavaModelUtil


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20
21 package org.netbeans.modules.javacore.internalapi;
22
23 import java.util.*;
24 import org.netbeans.jmi.javamodel.*;
25 import org.netbeans.modules.javacore.api.JavaModel;
26 import org.netbeans.modules.javacore.jmiimpl.javamodel.ArrayCloneMethod;
27 import org.netbeans.modules.javacore.jmiimpl.javamodel.JavaClassImpl;
28 import org.netbeans.modules.javacore.jmiimpl.javamodel.MetadataElement;
29 import org.netbeans.modules.javacore.jmiimpl.javamodel.MethodImpl;
30 import org.netbeans.modules.javacore.jmiimpl.javamodel.ParameterizedTypeImpl;
31 import org.netbeans.modules.javacore.jmiimpl.javamodel.SemiPersistentElement;
32 import org.netbeans.modules.javacore.parser.Scope;
33 import org.netbeans.modules.javacore.parser.TypeRef;
34
35 /**
36  *
37  * @author Tomas Hurka
38  */

39 public class JavaModelUtil {
40     
41     private JavaModelUtil() {
42     }
43
44     /**
45      * Analyze list of statements and returns all unhandled exceptions in this list.
46      * @param statements List of {@link Statement} to be analyzed
47      * @return Set of unhandled exceptions. The Set contains {@link JavaClass}
48      */

49     public static Set getExceptionsFromStatements(List statements) {
50         return computeAllExceptions(statements, new HashSet());
51     }
52     
53     private static Set computeAllExceptions(List elements,Set ignoredExceptions) {
54         Iterator elIt=elements.iterator();
55         Set foundExceptions=new HashSet();
56         
57         while(elIt.hasNext()) {
58             Object JavaDoc el=elIt.next();
59             
60             if (el instanceof Invocation) {
61                 Invocation inv=(Invocation)el;
62                 CallableFeature cf=(CallableFeature)inv.getElement();
63                 
64                 if (cf!=null) {
65                     List exceptions=cf.getExceptions();
66
67                     if (!exceptions.isEmpty()) {
68                         Iterator exIt=exceptions.iterator();
69
70                         while(exIt.hasNext()) {
71                             addException((JavaClass)exIt.next(), foundExceptions, ignoredExceptions);
72                         }
73                     }
74                 }
75             } else if (el instanceof MultipartId) {
76                 continue;
77             } else if (el instanceof ThrowStatement) {
78                 ThrowStatement throwSt=(ThrowStatement)el;
79                 Expression ex=throwSt.getExpression();
80
81                 if (ex!=null) addException((JavaClass)ex.getType(), foundExceptions, ignoredExceptions);
82             } else if (el instanceof TryStatement) {
83                 TryStatement trySt=(TryStatement)el;
84                 StatementBlock body=trySt.getBody();
85                 
86                 if (body!=null) {
87                     List catches=trySt.getCatches();
88                     Iterator catchIt=catches.iterator();
89                     Set localIgnores=new HashSet(ignoredExceptions);
90                     StatementBlock finalizer=trySt.getFinalizer();
91
92                     while (catchIt.hasNext()) {
93                         Catch c=(Catch)catchIt.next();
94                         JavaClass ex=(JavaClass)c.getParameter().getType();
95                         
96                         addException(ex, localIgnores, Collections.EMPTY_SET);
97                     }
98                     foundExceptions.addAll(computeAllExceptions(Collections.singletonList(body), localIgnores));
99                     foundExceptions.addAll(computeAllExceptions(catches, ignoredExceptions));
100                     if (finalizer!=null)
101                         foundExceptions.addAll(computeAllExceptions(Collections.singletonList(finalizer), ignoredExceptions));
102                     return foundExceptions;
103                 }
104             }
105             foundExceptions.addAll(computeAllExceptions(((Element)el).getChildren(), ignoredExceptions));
106         }
107         return foundExceptions;
108     }
109
110     private static void addException(final JavaClass ex, final Set foundExceptions, final Set ignoredExceptions) {
111         Iterator jclsIt;
112         JavaClass exc = (JavaClass) unwrapElement(ex);
113         
114         if (exc==null || exc instanceof UnresolvedClass)
115             return;
116         if (ignoredExceptions.contains(exc) || foundExceptions.contains(exc))
117             return;
118         jclsIt=ignoredExceptions.iterator();
119         while(jclsIt.hasNext()) {
120             JavaClass igEx=(JavaClass)jclsIt.next();
121             
122             if (exc.isSubTypeOf(igEx)) {
123                 return;
124             }
125         }
126         jclsIt=foundExceptions.iterator();
127         while(jclsIt.hasNext()) {
128             JavaClass fex=(JavaClass)jclsIt.next();
129             
130             if (exc.isSubTypeOf(fex)) {
131                 return;
132             }
133         }
134         foundExceptions.add(exc);
135     }
136
137     /**
138      * Computes List of {@link Statement} specified by start and end offset.
139      * Handles all cases where start and end offset are between statements
140      * as well as cases where start and end statements are form different context.
141      * @param rsc {@link Resource} of the source file.
142      * @param startOffset start offset of the selection
143      * @param endOffset end offset of the selection
144      * @return List of {@link Statement} or null if the selection specified by startOffset and endOffset is incorrect
145      */

146     public static List getSelectedStatements(Resource rsc,int startOffset,int endOffset) {
147         Element firstStComposite;
148         Element lastStComposite;
149         int lastStEndOffset;
150         List selectedStatements;
151         Statement firstStatement=getStatement(rsc, startOffset);
152         Statement lastStatement=getStatement(rsc, endOffset-1);
153         if (firstStatement==null || lastStatement==null) {
154             return null; // ERR_ExtractMethodWrongSelection"
155
}
156         firstStatement=adjustFirstStatement(startOffset,firstStatement);
157         lastStatement=adjustLastStatement(endOffset,lastStatement);
158         if (firstStatement==null || lastStatement==null) {
159             return null; // ERR_ExtractMethodWrongSelection
160
}
161         firstStComposite=(Element)firstStatement.refImmediateComposite();
162         lastStComposite=(Element)lastStatement.refImmediateComposite();
163         lastStEndOffset=lastStComposite.getEndOffset();
164         while (!firstStComposite.equals(lastStComposite)) {
165             if (!(lastStComposite instanceof Statement) || lastStComposite.getEndOffset()!=lastStEndOffset) {
166                 return null; // ERR_ExtractMethodWrongList
167
}
168             lastStatement=(Statement)lastStComposite;
169             lastStComposite=(Element)lastStatement.refImmediateComposite();
170         }
171         if (firstStatement.equals(lastStatement)) {
172             selectedStatements=Collections.singletonList(firstStatement);
173         } else {
174             List statements;
175             if (firstStComposite instanceof StatementBlock) {
176                 statements = ((StatementBlock)firstStComposite).getStatements();
177             } else {
178                 statements = ((Case)firstStComposite).getStatements();
179             }
180             int firstIndex=statements.indexOf(firstStatement);
181             Iterator sIt=statements.listIterator(firstIndex);
182             Object JavaDoc st;
183             selectedStatements=new ArrayList();
184             if (sIt.hasNext()) {
185                 do {
186                     st=sIt.next();
187                     selectedStatements.add(st);
188                     
189                 } while(!st.equals(lastStatement));
190             }
191         }
192         return selectedStatements;
193     }
194
195     private static Statement getStatement(Resource rsc,int offset) {
196         Element el=rsc.getElementByOffset(offset);
197         int elStart,elEnd;
198
199         if (el instanceof Feature || el instanceof Resource)
200             return null;
201         elStart=el.getStartOffset();
202         elEnd=el.getEndOffset();
203         while(el!=null && !(el instanceof Statement)) {
204             el = (Element)el.refImmediateComposite();
205             if (el instanceof Feature || (el.getStartOffset()!=elStart && el.getEndOffset()!=elEnd))
206                 return null;
207         }
208         return (Statement)el;
209     }
210     
211     private static Statement adjustFirstStatement(int startOffset,Statement s) {
212         JavaMetamodel model=JavaMetamodel.getManager();
213         Iterator chIt;
214         
215         if (model.getElementPosition(s).getBegin().getOffset()==startOffset)
216             return s;
217         chIt=s.getChildren().iterator();
218         while(chIt.hasNext()) {
219             Element el=(Element)chIt.next();
220             
221             if (el instanceof Statement) {
222                 if (model.getElementPosition(el).getBegin().getOffset()>startOffset) {
223                     return (Statement)el;
224                 }
225             }
226         }
227         return null;
228     }
229     
230     private static Statement adjustLastStatement(int endOffset,Statement s) {
231         JavaMetamodel model=JavaMetamodel.getManager();
232         ListIterator chIt;
233         List children;
234         
235         if (model.getElementPosition(s).getEnd().getOffset()==endOffset)
236             return s;
237         children=s.getChildren();
238         chIt=children.listIterator(children.size());
239         while(chIt.hasPrevious()) {
240             Element el=(Element)chIt.previous();
241             
242             if (el instanceof Statement) {
243                 if (model.getElementPosition(el).getEnd().getOffset()<endOffset) {
244                     return (Statement)el;
245                 }
246             }
247         }
248         return null;
249     }
250
251     /**
252      * This helper method takes {@link Element} as a scope and {@link JavaClass} and creates
253      * {@link MultipartId} and possibly adds appropriate {@link Import} statement to
254      * {@link Resource}. Returned {@link MultipartId} contains simple name of resolved class
255      * if this does not introduce name conflict in source file.
256      * @param scope scope defines place where jcls should be resolved.
257      * @param jcls {@link JavaClass} which will be put in to source code in place defined by scope
258      * @return Returns {@link MulitpartId} which resolves to jcls.
259      */

260     public static MultipartId resolveImportsForClass(Element scope,JavaClass jcls) {
261         return (MultipartId)typeToTypeReference(scope,jcls);
262     }
263     
264     /**
265      * This helper method takes {@link Element} as a scope and {@link Type} and creates
266      * {@link TypeReference} and possibly adds appropriate {@link Import} statement to
267      * {@link Resource}. Returned {@link TypeReference} contains simple name of resolved class
268      * if this does not introduce name conflict in source file or TypeReference of primitive type
269      * if {@link Type} is primitive type.
270      * @param scope scope defines place where type should be resolved.
271      * @param type {@link Type} which will be put in to source code in place defined by scope
272      * @return Returns {@link TypeReference} which resolves to type.
273      */

274     public static TypeReference resolveImportsForType(Element scope,Type type) {
275         return (TypeReference)typeToTypeReference(scope,type);
276     }
277     
278     private static Element typeToTypeReference(Element scope,Type type) {
279         JavaModelPackage jpck;
280         MultipartIdClass mpidClass;
281         
282         if (type == null) {
283             return null;
284         }
285         scope=unwrapElement(scope);
286         jpck=(JavaModelPackage)scope.refImmediatePackage();
287         mpidClass=jpck.getMultipartId();
288         if (type instanceof TypeParameter) {
289             return mpidClass.createMultipartId(type.getName(),null,null);
290         } else if (type instanceof ParameterizedType) {
291             ParameterizedTypeImpl paramType = (ParameterizedTypeImpl) type;
292             Type typePars[] = (Type[])paramType.getParameters().toArray(new Type[0]);
293             TypeArgument args[] = new TypeArgument[typePars.length];
294             int i = 0;
295             for (; i<typePars.length; i++) {
296                 args[i] = (TypeArgument)typeToTypeReference(scope,typePars[i]);
297                 int status = paramType.getWildCardStatus(i);
298                 if (status != 0) {
299                     args[i] = jpck.getWildCard().createWildCard(status == 1, status == 3 ? null : (MultipartId) args[i]);
300                 }
301             }
302             MultipartId parentName=(MultipartId) typeToTypeReference(scope,paramType.getDeclaringClass());
303             JavaClass def=paramType.getDefinition();
304             String JavaDoc name;
305             
306             if (parentName==null) {
307                 MultipartId defId=createImportsForClass(scope,def);
308                 
309                 if (typePars.length==0)
310                     return defId;
311                 name=defId.getName();
312             } else
313                 name=def.getSimpleName();
314             return mpidClass.createMultipartId(name, parentName, Arrays.asList(args));
315         } else if (type instanceof Array) {
316             int dimCount = 0;
317             Type currType = type;
318             while (currType instanceof Array) {
319                 dimCount++;
320                 currType = ((Array) currType).getType();
321             }
322             return jpck.getArrayReference().createArrayReference(null,(MultipartId)typeToTypeReference(scope,currType), dimCount);
323         } else if (type instanceof JavaClass) {
324             if (type instanceof JavaClassImpl && ((JavaClassImpl)type).isTransient()) // local class
325
return mpidClass.createMultipartId(type.getName(),null,null);
326             return createImportsForClass(scope,(JavaClass)type);
327         } else if (type instanceof PrimitiveType) {
328             return mpidClass.createMultipartId(type.getName(),null,null);
329         }
330         throw new IllegalArgumentException JavaDoc("Unable to convert to typeref: " + type.getClass().getName()); // NOI18N
331
}
332     
333     private static MultipartId createImportsForClass(Element scope,JavaClass type) {
334         JavaModelPackage jpck=(JavaModelPackage)scope.refImmediatePackage();
335         MultipartIdClass mpidClass=jpck.getMultipartId();
336
337         if (type instanceof UnresolvedClass) {
338             return mpidClass.createMultipartId(type.getName(),null,null);
339         } else {
340             Scope sc=Scope.computeTypeScope(scope);
341             String JavaDoc simpleName=type.getSimpleName();
342             Object JavaDoc resolvedClass=sc.lookup(simpleName);
343             Import imp;
344
345             if (resolvedClass!=null) {
346                 if (type.getName().equals(resolvedClass)) { // correct class found - use simple name
347
return mpidClass.createMultipartId(simpleName,null,null);
348                 }
349                 // name confilict - use FQN
350
return mpidClass.createMultipartId(type.getName(),null,null);
351             }
352             // class not found use simple name and add import
353
imp=jpck.getImport().createImport(type.getName(),null,false,false);
354             scope.getResource().addImport(imp);
355             return mpidClass.createMultipartId(simpleName,null,null);
356         }
357     }
358     
359     /**
360      * This method returns the closest {@link Feature}, which contains
361      * {@link Element} element.
362      * @param element {@link Element} where to start
363      * @return {@link Feature} or <CODE>null</CODE> if element is
364      * not part of any {@link Feature} (e.g. {@link Import})
365      */

366     public static Feature getDeclaringFeature(Element element) {
367         while (!(element instanceof Feature) && element!=null) {
368             element=(Element)element.refImmediateComposite();
369         }
370         return (Feature)element;
371     }
372     
373     /**
374      * This helper method takes {@link Element} as a scope and original {@link Element}. It duplicates
375      * original element and resolves types in duplicated element according to scope.
376      * It can add appropriate {@link Import} statement to
377      * {@link Resource}. Returned {@link Element} contains simple names of resolved classes
378      * if this does not introduce name conflict in source file.
379      * @param scope scope defines place where duplicated element should be placed.
380      * @param original {@link Element} which will be put in to source code in place defined by scope
381      * @return Returns duplicated {@link Element} with correctly resolved classes.
382      */

383     public static Element duplicateInScope(Element scope,Element original) {
384         scope=unwrapElement(scope);
385         JavaModelPackage pck=(JavaModelPackage)scope.refImmediatePackage();
386         MetadataElement newElement=(MetadataElement)unwrapElement(original).duplicate(pck);
387
388         newElement.fixImports(scope,original);
389         return newElement;
390     }
391
392     private static MetadataElement unwrapElement(Element el) {
393         if (el instanceof MetadataElement)
394             return (MetadataElement)el;
395         if (el instanceof ParameterizedType) {
396             return (MetadataElement)((ParameterizedType)el).getDefinition();
397         }
398         if (el instanceof ParameterizedTypeImpl.Wrapper) {
399             return (MetadataElement)((ParameterizedTypeImpl.Wrapper)el).getWrappedObject();
400         }
401         throw new IllegalArgumentException JavaDoc("Unknown type "+el.getClass());
402     }
403     
404     /**
405      * This helper method computes and returns collection of overridden methods
406      * @param method for which overridden methods will be computed
407      * @return Collection of overridden methods. If there are no overridden methods empty list is returned.
408      */

409     public static Collection getOverriddenMethods(Method method) {
410         if (method instanceof ArrayCloneMethod) {
411             ArrayList result = new ArrayList(1);
412             result.add(
413                     ((JavaClass)JavaModel.getDefaultExtent().getType()
414                     .resolve("java.lang.Object")).getMethod("clone",Collections.EMPTY_LIST, false)); //NOI18N
415
return result;
416         }
417         MethodImpl mImpl=(MethodImpl)unwrapElement(method);
418         
419         return mImpl.getOverriddenMethods();
420     }
421     /**
422      * This method creates {@link TypeReference} based on parameter {@link Type} type. New instance of
423      * TypeReference is created in default JavaModelPackage returned by JavaModel.getDefaultExtent().
424      * @param type {@link Type} used to generate new instance of {@link TypeReference}
425      * @return new instance of {@link TypeReference} representing parameter type
426      */

427     public static TypeReference createTypeReferenceFromType(Type type) {
428         JavaModelPackage extent = JavaModel.getDefaultExtent();
429         TypeRef typeRef = SemiPersistentElement.typeToTypeRef(type);
430         
431         return (TypeReference)SemiPersistentElement.typeRefToTypeReference(extent, typeRef, 0);
432     }
433 }
434
Popular Tags