Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Herrmann2021-02-09 12:01:47 +0000
committerStephan Herrmann2021-02-09 13:00:20 +0000
commit4c1496dfbd11b3ad81e483bf468882e56f00e870 (patch)
tree1b96271752e433b436a2692727f85da0b70378ba
parent7744b1ebb9582f7f915951b6ebfc4a79830e785e (diff)
downloadeclipse.jdt.core-4c1496dfbd11b3ad81e483bf468882e56f00e870.tar.gz
eclipse.jdt.core-4c1496dfbd11b3ad81e483bf468882e56f00e870.tar.xz
eclipse.jdt.core-4c1496dfbd11b3ad81e483bf468882e56f00e870.zip
Bug 571055 - [null][batch] EEA for sources also during batch compilationI20210210-1800I20210210-0910I20210209-1800
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationBatchCompilerTest.java94
-rw-r--r--org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java2
-rw-r--r--org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java18
-rw-r--r--org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java23
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java5
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SourceFile.java2
8 files changed, 141 insertions, 7 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationBatchCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationBatchCompilerTest.java
index f1aa48c907..2a4158b899 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationBatchCompilerTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationBatchCompilerTest.java
@@ -1022,4 +1022,98 @@ public class NullAnnotationBatchCompilerTest extends AbstractBatchCompilerTest {
"3 problems (3 warnings)\n",
true);
}
+ public void testBug571055_explicit() throws IOException {
+ runTestBug571055(false, false);
+ }
+ public void testBug571055_inherit() throws IOException {
+ runTestBug571055(true, false);
+ }
+ public void testBug571055_dedicatedAnnotationPath() throws IOException {
+ runTestBug571055(false, true);
+ }
+ private void runTestBug571055(boolean inheritAnnotations, boolean dedicatedAnnotationPath) throws IOException {
+ String annots_dir = Util.getOutputDirectory() + File.separator + "annots";
+ String annots_api = annots_dir + File.separator + "api";
+ new File(annots_api).mkdirs();
+ Util.createFile(
+ annots_api + File.separator + "Foo.eea",
+ "class api/Foo\n" +
+ "m\n" +
+ " (Ljava/lang/String;)Ljava/lang/String;\n" +
+ " (L1java/lang/String;)L0java/lang/String;\n");
+ if (!inheritAnnotations) {
+ // 'manually' establish consistency:
+ String annots_impl = annots_dir + File.separator + "impl";
+ new File(annots_impl).mkdirs();
+ Util.createFile(
+ annots_impl + File.separator + "FooImpl.eea",
+ "class impl/FooImpl\n" +
+ "m\n" +
+ " (Ljava/lang/String;)Ljava/lang/String;\n" +
+ " (L1java/lang/String;)L0java/lang/String;\n");
+ }
+
+ String[] testFiles = new String[] {
+ "java/lang/annotation/ElementType.java",
+ ELEMENT_TYPE_18_CONTENT,
+ "org/eclipse/jdt/annotation/NonNull.java",
+ NONNULL_ANNOTATION_18_CONTENT,
+ "org/eclipse/jdt/annotation/Nullable.java",
+ NULLABLE_ANNOTATION_18_CONTENT,
+ "org/eclipse/jdt/annotation/DefaultLocation.java",
+ DEFAULT_LOCATION_CONTENT,
+ "api/Foo.java",
+ "package api;\n" +
+ "public interface Foo {\n" +
+ " String m(String a);\n" +
+ "}\n",
+ "impl/FooImpl.java",
+ "package impl;\n" +
+ "import api.Foo;\n" +
+ "public class FooImpl implements Foo {\n" +
+ " public String m(String a) { return null; }\n" + // ensure Foo & FooImpl are seen with consistent nullness
+ "}\n",
+ "test1/Test1.java",
+ "package test1;\n" +
+ "\n" +
+ "import api.Foo;\n" +
+ "\n" +
+ "public class Test1 {\n" +
+ " void test(Foo api) {\n" +
+ " String result = api.m(null);\n" +
+ " System.out.println(result.toUpperCase());\n" +
+ " }\n" +
+ "}\n"
+ };
+
+ String commandLine;
+ if (dedicatedAnnotationPath) {
+ commandLine = "-annotationpath \"" + annots_dir + "\" " +
+ " -1.8 -proc:none -err:+nullAnnot -warn:+null " +
+ (inheritAnnotations ? " -warn:+inheritNullAnnot ": "") +
+ " \"" + OUTPUT_DIR + "\"";
+ } else {
+ commandLine = "-annotationpath CLASSPATH " +
+ " -1.8 -proc:none -err:+nullAnnot -warn:+null " +
+ (inheritAnnotations ? " -warn:+inheritNullAnnot ": "") +
+ " -classpath \"" + annots_dir + "\" " +
+ " \"" + OUTPUT_DIR + "\"";
+ }
+
+ // expect eea-motivated problems in Test1 but no in FooImpl:
+ String expectedCompilerMessage =
+ "----------\n" +
+ "1. ERROR in " + OUTPUT_DIR + File.separator + "test1" + File.separator + "Test1.java (at line 7)\n" +
+ " String result = api.m(null);\n" +
+ " ^^^^\n" +
+ "Null type mismatch: required '@NonNull String' but the provided value is null\n" +
+ "----------\n" +
+ "2. WARNING in " + OUTPUT_DIR + File.separator + "test1" + File.separator + "Test1.java (at line 8)\n" +
+ " System.out.println(result.toUpperCase());\n" +
+ " ^^^^^^\n" +
+ "Potential null pointer access: The variable result may be null at this location\n" +
+ "----------\n" +
+ "2 problems (1 error, 1 warning)\n";
+ this.runNegativeTest(testFiles, commandLine, "", expectedCompilerMessage, false);
+ }
}
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java
index 1fcce4beec..f04669c6cf 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java
@@ -156,6 +156,8 @@ public NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageN
}
@Override
public boolean hasAnnotationFileFor(String qualifiedTypeName) {
+ if (this.zipFile == null)
+ return false;
return this.zipFile.getEntry(qualifiedTypeName+ExternalAnnotationProvider.ANNOTATION_FILE_SUFFIX) != null;
}
@Override
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java
index 80d9d1d20f..aa9c1d100e 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java
@@ -15,6 +15,7 @@ package org.eclipse.jdt.internal.compiler.batch;
import java.io.File;
import java.io.IOException;
+import java.util.function.Function;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
@@ -39,6 +40,11 @@ public class CompilationUnit implements ICompilationUnit {
// be written.
private boolean ignoreOptionalProblems;
private ModuleBinding moduleBinding;
+ /**
+ * annotation path can only be retrieved once the qualified type name is known.
+ * This is the provided function for computing the annotation path from that type name.
+ */
+ private Function<String,String> annotationPathProvider;
public CompilationUnit(char[] contents, String fileName, String encoding) {
this(contents, fileName, encoding, null);
@@ -49,6 +55,12 @@ public CompilationUnit(char[] contents, String fileName, String encoding,
}
public CompilationUnit(char[] contents, String fileName, String encoding,
String destinationPath, boolean ignoreOptionalProblems, String modName) {
+ this(contents, fileName, encoding, destinationPath, ignoreOptionalProblems, modName, null);
+}
+public CompilationUnit(char[] contents, String fileName, String encoding, String destinationPath,
+ boolean ignoreOptionalProblems, String modName, Function<String,String> annotationPathProvider)
+{
+ this.annotationPathProvider = annotationPathProvider;
this.contents = contents;
if (modName != null)
this.module = modName.toCharArray();
@@ -130,4 +142,10 @@ public ModuleBinding module(LookupEnvironment rootEnvironment) {
public String getDestinationPath() {
return this.destinationPath;
}
+@Override
+public String getExternalAnnotationPath(String qualifiedTypeName) {
+ if (this.annotationPathProvider != null)
+ return this.annotationPathProvider.apply(qualifiedTypeName);
+ return null;
+}
}
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
index 8ea28566b4..b88205fa84 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
@@ -72,6 +72,7 @@ import java.util.Properties;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.StringTokenizer;
+import java.util.function.Function;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.core.compiler.CharOperation;
@@ -91,6 +92,7 @@ import org.eclipse.jdt.internal.compiler.batch.ModuleFinder.AddExport;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationProvider;
import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.eclipse.jdt.internal.compiler.env.AccessRule;
import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
@@ -3439,9 +3441,28 @@ public CompilationUnit[] getCompilationUnits() {
// if we got exception during canonicalization, fall back to the name that was specified
fileName = this.filenames[i];
}
+ Function<String,String> annotationPathProvider = null;
+ if (this.annotationsFromClasspath) {
+ annotationPathProvider = (String qualifiedTypeName) -> {
+ for (Classpath classpathEntry : this.checkedClasspaths) {
+ if (classpathEntry.hasAnnotationFileFor(qualifiedTypeName.replace('.', '/')))
+ return classpathEntry.getPath();
+ }
+ return null;
+ };
+ } else if (this.annotationPaths != null) {
+ annotationPathProvider = (String qualifiedTypeName) -> {
+ String eeaFileName = '/'+qualifiedTypeName.replace('.', '/')+ExternalAnnotationProvider.ANNOTATION_FILE_SUFFIX;
+ for (String annotationPath : this.annotationPaths) {
+ if (new File(annotationPath+eeaFileName).exists())
+ return annotationPath;
+ }
+ return null;
+ };
+ }
units[i] = new CompilationUnit(null, fileName, encoding, this.destinationPaths[i],
shouldIgnoreOptionalProblems(this.ignoreOptionalProblemsFromFolders, fileName.toCharArray()),
- this.modNames[i]);
+ this.modNames[i], annotationPathProvider);
}
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java
index 5e2cdfa662..7d846729cf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java
@@ -78,6 +78,6 @@ default String getDestinationPath() {
* Answers a path for external annotations that has been configured for
* the providing classpath entry, or <code>null</code>.
*/
-default String getExternalAnnotationPath() { return null; }
+default String getExternalAnnotationPath(String qualifiedTypeName) { return null; }
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
index a2affaf198..fee27d3e8f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
@@ -525,7 +525,7 @@ public class ClassScope extends Scope {
environment().setAccessRestriction(sourceType, accessRestriction);
ICompilationUnit compilationUnit = this.referenceContext.compilationResult.getCompilationUnit();
if (compilationUnit != null && compilerOptions().isAnnotationBasedNullAnalysisEnabled) {
- String externalAnnotationPath = compilationUnit.getExternalAnnotationPath();
+ String externalAnnotationPath = compilationUnit.getExternalAnnotationPath(CharOperation.toString(sourceType.compoundName));
if (externalAnnotationPath != null) {
ExternalAnnotationSuperimposer.apply(sourceType, externalAnnotationPath);
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
index 7a1b542b22..d2b9fcc2e9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
@@ -2834,15 +2834,14 @@ private MethodBinding resolveTypesWithSuspendedTempErrorHandlingPolicy(MethodBin
}
}
}
+ if (this.externalAnnotationProvider != null)
+ ExternalAnnotationSuperimposer.annotateMethodBinding(method, arguments, this.externalAnnotationProvider, this.environment);
if (compilerOptions.storeAnnotations)
createArgumentBindings(method, compilerOptions); // need annotations resolved already at this point
if (foundReturnTypeProblem)
return method; // but its still unresolved with a null return type & is still connected to its method declaration
method.modifiers &= ~ExtraCompilerModifiers.AccUnresolved;
- if (this.externalAnnotationProvider != null) {
- ExternalAnnotationSuperimposer.annotateMethodBinding(method, arguments, this.externalAnnotationProvider, this.environment);
- }
return method;
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SourceFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SourceFile.java
index 891a4ec581..289d2f5d50 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SourceFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SourceFile.java
@@ -118,7 +118,7 @@ public boolean ignoreOptionalProblems() {
return this.sourceLocation.ignoreOptionalProblems;
}
@Override
-public String getExternalAnnotationPath() {
+public String getExternalAnnotationPath(String qualifiedTypeName) {
return this.sourceLocation.externalAnnotationPath;
}
String typeLocator() {

Back to the top