| /******************************************************************************* |
| * Copyright (c) 2005, 2017 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 |
| * |
| *******************************************************************************/ |
| package org.eclipse.dltk.internal.core; |
| |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.dltk.compiler.CharOperation; |
| import org.eclipse.dltk.core.CompletionRequestor; |
| import org.eclipse.dltk.core.DLTKCore; |
| import org.eclipse.dltk.core.DLTKLanguageManager; |
| import org.eclipse.dltk.core.IField; |
| import org.eclipse.dltk.core.IMethod; |
| import org.eclipse.dltk.core.IModelElement; |
| import org.eclipse.dltk.core.IScriptFolder; |
| import org.eclipse.dltk.core.IScriptProject; |
| import org.eclipse.dltk.core.ISourceModule; |
| import org.eclipse.dltk.core.IType; |
| import org.eclipse.dltk.core.ITypeHierarchy; |
| import org.eclipse.dltk.core.ModelException; |
| import org.eclipse.dltk.core.WorkingCopyOwner; |
| import org.eclipse.dltk.core.search.IDLTKSearchScope; |
| import org.eclipse.dltk.core.search.SearchEngine; |
| import org.eclipse.dltk.internal.core.hierarchy.TypeHierarchy; |
| import org.eclipse.dltk.internal.core.hierarchy.TypeHierarchyBuilders; |
| import org.eclipse.dltk.internal.core.util.MementoTokenizer; |
| import org.eclipse.dltk.internal.core.util.Messages; |
| import org.eclipse.dltk.utils.CorePrinter; |
| |
| public class SourceType extends NamedMember implements IType { |
| |
| public SourceType(ModelElement parent, String name) { |
| super(parent, name); |
| } |
| |
| @Override |
| public int getElementType() { |
| return TYPE; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (!(o instanceof SourceType)) { |
| return false; |
| } |
| return super.equals(o); |
| } |
| |
| @Override |
| public String[] getSuperClasses() throws ModelException { |
| SourceTypeElementInfo info = (SourceTypeElementInfo) this |
| .getElementInfo(); |
| if (info == null) { |
| return CharOperation.NO_STRINGS; |
| } |
| return info.superclassNames; |
| } |
| |
| @Override |
| public void printNode(CorePrinter output) { |
| output.formatPrint("DLTK Source Type:" + getElementName()); //$NON-NLS-1$ |
| output.indent(); |
| try { |
| IModelElement modelElements[] = this.getChildren(); |
| for (int i = 0; i < modelElements.length; ++i) { |
| IModelElement element = modelElements[i]; |
| if (element instanceof ModelElement) { |
| ((ModelElement) element).printNode(output); |
| } else { |
| output.print("Unknown element:" + element); //$NON-NLS-1$ |
| } |
| } |
| } catch (ModelException ex) { |
| output.formatPrint(ex.getLocalizedMessage()); |
| } |
| output.dedent(); |
| } |
| |
| @Override |
| public IField getField(String fieldName) { |
| return new SourceField(this, fieldName); |
| } |
| |
| @Override |
| public IField[] getFields() throws ModelException { |
| List<IModelElement> list = getChildrenOfType(FIELD); |
| IField[] array = new IField[list.size()]; |
| list.toArray(array); |
| return array; |
| } |
| |
| @Override |
| public IType getType(String typeName) { |
| return new SourceType(this, typeName); |
| } |
| |
| @Override |
| public IType[] getTypes() throws ModelException { |
| List<IModelElement> list = getChildrenOfType(TYPE); |
| IType[] array = new IType[list.size()]; |
| list.toArray(array); |
| return array; |
| } |
| |
| @Override |
| public IMethod getMethod(String selector) { |
| return new SourceMethod(this, selector); |
| } |
| |
| @Override |
| public IMethod[] getMethods() throws ModelException { |
| List<IModelElement> list = getChildrenOfType(METHOD); |
| IMethod[] array = new IMethod[list.size()]; |
| list.toArray(array); |
| return array; |
| } |
| |
| @Override |
| public IModelElement getHandleFromMemento(String token, |
| MementoTokenizer memento, WorkingCopyOwner workingCopyOwner) { |
| switch (token.charAt(0)) { |
| case JEM_COUNT: |
| return getHandleUpdatingCountFromMemento(memento, workingCopyOwner); |
| case JEM_FIELD: |
| if (!memento.hasMoreTokens()) { |
| return this; |
| } |
| String fieldName = memento.nextToken(); |
| ModelElement field = (ModelElement) getField(fieldName); |
| return field.getHandleFromMemento(memento, workingCopyOwner); |
| // case JEM_INITIALIZER: |
| // if (!memento.hasMoreTokens()) return this; |
| // String count = memento.nextToken(); |
| // JavaElement initializer = |
| // (JavaElement)getInitializer(Integer.parseInt(count)); |
| // return initializer.getHandleFromMemento(memento, |
| // workingCopyOwner); |
| case JEM_METHOD: |
| if (!memento.hasMoreTokens()) { |
| return this; |
| } |
| |
| String selector = memento.nextToken(); |
| ArrayList<String> params = new ArrayList<>(); |
| nextParam: while (memento.hasMoreTokens()) { |
| token = memento.nextToken(); |
| switch (token.charAt(0)) { |
| case JEM_TYPE: |
| case JEM_TYPE_PARAMETER: |
| break nextParam; |
| case JEM_METHOD: |
| if (!memento.hasMoreTokens()) { |
| return this; |
| } |
| |
| String param = memento.nextToken(); |
| StringBuffer buffer = new StringBuffer(); |
| |
| // backward compatible with 3.0 mementos |
| /* |
| * while (param.length() == 1 && Signature.C_ARRAY == |
| * param.charAt(0)) { buffer.append(Signature.C_ARRAY); if |
| * (!memento.hasMoreTokens()) return this; param = |
| * memento.nextToken(); } |
| */ |
| |
| params.add(buffer.toString() + param); |
| break; |
| default: |
| break nextParam; |
| } |
| } |
| String[] parameters = new String[params.size()]; |
| params.toArray(parameters); |
| ModelElement method = (ModelElement) getMethod(selector); |
| switch (token.charAt(0)) { |
| case JEM_TYPE: |
| case JEM_TYPE_PARAMETER: |
| case JEM_LOCALVARIABLE: |
| return method.getHandleFromMemento(token, memento, |
| workingCopyOwner); |
| default: |
| return method; |
| } |
| case JEM_TYPE: |
| String typeName; |
| if (memento.hasMoreTokens()) { |
| typeName = memento.nextToken(); |
| char firstChar = typeName.charAt(0); |
| if (firstChar == JEM_FIELD /* || firstChar == JEM_INITIALIZER */ |
| || firstChar == JEM_METHOD || firstChar == JEM_TYPE |
| || firstChar == JEM_COUNT) { |
| token = typeName; |
| typeName = ""; //$NON-NLS-1$ |
| } else { |
| token = null; |
| } |
| } else { |
| typeName = ""; //$NON-NLS-1$ |
| token = null; |
| } |
| ModelElement type = (ModelElement) getType(typeName); |
| if (token == null) { |
| return type.getHandleFromMemento(memento, workingCopyOwner); |
| } else { |
| return type.getHandleFromMemento(token, memento, |
| workingCopyOwner); |
| } |
| // case JEM_TYPE_PARAMETER: |
| // if (!memento.hasMoreTokens()) return this; |
| // String typeParameterName = memento.nextToken(); |
| // ModelElement typeParameter = new TypeParameter(this, |
| // typeParameterName); |
| // return typeParameter.getHandleFromMemento(memento, |
| // workingCopyOwner); |
| |
| } |
| return null; |
| } |
| |
| @Override |
| protected char getHandleMementoDelimiter() { |
| |
| return JEM_TYPE; |
| } |
| |
| @Override |
| public String getFullyQualifiedName(String enclosingTypeSeparator) { |
| try { |
| return getFullyQualifiedName(enclosingTypeSeparator, |
| false/* |
| * don't show parameters |
| */); |
| } catch (ModelException e) { |
| // exception thrown only when showing parameters |
| return null; |
| } |
| } |
| |
| @Override |
| public String getFullyQualifiedName() { |
| return getFullyQualifiedName("$"); //$NON-NLS-1$ |
| } |
| |
| @Override |
| public void codeComplete(char[] snippet, int insertion, int position, |
| char[][] localVariableTypeNames, char[][] localVariableNames, |
| int[] localVariableModifiers, boolean isStatic, |
| CompletionRequestor requestor) throws ModelException { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| @Override |
| public void codeComplete(char[] snippet, int insertion, int position, |
| char[][] localVariableTypeNames, char[][] localVariableNames, |
| int[] localVariableModifiers, boolean isStatic, |
| CompletionRequestor requestor, WorkingCopyOwner owner) |
| throws ModelException { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| @Override |
| public IScriptFolder getScriptFolder() { |
| IModelElement parentElement = this.parent; |
| while (parentElement != null) { |
| if (parentElement.getElementType() == IModelElement.SCRIPT_FOLDER) { |
| return (IScriptFolder) parentElement; |
| } else { |
| parentElement = parentElement.getParent(); |
| } |
| } |
| Assert.isTrue(false); // should not happen |
| return null; |
| } |
| |
| /** |
| * @see IType#getTypeQualifiedName() |
| */ |
| @Override |
| public String getTypeQualifiedName() { |
| return this.getTypeQualifiedName("$"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * @see IType#getTypeQualifiedName(char) |
| */ |
| @Override |
| public String getTypeQualifiedName(String enclosingTypeSeparator) { |
| try { |
| return getTypeQualifiedName(enclosingTypeSeparator, |
| false/* |
| * don't show parameters |
| */); |
| } catch (ModelException e) { |
| // exception thrown only when showing parameters |
| return null; |
| } |
| } |
| |
| /* |
| * @see IType |
| */ |
| @Override |
| public IMethod[] findMethods(IMethod method) { |
| try { |
| return findMethods(method, getMethods()); |
| } catch (ModelException e) { |
| // if type doesn't exist, no matching method can exist |
| return null; |
| } |
| } |
| |
| /* |
| * Type hierarchies section |
| */ |
| |
| /** |
| * @see IType |
| */ |
| @Override |
| public ITypeHierarchy loadTypeHierachy(InputStream input, |
| IProgressMonitor monitor) throws ModelException { |
| return loadTypeHierachy(input, DefaultWorkingCopyOwner.PRIMARY, |
| monitor); |
| } |
| |
| /** |
| * NOTE: This method is not part of the API has it is not clear clients |
| * would easily use it: they would need to first make sure all working |
| * copies for the given owner exist before calling it. This is especially |
| * har at startup time. In case clients want this API, here is how it should |
| * be specified: |
| * <p> |
| * Loads a previously saved ITypeHierarchy from an input stream. A type |
| * hierarchy can be stored using ITypeHierachy#store(OutputStream). A |
| * compilation unit of a loaded type has the given owner if such a working |
| * copy exists, otherwise the type's compilation unit is a primary |
| * compilation unit. |
| * |
| * Only hierarchies originally created by the following methods can be |
| * loaded: |
| * <ul> |
| * <li>IType#newSupertypeHierarchy(IProgressMonitor)</li> |
| * <li>IType#newSupertypeHierarchy(WorkingCopyOwner, IProgressMonitor)</li> |
| * <li>IType#newTypeHierarchy(IJavaProject, IProgressMonitor)</li> |
| * <li>IType#newTypeHierarchy(IJavaProject, WorkingCopyOwner, |
| * IProgressMonitor)</li> |
| * <li>IType#newTypeHierarchy(IProgressMonitor)</li> |
| * <li>IType#newTypeHierarchy(WorkingCopyOwner, IProgressMonitor)</li> </u> |
| * |
| * @param input |
| * stream where hierarchy will be read |
| * @param monitor |
| * the given progress monitor |
| * @return the stored hierarchy |
| * @exception JavaModelException |
| * if the hierarchy could not be restored, reasons include: - |
| * type is not the focus of the hierarchy or - unable to read |
| * the input stream (wrong format, IOException during |
| * reading, ...) |
| * @see ITypeHierarchy#store(java.io.OutputStream, IProgressMonitor) |
| * @since 3.0 |
| */ |
| public ITypeHierarchy loadTypeHierachy(InputStream input, |
| WorkingCopyOwner owner, IProgressMonitor monitor) |
| throws ModelException { |
| // TODO monitor should be passed to TypeHierarchy.load(...) |
| return TypeHierarchy.load(this, input, owner); |
| } |
| |
| /** |
| * @see IType |
| */ |
| @Override |
| public ITypeHierarchy newSupertypeHierarchy(IProgressMonitor monitor) |
| throws ModelException { |
| return this.newSupertypeHierarchy(DefaultWorkingCopyOwner.PRIMARY, |
| monitor); |
| } |
| |
| /* |
| * @see IType#newSupertypeHierarchy(ICompilationUnit[], IProgressMonitor) |
| */ |
| @Override |
| public ITypeHierarchy newSupertypeHierarchy(ISourceModule[] workingCopies, |
| IProgressMonitor monitor) throws ModelException { |
| |
| CreateTypeHierarchyOperation op; |
| IScriptProject scriptProject = getScriptProject(); |
| IDLTKSearchScope scope = SearchEngine.createSearchScope(scriptProject); |
| op = new CreateTypeHierarchyOperation(this, workingCopies, scope, |
| false); |
| op.runOperation(monitor); |
| return op.getResult(); |
| } |
| |
| /** |
| * @see IType#newSupertypeHierarchy(WorkingCopyOwner, IProgressMonitor) |
| */ |
| @Override |
| public ITypeHierarchy newSupertypeHierarchy(WorkingCopyOwner owner, |
| IProgressMonitor monitor) throws ModelException { |
| final ITypeHierarchy hierarchy = TypeHierarchyBuilders |
| .getTypeHierarchy(this, ITypeHierarchy.Mode.SUPERTYPE, monitor); |
| if (hierarchy != null) { |
| return hierarchy; |
| } |
| |
| ISourceModule[] workingCopies = ModelManager.getModelManager() |
| .getWorkingCopies(owner, true/* add primary working copies */); |
| CreateTypeHierarchyOperation op; |
| IScriptProject scriptProject = getScriptProject(); |
| IDLTKSearchScope scope = SearchEngine.createSearchScope(scriptProject); |
| op = new CreateTypeHierarchyOperation(this, workingCopies, scope, |
| false); |
| op.runOperation(monitor); |
| return op.getResult(); |
| } |
| |
| /** |
| * @see IType |
| */ |
| @Override |
| public ITypeHierarchy newTypeHierarchy(IScriptProject project, |
| IProgressMonitor monitor) throws ModelException { |
| return newTypeHierarchy(project, DefaultWorkingCopyOwner.PRIMARY, |
| monitor); |
| } |
| |
| /** |
| * @see IType#newTypeHierarchy(IJavaProject, WorkingCopyOwner, |
| * IProgressMonitor) |
| */ |
| @Override |
| public ITypeHierarchy newTypeHierarchy(IScriptProject project, |
| WorkingCopyOwner owner, IProgressMonitor monitor) |
| throws ModelException { |
| if (project == null) { |
| throw new IllegalArgumentException(Messages.hierarchy_nullProject); |
| } |
| ISourceModule[] workingCopies = ModelManager.getModelManager() |
| .getWorkingCopies(owner, true/* add primary working copies */); |
| ISourceModule[] projectWCs = null; |
| if (workingCopies != null) { |
| int length = workingCopies.length; |
| projectWCs = new ISourceModule[length]; |
| int index = 0; |
| for (int i = 0; i < length; i++) { |
| ISourceModule wc = workingCopies[i]; |
| if (project.equals(wc.getScriptProject())) { |
| projectWCs[index++] = wc; |
| } |
| } |
| if (index != length) { |
| System.arraycopy(projectWCs, 0, |
| projectWCs = new ISourceModule[index], 0, index); |
| } |
| } |
| CreateTypeHierarchyOperation op = new CreateTypeHierarchyOperation(this, |
| projectWCs, project, true); |
| op.runOperation(monitor); |
| return op.getResult(); |
| } |
| |
| private IDLTKSearchScope createReferencingProjectsScope() { |
| |
| IScriptProject scriptProject = getScriptProject(); |
| IProject project = scriptProject.getProject(); |
| IProject[] referencingProjects = project.getReferencingProjects(); |
| |
| List<IScriptProject> scriptProjects = new ArrayList<>( |
| referencingProjects.length + 1); |
| scriptProjects.add(scriptProject); |
| |
| for (int i = 0; i < referencingProjects.length; ++i) { |
| IProject p = referencingProjects[i]; |
| if (p.isAccessible()) { |
| scriptProjects.add(DLTKCore.create(p)); |
| } |
| } |
| return SearchEngine.createSearchScope( |
| scriptProjects |
| .toArray(new IModelElement[scriptProjects.size()]), |
| false, DLTKLanguageManager.getLanguageToolkit(this)); |
| } |
| |
| /** |
| * @see IType |
| */ |
| @Override |
| public ITypeHierarchy newTypeHierarchy(IProgressMonitor monitor) |
| throws ModelException { |
| final ITypeHierarchy hierarchy = TypeHierarchyBuilders |
| .getTypeHierarchy(this, ITypeHierarchy.Mode.HIERARCHY, monitor); |
| if (hierarchy != null) { |
| return hierarchy; |
| } |
| CreateTypeHierarchyOperation op; |
| op = new CreateTypeHierarchyOperation(this, null, |
| createReferencingProjectsScope(), true); |
| op.runOperation(monitor); |
| return op.getResult(); |
| } |
| |
| /* |
| * @see IType#newTypeHierarchy(ICompilationUnit[], IProgressMonitor) |
| */ |
| @Override |
| public ITypeHierarchy newTypeHierarchy(ISourceModule[] workingCopies, |
| IProgressMonitor monitor) throws ModelException { |
| |
| CreateTypeHierarchyOperation op; |
| op = new CreateTypeHierarchyOperation(this, workingCopies, |
| createReferencingProjectsScope(), true); |
| op.runOperation(monitor); |
| return op.getResult(); |
| } |
| |
| /** |
| * @see IType#newTypeHierarchy(WorkingCopyOwner, IProgressMonitor) |
| */ |
| @Override |
| public ITypeHierarchy newTypeHierarchy(WorkingCopyOwner owner, |
| IProgressMonitor monitor) throws ModelException { |
| |
| ISourceModule[] workingCopies = ModelManager.getModelManager() |
| .getWorkingCopies(owner, true/* add primary working copies */); |
| CreateTypeHierarchyOperation op; |
| op = new CreateTypeHierarchyOperation(this, workingCopies, |
| createReferencingProjectsScope(), true); |
| op.runOperation(monitor); |
| return op.getResult(); |
| } |
| } |