| /******************************************************************************* |
| * Copyright (c) 2010, 2018 GK Software AG and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Stephan Herrmann - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.core.tests.compiler.regression; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.FileLocator; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
| import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; |
| import org.osgi.framework.Bundle; |
| |
| @SuppressWarnings({ "unchecked", "rawtypes" }) |
| public abstract class AbstractNullAnnotationTest extends AbstractComparableTest { |
| |
| // class libraries including our default null annotation types: |
| String[] LIBS; |
| |
| // names and content of custom annotations used in a few tests: |
| static final String CUSTOM_NONNULL_NAME = "org/foo/NonNull.java"; |
| static final String CUSTOM_NONNULL_CONTENT = |
| "package org.foo;\n" + |
| "import static java.lang.annotation.ElementType.*;\n" + |
| "import java.lang.annotation.*;\n" + |
| "@Retention(RetentionPolicy.CLASS)\n" + |
| "@Target({METHOD,PARAMETER,LOCAL_VARIABLE})\n" + |
| "public @interface NonNull {\n" + |
| "}\n"; |
| static final String CUSTOM_NONNULL_CONTENT_JSR308 = |
| "package org.foo;\n" + |
| "import static java.lang.annotation.ElementType.*;\n" + |
| "import java.lang.annotation.*;\n" + |
| "@Retention(RetentionPolicy.CLASS)\n" + |
| "@Target({METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})\n" + |
| "public @interface NonNull {\n" + |
| "}\n"; |
| static final String CUSTOM_NULLABLE_NAME = "org/foo/Nullable.java"; |
| static final String CUSTOM_NULLABLE_CONTENT = "package org.foo;\n" + |
| "import static java.lang.annotation.ElementType.*;\n" + |
| "import java.lang.annotation.*;\n" + |
| "@Retention(RetentionPolicy.CLASS)\n" + |
| "@Target({METHOD,PARAMETER,LOCAL_VARIABLE})\n" + |
| "public @interface Nullable {\n" + |
| "}\n"; |
| static final String CUSTOM_NULLABLE_CONTENT_JSR308 = "package org.foo;\n" + |
| "import static java.lang.annotation.ElementType.*;\n" + |
| "import java.lang.annotation.*;\n" + |
| "@Retention(RetentionPolicy.CLASS)\n" + |
| "@Target({METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})\n" + |
| "public @interface Nullable {\n" + |
| "}\n"; |
| static final String CUSTOM_NNBD_NAME = "org/foo/NonNullByDefault.java"; |
| static final String CUSTOM_NNBD_CONTENT = "package org.foo;\n" + |
| "import java.lang.annotation.*;\n" + |
| "import static java.lang.annotation.ElementType.*;\n" + |
| "@Retention(RetentionPolicy.CLASS)\n" + |
| "@Target({PACKAGE, TYPE, METHOD, CONSTRUCTOR })\n" + |
| "public @interface NonNullByDefault {\n" + // has no details, so default default locations should be applied |
| "}\n"; |
| |
| public AbstractNullAnnotationTest(String name) { |
| super(name); |
| } |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| setUpAnnotationLib(); |
| } |
| |
| /** |
| * @deprecated indirectly uses deprecated class PackageAdmin |
| */ |
| protected void setUpAnnotationLib() throws IOException { |
| if (this.LIBS == null) { |
| String[] defaultLibs = getDefaultClassPaths(); |
| int len = defaultLibs.length; |
| this.LIBS = new String[len+1]; |
| System.arraycopy(defaultLibs, 0, this.LIBS, 0, len); |
| String version = this.complianceLevel >= ClassFileConstants.JDK1_8 ? "[2.0.0,3.0.0)" : "[1.1.0,2.0.0)"; |
| Bundle[] bundles = org.eclipse.jdt.core.tests.compiler.Activator.getPackageAdmin().getBundles("org.eclipse.jdt.annotation", version); |
| File bundleFile = FileLocator.getBundleFile(bundles[0]); |
| if (bundleFile.isDirectory()) |
| this.LIBS[len] = bundleFile.getPath()+"/bin"; |
| else |
| this.LIBS[len] = bundleFile.getPath(); |
| } |
| } |
| |
| // Conditionally augment problem detection settings |
| static boolean setNullRelatedOptions = true; |
| |
| @Override |
| protected Map getCompilerOptions() { |
| Map defaultOptions = super.getCompilerOptions(); |
| if (setNullRelatedOptions) { |
| defaultOptions.put(JavaCore.COMPILER_PB_NULL_REFERENCE, JavaCore.ERROR); |
| defaultOptions.put(JavaCore.COMPILER_PB_POTENTIAL_NULL_REFERENCE, JavaCore.ERROR); |
| defaultOptions.put(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK, JavaCore.ERROR); |
| defaultOptions.put(JavaCore.COMPILER_PB_INCLUDE_ASSERTS_IN_NULL_ANALYSIS, JavaCore.ENABLED); |
| |
| defaultOptions.put(JavaCore.COMPILER_PB_MISSING_OVERRIDE_ANNOTATION_FOR_INTERFACE_METHOD_IMPLEMENTATION, JavaCore.DISABLED); |
| |
| // enable null annotations: |
| defaultOptions.put(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED); |
| |
| defaultOptions.put(CompilerOptions.OPTION_PessimisticNullAnalysisForFreeTypeVariables, JavaCore.ERROR); |
| defaultOptions.put(CompilerOptions.OPTION_ReportNonNullTypeVariableFromLegacyInvocation, JavaCore.WARNING); |
| |
| // leave other new options at these defaults: |
| // defaultOptions.put(CompilerOptions.OPTION_ReportNullContractViolation, JavaCore.ERROR); |
| // defaultOptions.put(CompilerOptions.OPTION_ReportPotentialNullContractViolation, JavaCore.ERROR); |
| // defaultOptions.put(CompilerOptions.OPTION_ReportNullContractInsufficientInfo, CompilerOptions.WARNING); |
| |
| // defaultOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "org.eclipse.jdt.annotation.Nullable"); |
| // defaultOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "org.eclipse.jdt.annotation.NonNull"); |
| } |
| return defaultOptions; |
| } |
| /** Test expecting a null-error from ecj, none from javac. */ |
| protected void runNegativeNullTest(String[] sourceFiles, String expectedCompileError, String[] libs, boolean shouldFlush, Map options) { |
| runNegativeTest( |
| sourceFiles, |
| expectedCompileError, |
| libs, |
| shouldFlush, |
| options, |
| null /* do not check error string */, |
| JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
| } |
| /** Test with JDT null annotations, expecting a null-error from ecj, none from javac. */ |
| void runNegativeTestWithLibs(String[] testFiles, String expectedErrorLog) { |
| runNegativeTestWithLibs( |
| false /*shouldFlush*/, |
| testFiles, |
| getCompilerOptions(), |
| expectedErrorLog, |
| false /*skipJavac*/); |
| } |
| /** Test with JDT null annotations, expecting a null-error from ecj, none from javac. */ |
| void runNegativeTestWithLibs(boolean shouldFlushOutputDirectory, String[] testFiles, Map customOptions, String expectedErrorLog) { |
| runNegativeTestWithLibs( |
| shouldFlushOutputDirectory, |
| testFiles, |
| customOptions, |
| expectedErrorLog, |
| // runtime options |
| false); |
| } |
| /** Test with JDT null annotations, expecting a null-error from ecj, none from javac. */ |
| void runNegativeTestWithLibs(boolean shouldFlushOutputDirectory, String[] testFiles, Map customOptions, |
| String expectedErrorLog, boolean skipJavaC) { |
| runNegativeTest( |
| shouldFlushOutputDirectory, |
| testFiles, |
| this.LIBS, |
| customOptions, |
| expectedErrorLog, |
| // runtime options |
| skipJavaC ? JavacTestOptions.SKIP : |
| JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
| } |
| //{ObjectTeams: make visible to downstream: |
| protected |
| // SH} |
| void runNegativeTestWithLibs(String[] testFiles, Map customOptions, String expectedErrorLog) { |
| runNegativeTestWithLibs(false /* flush output directory */, testFiles, customOptions, expectedErrorLog); |
| } |
| //{ObjectTeams: make visible to downstream: |
| protected |
| // SH} |
| void runNegativeTestWithLibs(String[] testFiles, Map customOptions, String expectedErrorLog, boolean skipJavac) { |
| runNegativeTestWithLibs(false /* flush output directory */, testFiles, customOptions, expectedErrorLog, skipJavac); |
| } |
| //{ObjectTeams: make visible to downstream: |
| protected |
| // SH} |
| void runConformTestWithLibs(String[] testFiles, Map customOptions, String expectedCompilerLog) { |
| runConformTestWithLibs(true /* flush output directory */, testFiles, customOptions, expectedCompilerLog); |
| } |
| //{ObjectTeams: make visible to downstream: |
| protected |
| // SH} |
| void runConformTestWithLibs(String[] testFiles, Map customOptions, String expectedCompilerLog, String expectedOutput) { |
| runConformTestWithLibs(true/* flush output directory */, testFiles, customOptions, expectedCompilerLog, expectedOutput); |
| } |
| void runConformTestWithLibs(boolean shouldFlushOutputDirectory, String[] testFiles, Map customOptions, |
| String expectedCompilerLog, String expectedOutput) { |
| runConformTest( |
| shouldFlushOutputDirectory, |
| testFiles, |
| this.LIBS, |
| customOptions, |
| expectedCompilerLog, |
| expectedOutput, |
| "",/* expected error */ |
| JavacTestOptions.DEFAULT); |
| } |
| void runConformTestWithLibs(boolean shouldFlushOutputDirectory, String[] testFiles, Map customOptions, String expectedCompilerLog) { |
| runConformTest( |
| shouldFlushOutputDirectory, |
| testFiles, |
| this.LIBS, |
| customOptions, |
| expectedCompilerLog, |
| "",/* expected output */ |
| "",/* expected error */ |
| JavacTestOptions.DEFAULT); |
| } |
| /** Test with JDT null annotations, expecting a null-warning from ecj, none from javac. */ |
| void runWarningTestWithLibs(boolean shouldFlushOutputDirectory, String[] testFiles, |
| Map customOptions, String expectedCompilerLog) |
| { |
| runWarningTestWithLibs(shouldFlushOutputDirectory, testFiles, customOptions, expectedCompilerLog, ""); |
| } |
| void runWarningTestWithLibs(boolean shouldFlushOutputDirectory, String[] testFiles, |
| Map customOptions, String expectedCompilerLog, String expectedOutput) |
| { |
| runConformTest( |
| shouldFlushOutputDirectory, |
| testFiles, |
| this.LIBS, |
| customOptions, |
| expectedCompilerLog, |
| expectedOutput, |
| "",/* expected error */ |
| JavacTestOptions.Excuse.EclipseHasSomeMoreWarnings); |
| } |
| void runConformTest(String[] testFiles, Map customOptions, String expectedOutputString) { |
| runConformTest( |
| testFiles, |
| expectedOutputString, |
| null /*classLibraries*/, |
| true /*shouldFlushOutputDirectory*/, |
| null /*vmArguments*/, |
| customOptions, |
| null /*customRequestor*/); |
| |
| } |
| } |