| /******************************************************************************* |
| * Copyright (c) 2000, 2018 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Stephan Herrmann <stephan@cs.tu-berlin.de> - [refactoring] pull-up with "use the destination type where possible" creates bogus import of nested type - https://bugs.eclipse.org/393932 |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.corext.refactoring.structure.constraints; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| |
| import org.eclipse.text.edits.MalformedTreeException; |
| import org.eclipse.text.edits.TextEdit; |
| import org.eclipse.text.edits.TextEditGroup; |
| |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.IDocument; |
| |
| import org.eclipse.ltk.core.refactoring.GroupCategory; |
| import org.eclipse.ltk.core.refactoring.GroupCategorySet; |
| import org.eclipse.ltk.core.refactoring.RefactoringStatus; |
| import org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor; |
| |
| import org.eclipse.jdt.core.BindingKey; |
| 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.IMember; |
| import org.eclipse.jdt.core.IMethod; |
| import org.eclipse.jdt.core.IPackageFragment; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.ITypeParameter; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.WorkingCopyOwner; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.ASTParser; |
| import org.eclipse.jdt.core.dom.ASTRequestor; |
| import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; |
| import org.eclipse.jdt.core.dom.ArrayType; |
| import org.eclipse.jdt.core.dom.BodyDeclaration; |
| import org.eclipse.jdt.core.dom.CastExpression; |
| import org.eclipse.jdt.core.dom.CompilationUnit; |
| import org.eclipse.jdt.core.dom.FieldDeclaration; |
| import org.eclipse.jdt.core.dom.IBinding; |
| import org.eclipse.jdt.core.dom.IMethodBinding; |
| import org.eclipse.jdt.core.dom.ITypeBinding; |
| import org.eclipse.jdt.core.dom.IVariableBinding; |
| import org.eclipse.jdt.core.dom.MethodDeclaration; |
| import org.eclipse.jdt.core.dom.NodeFinder; |
| import org.eclipse.jdt.core.dom.QualifiedName; |
| import org.eclipse.jdt.core.dom.SimpleName; |
| import org.eclipse.jdt.core.dom.SingleVariableDeclaration; |
| import org.eclipse.jdt.core.dom.Type; |
| import org.eclipse.jdt.core.dom.TypeDeclaration; |
| import org.eclipse.jdt.core.dom.TypeParameter; |
| import org.eclipse.jdt.core.dom.VariableDeclaration; |
| import org.eclipse.jdt.core.dom.VariableDeclarationFragment; |
| import org.eclipse.jdt.core.dom.VariableDeclarationStatement; |
| import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; |
| import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; |
| import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext; |
| import org.eclipse.jdt.core.dom.rewrite.ListRewrite; |
| import org.eclipse.jdt.core.formatter.CodeFormatter; |
| import org.eclipse.jdt.core.manipulation.CodeGeneration; |
| import org.eclipse.jdt.core.search.IJavaSearchConstants; |
| import org.eclipse.jdt.core.search.SearchMatch; |
| import org.eclipse.jdt.core.search.SearchPattern; |
| |
| import org.eclipse.jdt.internal.core.manipulation.StubUtility; |
| import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings; |
| import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext; |
| import org.eclipse.jdt.internal.corext.dom.ASTNodes; |
| import org.eclipse.jdt.internal.corext.dom.IASTSharedValues; |
| import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment; |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory; |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2; |
| import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; |
| import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil; |
| import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; |
| import org.eclipse.jdt.internal.corext.refactoring.structure.ImportRewriteUtil; |
| import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.CompilationUnitRange; |
| import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType; |
| import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TypeEnvironment; |
| import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.CastVariable2; |
| import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeConstraintVariable; |
| import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; |
| import org.eclipse.jdt.internal.corext.refactoring.util.TextEditBasedChangeManager; |
| import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil; |
| import org.eclipse.jdt.internal.corext.util.JavaModelUtil; |
| import org.eclipse.jdt.internal.corext.util.JdtFlags; |
| import org.eclipse.jdt.internal.corext.util.SearchUtils; |
| |
| import org.eclipse.jdt.internal.ui.JavaPlugin; |
| import org.eclipse.jdt.internal.ui.preferences.formatter.FormatterProfileManager; |
| |
| /** |
| * Partial implementation of a refactoring processor solving supertype |
| * constraint models. |
| * |
| * @since 3.1 |
| */ |
| public abstract class SuperTypeRefactoringProcessor extends RefactoringProcessor { |
| |
| protected static final String ATTRIBUTE_INSTANCEOF= "instanceof"; //$NON-NLS-1$ |
| |
| protected static final String ATTRIBUTE_REPLACE= "replace"; //$NON-NLS-1$ |
| |
| /** The super type group category set */ |
| protected static final GroupCategorySet SET_SUPER_TYPE= new GroupCategorySet(new GroupCategory("org.eclipse.jdt.internal.corext.superType", //$NON-NLS-1$ |
| RefactoringCoreMessages.SuperTypeRefactoringProcessor_category_name, RefactoringCoreMessages.SuperTypeRefactoringProcessor_category_description)); |
| |
| /** Number of compilation units to parse at once */ |
| private static final int SIZE_BATCH= 500; |
| |
| /** |
| * Returns a new ast node corresponding to the given type. |
| * |
| * @param rewrite the compilation unit rewrite to use |
| * @param type the new type |
| * @param node the old node |
| * @return A corresponding ast node |
| */ |
| protected static ASTNode createCorrespondingNode(final CompilationUnitRewrite rewrite, final TType type, ASTNode node) { |
| ImportRewrite importRewrite= rewrite.getImportRewrite(); |
| ImportRewriteContext context = new ContextSensitiveImportRewriteContext(node, importRewrite); |
| return importRewrite.addImportFromSignature(new BindingKey(type.getBindingKey()).toSignature(), rewrite.getAST(), context); |
| } |
| |
| /** Should type occurrences on instanceof's also be rewritten? */ |
| protected boolean fInstanceOf= false; |
| |
| /** |
| * The obsolete casts (element type: |
| * <code><ICompilationUnit, Collection<CastVariable2>></code>) |
| */ |
| protected Map<ICompilationUnit, Collection<CastVariable2>> fObsoleteCasts= null; |
| |
| /** The working copy owner */ |
| protected final WorkingCopyOwner fOwner= new WorkingCopyOwner() { |
| // use default implementation |
| }; |
| |
| /** Should occurrences of the type be replaced by the supertype? */ |
| protected boolean fReplace= false; |
| |
| /** The code generation settings, or <code>null</code> */ |
| protected CodeGenerationSettings fSettings; |
| |
| /** The static bindings to import */ |
| protected final Set<IBinding> fStaticBindings= new HashSet<>(); |
| |
| /** The type bindings to import */ |
| protected final Set<ITypeBinding> fTypeBindings= new HashSet<>(); |
| |
| /** |
| * The type occurrences (element type: |
| * <code><ICompilationUnit, Collection<IDeclaredConstraintVariable>></code>) |
| */ |
| protected Map<ICompilationUnit, Collection<ITypeConstraintVariable>> fTypeOccurrences= null; |
| |
| /** |
| * Creates a new supertype refactoring processor. |
| * |
| * @param settings |
| * the code generation settings, or <code>null</code> |
| */ |
| protected SuperTypeRefactoringProcessor(final CodeGenerationSettings settings) { |
| fSettings= settings; |
| } |
| |
| /** |
| * Adds the refactoring settings to the specified comment. |
| * |
| * @param comment |
| * the java refactoring descriptor comment |
| * @param addUseSupertype |
| * <code>true</code> to add the use supertype setting, |
| * <code>false</code> otherwise |
| */ |
| protected void addSuperTypeSettings(final JDTRefactoringDescriptorComment comment, final boolean addUseSupertype) { |
| Assert.isNotNull(comment); |
| if (fReplace) { |
| if (addUseSupertype) |
| comment.addSetting(RefactoringCoreMessages.SuperTypeRefactoringProcessor_user_supertype_setting); |
| if (fInstanceOf) |
| comment.addSetting(RefactoringCoreMessages.SuperTypeRefactoringProcessor_use_in_instanceof_setting); |
| } |
| } |
| |
| /** |
| * Creates the super type constraint solver to solve the model. |
| * |
| * @param model |
| * the model to create a solver for |
| * @return The created super type constraint solver |
| */ |
| protected abstract SuperTypeConstraintsSolver createContraintSolver(SuperTypeConstraintsModel model); |
| |
| /** |
| * Creates the declarations of the new supertype members. |
| * |
| * @param sourceRewrite |
| * the source compilation unit rewrite |
| * @param targetRewrite |
| * the target rewrite |
| * @param targetDeclaration |
| * the target type declaration |
| * @throws CoreException |
| * if a buffer could not be retrieved |
| */ |
| protected void createMemberDeclarations(CompilationUnitRewrite sourceRewrite, ASTRewrite targetRewrite, AbstractTypeDeclaration targetDeclaration) throws CoreException { |
| // Do nothing |
| } |
| |
| /** |
| * Creates the declaration of the new supertype, excluding any comments or |
| * package declaration. |
| * |
| * @param sourceRewrite |
| * the source compilation unit rewrite |
| * @param subType |
| * the subtype |
| * @param superName |
| * the name of the supertype |
| * @param sourceDeclaration |
| * the type declaration of the source type |
| * @param buffer |
| * the string buffer containing the declaration |
| * @param isInterface |
| * <code>true</code> if the type declaration is an interface, |
| * <code>false</code> otherwise |
| * @param status |
| * the refactoring status |
| * @param monitor |
| * the progress monitor to use |
| * @throws CoreException |
| * if an error occurs |
| */ |
| protected final void createTypeDeclaration(final CompilationUnitRewrite sourceRewrite, final IType subType, final String superName, final AbstractTypeDeclaration sourceDeclaration, final StringBuffer buffer, boolean isInterface, final RefactoringStatus status, final IProgressMonitor monitor) throws CoreException { |
| Assert.isNotNull(sourceRewrite); |
| Assert.isNotNull(subType); |
| Assert.isNotNull(superName); |
| Assert.isNotNull(sourceDeclaration); |
| Assert.isNotNull(buffer); |
| Assert.isNotNull(status); |
| Assert.isNotNull(monitor); |
| try { |
| monitor.beginTask("", 100); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating); |
| final String delimiter= StubUtility.getLineDelimiterUsed(subType.getJavaProject()); |
| if (JdtFlags.isPublic(subType)) { |
| buffer.append(JdtFlags.VISIBILITY_STRING_PUBLIC); |
| buffer.append(" "); //$NON-NLS-1$ |
| } |
| if (isInterface) |
| buffer.append("interface "); //$NON-NLS-1$ |
| else |
| buffer.append("class "); //$NON-NLS-1$ |
| buffer.append(superName); |
| buffer.append(" {"); //$NON-NLS-1$ |
| buffer.append(delimiter); |
| buffer.append(delimiter); |
| buffer.append('}'); |
| final IDocument document= new Document(buffer.toString()); |
| final ASTParser parser= ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL); |
| parser.setSource(document.get().toCharArray()); |
| final CompilationUnit unit= (CompilationUnit) parser.createAST(new SubProgressMonitor(monitor, 100)); |
| final ASTRewrite targetRewrite= ASTRewrite.create(unit.getAST()); |
| final AbstractTypeDeclaration targetDeclaration= (AbstractTypeDeclaration) unit.types().get(0); |
| createTypeParameters(targetRewrite, subType, sourceDeclaration, targetDeclaration); |
| createMemberDeclarations(sourceRewrite, targetRewrite, targetDeclaration); |
| final TextEdit edit= targetRewrite.rewriteAST(document, subType.getJavaProject().getOptions(true)); |
| try { |
| edit.apply(document, TextEdit.UPDATE_REGIONS); |
| } catch (MalformedTreeException exception) { |
| JavaPlugin.log(exception); |
| } catch (BadLocationException exception) { |
| JavaPlugin.log(exception); |
| } |
| buffer.setLength(0); |
| buffer.append(document.get()); |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Creates the necessary imports for the extracted supertype. |
| * |
| * @param unit |
| * the working copy of the new supertype |
| * @param monitor |
| * the progress monitor to use |
| * @return the generated import declaration |
| * @throws CoreException |
| * if the imports could not be generated |
| */ |
| protected final String createTypeImports(final ICompilationUnit unit, final IProgressMonitor monitor) throws CoreException { |
| Assert.isNotNull(unit); |
| Assert.isNotNull(monitor); |
| try { |
| monitor.beginTask("", 100); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating); |
| final ImportRewrite rewrite= StubUtility.createImportRewrite(unit, true); |
| ITypeBinding type= null; |
| for (final Iterator<ITypeBinding> iterator= fTypeBindings.iterator(); iterator.hasNext();) { |
| type= iterator.next(); |
| if (type.isTypeVariable()) { |
| for (ITypeBinding bound : type.getTypeBounds()) { |
| rewrite.addImport(bound); |
| } |
| } |
| rewrite.addImport(type); |
| } |
| IBinding binding= null; |
| for (final Iterator<IBinding> iterator= fStaticBindings.iterator(); iterator.hasNext();) { |
| binding= iterator.next(); |
| rewrite.addStaticImport(binding); |
| } |
| final IDocument document= new Document(); |
| try { |
| rewrite.rewriteImports(new SubProgressMonitor(monitor, 100)).apply(document); |
| } catch (MalformedTreeException exception) { |
| JavaPlugin.log(exception); |
| } catch (BadLocationException exception) { |
| JavaPlugin.log(exception); |
| } catch (CoreException exception) { |
| JavaPlugin.log(exception); |
| } |
| fTypeBindings.clear(); |
| fStaticBindings.clear(); |
| return document.get(); |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Creates the type parameters of the new supertype. |
| * |
| * @param targetRewrite |
| * the target compilation unit rewrite |
| * @param subType |
| * the subtype |
| * @param sourceDeclaration |
| * the type declaration of the source type |
| * @param targetDeclaration |
| * the type declaration of the target type |
| */ |
| protected final void createTypeParameters(final ASTRewrite targetRewrite, final IType subType, final AbstractTypeDeclaration sourceDeclaration, final AbstractTypeDeclaration targetDeclaration) { |
| Assert.isNotNull(targetRewrite); |
| Assert.isNotNull(sourceDeclaration); |
| Assert.isNotNull(targetDeclaration); |
| if (sourceDeclaration instanceof TypeDeclaration) { |
| TypeParameter parameter= null; |
| final ListRewrite rewrite= targetRewrite.getListRewrite(targetDeclaration, TypeDeclaration.TYPE_PARAMETERS_PROPERTY); |
| for (final Iterator<TypeParameter> iterator= ((TypeDeclaration) sourceDeclaration).typeParameters().iterator(); iterator.hasNext();) { |
| parameter= iterator.next(); |
| rewrite.insertLast(ASTNode.copySubtree(targetRewrite.getAST(), parameter), null); |
| ImportRewriteUtil.collectImports(subType.getJavaProject(), sourceDeclaration, fTypeBindings, fStaticBindings, false); |
| } |
| } |
| } |
| |
| /** |
| * Creates the source for the new compilation unit containing the supertype. |
| * |
| * @param copy |
| * the working copy of the new supertype |
| * @param subType |
| * the subtype |
| * @param superName |
| * the name of the supertype |
| * @param sourceRewrite |
| * the source compilation unit rewrite |
| * @param declaration |
| * the type declaration |
| * @param status |
| * the refactoring status |
| * @param monitor |
| * the progress monitor to display progress |
| * @return the source of the new compilation unit, or <code>null</code> |
| * @throws CoreException |
| * if an error occurs |
| */ |
| protected final String createTypeSource(final ICompilationUnit copy, final IType subType, final String superName, final CompilationUnitRewrite sourceRewrite, final AbstractTypeDeclaration declaration, final RefactoringStatus status, final IProgressMonitor monitor) throws CoreException { |
| Assert.isNotNull(copy); |
| Assert.isNotNull(subType); |
| Assert.isNotNull(superName); |
| Assert.isNotNull(sourceRewrite); |
| Assert.isNotNull(declaration); |
| Assert.isNotNull(status); |
| Assert.isNotNull(monitor); |
| String source= null; |
| try { |
| monitor.beginTask("", 100); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating); |
| final String delimiter= StubUtility.getLineDelimiterUsed(subType.getJavaProject()); |
| String typeComment= null; |
| String fileComment= null; |
| if (fSettings.createComments) { |
| final ITypeParameter[] parameters= subType.getTypeParameters(); |
| final String[] names= new String[parameters.length]; |
| for (int index= 0; index < parameters.length; index++) |
| names[index]= parameters[index].getElementName(); |
| typeComment= CodeGeneration.getTypeComment(copy, superName, names, delimiter); |
| fileComment= CodeGeneration.getFileComment(copy, delimiter); |
| } |
| final StringBuffer buffer= new StringBuffer(64); |
| createTypeDeclaration(sourceRewrite, subType, superName, declaration, buffer, true, status, new SubProgressMonitor(monitor, 40)); |
| final String imports= createTypeImports(copy, new SubProgressMonitor(monitor, 60)); |
| source= createTypeTemplate(copy, imports, fileComment, typeComment, buffer.toString()); |
| if (source == null) { |
| if (!subType.getPackageFragment().isDefaultPackage()) { |
| if (imports.length() > 0) |
| buffer.insert(0, imports); |
| buffer.insert(0, "package " + subType.getPackageFragment().getElementName() + ";"); //$NON-NLS-1$//$NON-NLS-2$ |
| } |
| source= buffer.toString(); |
| } |
| final IDocument document= new Document(source); |
| final TextEdit edit= CodeFormatterUtil.format2(CodeFormatter.K_COMPILATION_UNIT, source, 0, delimiter, FormatterProfileManager.getProjectSettings(copy.getJavaProject())); |
| if (edit != null) { |
| try { |
| edit.apply(document, TextEdit.UPDATE_REGIONS); |
| } catch (MalformedTreeException exception) { |
| JavaPlugin.log(exception); |
| status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error)); |
| } catch (BadLocationException exception) { |
| JavaPlugin.log(exception); |
| status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error)); |
| } |
| source= document.get(); |
| } |
| } finally { |
| monitor.done(); |
| } |
| return source; |
| } |
| |
| /** |
| * Creates the type template based on the code generation settings. |
| * |
| * @param unit |
| * the working copy for the new supertype |
| * @param imports |
| * the generated imports declaration |
| * @param fileComment |
| * the file comment |
| * @param comment |
| * the type comment |
| * @param content |
| * the type content |
| * @return a template for the supertype, or <code>null</code> |
| * @throws CoreException |
| * if the template could not be evaluated |
| */ |
| protected final String createTypeTemplate(final ICompilationUnit unit, final String imports, String fileComment, final String comment, final String content) throws CoreException { |
| Assert.isNotNull(unit); |
| Assert.isNotNull(imports); |
| Assert.isNotNull(content); |
| final IPackageFragment fragment= (IPackageFragment) unit.getParent(); |
| final StringBuilder buffer= new StringBuilder(); |
| final String delimiter= StubUtility.getLineDelimiterUsed(unit.getJavaProject()); |
| if (!fragment.isDefaultPackage()) { |
| buffer.append("package " + fragment.getElementName() + ";"); //$NON-NLS-1$ //$NON-NLS-2$ |
| buffer.append(delimiter); |
| buffer.append(delimiter); |
| } |
| if (imports.length() > 0) |
| buffer.append(imports); |
| |
| return StubUtility.getCompilationUnitContent(unit, buffer.toString(), fileComment, comment, content, delimiter); |
| } |
| |
| @Override |
| protected void finalize() throws Throwable { |
| resetWorkingCopies(); |
| } |
| |
| /** |
| * Returns the field which corresponds to the specified variable declaration |
| * fragment |
| * |
| * @param fragment |
| * the variable declaration fragment |
| * @return the corresponding field |
| * @throws JavaModelException |
| * if an error occurs |
| */ |
| protected final IField getCorrespondingField(final VariableDeclarationFragment fragment) throws JavaModelException { |
| final IBinding binding= fragment.getName().resolveBinding(); |
| if (binding instanceof IVariableBinding) { |
| final IVariableBinding variable= (IVariableBinding) binding; |
| if (variable.isField()) { |
| final ICompilationUnit unit= RefactoringASTParser.getCompilationUnit(fragment); |
| final IJavaElement element= unit.getElementAt(fragment.getStartPosition()); |
| if (element instanceof IField) |
| return (IField) element; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Computes the compilation units of fields referencing the specified type |
| * occurrences. |
| * |
| * @param units |
| * the compilation unit map (element type: |
| * <code><IJavaProject, Set<ICompilationUnit>></code>) |
| * @param nodes |
| * the ast nodes representing the type occurrences |
| * @throws JavaModelException |
| * if an error occurs |
| */ |
| protected final void getFieldReferencingCompilationUnits(final Map<IJavaProject, Set<ICompilationUnit>> units, final ASTNode[] nodes) throws JavaModelException { |
| for (ASTNode node : nodes) { |
| IJavaProject project= RefactoringASTParser.getCompilationUnit(node).getJavaProject(); |
| if (project != null) { |
| final List<IField> fields= getReferencingFields(node, project); |
| for (int offset= 0; offset < fields.size(); offset++) { |
| IField field= fields.get(offset); |
| Set<ICompilationUnit> set= units.get(project); |
| if (set == null) { |
| set= new HashSet<>(); |
| units.put(project, set); |
| } |
| final ICompilationUnit unit= field.getCompilationUnit(); |
| if (unit != null) |
| set.add(unit); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Computes the compilation units of methods referencing the specified type |
| * occurrences. |
| * |
| * @param units |
| * the compilation unit map (element type: |
| * <code><IJavaProject, Set<ICompilationUnit>></code>) |
| * @param nodes |
| * the ast nodes representing the type occurrences |
| * @throws JavaModelException |
| * if an error occurs |
| */ |
| protected final void getMethodReferencingCompilationUnits(final Map<IJavaProject, Set<ICompilationUnit>> units, final ASTNode[] nodes) throws JavaModelException { |
| for (ASTNode node : nodes) { |
| IJavaProject project= RefactoringASTParser.getCompilationUnit(node).getJavaProject(); |
| if (project != null) { |
| IMethod method= getReferencingMethod(node); |
| if (method != null) { |
| Set<ICompilationUnit> set= units.get(project); |
| if (set == null) { |
| set= new HashSet<>(); |
| units.put(project, set); |
| } |
| final ICompilationUnit unit= method.getCompilationUnit(); |
| if (unit != null) |
| set.add(unit); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Computes the compilation units referencing the subtype to replace. |
| * |
| * @param type |
| * the subtype |
| * @param monitor |
| * the progress monitor to use |
| * @param status |
| * the refactoring status |
| * @return the referenced compilation units (element type: |
| * <code><IJavaProject, Collection<SearchResultGroup>></code>) |
| * @throws JavaModelException |
| * if an error occurs |
| */ |
| protected final Map<IJavaProject, Set<SearchResultGroup>> getReferencingCompilationUnits(final IType type, final IProgressMonitor monitor, final RefactoringStatus status) throws JavaModelException { |
| try { |
| monitor.beginTask("", 100); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating); |
| final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(); |
| engine.setOwner(fOwner); |
| engine.setFiltering(true, true); |
| engine.setStatus(status); |
| engine.setScope(RefactoringScopeFactory.create(type)); |
| engine.setPattern(SearchPattern.createPattern(type, IJavaSearchConstants.REFERENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE)); |
| engine.searchPattern(new SubProgressMonitor(monitor, 100)); |
| @SuppressWarnings("unchecked") |
| Map<IJavaProject, Set<SearchResultGroup>> result= (Map<IJavaProject, Set<SearchResultGroup>>) engine.getAffectedProjects(); |
| return result; |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Returns the fields which reference the specified ast node. |
| * |
| * @param node |
| * the ast node |
| * @param project |
| * the java project |
| * @return the referencing fields |
| * @throws JavaModelException |
| * if an error occurs |
| */ |
| protected final List<IField> getReferencingFields(final ASTNode node, final IJavaProject project) throws JavaModelException { |
| List<IField> result= Collections.emptyList(); |
| if (node instanceof Type) { |
| final BodyDeclaration parent= ASTNodes.getParent(node, BodyDeclaration.class); |
| if (parent instanceof FieldDeclaration) { |
| final List<VariableDeclarationFragment> fragments= ((FieldDeclaration) parent).fragments(); |
| result= new ArrayList<>(fragments.size()); |
| VariableDeclarationFragment fragment= null; |
| for (final Iterator<VariableDeclarationFragment> iterator= fragments.iterator(); iterator.hasNext();) { |
| fragment= iterator.next(); |
| final IField field= getCorrespondingField(fragment); |
| if (field != null) |
| result.add(field); |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Returns the method which references the specified ast node. |
| * |
| * @param node |
| * the ast node |
| * @return the referencing method |
| * @throws JavaModelException |
| * if an error occurs |
| */ |
| protected final IMethod getReferencingMethod(final ASTNode node) throws JavaModelException { |
| if (node instanceof Type) { |
| final BodyDeclaration parent= ASTNodes.getParent(node, BodyDeclaration.class); |
| if (parent instanceof MethodDeclaration) { |
| final IMethodBinding binding= ((MethodDeclaration) parent).resolveBinding(); |
| if (binding != null) { |
| final ICompilationUnit unit= RefactoringASTParser.getCompilationUnit(node); |
| final IJavaElement element= unit.getElementAt(node.getStartPosition()); |
| if (element instanceof IMethod) |
| return (IMethod) element; |
| } |
| } |
| } |
| return null; |
| } |
| |
| protected ICompilationUnit getSharedWorkingCopy(final ICompilationUnit unit, final IProgressMonitor monitor) throws JavaModelException { |
| try { |
| ICompilationUnit copy= unit.findWorkingCopy(fOwner); |
| if (copy == null) |
| copy= unit.getWorkingCopy(fOwner, monitor); |
| return copy; |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Returns whether type occurrences in instanceof's should be rewritten. |
| * |
| * @return <code>true</code> if they are rewritten, <code>false</code> |
| * otherwise |
| */ |
| public final boolean isInstanceOf() { |
| return fInstanceOf; |
| } |
| |
| /** |
| * Should occurrences of the subtype be replaced by the supertype? |
| * |
| * @return <code>true</code> if the subtype should be replaced, |
| * <code>false</code> otherwise |
| */ |
| public final boolean isReplace() { |
| return fReplace; |
| } |
| |
| /** |
| * Performs the first pass of processing the affected compilation units. |
| * |
| * @param creator |
| * the constraints creator to use |
| * @param units |
| * the compilation unit map (element type: |
| * <code><IJavaProject, Set<ICompilationUnit>></code>) |
| * @param groups |
| * the search result group map (element type: |
| * <code><ICompilationUnit, SearchResultGroup></code>) |
| * @param unit |
| * the compilation unit of the subtype |
| * @param node |
| * the compilation unit node of the subtype |
| * @param monitor |
| * the progress monitor to use |
| */ |
| protected final void performFirstPass(final SuperTypeConstraintsCreator creator, final Map<IJavaProject, Set<ICompilationUnit>> units, final Map<ICompilationUnit, SearchResultGroup> groups, final ICompilationUnit unit, final CompilationUnit node, final IProgressMonitor monitor) { |
| try { |
| monitor.beginTask("", 100); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating); |
| node.accept(creator); |
| monitor.worked(20); |
| final SearchResultGroup group= groups.get(unit); |
| if (group != null) { |
| final ASTNode[] nodes= ASTNodeSearchUtil.getAstNodes(group.getSearchResults(), node); |
| try { |
| getMethodReferencingCompilationUnits(units, nodes); |
| monitor.worked(40); |
| getFieldReferencingCompilationUnits(units, nodes); |
| monitor.worked(40); |
| } catch (JavaModelException exception) { |
| JavaPlugin.log(exception); |
| } |
| } |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Performs the second pass of processing the affected compilation units. |
| * |
| * @param creator |
| * the constraints creator to use |
| * @param unit |
| * the compilation unit of the subtype |
| * @param node |
| * the compilation unit node of the subtype |
| * @param monitor |
| * the progress monitor to use |
| */ |
| protected final void performSecondPass(final SuperTypeConstraintsCreator creator, final ICompilationUnit unit, final CompilationUnit node, final IProgressMonitor monitor) { |
| try { |
| monitor.beginTask("", 20); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating); |
| node.accept(creator); |
| monitor.worked(20); |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Resets the working copies. |
| */ |
| protected void resetWorkingCopies() { |
| for (ICompilationUnit unit : JavaCore.getWorkingCopies(fOwner)) { |
| try { |
| unit.discardWorkingCopy(); |
| } catch (Exception exception) { |
| // Do nothing |
| } |
| } |
| } |
| |
| /** |
| * Resets the working copies. |
| * |
| * @param unit |
| * the compilation unit to discard |
| */ |
| protected void resetWorkingCopies(final ICompilationUnit unit) { |
| for (ICompilationUnit cu : JavaCore.getWorkingCopies(fOwner)) { |
| if (!cu.equals(unit)) { |
| try { |
| cu.discardWorkingCopy(); |
| } catch (Exception exception) { |
| // Do nothing |
| } |
| } else { |
| try { |
| cu.getBuffer().setContents(unit.getPrimary().getBuffer().getContents()); |
| JavaModelUtil.reconcile(cu); |
| } catch (JavaModelException exception) { |
| JavaPlugin.log(exception); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Creates the necessary text edits to replace the subtype occurrence by a |
| * supertype. |
| * |
| * @param range |
| * the compilation unit range |
| * @param estimate |
| * the type estimate |
| * @param requestor |
| * the ast requestor to use |
| * @param rewrite |
| * the compilation unit rewrite to use |
| * @param copy |
| * the compilation unit node of the working copy ast |
| * @param replacements |
| * the set of variable binding keys of formal parameters which |
| * must be replaced |
| * @param group |
| * the text edit group to use |
| */ |
| protected final void rewriteTypeOccurrence(final CompilationUnitRange range, final TType estimate, final ASTRequestor requestor, final CompilationUnitRewrite rewrite, final CompilationUnit copy, final Set<String> replacements, final TextEditGroup group) { |
| ASTNode node= null; |
| IBinding binding= null; |
| final CompilationUnit target= rewrite.getRoot(); |
| node= NodeFinder.perform(copy, range.getSourceRange()); |
| if (node != null) { |
| node= ASTNodes.getNormalizedNode(node).getParent(); |
| if (node instanceof VariableDeclaration) { |
| binding= ((VariableDeclaration) node).resolveBinding(); |
| node= target.findDeclaringNode(binding.getKey()); |
| if (node instanceof SingleVariableDeclaration) { |
| rewriteTypeOccurrence(estimate, rewrite, ((SingleVariableDeclaration) node).getType(), group); |
| if (node.getParent() instanceof MethodDeclaration) { |
| binding= ((VariableDeclaration) node).resolveBinding(); |
| if (binding != null) |
| replacements.add(binding.getKey()); |
| } |
| } |
| } else if (node instanceof VariableDeclarationStatement) { |
| binding= ((VariableDeclaration) ((VariableDeclarationStatement) node).fragments().get(0)).resolveBinding(); |
| node= target.findDeclaringNode(binding.getKey()); |
| if (node instanceof VariableDeclarationFragment) |
| rewriteTypeOccurrence(estimate, rewrite, ((VariableDeclarationStatement) ((VariableDeclarationFragment) node).getParent()).getType(), group); |
| } else if (node instanceof MethodDeclaration) { |
| binding= ((MethodDeclaration) node).resolveBinding(); |
| node= target.findDeclaringNode(binding.getKey()); |
| if (node instanceof MethodDeclaration) |
| rewriteTypeOccurrence(estimate, rewrite, ((MethodDeclaration) node).getReturnType2(), group); |
| } else if (node instanceof FieldDeclaration) { |
| binding= ((VariableDeclaration) ((FieldDeclaration) node).fragments().get(0)).resolveBinding(); |
| node= target.findDeclaringNode(binding.getKey()); |
| if (node instanceof VariableDeclarationFragment) { |
| node= node.getParent(); |
| if (node instanceof FieldDeclaration) |
| rewriteTypeOccurrence(estimate, rewrite, ((FieldDeclaration) node).getType(), group); |
| } |
| } else if (node instanceof ArrayType) { |
| final ASTNode type= node; |
| while (node != null && !(node instanceof MethodDeclaration) && !(node instanceof VariableDeclarationFragment)) |
| node= node.getParent(); |
| if (node != null) { |
| final int delta= node.getStartPosition() + node.getLength() - type.getStartPosition(); |
| if (node instanceof MethodDeclaration) |
| binding= ((MethodDeclaration) node).resolveBinding(); |
| else if (node instanceof VariableDeclarationFragment) |
| binding= ((VariableDeclarationFragment) node).resolveBinding(); |
| if (binding != null) { |
| node= target.findDeclaringNode(binding.getKey()); |
| if (node instanceof MethodDeclaration || node instanceof VariableDeclarationFragment) { |
| node= NodeFinder.perform(target, (node.getStartPosition() + node.getLength() - delta), 0); |
| if (node instanceof SimpleName) |
| rewriteTypeOccurrence(estimate, rewrite, node, group); |
| } |
| } |
| } |
| } else if (node instanceof QualifiedName) { |
| final ASTNode name= node; |
| while (node != null && !(node instanceof MethodDeclaration) && !(node instanceof VariableDeclarationFragment)) |
| node= node.getParent(); |
| if (node != null) { |
| final int delta= node.getStartPosition() + node.getLength() - name.getStartPosition(); |
| if (node instanceof MethodDeclaration) |
| binding= ((MethodDeclaration) node).resolveBinding(); |
| else if (node instanceof VariableDeclarationFragment) |
| binding= ((VariableDeclarationFragment) node).resolveBinding(); |
| if (binding != null) { |
| node= target.findDeclaringNode(binding.getKey()); |
| if (node instanceof SimpleName || node instanceof MethodDeclaration || node instanceof VariableDeclarationFragment) { |
| node= NodeFinder.perform(target, (node.getStartPosition() + node.getLength() - delta), 0); |
| if (node instanceof SimpleName) |
| rewriteTypeOccurrence(estimate, rewrite, node, group); |
| } |
| } |
| } |
| } else if (node instanceof CastExpression) { |
| final ASTNode expression= node; |
| while (node != null && !(node instanceof MethodDeclaration)) |
| node= node.getParent(); |
| if (node != null) { |
| final int delta= node.getStartPosition() + node.getLength() - expression.getStartPosition(); |
| binding= ((MethodDeclaration) node).resolveBinding(); |
| node= target.findDeclaringNode(binding.getKey()); |
| if (node instanceof MethodDeclaration) { |
| node= NodeFinder.perform(target, (node.getStartPosition() + node.getLength() - delta), 0); |
| if (node instanceof CastExpression) |
| rewriteTypeOccurrence(estimate, rewrite, ((CastExpression) node).getType(), group); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Creates the necessary text edits to replace the subtype occurrence by a |
| * supertype. |
| * |
| * @param estimate |
| * the type estimate |
| * @param rewrite |
| * the ast rewrite to use |
| * @param node |
| * the ast node to rewrite |
| * @param group |
| * the text edit group to use |
| */ |
| protected final void rewriteTypeOccurrence(final TType estimate, final CompilationUnitRewrite rewrite, final ASTNode node, final TextEditGroup group) { |
| rewrite.getImportRemover().registerRemovedNode(node); |
| rewrite.getASTRewrite().replace(node, createCorrespondingNode(rewrite, estimate, node), group); |
| } |
| |
| /** |
| * Creates the necessary text edits to replace the subtype occurrence by a |
| * supertype. |
| * |
| * @param manager |
| * the text change manager to use |
| * @param requestor |
| * the ast requestor to use |
| * @param rewrite |
| * the compilation unit rewrite of the subtype (not in working |
| * copy mode) |
| * @param unit |
| * the compilation unit |
| * @param node |
| * the compilation unit node |
| * @param replacements |
| * the set of variable binding keys of formal parameters which |
| * must be replaced |
| * @param monitor |
| * the progress monitor to use |
| * @throws CoreException |
| * if the change could not be generated |
| */ |
| protected abstract void rewriteTypeOccurrences(TextEditBasedChangeManager manager, ASTRequestor requestor, CompilationUnitRewrite rewrite, ICompilationUnit unit, CompilationUnit node, Set<String> replacements, IProgressMonitor monitor) throws CoreException; |
| |
| /** |
| * Creates the necessary text edits to replace the subtype occurrences by a |
| * supertype. |
| * |
| * @param manager |
| * the text change manager to use |
| * @param sourceRewrite |
| * the compilation unit rewrite of the subtype (not in working |
| * copy mode) |
| * @param sourceRequestor |
| * the ast requestor of the subtype, or <code>null</code> |
| * @param subUnit |
| * the compilation unit of the subtype, or <code>null</code> |
| * @param subNode |
| * the compilation unit node of the subtype, or <code>null</code> |
| * @param replacements |
| * the set of variable binding keys of formal parameters which |
| * must be replaced |
| * @param status |
| * the refactoring status |
| * @param monitor |
| * the progress monitor to use |
| */ |
| protected final void rewriteTypeOccurrences(final TextEditBasedChangeManager manager, final ASTRequestor sourceRequestor, final CompilationUnitRewrite sourceRewrite, final ICompilationUnit subUnit, final CompilationUnit subNode, final Set<String> replacements, final RefactoringStatus status, final IProgressMonitor monitor) { |
| try { |
| monitor.beginTask("", 300); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating); |
| if (fTypeOccurrences != null) { |
| final Set<ICompilationUnit> units= new HashSet<>(fTypeOccurrences.keySet()); |
| if (subUnit != null) |
| units.remove(subUnit); |
| final Map<IJavaProject, Collection<ICompilationUnit>> projects= new HashMap<>(); |
| Collection<ICompilationUnit> collection= null; |
| IJavaProject project= null; |
| ICompilationUnit current= null; |
| for (final Iterator<ICompilationUnit> iterator= units.iterator(); iterator.hasNext();) { |
| current= iterator.next(); |
| project= current.getJavaProject(); |
| collection= projects.get(project); |
| if (collection == null) { |
| collection= new ArrayList<>(); |
| projects.put(project, collection); |
| } |
| collection.add(current); |
| } |
| final ASTParser parser= ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL); |
| final IProgressMonitor subMonitor= new SubProgressMonitor(monitor, 320); |
| try { |
| final Set<IJavaProject> keySet= projects.keySet(); |
| subMonitor.beginTask("", keySet.size() * 100); //$NON-NLS-1$ |
| subMonitor.setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating); |
| for (final Iterator<IJavaProject> iterator= keySet.iterator(); iterator.hasNext();) { |
| project= iterator.next(); |
| collection= projects.get(project); |
| parser.setWorkingCopyOwner(fOwner); |
| parser.setResolveBindings(true); |
| parser.setProject(project); |
| parser.setCompilerOptions(RefactoringASTParser.getCompilerOptions(project)); |
| final IProgressMonitor subsubMonitor= new SubProgressMonitor(subMonitor, 100); |
| try { |
| subsubMonitor.beginTask("", collection.size() * 100 + 200); //$NON-NLS-1$ |
| subsubMonitor.setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating); |
| parser.createASTs(collection.toArray(new ICompilationUnit[collection.size()]), new String[0], new ASTRequestor() { |
| |
| @Override |
| public final void acceptAST(final ICompilationUnit unit, final CompilationUnit node) { |
| final IProgressMonitor subsubsubMonitor= new SubProgressMonitor(subsubMonitor, 100); |
| try { |
| subsubsubMonitor.beginTask("", 100); //$NON-NLS-1$ |
| subsubsubMonitor.setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating); |
| if (sourceRewrite != null) |
| rewriteTypeOccurrences(manager, this, sourceRewrite, unit, node, replacements, new SubProgressMonitor(subsubsubMonitor, 100)); |
| } catch (CoreException exception) { |
| status.merge(RefactoringStatus.createFatalErrorStatus(exception.getLocalizedMessage())); |
| } finally { |
| subsubsubMonitor.done(); |
| } |
| } |
| |
| @Override |
| public final void acceptBinding(final String key, final IBinding binding) { |
| // Do nothing |
| } |
| }, new SubProgressMonitor(subsubMonitor, 200)); |
| } finally { |
| subsubMonitor.done(); |
| } |
| } |
| try { |
| if (subUnit != null && subNode != null && sourceRewrite != null && sourceRequestor != null) |
| rewriteTypeOccurrences(manager, sourceRequestor, sourceRewrite, subUnit, subNode, replacements, new SubProgressMonitor(subMonitor, 20)); |
| } catch (CoreException exception) { |
| status.merge(RefactoringStatus.createFatalErrorStatus(exception.getLocalizedMessage())); |
| } |
| } finally { |
| subMonitor.done(); |
| } |
| } |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Determines whether type occurrences in instanceof's should be rewritten. |
| * |
| * @param rewrite |
| * <code>true</code> to rewrite them, <code>false</code> |
| * otherwise |
| */ |
| public final void setInstanceOf(final boolean rewrite) { |
| fInstanceOf= rewrite; |
| } |
| |
| /** |
| * Determines whether occurrences of the subtype should be replaced by the |
| * supertype. |
| * |
| * @param replace |
| * <code>true</code> to replace occurrences where possible, |
| * <code>false</code> otherwise |
| */ |
| public final void setReplace(final boolean replace) { |
| fReplace= replace; |
| } |
| |
| /** |
| * Solves the supertype constraints to replace subtype by a supertype. |
| * |
| * @param subUnit |
| * the compilation unit of the subtype, or <code>null</code> |
| * @param subNode |
| * the compilation unit node of the subtype, or <code>null</code> |
| * @param subType |
| * the java element of the subtype |
| * @param subBinding |
| * the type binding of the subtype to replace |
| * @param superBinding |
| * the type binding of the supertype to use as replacement |
| * @param monitor |
| * the progress monitor to use |
| * @param status |
| * the refactoring status |
| * @throws JavaModelException |
| * if an error occurs |
| */ |
| protected final void solveSuperTypeConstraints(final ICompilationUnit subUnit, final CompilationUnit subNode, final IType subType, final ITypeBinding subBinding, final ITypeBinding superBinding, final IProgressMonitor monitor, final RefactoringStatus status) throws JavaModelException { |
| Assert.isNotNull(subType); |
| Assert.isNotNull(subBinding); |
| Assert.isNotNull(superBinding); |
| Assert.isNotNull(monitor); |
| Assert.isNotNull(status); |
| int level= 3; |
| TypeEnvironment environment= new TypeEnvironment(); |
| final SuperTypeConstraintsModel model= new SuperTypeConstraintsModel(environment, environment.create(subBinding), environment.create(superBinding)); |
| final SuperTypeConstraintsCreator creator= new SuperTypeConstraintsCreator(model, fInstanceOf); |
| try { |
| monitor.beginTask("", 300); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating); |
| final Map<IJavaProject, Set<SearchResultGroup>> firstPass= getReferencingCompilationUnits(subType, new SubProgressMonitor(monitor, 100), status); |
| final Map<IJavaProject, Set<ICompilationUnit>> secondPass= new HashMap<>(); |
| Collection<SearchResultGroup> collection= null; |
| try { |
| final ASTParser parser= ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL); |
| ICompilationUnit current= null; |
| final Map<ICompilationUnit, SearchResultGroup> groups= new HashMap<>(); |
| for (IJavaProject project : firstPass.keySet()) { |
| if (level == 3 && !JavaModelUtil.is50OrHigher(project)) |
| level= 2; |
| collection= firstPass.get(project); |
| if (collection != null) { |
| for (SearchResultGroup group : collection) { |
| for (SearchMatch match : group.getSearchResults()) { |
| Object element= match.getElement(); |
| if (element instanceof IMember) { |
| current= ((IMember) element).getCompilationUnit(); |
| if (current != null) |
| groups.put(current, group); |
| } |
| } |
| } |
| } |
| } |
| final Set<ICompilationUnit> processed= new HashSet<>(); |
| if (subUnit != null) |
| processed.add(subUnit); |
| model.beginCreation(); |
| IProgressMonitor subMonitor= new SubProgressMonitor(monitor, 120); |
| try { |
| final Set<IJavaProject> keySet= firstPass.keySet(); |
| subMonitor.beginTask("", keySet.size() * 100); //$NON-NLS-1$ |
| subMonitor.setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating); |
| for (IJavaProject project : keySet) { |
| collection= firstPass.get(project); |
| if (collection != null) { |
| Set<ICompilationUnit> units= new HashSet<>(collection.size()); |
| for (SearchResultGroup group : collection) { |
| for (SearchMatch match : group.getSearchResults()) { |
| Object element= match.getElement(); |
| if (element instanceof IMember) { |
| current= ((IMember) element).getCompilationUnit(); |
| if (current != null) |
| units.add(current); |
| } |
| } |
| } |
| final List<ICompilationUnit> batches= new ArrayList<>(units); |
| final int size= batches.size(); |
| final int iterations= (size - 1) / SIZE_BATCH + 1; |
| final IProgressMonitor subsubMonitor= new SubProgressMonitor(subMonitor, 100); |
| try { |
| subsubMonitor.beginTask("", iterations * 100); //$NON-NLS-1$ |
| subsubMonitor.setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating); |
| final Map<String, String> options= RefactoringASTParser.getCompilerOptions(project); |
| for (int index= 0; index < iterations; index++) { |
| final List<ICompilationUnit> iteration= batches.subList(index * SIZE_BATCH, Math.min(size, (index + 1) * SIZE_BATCH)); |
| parser.setWorkingCopyOwner(fOwner); |
| parser.setResolveBindings(true); |
| parser.setProject(project); |
| parser.setCompilerOptions(options); |
| final IProgressMonitor subsubsubMonitor= new SubProgressMonitor(subsubMonitor, 100); |
| try { |
| final int count= iteration.size(); |
| subsubsubMonitor.beginTask("", count * 100); //$NON-NLS-1$ |
| subsubsubMonitor.setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating); |
| parser.createASTs(iteration.toArray(new ICompilationUnit[count]), new String[0], new ASTRequestor() { |
| |
| @Override |
| public final void acceptAST(final ICompilationUnit unit, final CompilationUnit node) { |
| if (!processed.contains(unit)) { |
| performFirstPass(creator, secondPass, groups, unit, node, new SubProgressMonitor(subsubsubMonitor, 100)); |
| processed.add(unit); |
| } else |
| subsubsubMonitor.worked(100); |
| } |
| |
| @Override |
| public final void acceptBinding(final String key, final IBinding binding) { |
| // Do nothing |
| } |
| }, new NullProgressMonitor()); |
| } finally { |
| subsubsubMonitor.done(); |
| } |
| } |
| } finally { |
| subsubMonitor.done(); |
| } |
| } |
| } |
| } finally { |
| firstPass.clear(); |
| subMonitor.done(); |
| } |
| if (subUnit != null && subNode != null) |
| performFirstPass(creator, secondPass, groups, subUnit, subNode, new SubProgressMonitor(subMonitor, 20)); |
| subMonitor= new SubProgressMonitor(monitor, 100); |
| try { |
| final Set<IJavaProject> keySet= secondPass.keySet(); |
| subMonitor.beginTask("", keySet.size() * 100); //$NON-NLS-1$ |
| subMonitor.setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating); |
| for (IJavaProject project : keySet) { |
| if (level == 3 && !JavaModelUtil.is50OrHigher(project)) |
| level= 2; |
| Collection<ICompilationUnit> cuCollection= null; |
| cuCollection= secondPass.get(project); |
| if (cuCollection != null) { |
| parser.setWorkingCopyOwner(fOwner); |
| parser.setResolveBindings(true); |
| parser.setProject(project); |
| parser.setCompilerOptions(RefactoringASTParser.getCompilerOptions(project)); |
| final IProgressMonitor subsubMonitor= new SubProgressMonitor(subMonitor, 100); |
| try { |
| subsubMonitor.beginTask("", cuCollection.size() * 100); //$NON-NLS-1$ |
| subsubMonitor.setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating); |
| parser.createASTs(cuCollection.toArray(new ICompilationUnit[cuCollection.size()]), new String[0], new ASTRequestor() { |
| |
| @Override |
| public final void acceptAST(final ICompilationUnit unit, final CompilationUnit node) { |
| if (!processed.contains(unit)) |
| performSecondPass(creator, unit, node, new SubProgressMonitor(subsubMonitor, 100)); |
| else |
| subsubMonitor.worked(100); |
| } |
| |
| @Override |
| public final void acceptBinding(final String key, final IBinding binding) { |
| // Do nothing |
| } |
| }, new NullProgressMonitor()); |
| } finally { |
| subsubMonitor.done(); |
| } |
| } |
| } |
| } finally { |
| secondPass.clear(); |
| subMonitor.done(); |
| } |
| } finally { |
| model.endCreation(); |
| model.setCompliance(level); |
| } |
| final SuperTypeConstraintsSolver solver= createContraintSolver(model); |
| solver.solveConstraints(); |
| fTypeOccurrences= solver.getTypeOccurrences(); |
| fObsoleteCasts= solver.getObsoleteCasts(); |
| } finally { |
| monitor.done(); |
| } |
| } |
| } |