/******************************************************************************* * Copyright (c) 2005, 2007 committers of openArchitectureWare 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: * committers of openArchitectureWare - initial API and implementation *******************************************************************************/ package org.eclipse.xtend.shared.ui.core.metamodel.jdt; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.internal.xtend.expression.parser.SyntaxConstants; import org.eclipse.internal.xtend.util.Cache; import org.eclipse.internal.xtend.util.Pair; import org.eclipse.jdt.core.ElementChangedEvent; import org.eclipse.jdt.core.IElementChangedListener; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeHierarchy; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; import org.eclipse.xtend.expression.TypeSystem; import org.eclipse.xtend.shared.ui.internal.XtendLog; import org.eclipse.xtend.typesystem.MetaModel; import org.eclipse.xtend.typesystem.Type; public class JdtMetaModel implements MetaModel, IElementChangedListener , IResourceChangeListener{ protected TypeSystem typesystem; private final String name; private final JdtTypeStrategy strategy; private final IJavaProject project; public TypeSystem getTypeSystem() { return typesystem; } public void setTypeSystem(final TypeSystem typeSystem) { typesystem = typeSystem; } private final static Map<IPath, JdtMetaModel> metaModels = new HashMap<IPath, JdtMetaModel>(); public boolean changed = false; public void elementChanged(final ElementChangedEvent event) { if (!changed && project.isOnClasspath(event.getDelta().getElement())) { changed = true; } } public void resourceChanged(IResourceChangeEvent event) { if (!typeNameCache.isEmpty()) typeNameCache.clear(); } public final static JdtMetaModel create(final String name, final IJavaProject project, final JdtTypeStrategy strategy) { JdtMetaModel mm = JdtMetaModel.metaModels.get(project.getPath()); if (mm == null || mm.changed) { if (mm != null) { JavaCore.removeElementChangedListener(mm); } mm = new JdtMetaModel(name, project, strategy); JavaCore.addElementChangedListener(mm); JavaCore.addPreProcessingResourceChangedListener(mm, IResourceChangeEvent.PRE_BUILD); JdtMetaModel.metaModels.put(project.getPath(), mm); } return mm; } public JdtMetaModel(final String name, final IJavaProject project, final JdtTypeStrategy strategy) { this.name = name; this.strategy = strategy; this.project = project; } private Type getTypeForIType(final IType type) { if (type == null || !type.exists()) { return null; } try { final ITypeHierarchy hierarchy = type.newSupertypeHierarchy(new NullProgressMonitor()); if (hierarchy.contains(type.getJavaProject().findType(List.class.getName()))) { return typesystem.getListType(typesystem.getObjectType()); } else if (hierarchy.contains(type.getJavaProject().findType(Set.class.getName()))) { return typesystem.getSetType(typesystem.getObjectType()); } else if (hierarchy.contains(type.getJavaProject().findType(Collection.class.getName()))) { return typesystem.getCollectionType(typesystem.getObjectType()); } } catch (final JavaModelException e) { XtendLog.logError(e); return null; } return new JdtTypeImpl(JdtMetaModel.this, type, getName(type), strategy); } protected Type getType(final String fqn) throws JavaModelException { if (fqn.indexOf(SyntaxConstants.NS_DELIM) == -1) { // namespace return null; } final String typeName = fqn.replaceAll(SyntaxConstants.NS_DELIM, "."); final IType type = findType(project, typeName); if (type != null) { return getTypeForIType(type); } else { return null; } } private String getName(final IType class1) { return class1.getFullyQualifiedName().replaceAll("\\.", SyntaxConstants.NS_DELIM); } private final Cache<String,Type> typeNameCache = new Cache<String,Type>() { @Override protected Type createNew(String typeName) { try { Type result = getType(typeName); return result; } catch (Exception e) { return null; } } }; public Type getTypeForName(final String typeName) { return typeNameCache.get(typeName); } public Type getType(final Object obj) { throw new UnsupportedOperationException(); } public Type getTypeForClass(final IType clazz) { return getTypeSystem().getTypeForName(getName(clazz)); } public Set<? extends Type> getKnownTypes() { final Set<Type> result = new HashSet<Type>(typeNameCache.getValues()); result.remove(null); return result; } public String getName() { return name; } private final Cache<Pair<String,IType>,String> signCache = new Cache<Pair<String,IType>,String>() { @Override protected String createNew(Pair<String,IType> p) { String signature = p.getFirst(); // primitives if (Signature.SIG_BOOLEAN.equals(signature)) { return "Boolean"; } else if (Signature.SIG_INT.equals(signature)) { return "Integer"; } else if (Signature.SIG_LONG.equals(signature)) { return "Integer"; } else if (Signature.SIG_SHORT.equals(signature)) { return "Integer"; } else if (Signature.SIG_CHAR.equals(signature)) { return "String"; } else if (Signature.SIG_BYTE.equals(signature)) { return "Integer"; } IType usingType = p.getSecond(); try { String[][] result = usingType.resolveType(Signature.toString(signature)); if (result == null) { return Signature.toString(signature).replaceAll("\\.", SyntaxConstants.NS_DELIM); } if (result.length > 0) { StringBuffer buff = new StringBuffer(); for (int i = 0; i < result[0].length; i++) { String part = result[0][i]; buff.append(part); if (i < result[0].length - 1) { buff.append("."); } } String fqn = buff.toString(); return fqn.replaceAll("\\.", SyntaxConstants.NS_DELIM); } } catch (JavaModelException e) { XtendLog.logError(e); } return null; } }; public String getFullyQualifiedName(final String signature, final IType usingType) { return signCache.get(new Pair<String,IType>(signature, usingType)); } public IType findType(final IJavaProject project, final String typeName) throws JavaModelException { IType t = project.findType(typeName); if (t == null) { final String[] projects = project.getRequiredProjectNames(); for (int i = 0; i < projects.length && t == null; i++) { final IJavaProject anotherProject = project.getJavaModel().getJavaProject(projects[i]); if (anotherProject != null) { t = anotherProject.findType(typeName); } } } return t; } public Set<String> getNamespaces() { return new HashSet<String>(); } }