Bug 466232 - [null] Annotate command should be resilient to "broken
classfiles"
Change-Id: I721ffc45cf5bf4dcb9da2d9af1baab2d58d98141
Signed-off-by: Stephan Herrmann <stephan.herrmann@berlin.de>
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AbstractAnnotateAssistTests.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AbstractAnnotateAssistTests.java
index 7fa0570..f80de0b 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AbstractAnnotateAssistTests.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AbstractAnnotateAssistTests.java
@@ -41,6 +41,7 @@
import org.eclipse.jdt.internal.corext.util.Strings;
import org.eclipse.jdt.ui.tests.core.ProjectTestSetup;
+import org.eclipse.jdt.ui.tests.quickfix.JarUtil.ClassFileFilter;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jdt.internal.ui.javaeditor.JavaSourceViewer;
@@ -86,9 +87,9 @@
// === from jdt.core.tests.model: ===
protected void addLibrary(IJavaProject javaProject, String jarName, String sourceZipName, String[] pathAndContents,
- String annotationpath, String compliance) throws CoreException, IOException
- {
- IProject project= createLibrary(javaProject, jarName, sourceZipName, pathAndContents, compliance);
+ String annotationpath, String compliance, ClassFileFilter classFileFilter) throws CoreException, IOException
+ {
+ IProject project= createLibrary(javaProject, jarName, sourceZipName, pathAndContents, compliance, classFileFilter);
String projectPath= '/' + project.getName() + '/';
IClasspathEntry entry= JavaCore.newLibraryEntry(
@@ -106,13 +107,13 @@
}
protected IProject createLibrary(IJavaProject javaProject, String jarName, String sourceZipName, String[] pathAndContents,
- String compliance) throws IOException, CoreException
+ String compliance, ClassFileFilter classFileFilter) throws IOException, CoreException
{
IProject project= javaProject.getProject();
String projectLocation= project.getLocation().toOSString();
String jarPath= projectLocation + File.separator + jarName;
String[] claspath= new String[] { javaProject.getResolvedClasspath(true)[0].getPath().toOSString() };
- JarUtil.createJar(pathAndContents, null, jarPath, claspath, compliance, null);
+ JarUtil.createJar(pathAndContents, null, jarPath, claspath, compliance, null, classFileFilter);
if (pathAndContents != null && pathAndContents.length != 0) {
String sourceZipPath= projectLocation + File.separator + sourceZipName;
JarUtil.createSourceZip(pathAndContents, sourceZipPath);
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest15.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest15.java
index 6e0fe9d..46ed0ef 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest15.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest15.java
@@ -13,11 +13,10 @@
import java.io.ByteArrayInputStream;
import java.util.List;
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
import org.eclipse.jdt.testplugin.JavaProjectHelper;
+import org.eclipse.core.runtime.ILogListener;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.resources.IFile;
@@ -32,13 +31,19 @@
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jdt.ui.tests.core.ProjectTestSetup;
+import org.eclipse.jdt.ui.tests.quickfix.JarUtil.ClassFileFilter;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jdt.internal.ui.javaeditor.JavaSourceViewer;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
public class AnnotateAssistTest15 extends AbstractAnnotateAssistTests {
protected static final String ANNOTATION_PATH= "annots";
@@ -67,19 +72,19 @@
/**
* Assert that the "Annotate" command can be invoked on a ClassFileEditor
- * @throws Exception
+ * @throws Exception
*/
public void testAnnotateReturn() throws Exception {
String MY_MAP_PATH= "pack/age/MyMap";
- String[] pathAndContents= new String[] {
- MY_MAP_PATH+".java",
+ String[] pathAndContents= new String[] {
+ MY_MAP_PATH+".java",
"package pack.age;\n" +
"public interface MyMap<K,V> {\n" +
" public V get(K key);\n" +
"}\n"
};
- addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_5);
+ addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_5, null);
IType type= fJProject1.findType(MY_MAP_PATH.replace('/', '.'));
JavaEditor javaEditor= (JavaEditor) JavaUI.openInEditor(type);
@@ -91,12 +96,12 @@
viewer.getQuickAssistAssistant().addCompletionListener(new ICompletionListener() {
public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) {
proposalBox[0]= proposal;
- }
+ }
public void assistSessionStarted(ContentAssistEvent event) { /* nop */ }
public void assistSessionEnded(ContentAssistEvent event) { /* nop */ }
});
- int offset= pathAndContents[1].indexOf("V get");
+ int offset= pathAndContents[1].indexOf("V get");
viewer.setSelection(new TextSelection(offset, 0));
viewer.doOperation(JavaSourceViewer.ANNOTATE_CLASS_FILE);
@@ -142,14 +147,14 @@
public void testAnnotateReturn2() throws Exception {
String MY_MAP_PATH= "pack/age/MyMap";
- String[] pathAndContents= new String[] {
+ String[] pathAndContents= new String[] {
MY_MAP_PATH+".java",
"package pack.age;\n" +
"public interface MyMap<K,V> {\n" +
" public V get(K key);\n" +
"}\n"
};
- addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_5);
+ addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_5, null);
IType type= fJProject1.findType(MY_MAP_PATH.replace('/', '.'));
JavaEditor javaEditor= (JavaEditor) JavaUI.openInEditor(type);
@@ -203,14 +208,14 @@
String MY_MAP_PATH= "pack/age/MyMap";
- String[] pathAndContents= new String[] {
- MY_MAP_PATH+".java",
+ String[] pathAndContents= new String[] {
+ MY_MAP_PATH+".java",
"package pack.age;\n" +
"public interface MyMap<K,V> {\n" +
" public V get(K key);\n" +
"}\n"
};
- addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_5);
+ addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_5, null);
IType type= fJProject1.findType(MY_MAP_PATH.replace('/', '.'));
IFile annotationFile= fJProject1.getProject().getFile(new Path(ANNOTATION_PATH).append(MY_MAP_PATH+".eea"));
String initialContent=
@@ -273,7 +278,7 @@
public void testAnnotateParameter_Array1() throws Exception {
String X_PATH= "pack/age/X";
- String[] pathAndContents= new String[] {
+ String[] pathAndContents= new String[] {
X_PATH+".java",
"package pack.age;\n" +
"import java.util.List;\n" +
@@ -281,7 +286,7 @@
" public String test(int[][] ints, List<String> list);\n" +
"}\n"
};
- addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_8);
+ addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_8, null);
IFile annotationFile= fJProject1.getProject().getFile(new Path(ANNOTATION_PATH).append(X_PATH+".eea"));
String initialContent=
@@ -343,14 +348,14 @@
public void testAnnotateField1() throws Exception {
String NODE_PATH= "pack/age/Node";
- String[] pathAndContents= new String[] {
+ String[] pathAndContents= new String[] {
NODE_PATH+".java",
"package pack.age;\n" +
"public class Node<V> {\n" +
" V value;\n" +
"}\n"
};
- addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_5);
+ addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_5, null);
IType type= fJProject1.findType(NODE_PATH.replace('/', '.'));
JavaEditor javaEditor= (JavaEditor) JavaUI.openInEditor(type);
@@ -403,14 +408,14 @@
public void testAnnotateField2() throws Exception {
String NODE_PATH= "pack/age/Node";
- String[] pathAndContents= new String[] {
+ String[] pathAndContents= new String[] {
NODE_PATH+".java",
"package pack.age;\n" +
"public class Node<V> {\n" +
" Node<String> next;\n" +
"}\n"
};
- addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_5);
+ addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_5, null);
IType type= fJProject1.findType(NODE_PATH.replace('/', '.'));
JavaEditor javaEditor= (JavaEditor) JavaUI.openInEditor(type);
@@ -455,4 +460,64 @@
}
}
+ public void testBug466232() throws Exception {
+ final String MISSINGPATH= "pack/age/Missing";
+ String CLASS1_PATH= "pack/age/Class1";
+ String CLASS2_PATH= "pack/age/Class2";
+ String[] pathAndContents= new String[] {
+ MISSINGPATH+".java",
+ "package pack.age;\n" +
+ "@interface Missing {}\n",
+ CLASS1_PATH+".java",
+ "package pack.age;\n" +
+ "import pack.age.Missing;\n" +
+ "@Missing\n" +
+ "public class Class1 {\n" +
+ " Class1 foo() { return this; }\n" +
+ "}\n",
+ CLASS2_PATH+".java",
+ "package pack.age;\n" +
+ "import pack.age.Class1;\n" + // creates UnresolvedReferenceBinding for transitively referenced "Missing"
+ "import pack.age.Missing;\n" + // throws AbortCompilation for unresolvable UnresolvedReferenceBinding "Missing"
+ "public class Class2 {\n" +
+ " void test(Class1 c1) {\n" +
+ " c1 = c1.foo();\n" +
+ " }\n" +
+ "}\n"
+ };
+
+ addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_5, new ClassFileFilter() {
+ public boolean include(CompilationResult unitResult) {
+ return !new Path(MISSINGPATH + ".java").equals(new Path(String.valueOf(unitResult.getFileName())));
+ }
+ });
+ IType type= fJProject1.findType(CLASS2_PATH.replace('/', '.'));
+ JavaEditor javaEditor= (JavaEditor) JavaUI.openInEditor(type);
+
+ ILogListener logListener= null;
+ try {
+ int offset= pathAndContents[5].indexOf("Class1 c1");
+
+ // not expecting proposals, but a log message, due to incomplete AST (no binding information available).
+ final IStatus[] resultingStatus= new IStatus[1];
+ logListener= new ILogListener() {
+ public void logging(IStatus status, String plugin) {
+ assertTrue("Only one status", resultingStatus[0] == null);
+ assertEquals("Expected status message",
+ "Error during computation of Annotate proposals: " +
+ "The type pack.age.Missing cannot be resolved.\n It is indirectly referenced from required .class files",
+ status.getMessage());
+ }
+ };
+ JavaPlugin.getDefault().getLog().addLogListener(logListener);
+ List<ICompletionProposal> list= collectAnnotateProposals(javaEditor, offset);
+
+ assertEquals("Expected number of proposals", 0, list.size());
+ } finally {
+ if (logListener != null) {
+ JavaPlugin.getDefault().getLog().removeLogListener(logListener);
+ }
+ JavaPlugin.getActivePage().closeAllEditors(false);
+ }
+ }
}
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest18.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest18.java
index d3fabd8..afe0ecc 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest18.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AnnotateAssistTest18.java
@@ -64,7 +64,7 @@
public void testAnnotateParameter_TypeArgument() throws Exception {
String X_PATH= "pack/age/X";
- String[] pathAndContents= new String[] {
+ String[] pathAndContents= new String[] {
X_PATH+".java",
"package pack.age;\n" +
"import java.util.List;\n" +
@@ -72,7 +72,7 @@
" public String test(int[] ints, List<String> list);\n" +
"}\n"
};
- addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_8);
+ addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_8, null);
IFile annotationFile= fJProject1.getProject().getFile(new Path(ANNOTATION_PATH).append(X_PATH+".eea"));
String initialContent=
@@ -134,7 +134,7 @@
public void testAnnotateParameter_ArrayOfPrimitive() throws Exception {
String X_PATH= "pack/age/X";
- String[] pathAndContents= new String[] {
+ String[] pathAndContents= new String[] {
X_PATH+".java",
"package pack.age;\n" +
"import java.util.List;\n" +
@@ -142,7 +142,7 @@
" public String test(int[] ints, List<String> list);\n" +
"}\n"
};
- addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_8);
+ addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_8, null);
IType type= fJProject1.findType(X_PATH.replace('/', '.'));
JavaEditor javaEditor= (JavaEditor) JavaUI.openInEditor(type);
@@ -167,7 +167,7 @@
public void testAnnotateParameter_WildcardBound() throws Exception {
String X_PATH= "pack/age/X";
- String[] pathAndContents= new String[] {
+ String[] pathAndContents= new String[] {
X_PATH+".java",
"package pack.age;\n" +
"import java.util.List;\n" +
@@ -175,7 +175,7 @@
" public String test(Object[] objects, List<? extends Number> list);\n" +
"}\n"
};
- addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_8);
+ addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_8, null);
IFile annotationFile= fJProject1.getProject().getFile(new Path(ANNOTATION_PATH).append(X_PATH+".eea"));
String initialContent=
@@ -241,7 +241,7 @@
public void testAnnotateParameter_Array2() throws Exception {
String X_PATH= "pack/age/X";
- String[] pathAndContents= new String[] {
+ String[] pathAndContents= new String[] {
X_PATH+".java",
"package pack.age;\n" +
"import java.util.List;\n" +
@@ -249,7 +249,7 @@
" public String test(int[][] ints, List<String> list);\n" +
"}\n"
};
- addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_8);
+ addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_8, null);
IFile annotationFile= fJProject1.getProject().getFile(new Path(ANNOTATION_PATH).append(X_PATH+".eea"));
String initialContent=
@@ -313,7 +313,7 @@
public void testAnnotateParameter_Array3() throws Exception {
String X_PATH= "pack/age/X";
- String[] pathAndContents= new String[] {
+ String[] pathAndContents= new String[] {
X_PATH+".java",
"package pack.age;\n" +
"import java.util.List;\n" +
@@ -321,7 +321,7 @@
" public String test(int[][] ints, List<String> list);\n" +
"}\n"
};
- addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_8);
+ addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_8, null);
IFile annotationFile= fJProject1.getProject().getFile(new Path(ANNOTATION_PATH).append(X_PATH+".eea"));
String initialContent=
@@ -387,7 +387,7 @@
public void _testAnnotateParameter_TypeParameter() throws Exception {
String X_PATH= "pack/age/X";
- String[] pathAndContents= new String[] {
+ String[] pathAndContents= new String[] {
X_PATH+".java",
"package pack.age;\n" +
"import java.util.List;\n" +
@@ -395,7 +395,7 @@
" public <X, T extends List<X>> X test(T list);\n" +
"}\n"
};
- addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_8);
+ addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_8, null);
IType type= fJProject1.findType(X_PATH.replace('/', '.'));
JavaEditor javaEditor= (JavaEditor) JavaUI.openInEditor(type);
@@ -449,7 +449,7 @@
public void testAnnotateField1() throws Exception {
String NODE_PATH= "pack/age/Node";
- String[] pathAndContents= new String[] {
+ String[] pathAndContents= new String[] {
NODE_PATH+".java",
"package pack.age;\n" +
"import java.util.List;\n" +
@@ -457,7 +457,7 @@
" List<Object[]> value;\n" +
"}\n"
};
- addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_5);
+ addLibrary(fJProject1, "lib.jar", "lib.zip", pathAndContents, ANNOTATION_PATH, JavaCore.VERSION_1_5, null);
IType type= fJProject1.findType(NODE_PATH.replace('/', '.'));
JavaEditor javaEditor= (JavaEditor) JavaUI.openInEditor(type);
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/JarUtil.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/JarUtil.java
index 275f2b2..02f2fe4 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/JarUtil.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/JarUtil.java
@@ -146,11 +146,30 @@
}
return result;
}
-/* inlined and simplified for JDT/UI */
+
+// should eventually be replaced by use of java.util.function.Predicate<CompilationResult>
+public interface ClassFileFilter {
+ boolean include(CompilationResult unitResult);
+}
+/* inlined and simplified / modified for JDT/UI */
private static class Requestor implements ICompilerRequestor {
public boolean hasErrors = false;
public String outputPath;
public String problemLog = "";
+ private ClassFileFilter classFileFilter= null;
+
+ public Requestor(ClassFileFilter classFileFilter) {
+ if (classFileFilter != null) {
+ this.classFileFilter = classFileFilter;
+ } else {
+ // default: all without errors
+ this.classFileFilter = new ClassFileFilter() {
+ public boolean include(CompilationResult unitResult) {
+ return (unitResult != null) && !unitResult.hasErrors();
+ }
+ };
+ }
+ }
public void acceptResult(CompilationResult compilationResult) {
this.hasErrors |= compilationResult.hasErrors();
@@ -158,7 +177,7 @@
outputClassFiles(compilationResult);
}
protected void outputClassFiles(CompilationResult unitResult) {
- if ((unitResult != null) && !unitResult.hasErrors()) {
+ if (this.classFileFilter.include(unitResult)) {
ClassFile[] classFiles = unitResult.getClassFiles();
if (this.outputPath != null) {
for (int i = 0, fileCount = classFiles.length; i < fileCount; i++) {
@@ -176,9 +195,9 @@
}
}
}
-public static void compile(String[] pathsAndContents, Map options, String[] classpath, String outputPath) {
+public static void compile(String[] pathsAndContents, Map options, String[] classpath, String outputPath, ClassFileFilter classFileFilter) {
IProblemFactory problemFactory = new DefaultProblemFactory(Locale.getDefault());
- Requestor requestor = new Requestor();
+ Requestor requestor = new Requestor(classFileFilter);
requestor.outputPath = outputPath.endsWith(File.separator) ? outputPath : outputPath + File.separator;
String[] classLibs = getJavaClassLibs();
@@ -229,12 +248,12 @@
output.close();
}
}
-public static void createJar(String[] pathsAndContents, String[] extraPathsAndContents, Map options, String[] classpath, String jarPath) throws IOException {
+public static void createJar(String[] pathsAndContents, String[] extraPathsAndContents, Map options, ClassFileFilter classFileFilter, String[] classpath, String jarPath) throws IOException {
String classesPath = getOutputDirectory() + File.separator + "classes";
File classesDir = new File(classesPath);
flushDirectoryContent(classesDir);
if (pathsAndContents != null) {
- compile(pathsAndContents, options, classpath, classesPath);
+ compile(pathsAndContents, options, classpath, classesPath, classFileFilter);
}
if (extraPathsAndContents != null) {
for (int i = 0, l = extraPathsAndContents.length; i < l; /* inc in loop */) {
@@ -245,12 +264,12 @@
}
zip(classesDir, jarPath);
}
-public static void createJar(String[] javaPathsAndContents, String[] extraPathsAndContents, String jarPath, String[] classpath, String compliance, Map options) throws IOException {
+public static void createJar(String[] javaPathsAndContents, String[] extraPathsAndContents, String jarPath, String[] classpath, String compliance, Map options, ClassFileFilter classFileFilter) throws IOException {
Map compileOptions = getCompileOptions(compliance);
if (options != null) {
compileOptions.putAll(options);
}
- createJar(javaPathsAndContents, extraPathsAndContents, compileOptions, classpath, jarPath);
+ createJar(javaPathsAndContents, extraPathsAndContents, compileOptions, classFileFilter, classpath, jarPath);
}
public static void createSourceZip(String[] pathsAndContents, String zipPath) throws IOException {
String sourcesPath = getOutputDirectory() + File.separator + "sources";
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/ExternalNullAnnotationChangeProposals.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/ExternalNullAnnotationChangeProposals.java
index 670d2c4..501918b 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/ExternalNullAnnotationChangeProposals.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/ExternalNullAnnotationChangeProposals.java
@@ -31,6 +31,7 @@
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
@@ -49,9 +50,11 @@
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.ArrayType;
+import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Dimension;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.IMethodBinding;
@@ -65,6 +68,7 @@
import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeParameter;
+import org.eclipse.jdt.core.dom.VariableDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.WildcardType;
import org.eclipse.jdt.core.util.ExternalAnnotationUtil;
@@ -79,6 +83,7 @@
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
+import org.eclipse.jdt.internal.ui.JavaUIStatus;
import org.eclipse.jdt.internal.ui.text.correction.ExternalNullAnnotationQuickAssistProcessor;
import org.eclipse.jdt.internal.ui.text.correction.IProposalRelevance;
@@ -277,6 +282,57 @@
}
}
+ static class MissingBindingException extends RuntimeException {
+ private static final long serialVersionUID= 1L;
+ ASTNode fNode;
+ MissingBindingException(ASTNode/*Type or TypeParameter or MethodDeclaration*/ node) {
+ fNode= node;
+ }
+ @Override
+ public String getMessage() {
+ // check if compilation may have been aborted due to classpath trouble / unreportable problem:
+ ASTNode cu= ASTNodes.getParent(fNode, ASTNode.COMPILATION_UNIT);
+ if (cu instanceof CompilationUnit) {
+ for (IProblem problem : ((CompilationUnit) cu).getProblems()) {
+ if (problem.getID() == IProblem.IsClassPathCorrect || problem.getOriginatingFileName() == null)
+ return problem.getMessage();
+ }
+ }
+ switch (fNode.getNodeType()) {
+ case ASTNode.METHOD_DECLARATION:
+ return "Could not resolve method "+fNode.toString(); //$NON-NLS-1$
+ case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
+ return "Could not resolve field "+fNode.toString(); //$NON-NLS-1$
+ default:
+ return "Could not resolve type "+fNode.toString(); //$NON-NLS-1$
+ }
+ }
+ }
+
+ static ITypeBinding resolveBinding(TypeParameter type) {
+ ITypeBinding binding= type.resolveBinding();
+ if (binding == null) throw new MissingBindingException(type);
+ return binding;
+ }
+
+ static ITypeBinding resolveBinding(Type type) {
+ ITypeBinding binding= type.resolveBinding();
+ if (binding == null) throw new MissingBindingException(type);
+ return binding;
+ }
+
+ static IMethodBinding resolveBinding(MethodDeclaration method) {
+ IMethodBinding binding= method.resolveBinding();
+ if (binding == null) throw new MissingBindingException(method);
+ return binding;
+ }
+
+ static IVariableBinding resolveBinding(VariableDeclaration variable) {
+ IVariableBinding binding= variable.resolveBinding();
+ if (binding == null) throw new MissingBindingException(variable);
+ return binding;
+ }
+
/* Quick assist on class file, propose changes an any type detail. */
public static void collectExternalAnnotationProposals(ICompilationUnit cu, ASTNode coveringNode, int offset, ArrayList<IJavaCompletionProposal> resultingCollection) {
@@ -316,42 +372,47 @@
if (!(outer.getNodeType() == ASTNode.PARAMETERIZED_TYPE && inner.getParent() == outer))
return;
}
- if (outer instanceof Type) {
- ITypeBinding typeBinding= ((Type) outer).resolveBinding();
- if (typeBinding != null && typeBinding.isPrimitive())
- return;
- outer.accept(rendererNonNull);
- outer.accept(rendererNullable);
- outer.accept(rendererRemove);
- } else {
- List<?> siblingList= (List<?>) outer.getParent().getStructuralProperty(outer.getLocationInParent());
- rendererNonNull.visitTypeParameters(siblingList);
- rendererNullable.visitTypeParameters(siblingList);
- rendererRemove.visitTypeParameters(siblingList);
- }
-
- StructuralPropertyDescriptor locationInParent= outer.getLocationInParent();
- ProposalCreator creator= null;
- if (locationInParent == MethodDeclaration.RETURN_TYPE2_PROPERTY) {
- MethodDeclaration method= (MethodDeclaration) ASTNodes.getParent(coveringNode, MethodDeclaration.class);
- creator= new ReturnProposalCreator(cu, method.resolveBinding());
- } else if (locationInParent == SingleVariableDeclaration.TYPE_PROPERTY) {
- ASTNode param= outer.getParent();
- if (param.getLocationInParent() == MethodDeclaration.PARAMETERS_PROPERTY) {
+ try {
+ if (outer instanceof Type) {
+ ITypeBinding typeBinding= resolveBinding((Type) outer);
+ if (typeBinding.isPrimitive())
+ return;
+ outer.accept(rendererNonNull);
+ outer.accept(rendererNullable);
+ outer.accept(rendererRemove);
+ } else {
+ List<?> siblingList= (List<?>) outer.getParent().getStructuralProperty(outer.getLocationInParent());
+ rendererNonNull.visitTypeParameters(siblingList);
+ rendererNullable.visitTypeParameters(siblingList);
+ rendererRemove.visitTypeParameters(siblingList);
+ }
+
+ StructuralPropertyDescriptor locationInParent= outer.getLocationInParent();
+ ProposalCreator creator= null;
+ if (locationInParent == MethodDeclaration.RETURN_TYPE2_PROPERTY) {
MethodDeclaration method= (MethodDeclaration) ASTNodes.getParent(coveringNode, MethodDeclaration.class);
- int paramIdx= method.parameters().indexOf(param);
- if (paramIdx != -1)
- creator= new ParameterProposalCreator(cu, method.resolveBinding(), paramIdx);
+ creator= new ReturnProposalCreator(cu, resolveBinding(method));
+ } else if (locationInParent == SingleVariableDeclaration.TYPE_PROPERTY) {
+ ASTNode param= outer.getParent();
+ if (param.getLocationInParent() == MethodDeclaration.PARAMETERS_PROPERTY) {
+ MethodDeclaration method= (MethodDeclaration) ASTNodes.getParent(coveringNode, MethodDeclaration.class);
+ int paramIdx= method.parameters().indexOf(param);
+ if (paramIdx != -1)
+ creator= new ParameterProposalCreator(cu, resolveBinding(method), paramIdx);
+ }
+ } else if (locationInParent == FieldDeclaration.TYPE_PROPERTY) {
+ FieldDeclaration field= (FieldDeclaration) ASTNodes.getParent(coveringNode, FieldDeclaration.class);
+ if (field.fragments().size() > 0) {
+ VariableDeclarationFragment fragment= (VariableDeclarationFragment) field.fragments().get(0);
+ creator= new FieldProposalCreator(cu, resolveBinding(fragment));
+ }
}
- } else if (locationInParent == FieldDeclaration.TYPE_PROPERTY) {
- FieldDeclaration field= (FieldDeclaration) ASTNodes.getParent(coveringNode, FieldDeclaration.class);
- if (field.fragments().size() > 0) {
- VariableDeclarationFragment fragment= (VariableDeclarationFragment) field.fragments().get(0);
- creator= new FieldProposalCreator(cu, fragment.resolveBinding());
+ if (creator != null) {
+ createProposalsForType(cu, inner, offset, rendererNonNull, rendererNullable, rendererRemove, creator, resultingCollection);
}
- }
- if (creator != null) {
- createProposalsForType(cu, inner, offset, rendererNonNull, rendererNullable, rendererRemove, creator, resultingCollection);
+ } catch (MissingBindingException mbe) {
+ JavaPlugin.log(JavaUIStatus.createError(IStatus.ERROR, "Error during computation of Annotate proposals: "+mbe.getMessage(), mbe)); //$NON-NLS-1$
+ return;
}
}
@@ -550,7 +611,7 @@
fBuffer.append('L');
if (type == fFocusType || type.getType() == fFocusType)
fBuffer.append(fAnnotation);
- fBuffer.append(binaryName(type.resolveBinding()));
+ fBuffer.append(binaryName(resolveBinding(type)));
fBuffer.append('<');
for (Object arg : type.typeArguments())
((Type) arg).accept(this);
@@ -601,7 +662,7 @@
Type classBound= null;
for (Object bound : parameter.typeBounds()) {
Type typeBound= (Type) bound;
- if (typeBound.resolveBinding().isClass()) {
+ if (resolveBinding(typeBound).isClass()) {
classBound= typeBound;
break;
}
@@ -610,7 +671,7 @@
fBuffer.append(':');
classBound.accept(this);
} else {
- ITypeBinding typeBinding= parameter.resolveBinding();
+ ITypeBinding typeBinding= resolveBinding(parameter);
fBuffer.append(":L").append(binaryName(typeBinding.getSuperclass())).append(';'); //$NON-NLS-1$
}
for (Object bound : parameter.typeBounds()) {
@@ -625,7 +686,7 @@
@Override
public boolean visit(SimpleType type) {
- ITypeBinding typeBinding= type.resolveBinding();
+ ITypeBinding typeBinding= resolveBinding(type);
if (typeBinding.isTypeVariable()) {
fBuffer.append('T');
if (fFocusType == type)
@@ -643,10 +704,10 @@
@Override
public boolean visit(PrimitiveType node) {
// not a legal focus type, but could be array element type
- fBuffer.append(node.resolveBinding().getBinaryName());
+ fBuffer.append(resolveBinding(node).getBinaryName());
return false;
}
-
+
String binaryName(ITypeBinding type) {
return type.getBinaryName().replace('.', '/');
}