X-Git-Url: http://git.uio.no/git/?a=blobdiff_plain;f=case-study%2Fjdt-before%2Fcore%20extension%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcorext%2Ffix%2FPotentialProgrammingProblemsFix.java;fp=case-study%2Fjdt-before%2Fcore%20extension%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcorext%2Ffix%2FPotentialProgrammingProblemsFix.java;h=dd34f48eb46ad8a340c733062d39233c8b8fbf21;hb=1b2798f607d741df30e5197f427381cbff326adc;hp=0000000000000000000000000000000000000000;hpb=246231e4bd9b24345490f369747c0549ca308c4d;p=ifi-stolz-refaktor.git 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 index 00000000..dd34f48e --- /dev/null +++ b/case-study/jdt-before/core extension/org/eclipse/jdt/internal/corext/fix/PotentialProgrammingProblemsFix.java @@ -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 fIdsTable; + + public SerialVersionHashContext(IJavaProject project, ICompilationUnit[] compilationUnits) { + fProject= project; + fCompilationUnits= compilationUnits; + fIdsTable= new Hashtable(); + } + + 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 types= new ArrayList(); + + 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 cus= new HashSet(); + 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 cus, List 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 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 declarationNodes= new ArrayList(); + 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 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