package br.uff.ic.gems.peixeespadacliente.tool; import br.uff.ic.gems.peixeespadacliente.exception.RefactoringException; import br.uff.ic.gems.peixeespadacliente.model.ProjectVCS; import br.uff.ic.gems.peixeespadacliente.resolution.InlineMethodResolution; import br.uff.ic.gems.peixeespadacliente.resolution.Resolution; import br.uff.ic.gems.peixeespadacliente.symptom.InlineMethodSymptom; import br.uff.ic.gems.peixeespadacliente.symptom.Symptom; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import net.sf.refactorit.classmodel.BinCIType; import net.sf.refactorit.classmodel.BinCITypeRef; import net.sf.refactorit.classmodel.BinMember; import net.sf.refactorit.classmodel.BinMethod; import net.sf.refactorit.classmodel.SourceConstruct; import net.sf.refactorit.classmodel.statements.BinCITypesDefStatement; import net.sf.refactorit.classmodel.statements.BinReturnStatement; import net.sf.refactorit.classmodel.statements.BinStatement; import net.sf.refactorit.query.SinglePointVisitor; import net.sf.refactorit.query.usage.Finder; import net.sf.refactorit.query.usage.InvocationData; import net.sf.refactorit.refactorings.RefactoringStatus; import net.sf.refactorit.refactorings.inlinemethod.InlineMethod; import net.sf.refactorit.test.refactorings.NullContext; import translation.Translate; /** * * @author João Felipe */ public class InlineMethods extends AbstractRefactoringTool { private InlineMethod inliner = null; private BinMethod currentMethod = null; public InlineMethods(ProjectVCS projectVCS) { super(projectVCS); } public boolean reloadRefactoring() { try { Finder.clearInvocationMap(); inliner = new InlineMethod(new NullContext(getProject()), currentMethod); return true; } catch (NullPointerException e) { return false; } } @Override public boolean prepareSymptom(Symptom symptom) throws RefactoringException { loadEnvironment(); // reloadEnv(); InlineMethodSymptom inlineMethodSymptom = (InlineMethodSymptom) symptom; BinCIType cls = getProject().getTypeRefForSourceName(inlineMethodSymptom.getParentQualifiedName()).getBinCIType(); BinMember member = cls.getDeclaredMethod(inlineMethodSymptom.getMethodName(), inlineMethodSymptom.getBinParameters()); if (member == null) { member = getMethodManually(inlineMethodSymptom.getMethodName(), cls, inlineMethodSymptom.getBinParameters()); } currentMethod = (BinMethod) member; return reloadRefactoring(); } private boolean usedOnlyInReturn(List invocations) { for (Iterator iter = invocations.iterator(); iter.hasNext();) { InvocationData invocation = (InvocationData) iter.next(); SourceConstruct inConstruct = invocation.getInConstruct(); if (!(inConstruct.getParent() instanceof BinReturnStatement)) { return false; } } return true; } private boolean usedInDirectReturn(List invocations) { for (Iterator iter = invocations.iterator(); iter.hasNext();) { InvocationData invocation = (InvocationData) iter.next(); SourceConstruct inConstruct = invocation.getInConstruct(); if ((inConstruct.getParent() instanceof BinReturnStatement)) { return true; } } return false; } private boolean checkReturnPoints(BinMethod method) { if (method.getBody().getStatements().length > 0) { final List deepReturns = new ArrayList(3); final BinStatement last = method.getBody().getStatements()[method.getBody().getStatements().length - 1]; SinglePointVisitor visitor = new SinglePointVisitor() { int inner = 0; @Override public void onEnter(Object o) { if (o instanceof BinCITypesDefStatement) { inner++; } else if (o instanceof BinReturnStatement) { if ((inner == 0) && (o != last)) { deepReturns.add(o); } } } @Override public void onLeave(Object o) { if (o instanceof BinCITypesDefStatement) { inner--; } } }; visitor.visit(method); if (deepReturns.size() > 0) { return false; } } return true; } private boolean checkLastReturnStatement(BinMethod method) { try { final BinStatement last = method.getBody().getStatements()[method.getBody().getStatements().length - 1]; if (!(last instanceof BinReturnStatement)) { return false; } return true; } catch (Exception e) { return false; } } @Override public List<Symptom> findAllSymptoms() throws RefactoringException { if (!loadEnvironment()) { return null; } List<Symptom> result = new ArrayList<Symptom>(); for (Object object : getProject().getDefinedTypes()) { BinCITypeRef binCITypeRef = (BinCITypeRef) object; BinCIType bcitr = binCITypeRef.getBinCIType(); if (bcitr.isInterface()) { continue; } if (!bcitr.isFromCompilationUnit()) { continue; } if (!classShouldBeVerified(binCITypeRef)) { continue; } BinMethod[] methods = bcitr.getDeclaredMethods(); for (BinMethod binMethod : methods) { if ((!binMethod.findOverrides().isEmpty()) || (!bcitr.getSubMethods(binMethod).isEmpty())) { continue; } List invocations = Finder.getInvocations(binMethod); if (!usedOnlyInReturn(invocations) && !checkReturnPoints(binMethod)) { continue; } if (usedInDirectReturn(invocations) && !checkLastReturnStatement(binMethod)) { continue; } Symptom symptom = new InlineMethodSymptom(binMethod, this); result.add(symptom); } } return result; } @Override public boolean applyCheckingPreAndPosCondictions(Resolution resolution) throws RefactoringException { Translate translate = Translate.getTranslate(); inliner.setMethodDeclarationAction(((InlineMethodResolution) resolution).getMethodDeclarationAction()); refactoring = inliner; RefactoringStatus status = checkPreconditions(); if (status.isErrorOrFatal()) { throw new RefactoringException(translate.notRefactored(status.getAllMessages())); } status.merge(checkUserInput()); status.merge(inliner.apply()); if (!status.isOk()) { throw new RefactoringException(translate.error(status.getAllMessages())); } System.out.println(status.getAllMessages()); return !status.isErrorOrFatal(); } }