blob: e4e341769fcd0cf173a2d52523acfebff707f8be [file] [log] [blame]
/*******************************************************************************
* 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();
}
}