1 11 package org.eclipse.jdt.internal.corext.fix; 12 13 import java.io.IOException ; 14 import java.util.ArrayList ; 15 import java.util.Date ; 16 import java.util.HashSet ; 17 import java.util.Hashtable ; 18 import java.util.Iterator ; 19 import java.util.List ; 20 import java.util.Random ; 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 71 private static final String SERIALIZABLE_NAME= "java.io.Serializable"; 73 74 private static final String NAME_FIELD= "serialVersionUID"; 76 private interface ISerialVersionFixContext { 77 public RefactoringStatus initialize(IProgressMonitor monitor) throws CoreException; 78 public boolean hasSerialVersionId(String qualifiedName); 79 public long getSerialVersionId(String 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 fIdsTable; 87 88 public SerialVersionHashContext(IJavaProject project, ICompilationUnit[] compilationUnits) { 89 fProject= project; 90 fCompilationUnits= compilationUnits; 91 fIdsTable= new Hashtable (); 92 } 93 94 public RefactoringStatus initialize(IProgressMonitor monitor) throws CoreException { 95 if (monitor == null) 96 monitor= new NullProgressMonitor(); 97 98 monitor.beginTask("", 3); 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 qualifiedNames= new ArrayList (); 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 getCorrespondingElement() { 119 return type; 120 } 121 }); 122 } 123 } 124 125 if (qualifiedNames.size() == 0) 126 return result; 127 128 try { 129 String [] names= (String [])qualifiedNames.toArray(new String [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 (ids[i])); 135 } else { 136 result.addWarning(Messages.format(FixMessages.PotentialProgrammingProblemsFix_calculatingUIDFailed_unknown, names[i])); 137 } 138 } 139 } catch (IOException 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 e) { 149 RefactoringStatus result= new RefactoringStatus(); 150 result.addWarning(Messages.format(FixMessages.PotentialProgrammingProblemsFix_calculatingUIDFailed_exception, new String [] {fProject.getElementName(), e.getLocalizedMessage()}), new RefactoringStatusContext() { 151 public Object getCorrespondingElement() { 152 return fProject; 153 } 154 }); 155 return result; 156 } 157 158 public boolean hasSerialVersionId(String qualifiedName) { 159 if (qualifiedName == null) 160 return false; 161 162 Long id= (Long )fIdsTable.get(qualifiedName); 163 if (id == null) 164 return false; 165 166 return true; 167 } 168 169 172 public long getSerialVersionId(String qualifiedName) { 173 return ((Long )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); 180 IType serializable= project.findType(SERIALIZABLE_NAME); 181 182 List types= new ArrayList (); 183 184 if (compilationUnits.length > 500) { 185 188 HashSet cus= new HashSet (); 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 cus, List 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 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 268 protected boolean addInitializer(VariableDeclarationFragment fragment, ASTNode declarationNode) throws CoreException { 269 String 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 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 qualifiedName) { 320 return 1; 321 } 322 public RefactoringStatus initialize(IProgressMonitor pm) throws CoreException { 323 return new RefactoringStatus(); 324 } 325 public boolean hasSerialVersionId(String qualifiedName) { 326 return true; 327 } 328 }; 329 return fCurrentContext.initialize(monitor); 330 } else if (randomId) { 331 fCurrentContext= new ISerialVersionFixContext() { 332 private Random rng; 333 public long getSerialVersionId(String qualifiedName) { 334 return rng.nextLong(); 335 } 336 public RefactoringStatus initialize(IProgressMonitor pm) throws CoreException { 337 rng= new Random ((new Date ()).getTime()); 338 return new RefactoringStatus(); 339 } 340 public boolean hasSerialVersionId(String 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 declarationNodes= new ArrayList (); 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 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 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 460 private static String 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 name, CompilationUnit compilationUnit, IFixRewriteOperation[] fixRewriteOperations) { 479 super(name, compilationUnit, fixRewriteOperations); 480 } 481 } | Popular Tags |