blob: b4cb3e7d3ca1132d428c0ef1522ac82e9e919510 [file] [log] [blame]
/*******************************************************************************
* 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*/);
}
}