[subversion:26] Fix for issue #99 - Automatic import statements
- From: sinnema313@kenai.com
- To: commits@eplugin.kenai.com
- Subject: [subversion:26] Fix for issue #99 - Automatic import statements
- Date: Sat, 10 Jan 2009 14:31:55 +0000 (GMT)
Repository: subversion
Revision: 26
Author: sinnema313
Date: 2009-01-10 14:31:51 UTC
Log Message:
-----------
Fix for issue #99 - Automatic import statements
Modified Paths:
--------------
trunk/com.sun.javafx.eclipse.core/.classpath
trunk/com.sun.javafx.eclipse.core/META-INF/MANIFEST.MF
trunk/com.sun.javafx.eclipse.core/build.properties
trunk/com.sun.javafx.eclipse.core/plugin.xml
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/JavaFXBuilder.java
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/JavaFXCompilerMessage.java
Added Paths:
-----------
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/AddImportStatementResolution.java
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/JavaFXMarkerResolutionGenerator.java
trunk/com.sun.javafx.eclipse.core/test
trunk/com.sun.javafx.eclipse.core/test/com
trunk/com.sun.javafx.eclipse.core/test/com/sun
trunk/com.sun.javafx.eclipse.core/test/com/sun/javafx
trunk/com.sun.javafx.eclipse.core/test/com/sun/javafx/eclipse
trunk/com.sun.javafx.eclipse.core/test/com/sun/javafx/eclipse/core
trunk/com.sun.javafx.eclipse.core/test/com/sun/javafx/eclipse/core/buil
der
trunk/com.sun.javafx.eclipse.core/test/com/sun/javafx/eclipse/core/buil
der/JavaFXCompilerMessageTest.java
trunk/com.sun.javafx.eclipse.core/test/com/sun/javafx/eclipse/core/buil
der/UnknownSymbolResolutionTest.java
Diffs:
-----
Index:
trunk/com.sun.javafx.eclipse.core/test/com/sun/javafx/eclipse/core/buil
der/JavaFXCompilerMessageTest.java
===================================================================
---
trunk/com.sun.javafx.eclipse.core/test/com/sun/javafx/eclipse/core/buil
der/JavaFXCompilerMessageTest.java (revision 0)
+++
trunk/com.sun.javafx.eclipse.core/test/com/sun/javafx/eclipse/core/buil
der/JavaFXCompilerMessageTest.java (revision 26)
@@ -0,0 +1,21 @@
+package com.sun.javafx.eclipse.core.builder;
+
+import junit.framework.TestCase;
+
+
+public class JavaFXCompilerMessageTest extends TestCase {
+
+ /**
+ * <code>javafxc</code> outputs errors on three lines; format this
in
+ * a way that is useful in Eclipse's Problems view.
+ */
+ public void testFormat() {
+ assertEquals("Default", "ape",
JavaFXCompilerMessage.format("ape"));
+ assertEquals("Remove new lines", "bear cheetah",
+ JavaFXCompilerMessage.format("bear\ncheetah"));
+ assertEquals("'Cannot find symbol'", "cannot find symbol:
class dingo",
+ JavaFXCompilerMessage.format(
+ "cannot find symbol\nsymbol : class
dingo\nlocation: class Elephant"));
+ }
+
+}
Index:
trunk/com.sun.javafx.eclipse.core/test/com/sun/javafx/eclipse/core/buil
der/UnknownSymbolResolutionTest.java
===================================================================
---
trunk/com.sun.javafx.eclipse.core/test/com/sun/javafx/eclipse/core/buil
der/UnknownSymbolResolutionTest.java (revision 0)
+++
trunk/com.sun.javafx.eclipse.core/test/com/sun/javafx/eclipse/core/buil
der/UnknownSymbolResolutionTest.java (revision 26)
@@ -0,0 +1,74 @@
+package com.sun.javafx.eclipse.core.builder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+
+public class UnknownSymbolResolutionTest extends TestCase {
+
+ private static final String CLASS_TO_IMPORT = "ape.bear.Cheetah";
+ private static final String PACKAGE_STATEMENT = "package
dingo.elephant;";
+
+ private AddImportStatementResolution resolution;
+ private List<String> lines;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ resolution = new
AddImportStatementResolution(CLASS_TO_IMPORT);
+ lines = new ArrayList<String>();
+ }
+
+ public void testAddImportWhenEmpty() {
+ assertImportStatement(0);
+ }
+
+ public void testAddImportWithPackage() {
+ lines.add(PACKAGE_STATEMENT);
+ assertImportStatement(1);
+ }
+
+ public void testAddImportWithClassComment() {
+ lines.add(PACKAGE_STATEMENT);
+ lines.add("/**");
+ lines.add(" * @author flamingo");
+ lines.add(" */");
+ lines.add("Giraffe {");
+ lines.add("}");
+ assertImportStatement(1);
+ }
+
+ public void testAddImportWithOtherImport() {
+ lines.add("/**");
+ lines.add(" * @author hyena");
+ lines.add(" */");
+ lines.add("import iguaga.jaguar.Koala;");
+ lines.add("Leopard {");
+ lines.add("}");
+ assertImportStatement(4);
+ }
+
+ private void assertImportStatement(int expectedLine) {
+ int index = resolution.getImportStatementIndex(getText());
+ if (lines.size() > 0) {
+ int actualLine = 0;
+ while (index >= 0) {
+ index -= lines.get(actualLine++).length() + 1;
+ }
+ assertEquals("Import statement index", expectedLine,
actualLine);
+ } else {
+ assertEquals("Import statement index", 0, index);
+ }
+ }
+
+ private String getText() {
+ final StringBuffer result = new StringBuffer();
+ for (String line : lines) {
+ result.append(line).append('\n');
+ }
+ return result.toString();
+ }
+
+}
Index: trunk/com.sun.javafx.eclipse.core/.classpath
===================================================================
--- trunk/com.sun.javafx.eclipse.core/.classpath (revision 25)
+++ trunk/com.sun.javafx.eclipse.core/.classpath (revision 26)
@@ -3,5 +3,6 @@
<classpathentry kind="con"
path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con"
path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="test"/>
<classpathentry kind="output" path="bin"/>
</classpath>
Index: trunk/com.sun.javafx.eclipse.core/META-INF/MANIFEST.MF
===================================================================
--- trunk/com.sun.javafx.eclipse.core/META-INF/MANIFEST.MF
(revision 25)
+++ trunk/com.sun.javafx.eclipse.core/META-INF/MANIFEST.MF
(revision 26)
@@ -26,8 +26,11 @@
org.eclipse.equinox.http.jetty,
org.eclipse.equinox.http.registry,
org.eclipse.equinox.http.servlet,
- javax.servlet
+ javax.servlet,
+ org.junit
Bundle-ActivationPolicy: lazy
-Import-Package: javax.tools;version="2.0.0"
+Import-Package: javax.tools;version="2.0.0",
+ org.eclipse.jface.text,
+ org.eclipse.ui.ide
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Export-Package: com.sun.javafx.eclipse.core
Index:
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/JavaFXCompilerMessage.java
===================================================================
---
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/JavaFXCompilerMessage.java (revision 25)
+++
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/JavaFXCompilerMessage.java (revision 26)
@@ -6,7 +6,7 @@
*/
public class JavaFXCompilerMessage {
- private static final String UNKNOWN_SYMBOL_BEGIN = "cannot find
symbol";
+ public static final String UNKNOWN_SYMBOL_BEGIN = "cannot find
symbol";
private static final int UNKNOWN_SYMBOL_REMOVE = " symbol
".length();
private static final String UNKNOWN_SYMBOL_END = " location:";
Index:
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/JavaFXBuilder.java
===================================================================
---
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/JavaFXBuilder.java (revision 25)
+++
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/JavaFXBuilder.java (revision 26)
@@ -27,7 +27,6 @@
package com.sun.javafx.eclipse.core.builder;
-import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -40,7 +39,6 @@
import javax.tools.FileObject;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
-import javax.tools.Diagnostic.Kind;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
@@ -58,13 +56,13 @@
import com.sun.javafx.eclipse.core.Activator;
import com.sun.javafx.eclipse.core.builder.classpath.ClasspathInfo;
import com.sun.javafx.eclipse.core.builder.classpath.SourceFileObject;
-import com.sun.tools.javac.code.Kinds;
import com.sun.tools.javafx.api.JavafxcTool;
+
public class JavaFXBuilder extends IncrementalProjectBuilder {
public static final String BUILDER_ID =
"com.sun.javafx.eclipse.core.builder.JavaFXBuilder";
- private static final String MARKER_TYPE =
"com.sun.javafx.eclipse.core.builder.fxproblem";
+ public static final String MARKER_TYPE =
"com.sun.javafx.eclipse.core.builder.fxproblem";
private Map<IResource,Long> lastCheck = new
WeakHashMap<IResource,Long>();
@@ -212,7 +210,6 @@
return;
}
if (resource instanceof IFile &&
resource.getName().endsWith(".fx")) {
- String srcDir =
resource.getParent().getLocation().toOSString();
IFile file = (IFile) resource;
Long last = lastCheck.get(file);
long now = System.currentTimeMillis();
@@ -232,7 +229,6 @@
List<String> options = new ArrayList<String>();
//options.add("-Xjcov"); //NOI18N, Make the
compiler store end positions
options.add("-XDdisableStringFolding");
//NOI18N
- File f = new File(srcDir, file.getName());
JavafxcTask task = tool.getTask(null, fm,
dl, options, Collections.singleton(jfo));
task.parse();
task.analyze();
Index:
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/AddImportStatementResolution.java
===================================================================
---
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/AddImportStatementResolution.java (revision 0)
+++
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/AddImportStatementResolution.java (revision 26)
@@ -0,0 +1,93 @@
+package com.sun.javafx.eclipse.core.builder;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.IMarkerResolution;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+
+
+/**
+ * Resolve 'Unknown Symbol' errors by adding an import statement.
+ */
+public class AddImportStatementResolution implements IMarkerResolution
{
+
+ private String className;
+
+ public AddImportStatementResolution(String className) {
+ this.className = className;
+ }
+
+ public String getLabel() {
+ return "Import '" + className + "'";
+ }
+
+ public String getDescription() {
+ return "Add '" + className + "' to the imports";
+ }
+
+ public Image getImage() {
+ return null;
+ }
+
+ public void run(IMarker marker) {
+ final IFile file = (IFile) marker.getResource();
+ try {
+ if (!file.isSynchronized(IResource.DEPTH_ZERO)) {
+ file.refreshLocal(IResource.DEPTH_ZERO, null);
+ }
+
+ addImportStatement(file, "import " + className + ";");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void addImportStatement(IFile file, String
importStatement)
+ throws PartInitException, BadLocationException {
+ ITextEditor editor = (ITextEditor) IDE.openEditor(PlatformUI
+
.getWorkbench().getActiveWorkbenchWindow().getActivePage(), file,
true);
+ IDocument doc = editor.getDocumentProvider().getDocument(
+ new FileEditorInput(file));
+ doc.replace(getImportStatementIndex(doc.get()), 0, "import " +
className + ";\n");
+ editor.doSave(null);
+ }
+
+ protected int getImportStatementIndex(final String text) {
+ int result = text.indexOf("import ");
+ if (result < 0) {
+ result = text.indexOf("package ");
+ if (result >= 0) {
+ result = text.indexOf(';', result) + 1;
+ } else {
+ result = 0;
+ }
+ int classStart = text.indexOf('{', result);
+ int commentStart = text.indexOf("/*", result);
+ if (0 <= commentStart && commentStart < classStart) {
+ result = commentStart - 1;
+ } else if (classStart >= 0) {
+ classStart--;
+ while
(Character.isWhitespace(text.charAt(classStart))) {
+ classStart--;
+ }
+ while (classStart > 0 &&
!Character.isWhitespace(text.charAt(classStart))) {
+ classStart--;
+ }
+ while (classStart > 0 &&
Character.isWhitespace(text.charAt(classStart))) {
+ classStart--;
+ }
+ result = classStart;
+ }
+ }
+ return result;
+ }
+
+}
Index:
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/JavaFXMarkerResolutionGenerator.java
===================================================================
---
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/JavaFXMarkerResolutionGenerator.java (revision 0)
+++
trunk/com.sun.javafx.eclipse.core/src/com/sun/javafx/eclipse/core/build
er/JavaFXMarkerResolutionGenerator.java (revision 26)
@@ -0,0 +1,117 @@
+package com.sun.javafx.eclipse.core.builder;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.ui.IMarkerResolution;
+import org.eclipse.ui.IMarkerResolutionGenerator2;
+
+
+public class JavaFXMarkerResolutionGenerator implements
+ IMarkerResolutionGenerator2 {
+
+ private static final String JAVA_CLASS_EXTENSION = "class";
+ private static final Object JAVA_LIBARY_EXTENSION = "jar";
+ private static final String CLASS = "class ";
+ private static final char INTERNAL_CLASS_SEPARATOR = '$';
+
+ public boolean hasResolutions(final IMarker marker) {
+ return isUnknownSymbolError(marker) &&
!getFullyQualifiedNames(marker).isEmpty();
+ }
+
+ public IMarkerResolution[] getResolutions(final IMarker marker) {
+ final List<IMarkerResolution> result = new
ArrayList<IMarkerResolution>();
+ if (isUnknownSymbolError(marker)) {
+ for (String className : getFullyQualifiedNames(marker)) {
+ result.add(new
AddImportStatementResolution(className));
+ }
+ }
+ return (IMarkerResolution[]) result.toArray(new
IMarkerResolution[result.size()]);
+ }
+
+ private boolean isUnknownSymbolError(final IMarker marker) {
+ return isError(marker) &&
getMessage(marker).startsWith(JavaFXCompilerMessage.UNKNOWN_SYMBOL_BEGI
N);
+ }
+
+ private String getMessage(final IMarker marker) {
+ return marker.getAttribute(IMarker.MESSAGE, "");
+ }
+
+ private boolean isError(final IMarker marker) {
+ return marker.getAttribute(IMarker.SEVERITY,
IMarker.SEVERITY_INFO) == IMarker.SEVERITY_ERROR;
+ }
+
+ private Set<String> getFullyQualifiedNames(final IMarker marker) {
+ final Set<String> result = new TreeSet<String>();
+ final String toMatch =
getMessage(marker).substring(JavaFXCompilerMessage.UNKNOWN_SYMBOL_BEGIN
.length() + 2);
+ if (toMatch.startsWith(CLASS)) {
+ addFullyQualifiedNames(marker.getResource().getProject(),
toMatch.substring(CLASS.length()), result);
+ }
+ return result;
+ }
+
+ private void addFullyQualifiedNames(final IProject project, final
String className, final Set<String> result) {
+ final String classFileName = className + "." +
JAVA_CLASS_EXTENSION;
+ try {
+ IJavaProject javaProject = JavaCore.create(project);
+ for (IClasspathEntry classPathEntry :
javaProject.getResolvedClasspath(true)) {
+ if (classPathEntry.getEntryKind() ==
IClasspathEntry.CPE_LIBRARY) {
+ if
(JAVA_LIBARY_EXTENSION.equals(classPathEntry.getPath().getFileExtension
())) {
+ try {
+ final JarFile jar = new
JarFile(classPathEntry.getPath().toFile());
+ try {
+ final Enumeration<JarEntry> entries =
jar.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry =
entries.nextElement();
+ if (!entry.isDirectory() &&
isClass(entry.getName(), classFileName)) {
+
result.add(getFullyQualifiedName(entry.getName()));
+ }
+ }
+ } finally {
+ jar.close();
+ }
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+ }
+ }
+ } catch (CoreException ce) {
+ ce.printStackTrace();
+ }
+ }
+
+ private String getFullyQualifiedName(final String path) {
+ return path.substring(0, path.lastIndexOf('.')).replaceAll(
+ "\\" + File.separator, ".").replaceAll(
+ "\\" + INTERNAL_CLASS_SEPARATOR, ".");
+ }
+
+ private boolean isClass(final String fileName, final String
classFileName) {
+ final boolean result;
+ final int index = fileName.lastIndexOf(classFileName);
+ if (index < 0) {
+ result = false;
+ } else if (index == 0) {
+ result = true;
+ } else {
+ final char before = fileName.charAt(index - 1);
+ result = before == File.separatorChar || before ==
INTERNAL_CLASS_SEPARATOR;
+ }
+ return result;
+ }
+
+}
Index: trunk/com.sun.javafx.eclipse.core/build.properties
===================================================================
--- trunk/com.sun.javafx.eclipse.core/build.properties (revision 25)
+++ trunk/com.sun.javafx.eclipse.core/build.properties (revision 26)
@@ -25,7 +25,7 @@
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
-source.. = src/
+source.. = src/,test/
output.. = bin/
bin.includes = META-INF/,\
.,\
Index: trunk/com.sun.javafx.eclipse.core/plugin.xml
===================================================================
--- trunk/com.sun.javafx.eclipse.core/plugin.xml (revision 25)
+++ trunk/com.sun.javafx.eclipse.core/plugin.xml (revision 26)
@@ -102,9 +102,8 @@
id="com.sun.javafx.eclipse.core.builder.fxproblem"
name="JavaFX Problem"
point="org.eclipse.core.resources.markers">
- <super
- type="org.eclipse.core.resources.problemmarker">
- </super>
+ <super type="org.eclipse.core.resources.problemmarker"/>
+ <super type="org.eclipse.core.resources.textmarker"/>
<persistent
value="true">
</persistent>
@@ -303,4 +302,11 @@
</menuContribution>
</extension>
+ <extension
+ point="org.eclipse.ui.ide.markerResolution">
+ <markerResolutionGenerator
+ markerType="com.sun.javafx.eclipse.core.builder.fxproblem"
+
class="com.sun.javafx.eclipse.core.builder.JavaFXMarkerResolutionGenera
tor"/>
+ </extension>
+
</plugin>
|
[subversion:26] Fix for issue #99 - Automatic import statements |
sinnema313 | 01/10/2009 |





