content: /*******************************************************************************
   * Copyright (c) 2000, 2008 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.wst.jsdt.internal.corext.refactoring.rename;
  
  import org.eclipse.core.resources.IResource;
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.core.runtime.IProgressMonitor;
  import org.eclipse.core.runtime.SubProgressMonitor;
  import org.eclipse.ltk.core.refactoring.GroupCategorySet;
  import org.eclipse.ltk.core.refactoring.RefactoringStatus;
  import org.eclipse.ltk.core.refactoring.RefactoringStatusContext;
  import org.eclipse.ltk.core.refactoring.TextChange;
  import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
  import org.eclipse.text.edits.ReplaceEdit;
  import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
  import org.eclipse.wst.jsdt.core.IFunction;
  import org.eclipse.wst.jsdt.core.ISourceRange;
  import org.eclipse.wst.jsdt.core.IType;
  import org.eclipse.wst.jsdt.core.dom.FunctionDeclaration;
  import org.eclipse.wst.jsdt.core.search.IJavaScriptSearchConstants;
  import org.eclipse.wst.jsdt.core.search.MethodDeclarationMatch;
  import org.eclipse.wst.jsdt.core.search.SearchEngine;
  import org.eclipse.wst.jsdt.core.search.SearchMatch;
  import org.eclipse.wst.jsdt.core.search.SearchPattern;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.Checks;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.RefactoringAvailabilityTester;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.RefactoringCoreMessages;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.RefactoringSearchEngine;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.SearchResultGroup;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.base.JavaStatusContext;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.CompilationUnitChange;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.delegates.DelegateMethodCreator;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.structure.ASTNodeSearchUtil;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.util.TextChangeManager;
  import org.eclipse.wst.jsdt.internal.corext.util.JavaModelUtil;
  import org.eclipse.wst.jsdt.internal.corext.util.Messages;
  import org.eclipse.wst.jsdt.internal.corext.util.SearchUtils;
  
  public class RenameNonVirtualMethodProcessor extends RenameMethodProcessor {
  
  	/**
  	 * Creates a new rename method processor.
  	 * <p>
  	 * This constructor is only invoked by <code>RenameTypeProcessor</code>.
  	 * </p>
  	 * 
  	 * @param method the method
  	 * @param manager the change manager
  	 * @param categorySet the group category set
  	 */
  	RenameNonVirtualMethodProcessor(IFunction method, TextChangeManager manager, GroupCategorySet categorySet) {
  		super(method, manager, categorySet);
  	}
  
  	/**
  	 * Creates a new rename method processor.
  	 * @param method the method, or <code>null</code> if invoked by scripting
  	 */
  	public RenameNonVirtualMethodProcessor(IFunction method) {
  		super(method);
  	}
  	
  	public boolean isApplicable() throws CoreException {
  		return RefactoringAvailabilityTester.isRenameNonVirtualMethodAvailable(getMethod());
  	}
  	
  	//----------- preconditions --------------
  	
  	protected RefactoringStatus doCheckFinalConditions(IProgressMonitor pm, CheckConditionsContext checkContext) throws CoreException {
  		try{
  			pm.beginTask("", 3); //$NON-NLS-1$
  			RefactoringStatus result= new RefactoringStatus();
  			result.merge(super.doCheckFinalConditions(new SubProgressMonitor(pm, 1), checkContext));
  			if (result.hasFatalError())
  				return result;
  			
  			final IFunction method= getMethod();
  			final IType declaring= method.getDeclaringType();
  			final String name= getNewElementName();
  			if (declaring!=null)
  			{
  			  IFunction[] hierarchyMethods= hierarchyDeclaresMethodName(
  				new SubProgressMonitor(pm, 1), declaring.newTypeHierarchy(new SubProgressMonitor(pm, 1)), method, name);
  			
  			  for (int i= 0; i < hierarchyMethods.length; i++) {
  				IFunction hierarchyMethod= hierarchyMethods[i];
  				RefactoringStatusContext context= JavaStatusContext.create(hierarchyMethod);
  				if (Checks.compareParamTypes(method.getParameterTypes(), hierarchyMethod.getParameterTypes())) {
  					String message= Messages.format(
  						RefactoringCoreMessages.RenamePrivateMethodRefactoring_hierarchy_defines, 
  						new String[]{JavaModelUtil.getFullyQualifiedName(
  							declaring), name});
  					result.addError(message, context);				
  				}else {
  					String message= Messages.format(
  						RefactoringCoreMessages.RenamePrivateMethodRefactoring_hierarchy_defines2, 
  						new String[]{JavaModelUtil.getFullyQualifiedName(
  							declaring), name});
  					result.addWarning(message, context);				
  				}
  			}
  			}
  			return result;
  		} finally{
  			pm.done();
  		}
  	}
  	
  	/*
  	 * The code below is needed to due bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=39700.
  	 * Declaration in hierarchy doesn't take visibility into account. 
  	 */
  
  	/*
  	 * XXX working around bug 39700
  	 */
  	protected SearchResultGroup[] getOccurrences(IProgressMonitor pm, RefactoringStatus status) throws CoreException {
  		pm.beginTask("", 2);	 //$NON-NLS-1$
  		SearchPattern pattern= createReferenceSearchPattern();
  		SearchResultGroup[] groups= RefactoringSearchEngine.search(pattern, createRefactoringScope(),
  			new MethodOccurenceCollector(getMethod().getElementName()), new SubProgressMonitor(pm, 1), status);
  		//Workaround bug 39700. Manually add declaration match:
  		for (int i= 0; i < groups.length; i++) {
  			SearchResultGroup group= groups[i];
  			IJavaScriptUnit cu= group.getCompilationUnit();
  			if (cu.equals(getDeclaringCU())) {
  				IResource resource= group.getResource();
  				int start= getMethod().getNameRange().getOffset();
  				int length= getMethod().getNameRange().getLength();
  				MethodDeclarationMatch declarationMatch= new MethodDeclarationMatch(getMethod(), SearchMatch.A_ACCURATE, start, length, SearchEngine.getDefaultSearchParticipant(), resource);
  				group.add(declarationMatch);
  				break;//no need to go further
  			}	
  		}
  		return groups;	
  	}
  		
  	/*
  	 * @see RenameMethodProcessor#addOccurrences(org.eclipse.wst.jsdt.internal.corext.refactoring.util.TextChangeManager, org.eclipse.core.runtime.IProgressMonitor, RefactoringStatus)
  	 */
  	void addOccurrences(TextChangeManager manager, IProgressMonitor pm, RefactoringStatus status) throws CoreException {
  		pm.beginTask("", 1); //$NON-NLS-1$
  		// declaration update must be registered first
  		addDeclarationUpdate(manager);
  		if (getUpdateReferences())
  			addReferenceUpdates(manager, pm, status);
  		pm.worked(1);
  	}
  	
  	private IJavaScriptUnit getDeclaringCU() {
  		return getMethod().getJavaScriptUnit();
  	}
  
  	/*
  	 * @see RenameMethodProcessor#createOccurrenceSearchPattern(org.eclipse.core.runtime.IProgressMonitor)
  	 */
  	SearchPattern createOccurrenceSearchPattern(IProgressMonitor pm) {
  		pm.beginTask("", 1); //$NON-NLS-1$
  		SearchPattern pattern= SearchPattern.createPattern(getMethod(), IJavaScriptSearchConstants.ALL_OCCURRENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE);
  		pm.done();
  		return pattern;
  	}
  
  	private SearchPattern createReferenceSearchPattern() {
  		return SearchPattern.createPattern(getMethod(), IJavaScriptSearchConstants.REFERENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE);
  	}
  	
  	final void addDeclarationUpdate(TextChangeManager manager) throws CoreException {
  
  		if (getDelegateUpdating()) {
  			// create the delegate
  			CompilationUnitRewrite rewrite= new CompilationUnitRewrite(getDeclaringCU());
  			rewrite.setResolveBindings(true);
  			FunctionDeclaration methodDeclaration= ASTNodeSearchUtil.getMethodDeclarationNode(getMethod(), rewrite.getRoot());
  			DelegateMethodCreator creator= new DelegateMethodCreator();
  			creator.setDeclaration(methodDeclaration);
  			creator.setDeclareDeprecated(getDeprecateDelegates());
  			creator.setSourceRewrite(rewrite);
  			creator.setCopy(true);
  			creator.setNewElementName(getNewElementName());
  			creator.prepareDelegate();
  			creator.createEdit();
  			CompilationUnitChange cuChange= rewrite.createChange();
  			if (cuChange != null) {
  				cuChange.setKeepPreviewEdits(true);
  				manager.manage(getDeclaringCU(), cuChange);
  			}
  		}
  
  		String editName= RefactoringCoreMessages.RenameMethodRefactoring_update_declaration;
  		ISourceRange nameRange= getMethod().getNameRange();
  		ReplaceEdit replaceEdit= new ReplaceEdit(nameRange.getOffset(), nameRange.getLength(), getNewElementName());
  		addTextEdit(manager.get(getDeclaringCU()), editName, replaceEdit);
  	}
  	
  	private void addReferenceUpdates(TextChangeManager manager, IProgressMonitor pm, RefactoringStatus status) throws CoreException {
  		SearchResultGroup[] grouped= getReferences(pm, status);
  		for (int i= 0; i < grouped.length; i++) {
  			SearchResultGroup group= grouped[i];
  			SearchMatch[] results= group.getSearchResults();
  			IJavaScriptUnit cu= group.getCompilationUnit();
  			TextChange change= manager.get(cu);
  			for (int j= 0; j < results.length; j++){
  				String editName= RefactoringCoreMessages.RenamePrivateMethodRefactoring_update; 
  				ReplaceEdit replaceEdit= createReplaceEdit(results[j], cu);
  				addTextEdit(change, editName, replaceEdit);
  				
  			}
  		}	
  	}
  
  	private SearchResultGroup[] getReferences(IProgressMonitor pm, RefactoringStatus status) throws CoreException {
  		//TODO: should not do the search again!
  		pm.beginTask("", 2);	 //$NON-NLS-1$
  		SearchPattern pattern= createReferenceSearchPattern();
  		return RefactoringSearchEngine.search(pattern, createRefactoringScope(),
  			new MethodOccurenceCollector(getMethod().getElementName()), new SubProgressMonitor(pm, 1), status);	
  	}
  
  	public String getDelegateUpdatingTitle(boolean plural) {
  		if (plural)
  			return RefactoringCoreMessages.DelegateMethodCreator_keep_original_renamed_plural;
  		else
  			return RefactoringCoreMessages.DelegateMethodCreator_keep_original_renamed_singular;
  	}
  }
  