blob: 6afc1d247f99581f30bfcca938a39b7b8f17ca35 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2011 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.jdt.internal.corext.refactoring;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourceAttributes;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.ResourceChangeChecker;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModelMarker;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.ILocalVariable;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.Expression;
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.Name;
import org.eclipse.jdt.core.dom.SwitchCase;
import org.eclipse.jdt.core.dom.VariableDeclaration;
import org.eclipse.jdt.internal.corext.Corext;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.dom.Bindings;
import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatusCodes;
import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil;
import org.eclipse.jdt.internal.corext.util.JavaConventionsUtil;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.JdtFlags;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.internal.corext.util.Resources;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
/**
* This class defines a set of reusable static checks methods.
*/
public class Checks {
/*
* no instances
*/
private Checks(){
}
/* Constants returned by checkExpressionIsRValue */
public static final int IS_RVALUE= 0;
public static final int NOT_RVALUE_MISC= 1;
public static final int NOT_RVALUE_VOID= 2;
/**
* @since 3.6
*/
public static final int IS_RVALUE_GUESSED= 3;
/**
* Checks if method will have a constructor name after renaming.
* @param method
* @param newMethodName
* @param newTypeName
* @return <code>RefactoringStatus</code> with <code>WARNING</code> severity if
* the give method will have a constructor name after renaming
* <code>null</code> otherwise.
*/
public static RefactoringStatus checkIfConstructorName(IMethod method, String newMethodName, String newTypeName){
if (! newMethodName.equals(newTypeName))
return null;
else
return RefactoringStatus.createWarningStatus(
Messages.format(RefactoringCoreMessages.Checks_constructor_name,
new Object[] {JavaElementUtil.createMethodSignature(method), JavaElementLabels.getElementLabel(method.getDeclaringType(), JavaElementLabels.ALL_FULLY_QUALIFIED) } ));
}
/**
* Checks if the given name is a valid Java field name.
*
* @param name the java field name.
* @param context an {@link IJavaElement} or <code>null</code>
* @return a refactoring status containing the error message if the
* name is not a valid java field name.
*/
public static RefactoringStatus checkFieldName(String name, IJavaElement context) {
return checkName(name, JavaConventionsUtil.validateFieldName(name, context));
}
/**
* Checks if the given name is a valid Java type parameter name.
*
* @param name the java type parameter name.
* @param context an {@link IJavaElement} or <code>null</code>
* @return a refactoring status containing the error message if the
* name is not a valid java type parameter name.
*/
public static RefactoringStatus checkTypeParameterName(String name, IJavaElement context) {
return checkName(name, JavaConventionsUtil.validateTypeVariableName(name, context));
}
/**
* Checks if the given name is a valid Java identifier.
*
* @param name the java identifier.
* @param context an {@link IJavaElement} or <code>null</code>
* @return a refactoring status containing the error message if the
* name is not a valid java identifier.
*/
public static RefactoringStatus checkIdentifier(String name, IJavaElement context) {
return checkName(name, JavaConventionsUtil.validateIdentifier(name, context));
}
/**
* Checks if the given name is a valid Java method name.
*
* @param name the java method name.
* @param context an {@link IJavaElement} or <code>null</code>
* @return a refactoring status containing the error message if the
* name is not a valid java method name.
*/
public static RefactoringStatus checkMethodName(String name, IJavaElement context) {
RefactoringStatus status= checkName(name, JavaConventionsUtil.validateMethodName(name, context));
if (status.isOK() && !startsWithLowerCase(name))
return RefactoringStatus.createWarningStatus(RefactoringCoreMessages.Checks_method_names_lowercase);
else
return status;
}
/**
* Checks if the given name is a valid Java type name.
*
* @param name the java method name.
* @param context an {@link IJavaElement} or <code>null</code>
* @return a refactoring status containing the error message if the
* name is not a valid java type name.
*/
public static RefactoringStatus checkTypeName(String name, IJavaElement context) {
//fix for: 1GF5Z0Z: ITPJUI:WINNT - assertion failed after renameType refactoring
if (name.indexOf(".") != -1) //$NON-NLS-1$
return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.Checks_no_dot);
else
return checkName(name, JavaConventionsUtil.validateJavaTypeName(name, context));
}
/**
* Checks if the given name is a valid Java package name.
*
* @param name the java package name.
* @param context an {@link IJavaElement} or <code>null</code>
* @return a refactoring status containing the error message if the
* name is not a valid java package name.
*/
public static RefactoringStatus checkPackageName(String name, IJavaElement context) {
return checkName(name, JavaConventionsUtil.validatePackageName(name, context));
}
/**
* Checks if the given name is a valid compilation unit name.
*
* @param name the compilation unit name.
* @param context an {@link IJavaElement} or <code>null</code>
* @return a refactoring status containing the error message if the
* name is not a valid compilation unit name.
*/
public static RefactoringStatus checkCompilationUnitName(String name, IJavaElement context) {
return checkName(name, JavaConventionsUtil.validateCompilationUnitName(name, context));
}
/**
* Returns ok status if the new name is ok. This is when no other file with that name exists.
* @param cu
* @param newName
* @return the status
*/
public static RefactoringStatus checkCompilationUnitNewName(ICompilationUnit cu, String newName) {
String newCUName= JavaModelUtil.getRenamedCUName(cu, newName);
IPath renamedResourcePath= cu.getParent().getPath().append(newCUName);
if (resourceExists(renamedResourcePath))
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.Checks_cu_name_used, BasicElementLabels.getResourceName(newCUName)));
else
return new RefactoringStatus();
}
public static boolean startsWithLowerCase(String s){
if (s == null)
return false;
else if ("".equals(s)) //$NON-NLS-1$
return false;
else
//workaround for JDK bug (see 26529)
return s.charAt(0) == Character.toLowerCase(s.charAt(0));
}
public static boolean resourceExists(IPath resourcePath){
return ResourcesPlugin.getWorkspace().getRoot().findMember(resourcePath) != null;
}
public static boolean isTopLevel(IType type){
return type.getDeclaringType() == null;
}
public static boolean isAnonymous(IType type) throws JavaModelException {
return type.isAnonymous();
}
public static boolean isTopLevelType(IMember member){
return member.getElementType() == IJavaElement.TYPE && isTopLevel((IType) member);
}
public static boolean isInsideLocalType(IType type) throws JavaModelException {
while (type != null) {
if (type.isLocal())
return true;
type= type.getDeclaringType();
}
return false;
}
public static boolean isAlreadyNamed(IJavaElement element, String name){
return name.equals(element.getElementName());
}
//-------------- main and native method checks ------------------
public static RefactoringStatus checkForMainAndNativeMethods(ICompilationUnit cu) throws JavaModelException {
return checkForMainAndNativeMethods(cu.getTypes());
}
public static RefactoringStatus checkForMainAndNativeMethods(IType[] types) throws JavaModelException {
RefactoringStatus result= new RefactoringStatus();
for (int i= 0; i < types.length; i++)
result.merge(checkForMainAndNativeMethods(types[i]));
return result;
}
public static RefactoringStatus checkForMainAndNativeMethods(IType type) throws JavaModelException {
RefactoringStatus result= new RefactoringStatus();
result.merge(checkForMainAndNativeMethods(type.getMethods()));
result.merge(checkForMainAndNativeMethods(type.getTypes()));
return result;
}
private static RefactoringStatus checkForMainAndNativeMethods(IMethod[] methods) throws JavaModelException {
RefactoringStatus result= new RefactoringStatus();
for (int i= 0; i < methods.length; i++) {
if (JdtFlags.isNative(methods[i])){
String typeName= JavaElementLabels.getElementLabel(methods[i].getDeclaringType(), JavaElementLabels.ALL_FULLY_QUALIFIED);
String methodName= JavaElementLabels.getElementLabel(methods[i], JavaElementLabels.ALL_DEFAULT);
String msg= Messages.format(RefactoringCoreMessages.Checks_method_native,
new String[]{typeName, methodName, "UnsatisfiedLinkError"});//$NON-NLS-1$
result.addEntry(RefactoringStatus.ERROR, msg, JavaStatusContext.create(methods[i]), Corext.getPluginId(), RefactoringStatusCodes.NATIVE_METHOD);
}
if (methods[i].isMainMethod()) {
String msg= Messages.format(RefactoringCoreMessages.Checks_has_main,
JavaElementLabels.getElementLabel(methods[i].getDeclaringType(), JavaElementLabels.ALL_FULLY_QUALIFIED));
result.addEntry(RefactoringStatus.WARNING, msg, JavaStatusContext.create(methods[i]), Corext.getPluginId(), RefactoringStatusCodes.MAIN_METHOD);
}
}
return result;
}
//---- New method name checking -------------------------------------------------------------
/**
* Checks if the new method is already used in the given type.
* @param type
* @param methodName
* @param parameters
* @return the status
*/
public static RefactoringStatus checkMethodInType(ITypeBinding type, String methodName, ITypeBinding[] parameters) {
RefactoringStatus result= new RefactoringStatus();
if (methodName.equals(type.getName()))
result.addWarning(RefactoringCoreMessages.Checks_methodName_constructor);
IMethodBinding method= org.eclipse.jdt.internal.corext.dom.Bindings.findMethodInType(type, methodName, parameters);
if (method != null)
result.addError(Messages.format(RefactoringCoreMessages.Checks_methodName_exists,
new Object[] {BasicElementLabels.getJavaElementName(methodName), BasicElementLabels.getJavaElementName(type.getName())}),
JavaStatusContext.create(method));
return result;
}
/**
* Checks if the new method somehow conflicts with an already existing method in
* the hierarchy. The following checks are done:
* <ul>
* <li> if the new method overrides a method defined in the given type or in one of its
* super classes. </li>
* </ul>
* @param type
* @param methodName
* @param returnType
* @param parameters
* @return the status
*/
public static RefactoringStatus checkMethodInHierarchy(ITypeBinding type, String methodName, ITypeBinding returnType, ITypeBinding[] parameters) {
RefactoringStatus result= new RefactoringStatus();
IMethodBinding method= Bindings.findMethodInHierarchy(type, methodName, parameters);
if (method != null) {
boolean returnTypeClash= false;
ITypeBinding methodReturnType= method.getReturnType();
if (returnType != null && methodReturnType != null) {
String returnTypeKey= returnType.getKey();
String methodReturnTypeKey= methodReturnType.getKey();
if (returnTypeKey == null && methodReturnTypeKey == null) {
returnTypeClash= returnType != methodReturnType;
} else if (returnTypeKey != null && methodReturnTypeKey != null) {
returnTypeClash= !returnTypeKey.equals(methodReturnTypeKey);
}
}
ITypeBinding dc= method.getDeclaringClass();
if (returnTypeClash) {
result.addError(Messages.format(RefactoringCoreMessages.Checks_methodName_returnTypeClash,
new Object[] {BasicElementLabels.getJavaElementName(methodName), BasicElementLabels.getJavaElementName(dc.getName())}),
JavaStatusContext.create(method));
} else {
result.addError(Messages.format(RefactoringCoreMessages.Checks_methodName_overrides,
new Object[] {BasicElementLabels.getJavaElementName(methodName), BasicElementLabels.getJavaElementName(dc.getName())}),
JavaStatusContext.create(method));
}
}
return result;
}
//---- Selection checks --------------------------------------------------------------------
public static boolean isExtractableExpression(ASTNode[] selectedNodes, ASTNode coveringNode) {
ASTNode node= coveringNode;
if (isEnumCase(node))
return false;
if (selectedNodes != null && selectedNodes.length == 1)
node= selectedNodes[0];
return isExtractableExpression(node);
}
public static boolean isEnumCase(ASTNode node) {
if (node instanceof SwitchCase) {
final SwitchCase caze= (SwitchCase) node;
final Expression expression= caze.getExpression();
if (expression instanceof Name) {
final Name name= (Name) expression;
final IBinding binding= name.resolveBinding();
if (binding instanceof IVariableBinding) {
IVariableBinding variableBinding= (IVariableBinding) binding;
return variableBinding.isEnumConstant();
}
}
}
return false;
}
public static boolean isExtractableExpression(ASTNode node) {
if (!(node instanceof Expression))
return false;
if (node instanceof Name) {
IBinding binding= ((Name) node).resolveBinding();
return binding == null || binding instanceof IVariableBinding;
}
return true;
}
public static boolean isInsideJavadoc(ASTNode node) {
do {
if (node.getNodeType() == ASTNode.JAVADOC)
return true;
node= node.getParent();
} while (node != null);
return false;
}
/**
* Returns a fatal error in case the name is empty. In all other cases, an
* error based on the given status is returned.
*
* @param name a name
* @param status a status
* @return RefactoringStatus based on the given status or the name, if
* empty.
*/
public static RefactoringStatus checkName(String name, IStatus status) {
RefactoringStatus result= new RefactoringStatus();
if ("".equals(name)) //$NON-NLS-1$
return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.Checks_Choose_name);
if (status.isOK())
return result;
switch (status.getSeverity()){
case IStatus.ERROR:
return RefactoringStatus.createFatalErrorStatus(status.getMessage());
case IStatus.WARNING:
return RefactoringStatus.createWarningStatus(status.getMessage());
case IStatus.INFO:
return RefactoringStatus.createInfoStatus(status.getMessage());
default: //no nothing
return new RefactoringStatus();
}
}
/**
* Finds a method in a type
* This searches for a method with the same name and signature. Parameter types are only
* compared by the simple name, no resolving for the fully qualified type name is done
* @param name
* @param parameterCount
* @param isConstructor
* @param type
* @return The first found method or null, if nothing found
* @throws JavaModelException
*/
public static IMethod findMethod(String name, int parameterCount, boolean isConstructor, IType type) throws JavaModelException {
return findMethod(name, parameterCount, isConstructor, type.getMethods());
}
/**
* Finds a method in a type.
* Searches for a method with the same name and the same parameter count.
* Parameter types are <b>not</b> compared.
* @param method
* @param type
* @return The first found method or null, if nothing found
* @throws JavaModelException
*/
public static IMethod findMethod(IMethod method, IType type) throws JavaModelException {
return findMethod(method.getElementName(), method.getParameterTypes().length, method.isConstructor(), type.getMethods());
}
/**
* Finds a method in an array of methods.
* Searches for a method with the same name and the same parameter count.
* Parameter types are <b>not</b> compared.
* @param method
* @param methods
* @return The first found method or null, if nothing found
* @throws JavaModelException
*/
public static IMethod findMethod(IMethod method, IMethod[] methods) throws JavaModelException {
return findMethod(method.getElementName(), method.getParameterTypes().length, method.isConstructor(), methods);
}
public static IMethod findMethod(String name, int parameters, boolean isConstructor, IMethod[] methods) throws JavaModelException {
for (int i= methods.length-1; i >= 0; i--) {
IMethod curr= methods[i];
if (name.equals(curr.getElementName())) {
if (isConstructor == curr.isConstructor()) {
if (parameters == curr.getParameterTypes().length) {
return curr;
}
}
}
}
return null;
}
/**
* Finds a method in a type.
* This searches for a method with the same name and signature. Parameter types are only
* compared by the simple name, no resolving for the fully qualified type name is done
* @param method
* @param type
* @return The first found method or null, if nothing found
* @throws JavaModelException
*/
public static IMethod findSimilarMethod(IMethod method, IType type) throws JavaModelException {
return findSimilarMethod(method, type.getMethods());
}
/**
* Finds a method in an array of methods.
* This searches for a method with the same name and signature. Parameter types are only
* compared by the simple name, no resolving for the fully qualified type name is done
* @param method
* @param methods
* @return The first found method or null, if nothing found
* @throws JavaModelException
*/
public static IMethod findSimilarMethod(IMethod method, IMethod[] methods) throws JavaModelException {
boolean isConstructor= method.isConstructor();
for (int i= 0; i < methods.length; i++) {
IMethod otherMethod= methods[i];
if (otherMethod.isConstructor() == isConstructor && method.isSimilar(otherMethod))
return otherMethod;
}
return null;
}
/*
* Compare two parameter signatures
*/
public static boolean compareParamTypes(String[] paramTypes1, String[] paramTypes2) {
if (paramTypes1.length == paramTypes2.length) {
int i= 0;
while (i < paramTypes1.length) {
String t1= Signature.getSimpleName(Signature.toString(paramTypes1[i]));
String t2= Signature.getSimpleName(Signature.toString(paramTypes2[i]));
if (!t1.equals(t2)) {
return false;
}
i++;
}
return true;
}
return false;
}
//---------------------
public static RefactoringStatus checkIfCuBroken(IMember member) throws JavaModelException{
ICompilationUnit cu= (ICompilationUnit)JavaCore.create(member.getCompilationUnit().getResource());
if (cu == null)
return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.Checks_cu_not_created);
else if (! cu.isStructureKnown())
return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.Checks_cu_not_parsed);
return new RefactoringStatus();
}
/**
* From SearchResultGroup[] passed as the parameter
* this method removes all those that correspond to a non-parsable ICompilationUnit
* and returns it as a result.
* @param grouped the array of search result groups from which non parsable compilation
* units are to be removed.
* @param status a refactoring status to collect errors and problems
* @return the array of search result groups
* @throws JavaModelException
*/
public static SearchResultGroup[] excludeCompilationUnits(SearchResultGroup[] grouped, RefactoringStatus status) throws JavaModelException{
List<SearchResultGroup> result= new ArrayList<SearchResultGroup>();
boolean wasEmpty= grouped.length == 0;
for (int i= 0; i < grouped.length; i++){
IResource resource= grouped[i].getResource();
IJavaElement element= JavaCore.create(resource);
if (! (element instanceof ICompilationUnit))
continue;
//XXX this is a workaround for a jcore feature that shows errors in cus only when you get the original element
ICompilationUnit cu= (ICompilationUnit)JavaCore.create(resource);
if (! cu.isStructureKnown()){
status.addError(Messages.format(RefactoringCoreMessages.Checks_cannot_be_parsed, BasicElementLabels.getPathLabel(cu.getPath(), false)));
continue; //removed, go to the next one
}
result.add(grouped[i]);
}
if ((!wasEmpty) && result.isEmpty())
status.addFatalError(RefactoringCoreMessages.Checks_all_excluded);
return result.toArray(new SearchResultGroup[result.size()]);
}
public static RefactoringStatus checkCompileErrorsInAffectedFiles(SearchResultGroup[] grouped) throws JavaModelException {
RefactoringStatus result= new RefactoringStatus();
for (int i= 0; i < grouped.length; i++)
checkCompileErrorsInAffectedFile(result, grouped[i].getResource());
return result;
}
public static void checkCompileErrorsInAffectedFile(RefactoringStatus result, IResource resource) throws JavaModelException {
if (hasCompileErrors(resource))
result.addWarning(Messages.format(RefactoringCoreMessages.Checks_cu_has_compile_errors, BasicElementLabels.getPathLabel(resource.getFullPath(), false)));
}
public static RefactoringStatus checkCompileErrorsInAffectedFiles(SearchResultGroup[] references, IResource declaring) throws JavaModelException {
RefactoringStatus result= new RefactoringStatus();
for (int i= 0; i < references.length; i++){
IResource resource= references[i].getResource();
if (resource.equals(declaring))
declaring= null;
checkCompileErrorsInAffectedFile(result, resource);
}
if (declaring != null)
checkCompileErrorsInAffectedFile(result, declaring);
return result;
}
private static boolean hasCompileErrors(IResource resource) throws JavaModelException {
try {
IMarker[] problemMarkers= resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE);
for (int i= 0; i < problemMarkers.length; i++) {
if (problemMarkers[i].getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_ERROR)
return true;
}
return false;
} catch (JavaModelException e){
throw e;
} catch (CoreException e){
throw new JavaModelException(e);
}
}
//------
public static boolean isReadOnly(Object element) throws JavaModelException{
if (element instanceof IResource)
return isReadOnly((IResource)element);
if (element instanceof IJavaElement) {
if ((element instanceof IPackageFragmentRoot) && isClasspathDelete((IPackageFragmentRoot)element))
return false;
return isReadOnly(((IJavaElement)element).getResource());
}
Assert.isTrue(false, "not expected to get here"); //$NON-NLS-1$
return false;
}
public static boolean isReadOnly(IResource res) throws JavaModelException {
ResourceAttributes attributes= res.getResourceAttributes();
if (attributes != null && attributes.isReadOnly())
return true;
if (! (res instanceof IContainer))
return false;
IContainer container= (IContainer)res;
try {
IResource[] children= container.members();
for (int i= 0; i < children.length; i++) {
if (isReadOnly(children[i]))
return true;
}
return false;
} catch (JavaModelException e){
throw e;
} catch (CoreException e) {
throw new JavaModelException(e);
}
}
public static boolean isClasspathDelete(IPackageFragmentRoot pkgRoot) {
IResource res= pkgRoot.getResource();
if (res == null)
return true;
IProject definingProject= res.getProject();
if (res.getParent() != null && pkgRoot.isArchive() && ! res.getParent().equals(definingProject))
return true;
IProject occurringProject= pkgRoot.getJavaProject().getProject();
return !definingProject.equals(occurringProject);
}
//-------- validateEdit checks ----
public static RefactoringStatus validateModifiesFiles(IFile[] filesToModify, Object context) {
RefactoringStatus result= new RefactoringStatus();
IStatus status= Resources.checkInSync(filesToModify);
if (!status.isOK())
result.merge(RefactoringStatus.create(status));
status= Resources.makeCommittable(filesToModify, context);
if (!status.isOK()) {
result.merge(RefactoringStatus.create(status));
if (!result.hasFatalError()) {
result.addFatalError(RefactoringCoreMessages.Checks_validateEdit);
}
}
return result;
}
public static void addModifiedFilesToChecker(IFile[] filesToModify, CheckConditionsContext context) {
ResourceChangeChecker checker= (ResourceChangeChecker) context.getChecker(ResourceChangeChecker.class);
IResourceChangeDescriptionFactory deltaFactory= checker.getDeltaFactory();
for (int i= 0; i < filesToModify.length; i++) {
deltaFactory.change(filesToModify[i]);
}
}
public static RefactoringStatus validateEdit(ICompilationUnit unit, Object context) {
IResource resource= unit.getPrimary().getResource();
RefactoringStatus result= new RefactoringStatus();
if (resource == null)
return result;
IStatus status= Resources.checkInSync(resource);
if (!status.isOK())
result.merge(RefactoringStatus.create(status));
status= Resources.makeCommittable(resource, context);
if (!status.isOK()) {
result.merge(RefactoringStatus.create(status));
if (!result.hasFatalError()) {
result.addFatalError(RefactoringCoreMessages.Checks_validateEdit);
}
}
return result;
}
/**
* Checks whether it is possible to modify the given <code>IJavaElement</code>.
* The <code>IJavaElement</code> must exist and be non read-only to be modifiable.
* Moreover, if it is a <code>IMember</code> it must not be binary.
* The returned <code>RefactoringStatus</code> has <code>ERROR</code> severity if
* it is not possible to modify the element.
* @param javaElement
* @return the status
* @throws JavaModelException
*
* @see IJavaElement#exists
* @see IJavaElement#isReadOnly
* @see IMember#isBinary
* @see RefactoringStatus
*/
public static RefactoringStatus checkAvailability(IJavaElement javaElement) throws JavaModelException{
RefactoringStatus result= new RefactoringStatus();
if (! javaElement.exists())
result.addFatalError(Messages.format(RefactoringCoreMessages.Refactoring_not_in_model, getJavaElementName(javaElement)));
if (javaElement.isReadOnly())
result.addFatalError(Messages.format(RefactoringCoreMessages.Refactoring_read_only, getJavaElementName(javaElement)));
if (javaElement.exists() && !javaElement.isStructureKnown())
result.addFatalError(Messages.format(RefactoringCoreMessages.Refactoring_unknown_structure, getJavaElementName(javaElement)));
if (javaElement instanceof IMember && ((IMember)javaElement).isBinary())
result.addFatalError(Messages.format(RefactoringCoreMessages.Refactoring_binary, getJavaElementName(javaElement)));
return result;
}
private static String getJavaElementName(IJavaElement element) {
return JavaElementLabels.getElementLabel(element, JavaElementLabels.ALL_DEFAULT);
}
public static boolean isAvailable(IJavaElement javaElement) throws JavaModelException {
if (javaElement == null)
return false;
if (! javaElement.exists())
return false;
if (javaElement.isReadOnly())
return false;
// work around for https://bugs.eclipse.org/bugs/show_bug.cgi?id=48422
// the Java project is now cheating regarding its children so we shouldn't
// call isStructureKnown if the project isn't open.
// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=52474
if (!(javaElement instanceof IJavaProject) && !(javaElement instanceof ILocalVariable) && !javaElement.isStructureKnown())
return false;
if (javaElement instanceof IMember && ((IMember)javaElement).isBinary())
return false;
return true;
}
public static IType findTypeInPackage(IPackageFragment pack, String elementName) throws JavaModelException {
Assert.isTrue(pack.exists());
Assert.isTrue(!pack.isReadOnly());
String packageName= pack.getElementName();
elementName= packageName.length() > 0 ? packageName + '.' + elementName : elementName;
return pack.getJavaProject().findType(elementName, (IProgressMonitor) null);
}
public static RefactoringStatus checkTempName(String newName, IJavaElement context) {
RefactoringStatus result= Checks.checkIdentifier(newName, context);
if (result.hasFatalError())
return result;
if (! Checks.startsWithLowerCase(newName))
result.addWarning(RefactoringCoreMessages.ExtractTempRefactoring_convention);
return result;
}
public static RefactoringStatus checkEnumConstantName(String newName, IJavaElement context) {
RefactoringStatus result= Checks.checkFieldName(newName, context);
if (result.hasFatalError())
return result;
for (int i= 0; i < newName.length(); i++) {
char c= newName.charAt(i);
if (Character.isLetter(c) && !Character.isUpperCase(c)) {
result.addWarning(RefactoringCoreMessages.RenameEnumConstRefactoring_convention);
break;
}
}
return result;
}
public static RefactoringStatus checkConstantName(String newName, IJavaElement context) {
RefactoringStatus result= Checks.checkFieldName(newName, context);
if (result.hasFatalError())
return result;
for (int i= 0; i < newName.length(); i++) {
char c= newName.charAt(i);
if (Character.isLetter(c) && !Character.isUpperCase(c)) {
result.addWarning(RefactoringCoreMessages.ExtractConstantRefactoring_convention);
break;
}
}
return result;
}
public static boolean isException(IType iType, IProgressMonitor pm) throws JavaModelException {
try{
if (! iType.isClass())
return false;
IType[] superTypes= iType.newSupertypeHierarchy(pm).getAllSupertypes(iType);
for (int i= 0; i < superTypes.length; i++) {
if ("java.lang.Throwable".equals(superTypes[i].getFullyQualifiedName())) //$NON-NLS-1$
return true;
}
return false;
} finally{
pm.done();
}
}
/**
* @param e
* @return int
* Checks.IS_RVALUE if e is an rvalue
* Checks.IS_RVALUE_GUESSED if e is guessed as an rvalue
* Checks.NOT_RVALUE_VOID if e is not an rvalue because its type is void
* Checks.NOT_RVALUE_MISC if e is not an rvalue for some other reason
*/
public static int checkExpressionIsRValue(Expression e) {
if (e instanceof Name) {
if(!(((Name) e).resolveBinding() instanceof IVariableBinding)) {
return NOT_RVALUE_MISC;
}
}
if (e instanceof Annotation)
return NOT_RVALUE_MISC;
ITypeBinding tb= e.resolveTypeBinding();
boolean guessingRequired= false;
if (tb == null) {
guessingRequired= true;
tb= ASTResolving.guessBindingForReference(e);
}
if (tb == null)
return NOT_RVALUE_MISC;
else if (tb.getName().equals("void")) //$NON-NLS-1$
return NOT_RVALUE_VOID;
return guessingRequired ? IS_RVALUE_GUESSED : IS_RVALUE;
}
public static boolean isDeclaredIn(VariableDeclaration tempDeclaration, Class<? extends ASTNode> astNodeClass) {
ASTNode initializer= ASTNodes.getParent(tempDeclaration, astNodeClass);
if (initializer == null)
return false;
ASTNode anonymous= ASTNodes.getParent(tempDeclaration, AnonymousClassDeclaration.class);
if (anonymous == null)
return true;
// stupid code. Is to find out if the variable declaration isn't a field.
if (ASTNodes.isParent(anonymous, initializer))
return false;
return true;
}
}