/******************************************************************************* * Copyright (c) 2007, 2015 Zend Technologies 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: * Zend Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.php.refactoring.core.utils; import java.util.ArrayList; import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.*; import org.eclipse.dltk.core.DLTKCore; import org.eclipse.dltk.core.IBuildpathEntry; import org.eclipse.dltk.core.IModelElement; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.php.core.ast.nodes.*; import org.eclipse.php.internal.ui.corext.util.Resources; import org.eclipse.php.refactoring.core.PhpRefactoringCoreMessages; import org.eclipse.php.refactoring.core.extract.NameSuggestVisitor; /** * @author seva */ @SuppressWarnings("restriction") public class RefactoringUtility { /** * @param project * @param file * @throws Exception */ public static Program getProgramForFile(IProject project, final IFile file) throws Exception { // fix Mantis #0022461 - Refactoring does not seem to work properly if // the encoding of the file to be refactored is utf-8 // The InputStreamReader must receive the file charset, otherwise // default charset is used final ISourceModule source = DLTKCore.createSourceModuleFrom(file); return ASTParser.newParser(source).createAST(new NullProgressMonitor()); } /** * @param file */ public static Program getProgramForFile(final IFile file) throws Exception { return getProgramForFile(file.getProject(), file); } /** * @param expression * @return For a given expression return a list of suggested variable names */ public static String[] getVariableNameSuggestions( Expression assignedExpression) { List<String> res = new ArrayList<String>(); NameSuggestVisitor visitor = new NameSuggestVisitor(); assignedExpression.accept(visitor); res = visitor.getSuggestions(); return (String[]) res.toArray(new String[res.size()]); } public static RefactoringStatus checkNewElementName(String newName) { if (!isValidIdentifier(newName)) { return getFatalError(newName); } return new RefactoringStatus(); } /** * @param newName * @return */ public static final RefactoringStatus getFatalError(String newName) { return RefactoringStatus .createFatalErrorStatus(PhpRefactoringCoreMessages.format( "RefactoringUtility.0", new Object[] { newName })); //$NON-NLS-1$ } /** * @param newName * @return true of the given string is valid PHP identifier */ public static final boolean isValidIdentifier(String newName) { if (newName == null || newName.length() == 0 || !Character.isLetter(newName.charAt(0)) && newName.charAt(0) != '_') { return false; } final int length = newName.length(); for (int i = 1; i < length; i++) { if (!Character.isJavaIdentifierPart(newName.charAt(i))) { return false; } if (newName.charAt(i) == '$') { // Seva: in addition to java rules, PHP doesn't allow dollar // signs inside element names return false; } } return true; } // -------- validateEdit checks ---- public static RefactoringStatus validateModifiesFiles( IResource[] iResources, Object context) { RefactoringStatus result = new RefactoringStatus(); IStatus status = Resources.checkInSync(iResources); if (!status.isOK()) result.merge(RefactoringStatus.create(status)); status = Resources.makeCommittable(iResources, context); if (!status.isOK()) { result.merge(RefactoringStatus.create(status)); if (!result.hasFatalError()) { result.addFatalError(PhpRefactoringCoreMessages .getString("ExtractVariableRefactoring.1")); //$NON-NLS-1$ } } return result; } public static IResource getResource(Object element) { if (element instanceof IPath) { return ResourcesPlugin.getWorkspace().getRoot() .findMember((IPath) element); } if (element instanceof IResource) { return (IResource) element; } if (element instanceof ISourceModule) { return ((ISourceModule) element).getPrimary().getResource(); } if (element instanceof IModelElement) { return ((IModelElement) element).getResource(); } if (element instanceof IAdaptable) { return (IResource) ((IAdaptable) element) .getAdapter(IResource.class); } return null; } public static IBuildpathEntry createNewBuildpathEntry(int bpeSource, IPath path) { switch (bpeSource) { case IBuildpathEntry.BPE_LIBRARY: return DLTKCore.newLibraryEntry(path); case IBuildpathEntry.BPE_PROJECT: return DLTKCore.newProjectEntry(path); case IBuildpathEntry.BPE_SOURCE: return DLTKCore.newSourceEntry(path); case IBuildpathEntry.BPE_CONTAINER: return DLTKCore.newContainerEntry(path); case IBuildpathEntry.BPE_VARIABLE: return DLTKCore.newVariableEntry(path); default: Assert.isTrue(false); return null; } } public static IBuildpathEntry createNewBuildpathEntry( IBuildpathEntry fEntryToChange, IPath path, IPath filePath, String newName) { switch (fEntryToChange.getEntryKind()) { case IBuildpathEntry.BPE_LIBRARY: return DLTKCore.newLibraryEntry(path, fEntryToChange.getAccessRules(), fEntryToChange.getExtraAttributes(), fEntryToChange.isExported(), fEntryToChange.isExternal()); case IBuildpathEntry.BPE_PROJECT: return DLTKCore.newProjectEntry(path, fEntryToChange.getAccessRules(), fEntryToChange.combineAccessRules(), fEntryToChange.getExtraAttributes(), fEntryToChange.isExported()); case IBuildpathEntry.BPE_SOURCE: IPath[] excludes = updatePathPatternes( fEntryToChange.getExclusionPatterns(), fEntryToChange.getPath(), filePath, newName); IPath[] includes = updatePathPatternes( fEntryToChange.getInclusionPatterns(), fEntryToChange.getPath(), filePath, newName); return DLTKCore.newSourceEntry(path, includes, excludes, fEntryToChange.getExtraAttributes()); case IBuildpathEntry.BPE_CONTAINER: return DLTKCore.newContainerEntry(path, fEntryToChange.getAccessRules(), fEntryToChange.getExtraAttributes(), fEntryToChange.isExported()); case IBuildpathEntry.BPE_VARIABLE: return DLTKCore.newVariableEntry(path, fEntryToChange.getAccessRules(), fEntryToChange.getExtraAttributes(), fEntryToChange.isExported()); default: Assert.isTrue(false); return null; } } private static IPath[] updatePathPatternes(IPath[] updatingPaths, IPath entryPath, IPath filePath, String newName) { IPath[] paths = updatingPaths; IPath relativePath = filePath.makeRelativeTo(entryPath); ArrayList<IPath> excludeList = new ArrayList<IPath>(); for (IPath path : paths) { if (!relativePath.isEmpty() && relativePath.isPrefixOf(path)) { int mattchedPath = path.matchingFirstSegments(relativePath); IPath truncatedPath = path.uptoSegment(mattchedPath); IPath remaingPath = path.removeFirstSegments(mattchedPath); if (mattchedPath == 0) { excludeList.add(truncatedPath.removeLastSegments(1).append( newName + "/")); //$NON-NLS-1$ } else { excludeList.add(truncatedPath.removeLastSegments(1) .append(newName + "/") //$NON-NLS-1$ .append(remaingPath.toString())); } } else { excludeList.add(path); } } return excludeList.toArray(new IPath[excludeList.size()]); } /** * Figure out the type parent of the given element * * @param node * @return the type which the element belongs to, or null if can't find. */ public static TypeDeclaration getType(ASTNode node) { if (node == null) { return null; } ASTNode model = node; while (!(model instanceof TypeDeclaration)) { if (node == null) { return null; } ASTNode parent = model.getParent(); if (parent == model) { return null; } model = parent; if (model instanceof Program) { return null; } } return (TypeDeclaration) model; } static public ISourceModule getSourceModule(IModelElement type) { IModelElement root = null; root = type; while (root != null && !(root instanceof ISourceModule)) { root = root.getParent(); } if (root != null) { return ((ISourceModule) root); } return null; } public static ASTNode getTypeOrClassInstance(ASTNode node) { if (node == null) { return null; } ASTNode model = node; while (!(model instanceof TypeDeclaration) && !(model instanceof ClassInstanceCreation)) { if (node == null) { return null; } ASTNode parent = model.getParent(); if (parent == model) { return null; } if (parent instanceof TraitUseStatement) { return null; } model = parent; if (model instanceof Program) { return null; } } return model; } }