/******************************************************************************* * Copyright (c) 2009-2011 CWI * 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: * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI * * Mark Hills - Mark.Hills@cwi.nl (CWI) * * Arnold Lankamp - Arnold.Lankamp@cwi.nl *******************************************************************************/ package lang.java.jdt.internal; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.imp.pdb.facts.ISet; import org.eclipse.imp.pdb.facts.ISourceLocation; import org.eclipse.imp.pdb.facts.IValue; import org.eclipse.imp.pdb.facts.IValueFactory; import org.eclipse.imp.pdb.facts.type.TypeFactory; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.Modifier; import org.eclipse.jdt.internal.corext.fix.CleanUpConstants; import org.eclipse.jdt.internal.corext.fix.CleanUpRefactoring; import org.eclipse.jdt.internal.corext.refactoring.sef.SelfEncapsulateFieldRefactoring; import org.eclipse.jdt.internal.corext.refactoring.structure.ChangeSignatureProcessor; import org.eclipse.jdt.internal.ui.fix.CodeStyleCleanUp; import org.eclipse.ltk.core.refactoring.CheckConditionsOperation; import org.eclipse.ltk.core.refactoring.PerformRefactoringOperation; import org.eclipse.ltk.core.refactoring.Refactoring; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry; import org.eclipse.ltk.core.refactoring.participants.ProcessorBasedRefactoring; import org.rascalmpl.interpreter.control_exceptions.Throw; @SuppressWarnings("restriction") public class JDTRefactoring { private final IValueFactory VF; private final JDT jdt; private static final TypeFactory TF = TypeFactory.getInstance(); public JDTRefactoring(IValueFactory vf) { this.VF = vf; this.jdt = new JDT(vf); } public ISet encapsulateFields(ISet fieldOffsetsFromLoc, ISourceLocation loc) { ISet result = VF.relation(TF.tupleType(TF.stringType(), TF.stringType())); Job.getJobManager().beginRule(ResourcesPlugin.getWorkspace().getRoot(), new NullProgressMonitor()); try { IFile file = jdt.getJavaIFileForLocation(loc); Set<IField> fields = new FindIFields().findFieldsAtLocs(fieldOffsetsFromLoc, loc, file); for (IField field : fields) { String fieldForGS = field.getElementName().substring(0,1).toUpperCase(); if (field.getElementName().length() > 1) fieldForGS += field.getElementName().substring(1); String getterName = "__get" + fieldForGS; String setterName = "__set" + fieldForGS; result.union(encapsulateField(field, Flags.AccPublic, getterName, setterName )); } } finally { Job.getJobManager().endRule(ResourcesPlugin.getWorkspace().getRoot()); } return result; } private ISet encapsulateField(IField field, int flags, String getterName, String setterName) { try { SelfEncapsulateFieldRefactoring refactoring = new SelfEncapsulateFieldRefactoring(field); refactoring.setVisibility(flags); refactoring.setConsiderVisibility(false); // only matters for IMethod objects refactoring.setGetterName(getterName); refactoring.setSetterName(setterName); PerformRefactoringOperation operation = new PerformRefactoringOperation(refactoring, CheckConditionsOperation.ALL_CONDITIONS); operation.run(new NullProgressMonitor()); ISet result = VF.relation(TF.tupleType(TF.stringType(), TF.stringType())); RefactoringStatus rs = operation.getConditionStatus(); if (rs != null && rs.hasWarning()) { for (RefactoringStatusEntry rse : rs.getEntries()) { result.insert(VF.tuple(VF.string(field.getElementName()), VF.string(rse.getMessage()))); } } rs = operation.getValidationStatus(); if (rs != null && rs.hasWarning()) { for (RefactoringStatusEntry rse : rs.getEntries()) { result.insert(VF.tuple(VF.string(field.getElementName()), VF.string(rse.getMessage()))); } } return result; } catch (JavaModelException e) { throw new Throw(VF.string(e.getMessage()), (ISourceLocation) null, null); } catch (CoreException e) { throw new Throw(VF.string(e.getMessage()), (ISourceLocation) null, null); } } public ISet makeMethodsPublic(ISet methodOffsetsFromLoc, ISourceLocation loc) { IFile file = jdt.getJavaIFileForLocation(loc); Set<IMethod> methods = new FindIMethods().findMethodsAtLocs(methodOffsetsFromLoc, loc, file); ISet result = VF.relation(TF.tupleType(TF.stringType(), TF.stringType())); for (IMethod method : methods) { result.union(changeMethodSignature(method, Modifier.PUBLIC)); } return result; } private ISet changeMethodSignature(IMethod method, int visibility) { ISet result = VF.relation(TF.tupleType(TF.stringType(), TF.stringType())); try { Job.getJobManager().beginRule(ResourcesPlugin.getWorkspace().getRoot(), new NullProgressMonitor()); ChangeSignatureProcessor processor = new ChangeSignatureProcessor(method); Refactoring refactoring = new ProcessorBasedRefactoring(processor); processor.setVisibility(visibility); PerformRefactoringOperation operation = new PerformRefactoringOperation(refactoring, CheckConditionsOperation.ALL_CONDITIONS); operation.run(new NullProgressMonitor()); RefactoringStatus rs = operation.getConditionStatus(); if (rs != null && rs.hasWarning()) { for (RefactoringStatusEntry rse : rs.getEntries()) { result.insert(VF.tuple(VF.string(method.getElementName() + " " + method.getSignature()), VF.string(rse.getMessage()))); } } rs = operation.getValidationStatus(); if (rs != null && rs.hasWarning()) { for (RefactoringStatusEntry rse : rs.getEntries()) { result.insert(VF.tuple(VF.string(method.getElementName() + " " + method.getSignature()), VF.string(rse.getMessage()))); } } } catch (JavaModelException e) { throw new Throw(VF.string(e.getMessage()), (ISourceLocation) null, null); } catch (CoreException e) { throw new Throw(VF.string(e.getMessage()), (ISourceLocation) null, null); } finally { Job.getJobManager().endRule(ResourcesPlugin.getWorkspace().getRoot()); } return result; } public ISet cleanUpSource(ISourceLocation loc) { IFile file = jdt.getJavaIFileForLocation(loc); ISet result = VF.relation(TF.tupleType(TF.stringType(), TF.stringType())); try { Job.getJobManager().beginRule(ResourcesPlugin.getWorkspace().getRoot(), new NullProgressMonitor()); // Create the refactoring for the cleanup CleanUpRefactoring refactoring = new CleanUpRefactoring(); // Add the given file as the compilation unit we will clean ICompilationUnit icu = JavaCore.createCompilationUnitFrom(file); refactoring.addCompilationUnit(icu); // Set the options: we want to identify local accesses with this, and static accesses with // the class name Map<String,String> cleanUpOptions = new HashMap<String,String>(); // NOTE: We could use "true" instead of "true", but this requires 3.5 at least cleanUpOptions.put(CleanUpConstants.MEMBER_ACCESSES_NON_STATIC_FIELD_USE_THIS, "true"); cleanUpOptions.put(CleanUpConstants.MEMBER_ACCESSES_NON_STATIC_FIELD_USE_THIS_ALWAYS, "true"); cleanUpOptions.put(CleanUpConstants.MEMBER_ACCESSES_NON_STATIC_METHOD_USE_THIS, "true"); cleanUpOptions.put(CleanUpConstants.MEMBER_ACCESSES_NON_STATIC_METHOD_USE_THIS_ALWAYS, "true"); cleanUpOptions.put(CleanUpConstants.MEMBER_ACCESSES_STATIC_QUALIFY_WITH_DECLARING_CLASS, "true"); cleanUpOptions.put(CleanUpConstants.MEMBER_ACCESSES_STATIC_QUALIFY_WITH_DECLARING_CLASS_FIELD, "true"); cleanUpOptions.put(CleanUpConstants.MEMBER_ACCESSES_STATIC_QUALIFY_WITH_DECLARING_CLASS_INSTANCE_ACCESS, "true"); cleanUpOptions.put(CleanUpConstants.MEMBER_ACCESSES_STATIC_QUALIFY_WITH_DECLARING_CLASS_METHOD, "true"); cleanUpOptions.put(CleanUpConstants.MEMBER_ACCESSES_STATIC_QUALIFY_WITH_DECLARING_CLASS_SUBTYPE_ACCESS, "true"); // Register this clean-up set of options CodeStyleCleanUp cleanUp = new CodeStyleCleanUp(cleanUpOptions); refactoring.addCleanUp(cleanUp); // Now, actually do the clean-up refactoring.setValidationContext(null); PerformRefactoringOperation operation = new PerformRefactoringOperation(refactoring, CheckConditionsOperation.ALL_CONDITIONS); operation.run(new NullProgressMonitor()); RefactoringStatus rs = operation.getConditionStatus(); if (rs != null && rs.hasWarning()) { for (RefactoringStatusEntry rse : rs.getEntries()) { result.insert(VF.tuple(VF.string(file.getName()), VF.string(rse.getMessage()))); } } rs = operation.getValidationStatus(); if (rs != null && rs.hasWarning()) { for (RefactoringStatusEntry rse : rs.getEntries()) { result.insert(VF.tuple(VF.string(file.getName()), VF.string(rse.getMessage()))); } } } catch (JavaModelException e) { throw new Throw(VF.string(e.getMessage()), (ISourceLocation) null, null); } catch (CoreException e) { throw new Throw(VF.string(e.getMessage()), (ISourceLocation) null, null); } finally { Job.getJobManager().endRule(ResourcesPlugin.getWorkspace().getRoot()); } return result; } public IValue fullyQualifyTypeNames(ISourceLocation loc) { IFile file = jdt.getJavaIFileForLocation(loc); return new FullyQualifyTypeNames().fullyQualifyTypeNames(loc, file); } public void removeMethods(ISet methodOffsetsFromLoc, ISourceLocation loc) { IFile file = jdt.getJavaIFileForLocation(loc); new RemoveMethods().removeMethodsAtLocs(methodOffsetsFromLoc, loc, file); } public void unqualifyTypeNames(ISourceLocation loc) { IFile file = jdt.getJavaIFileForLocation(loc); new UnqualifyTypeNames().unqualifyTypeNames(loc, file); } }