]> git.uio.no Git - ifi-stolz-refaktor.git/blobdiff - case-study/jdt-before/core extension/org/eclipse/jdt/internal/corext/fix/PotentialProgrammingProblemsFix.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / core extension / org / eclipse / jdt / internal / corext / fix / PotentialProgrammingProblemsFix.java
diff --git a/case-study/jdt-before/core extension/org/eclipse/jdt/internal/corext/fix/PotentialProgrammingProblemsFix.java b/case-study/jdt-before/core extension/org/eclipse/jdt/internal/corext/fix/PotentialProgrammingProblemsFix.java
new file mode 100644 (file)
index 0000000..dd34f48
--- /dev/null
@@ -0,0 +1,453 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.corext.fix;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IField;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.ITypeHierarchy;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.ASTParser;
+import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
+import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
+import org.eclipse.jdt.core.dom.ClassInstanceCreation;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.ITypeBinding;
+import org.eclipse.jdt.core.dom.Name;
+import org.eclipse.jdt.core.dom.ParameterizedType;
+import org.eclipse.jdt.core.dom.QualifiedName;
+import org.eclipse.jdt.core.dom.QualifiedType;
+import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.SimpleType;
+import org.eclipse.jdt.core.dom.Type;
+import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
+import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
+
+import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
+import org.eclipse.jdt.internal.corext.util.Messages;
+
+import org.eclipse.jdt.ui.cleanup.ICleanUpFix;
+import org.eclipse.jdt.ui.text.java.IProblemLocation;
+
+import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
+import org.eclipse.jdt.internal.ui.text.correction.ProblemLocation;
+import org.eclipse.jdt.internal.ui.text.correction.SerialVersionHashOperation;
+import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
+
+
+public class PotentialProgrammingProblemsFix extends CompilationUnitRewriteOperationsFix {
+
+       /** Name of the serializable class */
+       private static final String SERIALIZABLE_NAME= "java.io.Serializable"; //$NON-NLS-1$
+
+       /** The name of the serial version field */
+       private static final String NAME_FIELD= "serialVersionUID"; //$NON-NLS-1$
+
+       private interface ISerialVersionFixContext {
+               public RefactoringStatus initialize(IProgressMonitor monitor) throws CoreException;
+               public Long getSerialVersionId(ITypeBinding binding);
+       }
+
+       private static class SerialVersionHashContext implements ISerialVersionFixContext {
+
+               private final IJavaProject fProject;
+               private final ICompilationUnit[] fCompilationUnits;
+               private final Hashtable<String, Long> fIdsTable;
+
+               public SerialVersionHashContext(IJavaProject project, ICompilationUnit[] compilationUnits) {
+                       fProject= project;
+                       fCompilationUnits= compilationUnits;
+                       fIdsTable= new Hashtable<String, Long>();
+        }
+
+               public RefactoringStatus initialize(IProgressMonitor monitor) throws CoreException {
+                       if (monitor == null)
+                               monitor= new NullProgressMonitor();
+
+                       RefactoringStatus result;
+                       try {
+                               monitor.beginTask("", 10); //$NON-NLS-1$
+
+                               IType[] types= findTypesWithMissingUID(fProject, fCompilationUnits, new SubProgressMonitor(monitor, 1));
+                               if (types.length == 0)
+                                       return new RefactoringStatus();
+
+                               fProject.getProject().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, new SubProgressMonitor(monitor, 60));
+                               if (monitor.isCanceled())
+                                       throw new OperationCanceledException();
+
+                               result= new RefactoringStatus();
+                               ASTParser parser= ASTParser.newParser(ASTProvider.SHARED_AST_LEVEL);
+                               parser.setProject(fProject);
+                               IBinding[] bindings= parser.createBindings(types, new SubProgressMonitor(monitor, 1));
+                               for (int i= 0; i < bindings.length; i++) {
+                                       IBinding curr= bindings[i];
+                                       if (curr instanceof ITypeBinding) {
+                                               ITypeBinding typeBinding= (ITypeBinding) curr;
+                                               try {
+                                                       Long id= SerialVersionHashOperation.calculateSerialVersionId(typeBinding, new SubProgressMonitor(monitor, 1));
+                                                       if (id != null) {
+                                                               setSerialVersionId(typeBinding, id);
+                                                       } else {
+                                                               result.addWarning(Messages.format(FixMessages.PotentialProgrammingProblemsFix_calculatingUIDFailed_unknown, BasicElementLabels.getJavaElementName(typeBinding.getName())));
+                                                       }
+                                               } catch (IOException e) {
+                                                       result.addWarning(Messages.format(FixMessages.PotentialProgrammingProblemsFix_calculatingUIDFailed_exception, new String[] { BasicElementLabels.getJavaElementName(typeBinding.getName()), e.getLocalizedMessage()}), JavaStatusContext.create(types[i]));
+                                       } catch (CoreException e) {
+                                                       result.addWarning(Messages.format(FixMessages.PotentialProgrammingProblemsFix_calculatingUIDFailed_exception, new String[] { BasicElementLabels.getJavaElementName(typeBinding.getName()), e.getLocalizedMessage()}), JavaStatusContext.create(types[i]));
+                                       }
+                                       }
+                               }
+                       } finally {
+                               monitor.done();
+                       }
+                       return result;
+               }
+
+               /**
+                * {@inheritDoc}
+                */
+               public Long getSerialVersionId(ITypeBinding binding) {
+                       return fIdsTable.get(binding.getKey());
+               }
+
+               protected void setSerialVersionId(ITypeBinding binding, Long id) {
+                       fIdsTable.put(binding.getKey(), id);
+               }
+
+               private IType[] findTypesWithMissingUID(IJavaProject project, ICompilationUnit[] compilationUnits, IProgressMonitor monitor) throws CoreException {
+                       try {
+                               monitor.beginTask("", compilationUnits.length); //$NON-NLS-1$
+
+                               IType serializable= project.findType(SERIALIZABLE_NAME);
+
+                               List<IType> types= new ArrayList<IType>();
+
+                               if (compilationUnits.length > 500) {
+                                       //500 is a guess. Building the type hierarchy on serializable is very expensive
+                                       //depending on how many subtypes exit in the project.
+
+                                       HashSet<ICompilationUnit> cus= new HashSet<ICompilationUnit>();
+                                       for (int i= 0; i < compilationUnits.length; i++) {
+                                               cus.add(compilationUnits[i]);
+                                       }
+
+                                       monitor.subTask(Messages.format(FixMessages.Java50Fix_SerialVersion_CalculateHierarchy_description, SERIALIZABLE_NAME));
+                                       ITypeHierarchy hierarchy1= serializable.newTypeHierarchy(project, new SubProgressMonitor(monitor, compilationUnits.length));
+                                       IType[] allSubtypes1= hierarchy1.getAllSubtypes(serializable);
+                                       addTypes(allSubtypes1, cus, types);
+                               } else {
+                                       monitor.subTask(FixMessages.Java50Fix_InitializeSerialVersionId_subtask_description);
+                    for (int i= 0; i < compilationUnits.length; i++) {
+                       collectChildrenWithMissingSerialVersionId(compilationUnits[i].getChildren(), serializable, types);
+                       if (monitor.isCanceled())
+                               throw new OperationCanceledException();
+                       monitor.worked(1);
+                    }
+                               }
+
+                               return types.toArray(new IType[types.size()]);
+                       } finally {
+                               monitor.done();
+                       }
+               }
+
+               private void addTypes(IType[] allSubtypes, HashSet<ICompilationUnit> cus, List<IType> types) throws JavaModelException {
+                       for (int i= 0; i < allSubtypes.length; i++) {
+                               IType type= allSubtypes[i];
+
+                               IField field= type.getField(NAME_FIELD);
+                               if (!field.exists()) {
+                                       if (type.isClass() && cus.contains(type.getCompilationUnit())){
+                                               types.add(type);
+                                       }
+                               }
+                       }
+               }
+
+               private void collectChildrenWithMissingSerialVersionId(IJavaElement[] children, IType serializable, List<IType> result) throws JavaModelException {
+                       for (int i= 0; i < children.length; i++) {
+                               IJavaElement child= children[i];
+                               if (child instanceof IType) {
+                                       IType type= (IType)child;
+
+                                       if (type.isClass()) {
+                                       IField field= type.getField(NAME_FIELD);
+                                       if (!field.exists()) {
+                                               ITypeHierarchy hierarchy= type.newSupertypeHierarchy(new NullProgressMonitor());
+                                               IType[] interfaces= hierarchy.getAllSuperInterfaces(type);
+                                               for (int j= 0; j < interfaces.length; j++) {
+                                                       if (interfaces[j].equals(serializable)) {
+                                                               result.add(type);
+                                                               break;
+                                                       }
+                                               }
+                                               }
+                                       }
+
+                                       collectChildrenWithMissingSerialVersionId(type.getChildren(), serializable, result);
+                               } else if (child instanceof IMethod) {
+                                       collectChildrenWithMissingSerialVersionId(((IMethod)child).getChildren(), serializable, result);
+                               } else if (child instanceof IField) {
+                                       collectChildrenWithMissingSerialVersionId(((IField)child).getChildren(), serializable, result);
+                               }
+                       }
+               }
+       }
+
+       private static class SerialVersionHashBatchOperation extends AbstractSerialVersionOperation {
+
+               private final ISerialVersionFixContext fContext;
+
+               protected SerialVersionHashBatchOperation(ICompilationUnit unit, ASTNode[] node, ISerialVersionFixContext context) {
+                       super(unit, node);
+                       fContext= context;
+               }
+
+               /**
+                * {@inheritDoc}
+                */
+               @Override
+               protected boolean addInitializer(VariableDeclarationFragment fragment, ASTNode declarationNode) {
+                       ITypeBinding typeBinding= getTypeBinding(declarationNode);
+                       if (typeBinding == null)
+                               return false;
+
+                       Long id= fContext.getSerialVersionId(typeBinding);
+                       if (id == null)
+                               return false;
+
+                       fragment.setInitializer(fragment.getAST().newNumberLiteral(id.toString() + LONG_SUFFIX));
+                       return true;
+               }
+
+               /**
+                * {@inheritDoc}
+                */
+               @Override
+               protected void addLinkedPositions(ASTRewrite rewrite, VariableDeclarationFragment fragment, LinkedProposalModel positionGroups) {}
+
+       }
+
+       private static ISerialVersionFixContext fCurrentContext;
+
+       public static IProposableFix[] createMissingSerialVersionFixes(CompilationUnit compilationUnit, IProblemLocation problem) {
+               if (problem.getProblemId() != IProblem.MissingSerialVersion)
+                       return null;
+
+               final ICompilationUnit unit= (ICompilationUnit)compilationUnit.getJavaElement();
+               if (unit == null)
+                       return null;
+
+               final SimpleName simpleName= getSelectedName(compilationUnit, problem);
+               if (simpleName == null)
+                       return null;
+
+               ASTNode declaringNode= getDeclarationNode(simpleName);
+               if (declaringNode == null)
+                       return null;
+
+               SerialVersionDefaultOperation defop= new SerialVersionDefaultOperation(unit, new ASTNode[] {declaringNode});
+               IProposableFix fix1= new PotentialProgrammingProblemsFix(FixMessages.Java50Fix_SerialVersion_default_description, compilationUnit, new CompilationUnitRewriteOperation[] {defop});
+
+               SerialVersionHashOperation hashop= new SerialVersionHashOperation(unit, new ASTNode[] {declaringNode});
+               IProposableFix fix2= new PotentialProgrammingProblemsFix(FixMessages.Java50Fix_SerialVersion_hash_description, compilationUnit, new CompilationUnitRewriteOperation[] {hashop});
+
+               return new IProposableFix[] {fix1, fix2};
+       }
+
+       public static RefactoringStatus checkPreConditions(IJavaProject project, ICompilationUnit[] compilationUnits, IProgressMonitor monitor,
+                       boolean calculatedId,
+                       boolean defaultId,
+                       boolean randomId) throws CoreException {
+
+               if (defaultId) {
+                       fCurrentContext= new ISerialVersionFixContext() {
+                               public Long getSerialVersionId(ITypeBinding binding) {
+                                       return new Long(1);
+                               }
+                               public RefactoringStatus initialize(IProgressMonitor pm) throws CoreException {
+                       return new RefactoringStatus();
+                }
+                       };
+                       return fCurrentContext.initialize(monitor);
+               } else if (randomId) {
+                       fCurrentContext= new ISerialVersionFixContext() {
+                               private Random rng;
+                               public Long getSerialVersionId(ITypeBinding binding) {
+                                       return new Long(rng.nextLong());
+                               }
+                               public RefactoringStatus initialize(IProgressMonitor pm) throws CoreException {
+                                       rng= new Random((new Date()).getTime());
+                       return new RefactoringStatus();
+                }
+                       };
+                       return fCurrentContext.initialize(monitor);
+               } else if (calculatedId) {
+                       fCurrentContext= new SerialVersionHashContext(project, compilationUnits);
+                       return fCurrentContext.initialize(monitor);
+               } else {
+                       return new RefactoringStatus();
+               }
+    }
+
+       public static RefactoringStatus checkPostConditions(IProgressMonitor monitor) {
+               if (monitor != null)
+                       monitor.done();
+
+               fCurrentContext= null;
+           return new RefactoringStatus();
+    }
+
+       public static ICleanUpFix createCleanUp(CompilationUnit compilationUnit, boolean addSerialVersionIds) {
+
+               IProblem[] problems= compilationUnit.getProblems();
+               IProblemLocation[] locations= new IProblemLocation[problems.length];
+               for (int i= 0; i < problems.length; i++) {
+                       locations[i]= new ProblemLocation(problems[i]);
+               }
+               return createCleanUp(compilationUnit, locations, addSerialVersionIds);
+       }
+
+       public static ICleanUpFix createCleanUp(CompilationUnit compilationUnit, IProblemLocation[] problems, boolean addSerialVersionIds) {
+               if (addSerialVersionIds) {
+
+                       final ICompilationUnit unit= (ICompilationUnit)compilationUnit.getJavaElement();
+                       if (unit == null)
+                               return null;
+
+                       List<ASTNode> declarationNodes= new ArrayList<ASTNode>();
+                       for (int i= 0; i < problems.length; i++) {
+                               if (problems[i].getProblemId() == IProblem.MissingSerialVersion) {
+                                       final SimpleName simpleName= getSelectedName(compilationUnit, problems[i]);
+                                       if (simpleName != null) {
+                                               ASTNode declarationNode= getDeclarationNode(simpleName);
+                                               if (declarationNode != null) {
+                                                       declarationNodes.add(declarationNode);
+                                               }
+                                       }
+                               }
+                       }
+                       if (declarationNodes.size() == 0)
+                               return null;
+
+                       for (Iterator<ASTNode> iter= declarationNodes.iterator(); iter.hasNext();) {
+                   ASTNode declarationNode= iter.next();
+                   ITypeBinding binding= getTypeBinding(declarationNode);
+                   if (fCurrentContext.getSerialVersionId(binding) != null) {
+                       SerialVersionHashBatchOperation op= new SerialVersionHashBatchOperation(unit, declarationNodes.toArray(new ASTNode[declarationNodes.size()]), fCurrentContext);
+                               return new PotentialProgrammingProblemsFix(FixMessages.PotentialProgrammingProblemsFix_add_id_change_name, compilationUnit, new CompilationUnitRewriteOperation[] {op});
+                   }
+            }
+               }
+               return null;
+       }
+
+       private static SimpleName getSelectedName(CompilationUnit compilationUnit, IProblemLocation problem) {
+               final ASTNode selection= problem.getCoveredNode(compilationUnit);
+               if (selection == null)
+                       return null;
+
+               Name name= null;
+               if (selection instanceof SimpleType) {
+                       final SimpleType type= (SimpleType) selection;
+                       name= type.getName();
+               } else if (selection instanceof ParameterizedType) {
+                       final ParameterizedType type= (ParameterizedType) selection;
+                       final Type raw= type.getType();
+                       if (raw instanceof SimpleType)
+                               name= ((SimpleType) raw).getName();
+                       else if (raw instanceof QualifiedType)
+                               name= ((QualifiedType) raw).getName();
+               } else if (selection instanceof Name) {
+                       name= (Name) selection;
+               }
+               if (name == null)
+                       return null;
+
+               if (name.isSimpleName()) {
+                       return (SimpleName)name;
+               } else {
+                       return ((QualifiedName)name).getName();
+               }
+       }
+
+       /**
+        * Returns the declaration node for the originally selected node.
+        * @param name the name of the node
+        *
+        * @return the declaration node
+        */
+       private static ASTNode getDeclarationNode(SimpleName name) {
+               ASTNode parent= name.getParent();
+               if (!(parent instanceof AbstractTypeDeclaration)) {
+
+                       parent= parent.getParent();
+                       if (parent instanceof ParameterizedType || parent instanceof Type)
+                               parent= parent.getParent();
+                       if (parent instanceof ClassInstanceCreation) {
+
+                               final ClassInstanceCreation creation= (ClassInstanceCreation) parent;
+                               parent= creation.getAnonymousClassDeclaration();
+                       }
+               }
+               return parent;
+       }
+
+       /**
+        * Returns the type binding of the class declaration node.
+        *
+        * @param parent the node to get the type for
+        * @return the type binding
+        */
+       private static ITypeBinding getTypeBinding(final ASTNode parent) {
+               if (parent instanceof AbstractTypeDeclaration) {
+                       final AbstractTypeDeclaration declaration= (AbstractTypeDeclaration) parent;
+                       return declaration.resolveBinding();
+               } else if (parent instanceof AnonymousClassDeclaration) {
+                       final AnonymousClassDeclaration declaration= (AnonymousClassDeclaration) parent;
+                       return declaration.resolveBinding();
+               } else if (parent instanceof ParameterizedType) {
+                       final ParameterizedType type= (ParameterizedType) parent;
+                       return type.resolveBinding();
+               }
+               return null;
+       }
+
+       protected PotentialProgrammingProblemsFix(String name, CompilationUnit compilationUnit, CompilationUnitRewriteOperation[] fixRewriteOperations) {
+               super(name, compilationUnit, fixRewriteOperations);
+       }
+}
\ No newline at end of file