KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > fix > PotentialProgrammingProblemsFix


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
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  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.corext.fix;
12
13 import java.io.IOException JavaDoc;
14 import java.util.ArrayList JavaDoc;
15 import java.util.Date JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.Hashtable JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.List JavaDoc;
20 import java.util.Random JavaDoc;
21
22 import org.eclipse.core.runtime.CoreException;
23 import org.eclipse.core.runtime.IProgressMonitor;
24 import org.eclipse.core.runtime.NullProgressMonitor;
25 import org.eclipse.core.runtime.OperationCanceledException;
26 import org.eclipse.core.runtime.SubProgressMonitor;
27
28 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
29 import org.eclipse.ltk.core.refactoring.RefactoringStatusContext;
30
31 import org.eclipse.jdt.core.ICompilationUnit;
32 import org.eclipse.jdt.core.IField;
33 import org.eclipse.jdt.core.IJavaElement;
34 import org.eclipse.jdt.core.IJavaProject;
35 import org.eclipse.jdt.core.IMethod;
36 import org.eclipse.jdt.core.IType;
37 import org.eclipse.jdt.core.ITypeHierarchy;
38 import org.eclipse.jdt.core.JavaModelException;
39 import org.eclipse.jdt.core.compiler.IProblem;
40 import org.eclipse.jdt.core.dom.AST;
41 import org.eclipse.jdt.core.dom.ASTNode;
42 import org.eclipse.jdt.core.dom.ASTParser;
43 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
44 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
45 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
46 import org.eclipse.jdt.core.dom.CompilationUnit;
47 import org.eclipse.jdt.core.dom.IBinding;
48 import org.eclipse.jdt.core.dom.ITypeBinding;
49 import org.eclipse.jdt.core.dom.Name;
50 import org.eclipse.jdt.core.dom.ParameterizedType;
51 import org.eclipse.jdt.core.dom.QualifiedName;
52 import org.eclipse.jdt.core.dom.QualifiedType;
53 import org.eclipse.jdt.core.dom.SimpleName;
54 import org.eclipse.jdt.core.dom.SimpleType;
55 import org.eclipse.jdt.core.dom.Type;
56 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
57 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
58
59 import org.eclipse.jdt.internal.corext.util.Messages;
60
61 import org.eclipse.jdt.ui.text.java.IProblemLocation;
62
63 import org.eclipse.jdt.internal.ui.text.correction.ProblemLocation;
64 import org.eclipse.jdt.internal.ui.text.correction.SerialVersionHashOperation;
65 import org.eclipse.jdt.internal.ui.text.correction.SerialVersionLaunchConfigurationDelegate;
66
67
68 public class PotentialProgrammingProblemsFix extends LinkedFix {
69     
70     /** Name of the serializable class */
71     private static final String JavaDoc SERIALIZABLE_NAME= "java.io.Serializable"; //$NON-NLS-1$
72

73     /** The name of the serial version field */
74     private static final String JavaDoc NAME_FIELD= "serialVersionUID"; //$NON-NLS-1$
75

76     private interface ISerialVersionFixContext {
77         public RefactoringStatus initialize(IProgressMonitor monitor) throws CoreException;
78         public boolean hasSerialVersionId(String JavaDoc qualifiedName);
79         public long getSerialVersionId(String JavaDoc qualifiedName);
80     }
81     
82     private static class SerialVersionHashContext implements ISerialVersionFixContext {
83         
84         private final IJavaProject fProject;
85         private final ICompilationUnit[] fCompilationUnits;
86         private final Hashtable JavaDoc fIdsTable;
87         
88         public SerialVersionHashContext(IJavaProject project, ICompilationUnit[] compilationUnits) {
89             fProject= project;
90             fCompilationUnits= compilationUnits;
91             fIdsTable= new Hashtable JavaDoc();
92         }
93
94         public RefactoringStatus initialize(IProgressMonitor monitor) throws CoreException {
95             if (monitor == null)
96                 monitor= new NullProgressMonitor();
97             
98             monitor.beginTask("", 3); //$NON-NLS-1$
99

100             IType[] types= findTypesWithMissingUID(fProject, fCompilationUnits, new SubProgressMonitor(monitor, 1));
101             if (types.length == 0)
102                 return new RefactoringStatus();
103             
104             RefactoringStatus result= new RefactoringStatus();
105             
106             ASTParser parser= ASTParser.newParser(AST.JLS3);
107             parser.setProject(fProject);
108             IBinding[] bindings= parser.createBindings(types, new SubProgressMonitor(monitor, 1));
109             
110             List JavaDoc qualifiedNames= new ArrayList JavaDoc();
111             for (int i= 0; i < bindings.length; i++) {
112                 ITypeBinding binding= (ITypeBinding)bindings[i];
113                 if (binding != null && binding.getBinaryName() != null) {
114                     qualifiedNames.add(binding.getBinaryName());
115                 } else {
116                     final IType type= types[i];
117                     result.addWarning(Messages.format(FixMessages.PotentialProgrammingProblemsFix_calculatingUIDFailed_binding, types[i].getFullyQualifiedName()), new RefactoringStatusContext() {
118                         public Object JavaDoc getCorrespondingElement() {
119                             return type;
120                         }
121                     });
122                 }
123             }
124             
125             if (qualifiedNames.size() == 0)
126                 return result;
127             
128             try {
129                 String JavaDoc[] names= (String JavaDoc[])qualifiedNames.toArray(new String JavaDoc[qualifiedNames.size()]);
130                 long[] ids= SerialVersionHashOperation.calculateSerialVersionIds(names, fProject, new SubProgressMonitor(monitor, 1));
131                 
132                 for (int i= 0; i < ids.length; i++) {
133                     if (ids[i] != SerialVersionLaunchConfigurationDelegate.FAILING_ID) {
134                         fIdsTable.put(names[i], new Long JavaDoc(ids[i]));
135                     } else {
136                         result.addWarning(Messages.format(FixMessages.PotentialProgrammingProblemsFix_calculatingUIDFailed_unknown, names[i]));
137                     }
138                 }
139             } catch (IOException JavaDoc e) {
140                 return createWarning(e);
141             } catch (CoreException ce) {
142                 return createWarning(ce);
143             }
144         
145             return result;
146         }
147         
148         private RefactoringStatus createWarning(Exception JavaDoc e) {
149             RefactoringStatus result= new RefactoringStatus();
150             result.addWarning(Messages.format(FixMessages.PotentialProgrammingProblemsFix_calculatingUIDFailed_exception, new String JavaDoc[] {fProject.getElementName(), e.getLocalizedMessage()}), new RefactoringStatusContext() {
151                 public Object JavaDoc getCorrespondingElement() {
152                     return fProject;
153                 }
154             });
155             return result;
156         }
157
158         public boolean hasSerialVersionId(String JavaDoc qualifiedName) {
159             if (qualifiedName == null)
160                 return false;
161             
162             Long JavaDoc id= (Long JavaDoc)fIdsTable.get(qualifiedName);
163             if (id == null)
164                 return false;
165             
166             return true;
167         }
168         
169         /**
170          * {@inheritDoc}
171          */

172         public long getSerialVersionId(String JavaDoc qualifiedName) {
173             return ((Long JavaDoc)fIdsTable.get(qualifiedName)).longValue();
174         }
175         
176         private IType[] findTypesWithMissingUID(IJavaProject project, ICompilationUnit[] compilationUnits, IProgressMonitor monitor) throws CoreException {
177             try {
178                 monitor.beginTask("", compilationUnits.length); //$NON-NLS-1$
179

180                 IType serializable= project.findType(SERIALIZABLE_NAME);
181                 
182                 List JavaDoc types= new ArrayList JavaDoc();
183                 
184                 if (compilationUnits.length > 500) {
185                     //500 is a guess. Building the type hierarchy on serializable is very expensive
186
//depending on how many subtypes exit in the project.
187

188                     HashSet JavaDoc cus= new HashSet JavaDoc();
189                     for (int i= 0; i < compilationUnits.length; i++) {
190                         cus.add(compilationUnits[i]);
191                     }
192                     
193                     monitor.subTask(Messages.format(FixMessages.Java50Fix_SerialVersion_CalculateHierarchy_description, SERIALIZABLE_NAME));
194                     ITypeHierarchy hierarchy1= serializable.newTypeHierarchy(project, new SubProgressMonitor(monitor, compilationUnits.length));
195                     IType[] allSubtypes1= hierarchy1.getAllSubtypes(serializable);
196                     addTypes(allSubtypes1, cus, types);
197                 } else {
198                     monitor.subTask(FixMessages.Java50Fix_InitializeSerialVersionId_subtask_description);
199                     for (int i= 0; i < compilationUnits.length; i++) {
200                         collectChildrenWithMissingSerialVersionId(compilationUnits[i].getChildren(), serializable, types);
201                         if (monitor.isCanceled())
202                             throw new OperationCanceledException();
203                         monitor.worked(1);
204                     }
205                 }
206                 
207                 return (IType[])types.toArray(new IType[types.size()]);
208             } finally {
209                 monitor.done();
210             }
211         }
212         
213         private void addTypes(IType[] allSubtypes, HashSet JavaDoc cus, List JavaDoc types) throws JavaModelException {
214             for (int i= 0; i < allSubtypes.length; i++) {
215                 IType type= allSubtypes[i];
216
217                 IField field= type.getField(NAME_FIELD);
218                 if (!field.exists()) {
219                     if (type.isClass() && cus.contains(type.getCompilationUnit())){
220                         types.add(type);
221                     }
222                 }
223             }
224         }
225         
226         private void collectChildrenWithMissingSerialVersionId(IJavaElement[] children, IType serializable, List JavaDoc result) throws JavaModelException {
227             for (int i= 0; i < children.length; i++) {
228                 IJavaElement child= children[i];
229                 if (child instanceof IType) {
230                     IType type= (IType)child;
231                     
232                     if (type.isClass()) {
233                         IField field= type.getField(NAME_FIELD);
234                         if (!field.exists()) {
235                             ITypeHierarchy hierarchy= type.newSupertypeHierarchy(new NullProgressMonitor());
236                             IType[] interfaces= hierarchy.getAllSuperInterfaces(type);
237                             for (int j= 0; j < interfaces.length; j++) {
238                                 if (interfaces[j].equals(serializable)) {
239                                     result.add(type);
240                                     break;
241                                 }
242                             }
243                         }
244                     }
245
246                     collectChildrenWithMissingSerialVersionId(type.getChildren(), serializable, result);
247                 } else if (child instanceof IMethod) {
248                     collectChildrenWithMissingSerialVersionId(((IMethod)child).getChildren(), serializable, result);
249                 } else if (child instanceof IField) {
250                     collectChildrenWithMissingSerialVersionId(((IField)child).getChildren(), serializable, result);
251                 }
252             }
253         }
254     }
255     
256     private static class SerialVersionHashBatchOperation extends AbstractSerialVersionOperation {
257
258         private final ISerialVersionFixContext fContext;
259
260         protected SerialVersionHashBatchOperation(ICompilationUnit unit, ASTNode[] node, ISerialVersionFixContext context) {
261             super(unit, node);
262             fContext= context;
263         }
264
265         /**
266          * {@inheritDoc}
267          */

268         protected boolean addInitializer(VariableDeclarationFragment fragment, ASTNode declarationNode) throws CoreException {
269             String JavaDoc qualifiedName= getQualifiedName(declarationNode);
270             if (!fContext.hasSerialVersionId(qualifiedName))
271                 return false;
272             
273             long id= fContext.getSerialVersionId(qualifiedName);
274             fragment.setInitializer(fragment.getAST().newNumberLiteral(id + LONG_SUFFIX));
275             return true;
276         }
277
278         /**
279          * {@inheritDoc}
280          */

281         protected void addLinkedPositions(ASTRewrite rewrite, VariableDeclarationFragment fragment, LinkedProposalModel positionGroups) {}
282         
283     }
284
285     private static ISerialVersionFixContext fCurrentContext;
286
287     public static IFix[] createMissingSerialVersionFixes(CompilationUnit compilationUnit, IProblemLocation problem) throws CoreException {
288         if (problem.getProblemId() != IProblem.MissingSerialVersion)
289             return null;
290         
291         final ICompilationUnit unit= (ICompilationUnit)compilationUnit.getJavaElement();
292         if (unit == null)
293             return null;
294         
295         final SimpleName simpleName= getSelectedName(compilationUnit, problem);
296         if (simpleName == null)
297             return null;
298         
299         ASTNode declaringNode= getDeclarationNode(simpleName);
300         if (declaringNode == null)
301             return null;
302         
303         SerialVersionDefaultOperation defop= new SerialVersionDefaultOperation(unit, new ASTNode[] {declaringNode});
304         IFix fix1= new PotentialProgrammingProblemsFix(FixMessages.Java50Fix_SerialVersion_default_description, compilationUnit, new IFixRewriteOperation[] {defop});
305         
306         SerialVersionHashOperation hashop= new SerialVersionHashOperation(unit, new ASTNode[] {declaringNode});
307         IFix fix2= new PotentialProgrammingProblemsFix(FixMessages.Java50Fix_SerialVersion_hash_description, compilationUnit, new IFixRewriteOperation[] {hashop});
308     
309         return new IFix[] {fix1, fix2};
310     }
311
312     public static RefactoringStatus checkPreConditions(IJavaProject project, ICompilationUnit[] compilationUnits, IProgressMonitor monitor,
313             boolean calculatedId,
314             boolean defaultId,
315             boolean randomId) throws CoreException {
316         
317         if (defaultId) {
318             fCurrentContext= new ISerialVersionFixContext() {
319                 public long getSerialVersionId(String JavaDoc qualifiedName) {
320                     return 1;
321                 }
322                 public RefactoringStatus initialize(IProgressMonitor pm) throws CoreException {
323                     return new RefactoringStatus();
324                 }
325                 public boolean hasSerialVersionId(String JavaDoc qualifiedName) {
326                     return true;
327                 }
328             };
329             return fCurrentContext.initialize(monitor);
330         } else if (randomId) {
331             fCurrentContext= new ISerialVersionFixContext() {
332                 private Random JavaDoc rng;
333                 public long getSerialVersionId(String JavaDoc qualifiedName) {
334                     return rng.nextLong();
335                 }
336                 public RefactoringStatus initialize(IProgressMonitor pm) throws CoreException {
337                     rng= new Random JavaDoc((new Date JavaDoc()).getTime());
338                     return new RefactoringStatus();
339                 }
340                 public boolean hasSerialVersionId(String JavaDoc qualifiedName) {
341                     return true;
342                 }
343             };
344             return fCurrentContext.initialize(monitor);
345         } else if (calculatedId) {
346             fCurrentContext= new SerialVersionHashContext(project, compilationUnits);
347             return fCurrentContext.initialize(monitor);
348         } else {
349             return new RefactoringStatus();
350         }
351     }
352     
353     public static RefactoringStatus checkPostConditions(IProgressMonitor monitor) throws CoreException {
354         if (monitor != null)
355             monitor.done();
356         
357         fCurrentContext= null;
358         return new RefactoringStatus();
359     }
360         
361     public static IFix createCleanUp(CompilationUnit compilationUnit, boolean addSerialVersionIds) {
362         
363         IProblem[] problems= compilationUnit.getProblems();
364         IProblemLocation[] locations= new IProblemLocation[problems.length];
365         for (int i= 0; i < problems.length; i++) {
366             locations[i]= new ProblemLocation(problems[i]);
367         }
368         return createCleanUp(compilationUnit, locations, addSerialVersionIds);
369     }
370     
371     public static IFix createCleanUp(CompilationUnit compilationUnit, IProblemLocation[] problems, boolean addSerialVersionIds) {
372         if (addSerialVersionIds) {
373             
374             final ICompilationUnit unit= (ICompilationUnit)compilationUnit.getJavaElement();
375             if (unit == null)
376                 return null;
377             
378             List JavaDoc declarationNodes= new ArrayList JavaDoc();
379             for (int i= 0; i < problems.length; i++) {
380                 if (problems[i].getProblemId() == IProblem.MissingSerialVersion) {
381                     final SimpleName simpleName= getSelectedName(compilationUnit, problems[i]);
382                     if (simpleName != null) {
383                         ASTNode declarationNode= getDeclarationNode(simpleName);
384                         if (declarationNode != null) {
385                             declarationNodes.add(declarationNode);
386                         }
387                     }
388                 }
389             }
390             if (declarationNodes.size() == 0)
391                 return null;
392             
393             for (Iterator JavaDoc iter= declarationNodes.iterator(); iter.hasNext();) {
394                 ASTNode declarationNode= (ASTNode)iter.next();
395                 if (fCurrentContext.hasSerialVersionId(getQualifiedName(declarationNode))) {
396                     SerialVersionHashBatchOperation op= new SerialVersionHashBatchOperation(unit, (ASTNode[])declarationNodes.toArray(new ASTNode[declarationNodes.size()]), fCurrentContext);
397                     return new PotentialProgrammingProblemsFix(FixMessages.PotentialProgrammingProblemsFix_add_id_change_name, compilationUnit, new IFixRewriteOperation[] {op});
398                 }
399             }
400         }
401         return null;
402     }
403     
404     private static SimpleName getSelectedName(CompilationUnit compilationUnit, IProblemLocation problem) {
405         final ASTNode selection= problem.getCoveredNode(compilationUnit);
406         if (selection == null)
407             return null;
408         
409         Name name= null;
410         if (selection instanceof SimpleType) {
411             final SimpleType type= (SimpleType) selection;
412             name= type.getName();
413         } else if (selection instanceof ParameterizedType) {
414             final ParameterizedType type= (ParameterizedType) selection;
415             final Type raw= type.getType();
416             if (raw instanceof SimpleType)
417                 name= ((SimpleType) raw).getName();
418             else if (raw instanceof QualifiedType)
419                 name= ((QualifiedType) raw).getName();
420         } else if (selection instanceof Name) {
421             name= (Name) selection;
422         }
423         if (name == null)
424             return null;
425         
426         if (name.isSimpleName()) {
427             return (SimpleName)name;
428         } else {
429             return ((QualifiedName)name).getName();
430         }
431     }
432     
433     /**
434      * Returns the declaration node for the originally selected node.
435      *
436      * @return the declaration node
437      */

438     private static ASTNode getDeclarationNode(SimpleName name) {
439
440         ASTNode parent= name.getParent();
441         if (!(parent instanceof AbstractTypeDeclaration)) {
442
443             parent= parent.getParent();
444             if (parent instanceof ParameterizedType || parent instanceof Type)
445                 parent= parent.getParent();
446             if (parent instanceof ClassInstanceCreation) {
447
448                 final ClassInstanceCreation creation= (ClassInstanceCreation) parent;
449                 parent= creation.getAnonymousClassDeclaration();
450             }
451         }
452         return parent;
453     }
454     
455     /**
456      * Returns the qualified type name of the class declaration.
457      *
458      * @return the qualified type name of the class
459      */

460     private static String JavaDoc getQualifiedName(final ASTNode parent) {
461         ITypeBinding binding= null;
462         if (parent instanceof AbstractTypeDeclaration) {
463             final AbstractTypeDeclaration declaration= (AbstractTypeDeclaration) parent;
464             binding= declaration.resolveBinding();
465         } else if (parent instanceof AnonymousClassDeclaration) {
466             final AnonymousClassDeclaration declaration= (AnonymousClassDeclaration) parent;
467             final ClassInstanceCreation creation= (ClassInstanceCreation) declaration.getParent();
468             binding= creation.resolveTypeBinding();
469         } else if (parent instanceof ParameterizedType) {
470             final ParameterizedType type= (ParameterizedType) parent;
471             binding= type.resolveBinding();
472         }
473         if (binding != null)
474             return binding.getBinaryName();
475         return null;
476     }
477
478     protected PotentialProgrammingProblemsFix(String JavaDoc name, CompilationUnit compilationUnit, IFixRewriteOperation[] fixRewriteOperations) {
479         super(name, compilationUnit, fixRewriteOperations);
480     }
481 }
Popular Tags