| /******************************************************************************* |
| * Copyright (c) 2000, 2008 IBM Corporation and others. |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Dmitry Stalnov (dstalnov@fusionone.com) - contributed fixes for: |
| * o inline call that is used in a field initializer |
| * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38137) |
| * o Allow 'this' constructor to be inlined |
| * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38093) |
| *******************************************************************************/ |
| package org.eclipse.dltk.internal.javascript.corext.refactoring.code; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| import org.eclipse.dltk.core.IMethod; |
| import org.eclipse.dltk.core.IModelElement; |
| import org.eclipse.dltk.core.IScriptProject; |
| import org.eclipse.dltk.core.ISourceModule; |
| import org.eclipse.dltk.core.ModelException; |
| import org.eclipse.dltk.core.manipulation.RefactoringChecks; |
| import org.eclipse.dltk.core.manipulation.SourceModuleChange; |
| import org.eclipse.dltk.internal.corext.refactoring.ScriptRefactoringDescriptor; |
| import org.eclipse.dltk.internal.corext.refactoring.changes.DynamicValidationRefactoringChange; |
| import org.eclipse.dltk.internal.corext.refactoring.util.TextChangeManager; |
| import org.eclipse.dltk.internal.javascript.core.manipulation.JavascriptManipulationPlugin; |
| import org.eclipse.dltk.internal.javascript.core.manipulation.Messages; |
| import org.eclipse.dltk.internal.javascript.corext.refactoring.RefactoringCoreMessages; |
| import org.eclipse.dltk.javascript.core.dom.CallExpression; |
| import org.eclipse.dltk.javascript.core.dom.FunctionExpression; |
| import org.eclipse.dltk.javascript.core.dom.Node; |
| import org.eclipse.dltk.javascript.core.dom.Source; |
| import org.eclipse.dltk.javascript.core.dom.rewrite.ASTConverter; |
| import org.eclipse.dltk.javascript.core.dom.rewrite.NodeFinder; |
| import org.eclipse.dltk.javascript.core.dom.rewrite.RefactoringUtils; |
| import org.eclipse.dltk.javascript.core.dom.rewrite.RewriteAnalyzer; |
| import org.eclipse.dltk.javascript.core.refactoring.descriptors.InlineMethodDescriptor; |
| import org.eclipse.dltk.javascript.parser.JavaScriptParserUtil; |
| import org.eclipse.emf.ecore.change.ChangeDescription; |
| import org.eclipse.emf.ecore.change.util.ChangeRecorder; |
| import org.eclipse.ltk.core.refactoring.Change; |
| import org.eclipse.ltk.core.refactoring.Refactoring; |
| import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; |
| import org.eclipse.ltk.core.refactoring.RefactoringStatus; |
| import org.eclipse.ltk.core.refactoring.TextChange; |
| import org.eclipse.ltk.core.refactoring.participants.ResourceChangeChecker; |
| import org.eclipse.ltk.internal.core.refactoring.BasicElementLabels; |
| |
| /* |
| * Open items: |
| * - generate import statements for newly generated local variable declarations. |
| * - forbid cases like foo(foo(10)) when inlining foo(). |
| * - case ref.foo(); and we want to inline foo. Inline a method in a different context; |
| * - optimize code when the method to be inlined returns an argument and that one is |
| * assigned to a parameter again. No need for a separate local (important to be able |
| * to reverse extract method correctly). |
| */ |
| public class InlineMethodRefactoring extends Refactoring { |
| |
| private static final String ATTRIBUTE_MODE= "mode"; //$NON-NLS-1$ |
| private static final String ATTRIBUTE_DELETE= "delete"; //$NON-NLS-1$ |
| |
| public enum Mode { |
| ALL,SINGLE; |
| } |
| |
| // constructor |
| private ISourceModule cu; |
| private int offset; |
| private int length; |
| // initial conditions |
| private IMethod method; |
| private Mode initialMode; |
| private Mode currentMode; |
| private boolean deleteSource; |
| private Source declRoot; |
| private Node declNode; |
| private SourceProvider sourceProvider; |
| private TargetProvider targetProvider; |
| // final conditions |
| private TextChangeManager changeManager; |
| |
| public InlineMethodRefactoring(ISourceModule cu, int offset, int length) { |
| this.cu = cu; |
| this.offset = offset; |
| this.length = length; |
| deleteSource= false; |
| } |
| |
| public String getName() { |
| return RefactoringCoreMessages.InlineMethodRefactoring_name; |
| } |
| |
| /** |
| * Returns the method to inline, or null if the method could not be found or |
| * {@link #checkInitialConditions(IProgressMonitor)} has not been called yet. |
| * |
| * @return the method, or <code>null</code> |
| */ |
| public IMethod getMethod() { |
| return method; |
| } |
| |
| public boolean canEnableDeleteSource() { |
| return !method.isReadOnly(); |
| } |
| |
| /*public boolean getDeleteSource() { |
| return fDeleteSource; |
| }*/ |
| |
| public void setDeleteSource(boolean remove) { |
| if (remove) |
| Assert.isTrue(canEnableDeleteSource()); |
| deleteSource= remove; |
| } |
| |
| public Mode getInitialMode() { |
| return initialMode; |
| } |
| |
| public RefactoringStatus setCurrentMode(Mode mode) { |
| if (currentMode == mode) |
| return new RefactoringStatus(); |
| Assert.isTrue(getInitialMode() == Mode.SINGLE); |
| currentMode= mode; |
| /*if (mode == Mode.INLINE_SINGLE) { |
| if (fInitialNode instanceof MethodInvocation) |
| fTargetProvider= TargetProvider.create((ICompilationUnit) fInitialTypeRoot, (MethodInvocation)fInitialNode); |
| else if (fInitialNode instanceof SuperMethodInvocation) |
| fTargetProvider= TargetProvider.create((ICompilationUnit) fInitialTypeRoot, (SuperMethodInvocation)fInitialNode); |
| else if (fInitialNode instanceof ConstructorInvocation) |
| fTargetProvider= TargetProvider.create((ICompilationUnit) fInitialTypeRoot, (ConstructorInvocation)fInitialNode); |
| else |
| throw new IllegalStateException(String.valueOf(fInitialNode)); |
| } else { |
| fTargetProvider= TargetProvider.create(fSourceProvider.getDeclaration()); |
| } |
| return fTargetProvider.checkActivation();*/ |
| return new RefactoringStatus(); |
| } |
| |
| /** |
| * Creates a new inline method refactoring |
| * @param unit the compilation unit or class file |
| * @param selectionStart start |
| * @param selectionLength length |
| * @return returns the refactoring |
| */ |
| /*public static InlineMethodRefactoring create(ISourceModule unit, int selectionStart, int selectionLength) { |
| try { |
| IModelElement[] elements = unit.codeSelect(selectionStart, selectionLength); |
| if (elements.length != 1 || !(elements[0] instanceof IMethod)) |
| return null; |
| IMethod method = (IMethod)elements[0]; |
| if (method.getSourceRange().getOffset() == selectionStart && method.getSourceModule() == unit) { |
| return new InlineMethodRefactoring(unit, method, selectionStart, selectionLength, Mode.ALL); |
| } else { |
| return new InlineMethodRefactoring(unit, method, selectionStart, selectionLength, Mode.SINGLE); |
| } |
| } catch (ModelException e) { |
| JavascriptManipulationPlugin.log(e); |
| } |
| return null; |
| }*/ |
| |
| public RefactoringStatus checkInitialConditions(IProgressMonitor pm) { |
| RefactoringStatus result= new RefactoringStatus(); |
| if (method == null) { |
| try { |
| IModelElement[] elements = cu.codeSelect(offset, length); |
| if (elements.length != 1 || !(elements[0] instanceof IMethod)) |
| return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineMethodRefactoring_error_noMethodDeclaration); |
| method = (IMethod)elements[0]; |
| int start = method.getNameRange().getOffset(); |
| if (start <= offset && offset <= start+method.getNameRange().getLength() && method.getSourceModule() == cu) |
| initialMode = Mode.ALL; |
| else |
| initialMode = Mode.SINGLE; |
| currentMode = initialMode; |
| declRoot = (Source)ASTConverter.convert(JavaScriptParserUtil.parse(method.getSourceModule())); |
| declNode = NodeFinder.findNode(declRoot, method.getNameRange()); |
| FunctionExpression expr = RefactoringUtils.getFunctionDeclaration(declNode); |
| if (expr == null) |
| return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineMethodRefactoring_error_noMethodDeclaration); |
| sourceProvider = new SourceProvider(expr, method); |
| if (result.hasFatalError()) |
| return result; |
| } catch (ModelException e) { |
| JavascriptManipulationPlugin.log(e); |
| return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineMethodRefactoring_error_noMethodDeclaration); |
| } |
| } |
| result.merge(sourceProvider.checkActivation()); |
| return result; |
| } |
| |
| public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException { |
| pm.beginTask("", 20); //$NON-NLS-1$ |
| changeManager= new TextChangeManager(); |
| RefactoringStatus result= new RefactoringStatus(); |
| sourceProvider.initialize(); |
| if (currentMode == Mode.ALL) |
| targetProvider = TargetProvider.create(method); |
| else { |
| targetProvider = TargetProvider.create(cu, offset, length); |
| deleteSource = false; |
| } |
| //fTargetProvider.initialize(); |
| |
| pm.setTaskName(RefactoringCoreMessages.InlineMethodRefactoring_searching); |
| RefactoringStatus searchStatus= new RefactoringStatus(); |
| /*String binaryRefsDescription= Messages.format(RefactoringCoreMessages.ReferencesInBinaryContext_ref_in_binaries_description , BasicElementLabels.getJavaElementName(fSourceProvider.getMethodName())); |
| ReferencesInBinaryContext binaryRefs= new ReferencesInBinaryContext(binaryRefsDescription);*/ |
| List<ISourceModule> units= targetProvider.getAffectedSourceModules(searchStatus, new SubProgressMonitor(pm, 1)); |
| //binaryRefs.addErrorIfNecessary(searchStatus); |
| if (searchStatus.hasFatalError()) { |
| result.merge(searchStatus); |
| return result; |
| } |
| |
| IFile[] filesToBeModified= getFilesToBeModified(units); |
| result.merge(RefactoringChecks.validateModifiesFiles(filesToBeModified, getValidationContext())); |
| if (result.hasFatalError()) |
| return result; |
| result.merge(ResourceChangeChecker.checkFilesToBeChanged(filesToBeModified, new SubProgressMonitor(pm, 1))); |
| // TODO check overrides |
| //checkOverridden(result, new SubProgressMonitor(pm, 4)); |
| IProgressMonitor sub= new SubProgressMonitor(pm, 15); |
| sub.beginTask("", (units.size()+1) * 3); //$NON-NLS-1$ |
| boolean occursInDeclUnit = false; |
| for(ISourceModule unit : units) { |
| if (!unit.equals(method.getSourceModule())) |
| processUnit(unit,sub,result); |
| else |
| occursInDeclUnit = true; |
| } |
| if (occursInDeclUnit) |
| sub.worked(3); |
| if (deleteSource || occursInDeclUnit) |
| processUnit(method.getSourceModule(),sub,result); |
| result.merge(searchStatus); |
| sub.done(); |
| pm.done(); |
| return result; |
| } |
| |
| private void processUnit(ISourceModule unit, IProgressMonitor pm, RefactoringStatus result) throws CoreException { |
| pm.subTask(Messages.format(RefactoringCoreMessages.InlineMethodRefactoring_processing, BasicElementLabels.getResourceName(unit.getCorrespondingResource()))); |
| CallInliner inliner= null; |
| boolean modified = false; |
| Source root = targetProvider.getRoot(unit); |
| ChangeRecorder cr = new ChangeRecorder(targetProvider.getRoot(unit)); |
| Node[] bodies=targetProvider.getAffectedBodyDeclarations(unit, new SubProgressMonitor(pm, 1)); |
| if (bodies.length == 0) |
| return; |
| inliner = new CallInliner(unit, sourceProvider); |
| for(Node body : bodies) { |
| inliner.initialize(body); |
| RefactoringStatus nestedInvocations= new RefactoringStatus(); |
| CallExpression[] invocations= removeNestedCalls(nestedInvocations, unit, |
| targetProvider.getInvocations(body, new SubProgressMonitor(pm, 2))); |
| for(CallExpression invocation : invocations) { |
| RefactoringStatus checkInline = inliner.initialize(invocation, targetProvider.getStatusSeverity()); |
| result.merge(checkInline); |
| if (result.hasFatalError()) |
| break; |
| if (checkInline.getSeverity() >= targetProvider.getStatusSeverity()) { |
| deleteSource= false; |
| } else { |
| modified = true; |
| inliner.perform(); |
| } |
| } |
| // do this after we have inlined the method calls. We still want |
| // to generate the modifications. |
| if (!nestedInvocations.isOK()) { |
| result.merge(nestedInvocations); |
| deleteSource=false; |
| } |
| } |
| if (deleteSource && unit.equals(method.getSourceModule())) { |
| modified = true; |
| Node node = sourceProvider.getDeclaration(); |
| node = NodeFinder.findNode(root, node.getBegin(), node.getEnd()); |
| while (!node.eContainmentFeature().isMany()) |
| node = (Node)node.eContainer(); |
| List<? extends Node> list = (List<? extends Node>)node.eContainer().eGet(node.eContainmentFeature()); |
| list.remove(node); |
| } |
| if (modified) { |
| ChangeDescription cd = cr.endRecording(); |
| RewriteAnalyzer rewrite = new RewriteAnalyzer(cd, unit.getSource()); |
| rewrite.rewrite(root); |
| cd.apply(); |
| TextChange change = new SourceModuleChange(unit.getElementName(), unit); |
| change.setEdit(rewrite.getEdit()); |
| changeManager.manage(unit, change); |
| } else |
| cr.endRecording(); |
| /*if (!added) { |
| changeManager.remove(unit); |
| } else { |
| root.addChild(inliner.getModifications()); |
| ImportRewrite rewrite= inliner.getImportEdit(); |
| if (rewrite.hasRecordedChanges()) { |
| TextEdit edit= rewrite.rewriteImports(null); |
| if (edit instanceof MultiTextEdit ? ((MultiTextEdit)edit).getChildrenSize() > 0 : true) { |
| root.addChild(edit); |
| change.addTextEditGroup( |
| new TextEditGroup(RefactoringCoreMessages.InlineMethodRefactoring_edit_import, new TextEdit[] {edit})); |
| } |
| } |
| }*/ |
| pm.worked(1); |
| if (pm.isCanceled()) |
| throw new OperationCanceledException(); |
| } |
| |
| public Change createChange(IProgressMonitor pm) throws CoreException { |
| //if (deleteSource && currentMode == Mode.ALL) { |
| //TextChange change= changeManager.get((ISourceModule) sourceProvider.getTypeRoot()); |
| //TextEdit delete= sourceProvider.getDeleteEdit(); |
| //TextEditGroup description= new TextEditGroup( |
| // RefactoringCoreMessages.InlineMethodRefactoring_edit_delete, new TextEdit[] { delete }); |
| //TextEdit root= change.getEdit(); |
| //if (root != null) { |
| // TODO instead of finding the right insert position the call inliner should |
| // reuse the AST & rewriter of the source provide and we should rewrite the |
| // whole AST at the end. However, since recursive calls aren't allowed there |
| // shouldn't be a text edit overlap. |
| // root.addChild(delete); |
| //TextChangeCompatibility.insert(root, delete); |
| //} else { |
| //change.setEdit(delete); |
| //} |
| //change.addTextEditGroup(description); |
| //} |
| final Map arguments= new HashMap(); |
| String project = null; |
| IScriptProject scriptProject= cu.getScriptProject(); |
| if (scriptProject != null) |
| project= scriptProject.getElementName(); |
| int flags= RefactoringDescriptor.STRUCTURAL_CHANGE | ScriptRefactoringDescriptor.ARCHIVE_REFACTORABLE | ScriptRefactoringDescriptor.ARCHIVE_IMPORTABLE; |
| //final IMethodBinding binding= sourceProvider.getDeclaration().resolveBinding(); |
| //final ITypeBinding declaring= binding.getDeclaringClass(); |
| //if (!Modifier.isPrivate(binding.getModifiers())) |
| // flags|= RefactoringDescriptor.MULTI_CHANGE; |
| final String description= Messages.format(RefactoringCoreMessages.InlineMethodRefactoring_descriptor_description_short, method.getElementName()); |
| final String header= Messages.format(RefactoringCoreMessages.InlineMethodRefactoring_descriptor_description, new String[] { method.getElementName(), cu.getElementName() }); |
| //final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header); |
| //comment.addSetting(Messages.format(RefactoringCoreMessages.InlineMethodRefactoring_original_pattern, BindingLabelProvider.getBindingLabel(binding, JavaElementLabels.ALL_FULLY_QUALIFIED))); |
| //if (fDeleteSource) |
| // comment.addSetting(RefactoringCoreMessages.InlineMethodRefactoring_remove_method); |
| //if (fCurrentMode == Mode.INLINE_ALL) |
| // comment.addSetting(RefactoringCoreMessages.InlineMethodRefactoring_replace_references); |
| final InlineMethodDescriptor descriptor = new InlineMethodDescriptor(project, description, ""/*comment.asString()*/, arguments, flags); |
| arguments.put(ScriptRefactoringDescriptor.ATTRIBUTE_INPUT, ScriptRefactoringDescriptor.elementToHandle(project, cu)); |
| arguments.put(ScriptRefactoringDescriptor.ATTRIBUTE_SELECTION, new Integer(offset).toString() + " " + new Integer(length).toString()); //$NON-NLS-1$ |
| arguments.put(ATTRIBUTE_DELETE, Boolean.valueOf(deleteSource).toString()); |
| arguments.put(ATTRIBUTE_MODE, new Integer(currentMode == Mode.ALL ? 1 : 0).toString()); |
| return new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.InlineMethodRefactoring_edit_inlineCall, changeManager.getAllChanges()); |
| } |
| |
| //private static SourceProvider resolveSourceProvider(RefactoringStatus status, Node nameNode) { |
| /*IMethodBinding methodBinding= Invocations.resolveBinding(invocation); |
| if (methodBinding == null) { |
| status.addFatalError(RefactoringCoreMessages.InlineMethodRefactoring_error_noMethodDeclaration); |
| return null; |
| }*/ |
| /*MethodDeclaration declaration= (MethodDeclaration)root.findDeclaringNode(methodBinding); |
| if (declaration != null) { |
| return new SourceProvider(typeRoot, declaration); |
| } |
| IMethod method= (IMethod)methodBinding.getJavaElement(); |
| if (method != null) { |
| CompilationUnit methodDeclarationAstRoot; |
| ICompilationUnit methodCu= method.getCompilationUnit(); |
| if (methodCu != null) { |
| methodDeclarationAstRoot= new RefactoringASTParser(AST.JLS3).parse(methodCu, true); |
| } else { |
| IClassFile classFile= method.getClassFile(); |
| if (! JavaElementUtil.isSourceAvailable(classFile)) { |
| String methodLabel= JavaElementLabels.getTextLabel(method, JavaElementLabels.M_FULLY_QUALIFIED | JavaElementLabels.M_PARAMETER_TYPES); |
| status.addFatalError(Messages.format(RefactoringCoreMessages.InlineMethodRefactoring_error_classFile, methodLabel)); |
| return null; |
| } |
| methodDeclarationAstRoot= new RefactoringASTParser(AST.JLS3).parse(classFile, true); |
| } |
| ASTNode node= methodDeclarationAstRoot.findDeclaringNode(methodBinding.getMethodDeclaration().getKey()); |
| if (node instanceof MethodDeclaration) { |
| return new SourceProvider(methodDeclarationAstRoot.getTypeRoot(), (MethodDeclaration) node); |
| } |
| }*/ |
| //} |
| |
| private IFile[] getFilesToBeModified(List<ISourceModule> units) { |
| List<IFile> result= new ArrayList<IFile>(units.size() + 1); |
| for (ISourceModule unit : units) { |
| IFile file= getFile(unit); |
| if (file != null) |
| result.add(file); |
| } |
| if (deleteSource) { |
| IFile file = getFile(method.getSourceModule()); |
| if (file != null && !units.contains(file)) |
| result.add(file); |
| } |
| return (IFile[])result.toArray(new IFile[result.size()]); |
| } |
| |
| private IFile getFile(ISourceModule unit) { |
| unit= unit.getPrimary(); |
| IResource resource= unit.getResource(); |
| if (resource != null && resource.getType() == IResource.FILE) |
| return (IFile)resource; |
| return null; |
| } |
| |
| /*private void checkOverridden(RefactoringStatus status, IProgressMonitor pm) throws JavaModelException { |
| pm.beginTask("", 9); //$NON-NLS-1$ |
| pm.setTaskName(RefactoringCoreMessages.InlineMethodRefactoring_checking_overridden); |
| MethodDeclaration decl= fSourceProvider.getDeclaration(); |
| IMethod method= (IMethod) decl.resolveBinding().getJavaElement(); |
| if (method == null || Flags.isPrivate(method.getFlags())) { |
| pm.worked(8); |
| return; |
| } |
| IType type= method.getDeclaringType(); |
| ITypeHierarchy hierarchy= type.newTypeHierarchy(new SubProgressMonitor(pm, 6)); |
| checkSubTypes(status, method, hierarchy.getAllSubtypes(type), new SubProgressMonitor(pm, 1)); |
| checkSuperClasses(status, method, hierarchy.getAllSuperclasses(type), new SubProgressMonitor(pm, 1)); |
| checkSuperInterfaces(status, method, hierarchy.getAllSuperInterfaces(type), new SubProgressMonitor(pm, 1)); |
| pm.setTaskName(""); //$NON-NLS-1$ |
| } |
| |
| private void checkSubTypes(RefactoringStatus result, IMethod method, IType[] types, IProgressMonitor pm) { |
| checkTypes( |
| result, method, types, |
| RefactoringCoreMessages.InlineMethodRefactoring_checking_overridden_error, |
| pm); |
| } |
| |
| private void checkSuperClasses(RefactoringStatus result, IMethod method, IType[] types, IProgressMonitor pm) { |
| checkTypes( |
| result, method, types, |
| RefactoringCoreMessages.InlineMethodRefactoring_checking_overrides_error, |
| pm); |
| } |
| |
| private void checkSuperInterfaces(RefactoringStatus result, IMethod method, IType[] types, IProgressMonitor pm) { |
| checkTypes( |
| result, method, types, |
| RefactoringCoreMessages.InlineMethodRefactoring_checking_implements_error, |
| pm); |
| } |
| private void checkTypes(RefactoringStatus result, IMethod method, IType[] types, String key, IProgressMonitor pm) { |
| pm.beginTask("", types.length); //$NON-NLS-1$ |
| for (int i= 0; i < types.length; i++) { |
| pm.worked(1); |
| IMethod[] overridden= types[i].findMethods(method); |
| if (overridden != null && overridden.length > 0) { |
| result.addError( |
| Messages.format(key, JavaElementLabels.getElementLabel(types[i], JavaElementLabels.ALL_DEFAULT)), |
| JavaStatusContext.create(overridden[0])); |
| } |
| } |
| }*/ |
| |
| private CallExpression[] removeNestedCalls(RefactoringStatus status, ISourceModule unit, CallExpression[] invocations) { |
| List<Node> result= new ArrayList<Node>(); |
| for(Node invocation : invocations) { |
| boolean ok = true; |
| for (Node parent : invocations) { |
| parent = (Node)parent.eContainer(); |
| while (parent != null && parent != invocation) |
| parent=(Node)parent.eContainer(); |
| if (parent != null) |
| ok = false; |
| } |
| if (ok) |
| result.add(invocation); |
| else |
| status.addError(RefactoringCoreMessages.InlineMethodRefactoring_nestedInvocation/*, |
| JavaStatusContext.create(unit, parent)*/); |
| } |
| return result.toArray(new CallExpression[result.size()]); |
| } |
| } |