Add UI support for SSA transformers

This commit is contained in:
konsoletyper 2014-09-18 20:40:33 +04:00
parent aefce514ff
commit 29e35e001a
8 changed files with 317 additions and 133 deletions

View File

@ -0,0 +1,5 @@
eclipse.preferences.version=1
org.eclipse.jdt.ui.ignorelowercasenames=true
org.eclipse.jdt.ui.importorder=java;javax;org;com;
org.eclipse.jdt.ui.ondemandthreshold=90
org.eclipse.jdt.ui.staticondemandthreshold=3

View File

@ -70,9 +70,15 @@
<extension id="dependencyMarker" point="org.eclipse.core.resources.markers" name="TeaVM dependency problem">
<super type="org.eclipse.core.resources.problemmarker"/>
<persistent value="false"/>
<persistent value="true"/>
<attribute name="severity"/>
<attribute name="message"/>
<attribute name="lineNumber"/>
</extension>
<extension id="configMarker" point="org.eclipse.core.resources.markers" name="TeaVM configuration problem">
<super type="org.eclipse.core.resources.problemmarker"/>
<persistent value="true"/>
<attribute name="severity"/>
<attribute name="message"/>
</extension>
</plugin>

View File

@ -37,8 +37,9 @@ public class TeaVMEclipsePlugin extends AbstractUIPlugin {
public static final String ID = "org.teavm.eclipse";
public static final String NATURE_ID = ID + ".nature";
public static final String BUILDER_ID = ID + ".builder";
public static final String MAIN_METHOD_DIALOG_ID = ID + ".dialogs.mainMethod";
public static final String CLASS_DIALOG_ID = ID + ".dialogs.classSelection";
public static final String DEPENDENCY_MARKER_ID = ID + ".dependencyMarker";
public static final String CONFIG_MARKER_ID = ID + ".configMarker";
private static TeaVMEclipsePlugin defaultInstance;
private ConcurrentMap<IProject, TeaVMProjectSettings> settingsMap = new ConcurrentHashMap<>();

View File

@ -1,6 +1,8 @@
package org.teavm.eclipse;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
@ -13,6 +15,7 @@ import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.teavm.dependency.*;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.InstructionLocation;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
@ -72,6 +75,7 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder {
if ((kind == AUTO_BUILD || kind == INCREMENTAL_BUILD) && !shouldBuild(profile)) {
return;
}
getProject().deleteMarkers(TeaVMEclipsePlugin.CONFIG_MARKER_ID, true, IResource.DEPTH_INFINITE);
IStringVariableManager varManager = VariablesPlugin.getDefault().getStringVariableManager();
TeaVMTool tool = new TeaVMTool();
tool.setClassLoader(classLoader);
@ -87,6 +91,9 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder {
tool.setIncremental(profile.isIncremental());
String cacheDir = profile.getCacheDirectory();
tool.setCacheDirectory(!cacheDir.isEmpty() ? new File(varManager.performStringSubstitution(cacheDir)) : null);
for (ClassHolderTransformer transformer : instantiateTransformers(profile, classLoader)) {
tool.getTransformers().add(transformer);
}
tool.setProgressListener(new TeaVMEclipseProgressListener(this, monitor, TICKS_PER_PROFILE));
try {
monitor.beginTask("Running TeaVM", 10000);
@ -328,6 +335,48 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder {
return projects;
}
private List<ClassHolderTransformer> instantiateTransformers(TeaVMProfile profile, ClassLoader classLoader)
throws CoreException{
List<ClassHolderTransformer> transformerInstances = new ArrayList<>();
for (String transformerName : profile.getTransformers()) {
Class<?> transformerRawType;
try {
transformerRawType = Class.forName(transformerName, true, classLoader);
} catch (ClassNotFoundException e) {
putConfigMarker("Transformer not found: " + transformerName);
continue;
}
if (!ClassHolderTransformer.class.isAssignableFrom(transformerRawType)) {
putConfigMarker("Transformer " + transformerName + " is not a subtype of " +
ClassHolderTransformer.class.getName());
continue;
}
Class<? extends ClassHolderTransformer> transformerType = transformerRawType.asSubclass(
ClassHolderTransformer.class);
Constructor<? extends ClassHolderTransformer> ctor;
try {
ctor = transformerType.getConstructor();
} catch (NoSuchMethodException e) {
putConfigMarker("Transformer " + transformerName + " has no default constructor");
continue;
}
try {
ClassHolderTransformer transformer = ctor.newInstance();
transformerInstances.add(transformer);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
putConfigMarker("Error instantiating transformer " + transformerName);
continue;
}
}
return transformerInstances;
}
private void putConfigMarker(String message) throws CoreException {
IMarker marker = getProject().createMarker(TeaVMEclipsePlugin.CONFIG_MARKER_ID);
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
marker.setAttribute(IMarker.MESSAGE, message);
}
private void prepareClassPath() throws CoreException {
classPath = new URL[0];
sourceContainers = new IContainer[0];

View File

@ -0,0 +1,161 @@
package org.teavm.eclipse.ui;
import static org.teavm.eclipse.TeaVMEclipsePlugin.CLASS_DIALOG_ID;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.dialogs.FilteredItemsSelectionDialog;
import org.teavm.eclipse.TeaVMEclipsePlugin;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public abstract class ClassSelectionDialog extends FilteredItemsSelectionDialog {
private IJavaProject javaProject;
public ClassSelectionDialog(Shell shell, IJavaProject javaProject) {
super(shell, false);
this.javaProject = javaProject;
LabelProvider labelProvider = new LabelProvider() {
@Override public String getText(Object element) {
return getElementName(element);
}
};
setListLabelProvider(labelProvider);
setDetailsLabelProvider(labelProvider);
}
@Override
protected String getInitialPattern() {
return "";
}
@Override
protected Control createExtendedContentArea(Composite parent) {
return null;
}
@Override
protected ItemsFilter createFilter() {
return new ItemsFilter() {
@Override public boolean matchItem(Object item) {
IType type = (IType)item;
return type.getFullyQualifiedName().toLowerCase().contains(getPattern().toLowerCase());
}
@Override public boolean isConsistentItem(Object item) {
return item instanceof IType;
}
};
}
@Override
protected void fillContentProvider(AbstractContentProvider contentProvider, ItemsFilter filter,
IProgressMonitor progressMonitor) throws CoreException {
IType[] mainTypes = findTypes(filter.getPattern(), progressMonitor);
for (IType type : mainTypes) {
contentProvider.add(type, filter);
}
}
@Override
protected IDialogSettings getDialogSettings() {
IDialogSettings settings = TeaVMEclipsePlugin.getDefault().getDialogSettings();
IDialogSettings section = settings.getSection(CLASS_DIALOG_ID);
if (section == null) {
section = settings.addNewSection(CLASS_DIALOG_ID);
}
return section;
}
@Override
public String getElementName(Object element) {
IType type = (IType)element;
return getTypeName(type);
}
private String getTypeName(IType type) {
if (type == null) {
return null;
}
StringBuilder sb = new StringBuilder(type.getTypeQualifiedName());
if (type.getPackageFragment() != null) {
sb.append(" in ").append(type.getPackageFragment().getElementName());
}
return sb.toString();
}
@Override
protected Comparator<?> getItemsComparator() {
return new Comparator<IType>() {
@Override public int compare(IType o1, IType o2) {
return getTypeName(o1).compareTo(getTypeName(o2));
}
};
}
@Override
protected IStatus validateItem(Object item) {
return Status.OK_STATUS;
}
private IType[] findTypes(String patternText, IProgressMonitor progressMonitor) {
IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaProject[] { javaProject },
IJavaSearchScope.SOURCES | IJavaSearchScope.REFERENCED_PROJECTS |
IJavaSearchScope.APPLICATION_LIBRARIES);
SearchPattern pattern = createSearchPattern(patternText);
SearchParticipant[] participants = new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() };
ClassCollector collector = new ClassCollector();
try {
new SearchEngine().search(pattern, participants, scope, collector, progressMonitor);
} catch (CoreException e) {
logError(e);
return new IType[0];
}
IType[] foundTypes = collector.getTypes().toArray(new IType[collector.getTypes().size()]);
return foundTypes;
}
private void logError(Throwable e) {
IStatus status = TeaVMEclipsePlugin.makeError(e);
TeaVMEclipsePlugin.getDefault().getLog().log(status);
ErrorDialog.openError(getShell(), "Error", "Error", status);
}
private class ClassCollector extends SearchRequestor {
private Set<IType> types = new HashSet<>();
public Set<IType> getTypes() {
return types;
}
@Override
public void acceptSearchMatch(SearchMatch match) throws CoreException {
IType type = acceptMatch(match);
if (type != null) {
types.add(type);
}
}
}
protected abstract SearchPattern createSearchPattern(String text);
protected abstract IType acceptMatch(SearchMatch match) throws CoreException;
}

View File

@ -1,146 +1,37 @@
package org.teavm.eclipse.ui;
import static org.teavm.eclipse.TeaVMEclipsePlugin.MAIN_METHOD_DIALOG_ID;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.search.*;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.dialogs.FilteredItemsSelectionDialog;
import org.teavm.eclipse.TeaVMEclipsePlugin;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class MainClassSelectionDialog extends FilteredItemsSelectionDialog {
private IJavaProject javaProject;
public class MainClassSelectionDialog extends ClassSelectionDialog {
public MainClassSelectionDialog(Shell shell, IJavaProject javaProject) {
super(shell, false);
this.javaProject = javaProject;
super(shell, javaProject);
setTitle("Selecting main class");
LabelProvider labelProvider = new LabelProvider() {
@Override public String getText(Object element) {
return getElementName(element);
}
};
setListLabelProvider(labelProvider);
setDetailsLabelProvider(labelProvider);
}
@Override
protected Control createExtendedContentArea(Composite parent) {
return null;
}
@Override
protected ItemsFilter createFilter() {
return new ItemsFilter() {
@Override public boolean matchItem(Object item) {
IType type = (IType)item;
return type.getTypeQualifiedName().toLowerCase().contains(getPattern().toLowerCase());
}
@Override public boolean isConsistentItem(Object item) {
return item instanceof IType;
}
};
}
@Override
protected void fillContentProvider(AbstractContentProvider contentProvider, ItemsFilter filter,
IProgressMonitor progressMonitor) throws CoreException {
IType[] mainTypes = findMainTypes(progressMonitor);
for (IType type : mainTypes) {
contentProvider.add(type, filter);
}
}
@Override
protected IDialogSettings getDialogSettings() {
IDialogSettings settings = TeaVMEclipsePlugin.getDefault().getDialogSettings();
IDialogSettings section = settings.getSection(MAIN_METHOD_DIALOG_ID);
if (section == null) {
section = settings.addNewSection(MAIN_METHOD_DIALOG_ID);
}
return section;
}
@Override
public String getElementName(Object element) {
IType type = (IType)element;
return getTypeName(type);
}
private String getTypeName(IType type) {
if (type == null) {
return null;
}
StringBuilder sb = new StringBuilder(type.getTypeQualifiedName());
if (type.getPackageFragment() != null) {
sb.append(" in ").append(type.getPackageFragment().getElementName());
}
return sb.toString();
}
@Override
protected Comparator<?> getItemsComparator() {
return new Comparator<IType>() {
@Override public int compare(IType o1, IType o2) {
return getTypeName(o1).compareTo(getTypeName(o2));
}
};
}
@Override
protected IStatus validateItem(Object item) {
return Status.OK_STATUS;
}
private IType[] findMainTypes(IProgressMonitor progressMonitor) {
IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaProject[] { javaProject },
IJavaSearchScope.SOURCES | IJavaSearchScope.REFERENCED_PROJECTS |
IJavaSearchScope.APPLICATION_LIBRARIES);
SearchPattern pattern = SearchPattern.createPattern("main(String[]) void", IJavaSearchConstants.METHOD,
protected SearchPattern createSearchPattern(String text) {
return SearchPattern.createPattern("main(String[]) void", IJavaSearchConstants.METHOD,
IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
SearchParticipant[] participants = new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() };
MainClassCollector collector = new MainClassCollector();
try {
new SearchEngine().search(pattern, participants, scope, collector, progressMonitor);
} catch (CoreException e) {
logError(e);
return new IType[0];
}
IType[] foundTypes = collector.getTypes().toArray(new IType[collector.getTypes().size()]);
return foundTypes;
}
private void logError(Throwable e) {
IStatus status = TeaVMEclipsePlugin.makeError(e);
TeaVMEclipsePlugin.getDefault().getLog().log(status);
ErrorDialog.openError(getShell(), "Error", "Error", status);
}
private static class MainClassCollector extends SearchRequestor {
private Set<IType> types = new HashSet<>();
public Set<IType> getTypes() {
return types;
}
@Override
public void acceptSearchMatch(SearchMatch match) throws CoreException {
protected IType acceptMatch(SearchMatch match) throws CoreException {
IMethod method = (IMethod)match.getElement();
if ((method.getFlags() & Flags.AccStatic) != 0) {
types.add(method.getDeclaringType());
}
return method.getDeclaringType();
}
return null;
}
}

View File

@ -284,10 +284,20 @@ public class TeaVMProfileDialog extends Dialog {
addTransformerButton = new Button(group, SWT.PUSH);
addTransformerButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
addTransformerButton.setText("Add...");
addTransformerButton.addSelectionListener(new SelectionAdapter() {
@Override public void widgetSelected(SelectionEvent e) {
addTransformer();
}
});
removeTransformerButton = new Button(group, SWT.PUSH);
removeTransformerButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
removeTransformerButton.setText("Remove");
removeTransformerButton.addSelectionListener(new SelectionAdapter() {
@Override public void widgetSelected(SelectionEvent e) {
removeTransformer();
}
});
}
private Group createGroup(Composite parent, String title, int columns, boolean fillVert) {
@ -480,6 +490,33 @@ public class TeaVMProfileDialog extends Dialog {
return filePath;
}
private void addTransformer() {
TransformerClassSelectionDialog selectionDialog = new TransformerClassSelectionDialog(getParentShell(),
javaProject);
if (selectionDialog.open() == MainClassSelectionDialog.OK) {
Object[] result = selectionDialog.getResult();
if (result.length > 0) {
IType type = (IType)result[0];
List<String> existingTypes = Arrays.asList(transormersList.getItems());
if (!existingTypes.contains(type.getFullyQualifiedName())) {
transormersList.add(type.getFullyQualifiedName());
}
}
}
}
private void removeTransformer() {
if (transormersList.getSelectionCount() != 1) {
return;
}
boolean confirmed = MessageDialog.openConfirm(getShell(), "Removal confirmation",
"Are you sure to delete the " + transormersList.getSelection()[0] + " transformer?");
if (!confirmed) {
return;
}
transormersList.remove(transormersList.getSelectionIndex());
}
@Override
protected void okPressed() {
if (save()) {
@ -518,6 +555,7 @@ public class TeaVMProfileDialog extends Dialog {
propertyList.add(property);
}
updateCacheFieldsEnabled();
transormersList.setItems(profile.getTransformers());
}
private boolean save() {
@ -543,6 +581,7 @@ public class TeaVMProfileDialog extends Dialog {
properties.setProperty(property.key, property.value);
}
profile.setProperties(properties);
profile.setTransformers(transormersList.getItems());
return true;
}
}

View File

@ -0,0 +1,32 @@
package org.teavm.eclipse.ui;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.swt.widgets.Shell;
import org.teavm.model.ClassHolderTransformer;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TransformerClassSelectionDialog extends ClassSelectionDialog {
public TransformerClassSelectionDialog(Shell shell, IJavaProject javaProject) {
super(shell, javaProject);
setTitle("Selecting TeaVM transformer");
}
@Override
protected SearchPattern createSearchPattern(String text) {
return SearchPattern.createPattern(ClassHolderTransformer.class.getName(), IJavaSearchConstants.CLASS,
IJavaSearchConstants.IMPLEMENTORS, SearchPattern.R_EXACT_MATCH);
}
@Override
protected IType acceptMatch(SearchMatch match) throws CoreException {
return (IType)match.getElement();
}
}