Make System.getProperty fail at compile time for undefined properties.
System.getProperty is designed to enable dead code stripping, so give an
early error if a property is used but not declared.
This patch also refactors the test infrastructure a bit to allow some
reused of CheckerTests by UnifyAstTest.
Change-Id: I7b24575f14e76ed74c32872bd9699155fa8c9cdd
diff --git a/dev/core/src/com/google/gwt/dev/javac/testing/impl/JavaResourceBase.java b/dev/core/src/com/google/gwt/dev/javac/testing/impl/JavaResourceBase.java
index 57138a9..db87a1d 100644
--- a/dev/core/src/com/google/gwt/dev/javac/testing/impl/JavaResourceBase.java
+++ b/dev/core/src/com/google/gwt/dev/javac/testing/impl/JavaResourceBase.java
@@ -345,6 +345,16 @@
" String[] value();",
"}");
+ public static final MockJavaResource SYSTEM =
+ createMockJavaResource("java.lang.System",
+ "package java.lang;",
+ "public class System {",
+ " public static String getProperty(String propertyName) { return null; }",
+ " public static String getProperty(String propertyName, String defaultValue) {",
+ " return defaultValue;",
+ " }",
+ "}");
+
public static final MockJavaResource THROWABLE =
createMockJavaResource("java.lang.Throwable",
"package java.lang;",
@@ -400,7 +410,7 @@
CLASS_NOT_FOUND_EXCEPTION, CLONEABLE, COLLECTION, COMPARABLE, DOUBLE, ENUM, EXCEPTION,
ERROR, FUNCTIONALINTERFACE, FLOAT, INTEGER, IS_SERIALIZABLE, JAVASCRIPTEXCEPTION,
JAVASCRIPTOBJECT, LIST, LONG, MAP, NO_CLASS_DEF_FOUND_ERROR, NUMBER, OBJECT,
- RUNTIME_EXCEPTION, SERIALIZABLE, SHORT, STRING, STRING_BUILDER, SUPPRESS_WARNINGS,
+ RUNTIME_EXCEPTION, SERIALIZABLE, SHORT, STRING, STRING_BUILDER, SUPPRESS_WARNINGS, SYSTEM,
THROWABLE, SPECIALIZE_METHOD, JSTYPE, JSTYPEPROTOTYPE, JSEXPORT, JSPROPERTY, JSFUNCTION};
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/AstConstructor.java b/dev/core/src/com/google/gwt/dev/jjs/AstConstructor.java
index 95a0c87..0531200 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/AstConstructor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/AstConstructor.java
@@ -40,19 +40,25 @@
*/
public class AstConstructor {
+ public static JProgram construct(TreeLogger logger, final CompilationState state,
+ PrecompileTaskOptions options, ConfigurationProperties config)
+ throws UnableToCompleteException {
+ CompilerContext compilerContext = new CompilerContext.Builder().options(options)
+ .minimalRebuildCache(new NullRebuildCache()).build();
+ return construct(logger, state, compilerContext, config);
+ }
+
/**
* Construct an simple AST representing an entire {@link CompilationState}.
* Does not support deferred binding. Implementation mostly copied from
* {@link JavaToJavaScriptCompiler}.
*/
public static JProgram construct(TreeLogger logger, final CompilationState state,
- PrecompileTaskOptions options, ConfigurationProperties config) throws UnableToCompleteException {
+ CompilerContext compilerContext, ConfigurationProperties config)
+ throws UnableToCompleteException {
InternalCompilerException.preload();
- CompilerContext compilerContext = new CompilerContext.Builder().options(options)
- .minimalRebuildCache(new NullRebuildCache()).build();
-
PrecompilationContext precompilationContext = new PrecompilationContext(
new RebindPermutationOracle() {
@Override
@@ -93,7 +99,7 @@
* TODO: If we defer this until later, we could maybe use the results of the
* assertions to enable more optimizations.
*/
- if (options.isEnableAssertions()) {
+ if (compilerContext.getOptions().isEnableAssertions()) {
// Turn into assertion checking calls.
AssertionNormalizer.exec(jprogram);
} else {
@@ -101,7 +107,7 @@
AssertionRemover.exec(jprogram);
}
- if (options.isRunAsyncEnabled()) {
+ if (compilerContext.getOptions().isRunAsyncEnabled()) {
ReplaceRunAsyncs.exec(logger, jprogram);
if (config != null) {
CodeSplitters.pickInitialLoadSequence(logger, jprogram, config);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
index 3a939d9..88f4f93 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
@@ -21,6 +21,8 @@
import com.google.gwt.dev.CompilerContext;
import com.google.gwt.dev.MinimalRebuildCache;
import com.google.gwt.dev.Permutation;
+import com.google.gwt.dev.cfg.ConfigurationProperty;
+import com.google.gwt.dev.cfg.Property;
import com.google.gwt.dev.javac.CompilationProblemReporter;
import com.google.gwt.dev.javac.CompilationState;
import com.google.gwt.dev.javac.CompilationUnit;
@@ -413,22 +415,30 @@
private JExpression handleSystemGetProperty(JMethodCall gwtGetPropertyCall) {
assert (gwtGetPropertyCall.getArgs().size() == 1 || gwtGetPropertyCall.getArgs().size() == 2);
JExpression propertyNameExpression = gwtGetPropertyCall.getArgs().get(0);
- JExpression defaultValueExpression = gwtGetPropertyCall.getArgs().size() == 2 ?
+ boolean defaultVersionCalled = gwtGetPropertyCall.getArgs().size() == 2;
+ JExpression defaultValueExpression = defaultVersionCalled ?
gwtGetPropertyCall.getArgs().get(1) : null;
if (!(propertyNameExpression instanceof JStringLiteral) ||
- (defaultValueExpression != null && !(defaultValueExpression instanceof JStringLiteral))) {
+ (defaultVersionCalled && !(defaultValueExpression instanceof JStringLiteral))) {
error(gwtGetPropertyCall,
"Only string constants may be used as arguments to System.getProperty()");
return null;
}
String propertyName = ((JStringLiteral) propertyNameExpression).getValue();
- if (isMultivaluedProperty(propertyName)) {
- error(gwtGetPropertyCall,
- "Multivalued properties are not supported by System.getProperty()");
+ if (!defaultVersionCalled && !isPropertyDefined(propertyName)) {
+ error(gwtGetPropertyCall, "Property '" + propertyName + "' is not defined.");
return null;
}
+
+ if (isMultivaluedProperty(propertyName)) {
+ error(gwtGetPropertyCall,
+ "Property '" + propertyName + "' is multivalued. " +
+ "Multivalued properties are not supported by System.getProperty().");
+ return null;
+ }
+
String defaultValue = defaultValueExpression == null ? null :
((JStringLiteral) defaultValueExpression).getValue();
return JPermutationDependentValue
@@ -591,9 +601,16 @@
}
private boolean isMultivaluedProperty(String propertyName) {
- // Multivalued properties can only be Configuration properties, and those do not change between
- // permutations.
- return permutations[0].getProperties().getConfigurationProperties().isMultiValued(propertyName);
+ Property property = compilerContext.getModule().getProperties().find(propertyName);
+ if (!(property instanceof ConfigurationProperty)) {
+ return false;
+ }
+
+ return ((ConfigurationProperty) property).allowsMultipleValues();
+ }
+
+ private boolean isPropertyDefined(String propertyName) {
+ return compilerContext.getModule().getProperties().find(propertyName) != null;
}
private static final String CLASS_DESIRED_ASSERTION_STATUS =
diff --git a/dev/core/test/com/google/gwt/dev/cfg/MockModuleDef.java b/dev/core/test/com/google/gwt/dev/cfg/MockModuleDef.java
index 7f1395c..fe89967 100644
--- a/dev/core/test/com/google/gwt/dev/cfg/MockModuleDef.java
+++ b/dev/core/test/com/google/gwt/dev/cfg/MockModuleDef.java
@@ -56,9 +56,16 @@
}
};
+ private Properties properties = new Properties();
+
public MockModuleDef() {
super("mock");
normalize(TreeLogger.NULL);
lazyPublicOracle = new MockResourceOracle(publicResource);
}
+
+ @Override
+ public Properties getProperties() {
+ return properties;
+ }
}
diff --git a/dev/core/test/com/google/gwt/dev/javac/CheckerTestCase.java b/dev/core/test/com/google/gwt/dev/javac/CheckerTestCase.java
index a1ef78f..8967543 100644
--- a/dev/core/test/com/google/gwt/dev/javac/CheckerTestCase.java
+++ b/dev/core/test/com/google/gwt/dev/javac/CheckerTestCase.java
@@ -23,10 +23,10 @@
import com.google.gwt.dev.resource.Resource;
import com.google.gwt.dev.util.UnitTestTreeLogger;
import com.google.gwt.thirdparty.guava.common.base.Joiner;
+import com.google.gwt.thirdparty.guava.common.collect.Sets;
import junit.framework.TestCase;
-import java.util.HashSet;
import java.util.Set;
/**
@@ -35,6 +35,18 @@
public abstract class CheckerTestCase extends TestCase {
/**
+ * Pass represents passes to be run by the checker test cases.
+ */
+ public interface Pass {
+ /**
+ * Run the pass. Returns true if pass completes successfully.
+ */
+ boolean run(TreeLogger logger, MockJavaResource buggyResource, MockJavaResource extraResource);
+
+ boolean classAvailable(String className);
+ String getTopErrorMessage(Type logLevel, MockJavaResource resource);
+ }
+ /**
* A warning or error message.
*/
protected static class Message {
@@ -49,6 +61,41 @@
}
}
+ /**
+ * Provide a pass to be checked by default runs only passes required to build TypeOracle.
+ */
+ protected Pass providePass() {
+ return new Pass() {
+ private TypeOracle oracle = null;
+ @Override
+ public boolean run(TreeLogger logger, MockJavaResource buggyResource,
+ MockJavaResource extraResource) {
+ Set<Resource> resources = Sets.newHashSet();
+ addLongCheckingCups(resources);
+ Set<GeneratedUnit> generatedUnits =
+ CompilationStateTestBase.getGeneratedUnits(buggyResource);
+ if (extraResource != null) {
+ generatedUnits.addAll(CompilationStateTestBase.getGeneratedUnits(extraResource));
+ }
+ CompilationState state = TypeOracleTestingUtils.buildCompilationStateWith(logger,
+ resources, generatedUnits);
+ oracle = state.getTypeOracle();
+ return !state.hasErrors();
+ }
+
+ @Override
+ public boolean classAvailable(String className) {
+ return oracle.findType(className) != null;
+ }
+
+ @Override
+ public String getTopErrorMessage(Type logLevel, MockJavaResource resource) {
+ return (logLevel == Type.WARN ? "Warnings" : "Errors") +
+ " in '" + resource.getLocation() + "'";
+ }
+ };
+ }
+
protected Message warning(int line, String message) {
return new Message(line, Type.WARN, message);
}
@@ -61,26 +108,32 @@
Type logLevel, Message... messages) {
UnitTestTreeLogger.Builder b = new UnitTestTreeLogger.Builder();
b.setLowestLogLevel(logLevel);
- if (messages.length != 0) {
- b.expect(logLevel, (logLevel == Type.WARN ? "Warnings" : "Errors") +
- " in '" + buggyCode.getLocation() + "'", null);
+ Pass pass = providePass();
+ String topLevelMessage = pass.getTopErrorMessage(logLevel, buggyCode);
+ if (messages.length != 0 && topLevelMessage != null) {
+ b.expect(logLevel, topLevelMessage, null);
}
for (Message message : messages) {
final String fullMessage = "Line " + message.line + ": " + message.message;
b.expect(message.logLevel, fullMessage, null);
}
UnitTestTreeLogger logger = b.createLogger();
- TypeOracle oracle = buildOracle(logger, buggyCode, extraCode);
+
+ boolean result = pass.run(logger, buggyCode, extraCode);
logger.assertCorrectLogEntries();
String className = buggyCode.getTypeName();
if (messages.length != 0 && logLevel == TreeLogger.ERROR) {
- assertNull("Buggy compilation unit not removed from type oracle",
- oracle.findType(className));
+ assertFalse("Compilation unit " + className + " not removed" +
+ " but should have been removed.",
+ pass.classAvailable(className));
} else {
- assertNotNull("Buggy compilation unit removed with only a warning",
- oracle.findType(className));
+ assertTrue("Compilation unit " + className + " was removed but shouldnt have.",
+ pass.classAvailable(className));
}
+
+ boolean expectingErrors = messages.length != 0 && logLevel == Type.ERROR;
+ assertEquals(!expectingErrors, result);
}
protected void shouldGenerateError(MockJavaResource buggyCode, MockJavaResource extraCode,
@@ -88,13 +141,6 @@
shouldGenerate(buggyCode, extraCode, TreeLogger.ERROR, error(line, message));
}
- protected void shouldGenerateError(CharSequence buggyCode, CharSequence extraCode, int line,
- String message) {
- StaticJavaResource codeResource = new StaticJavaResource("Buggy", buggyCode);
- StaticJavaResource extraResource = new StaticJavaResource("Extra", extraCode);
- shouldGenerate(codeResource, extraResource, TreeLogger.ERROR, error(line, message));
- }
-
protected void shouldGenerateError(MockJavaResource buggyCode, int line, String message) {
shouldGenerateError(buggyCode, null, line, message);
}
@@ -107,12 +153,6 @@
shouldGenerate(code, extraCode, TreeLogger.ERROR);
}
- protected void shouldGenerateNoError(CharSequence code, CharSequence extraCode) {
- StaticJavaResource codeResource = new StaticJavaResource("Buggy", code);
- StaticJavaResource extraResource = new StaticJavaResource("Extra", extraCode);
- shouldGenerate(codeResource, extraResource, TreeLogger.ERROR);
- }
-
protected void shouldGenerateNoWarning(MockJavaResource code) {
shouldGenerateNoWarning(code, null);
}
@@ -139,7 +179,6 @@
Message... messages) {
shouldGenerate(buggyCode, extraCode, TreeLogger.WARN, messages);
}
- private String buggyPackage = "";
private void addLongCheckingCups(Set<Resource> resources) {
String code = Joiner.on('\n').join(
@@ -149,17 +188,4 @@
resources.add(new StaticJavaResource(
"com.google.gwt.core.client.UnsafeNativeLong", code.toString()));
}
-
- private TypeOracle buildOracle(UnitTestTreeLogger logger, MockJavaResource buggyResource,
- MockJavaResource extraResource) {
- Set<Resource> resources = new HashSet<Resource>();
- addLongCheckingCups(resources);
- Set<GeneratedUnit> generatedUnits = CompilationStateTestBase.getGeneratedUnits(buggyResource);
- if (extraResource != null) {
- generatedUnits.addAll(CompilationStateTestBase.getGeneratedUnits(extraResource));
- }
- return TypeOracleTestingUtils.buildStandardTypeOracleWith(logger,
- resources, generatedUnits);
- }
-
}
diff --git a/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java b/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java
index ed642e7..a92e929 100644
--- a/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java
+++ b/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java
@@ -22,6 +22,7 @@
import com.google.gwt.dev.javac.testing.impl.JavaResourceBase;
import com.google.gwt.dev.resource.Resource;
import com.google.gwt.dev.util.arg.SourceLevel;
+import com.google.gwt.thirdparty.guava.common.collect.Sets;
import java.util.Arrays;
import java.util.Collections;
@@ -72,36 +73,13 @@
return buildUpdaterWith(logger, standardBuildersPlus(resources));
}
- public static TypeOracle buildStandardTypeOracleWith(TreeLogger logger,
- Resource... resources) {
- return buildStandardTypeOracleWith(logger, new HashSet<Resource>(
- Arrays.asList(resources)));
- }
-
- public static TypeOracle buildStandardTypeOracleWith(TreeLogger logger,
- Set<Resource> resources) {
- return buildTypeOracle(logger, standardBuildersPlus(resources));
- }
-
- public static TypeOracle buildStandardTypeOracleWith(TreeLogger logger,
- Set<Resource> resources, Set<GeneratedUnit> generatedUnits, SourceLevel sourceLevel) {
- return buildTypeOracle(logger, standardBuildersPlus(resources),
- generatedUnits, sourceLevel);
- }
-
- public static TypeOracle buildStandardTypeOracleWith(TreeLogger logger,
+ public static CompilationState buildCompilationStateWith(TreeLogger logger,
Set<Resource> resources, Set<GeneratedUnit> generatedUnits) {
- return buildTypeOracle(logger, standardBuildersPlus(resources),
+ return buildCompilationState(logger, standardBuildersPlus(resources),
generatedUnits, SourceLevel.DEFAULT_SOURCE_LEVEL);
}
- public static TypeOracle buildTypeOracle(TreeLogger logger,
- Set<Resource> resources) {
- return buildTypeOracle(logger, resources,
- Collections.<GeneratedUnit> emptySet());
- }
-
- public static TypeOracle buildTypeOracle(TreeLogger logger,
+ public static CompilationState buildCompilationState(TreeLogger logger,
Set<Resource> resources, Set<GeneratedUnit> generatedUnits, SourceLevel sourceLevel) {
try {
CompilerContext compilerContext = new CompilerContext();
@@ -110,15 +88,38 @@
CompilationState state =
CompilationStateBuilder.buildFrom(logger, compilerContext, resources);
state.addGeneratedCompilationUnits(logger, generatedUnits);
- return state.getTypeOracle();
+ return state;
} catch (UnableToCompleteException e) {
throw new RuntimeException(e);
}
}
+ public static TypeOracle buildTypeOracle(TreeLogger logger, Set<Resource> resources) {
+ return buildTypeOracle(logger, resources,
+ Collections.<GeneratedUnit>emptySet());
+ }
+
public static TypeOracle buildTypeOracle(TreeLogger logger,
Set<Resource> resources, Set<GeneratedUnit> generatedUnits) {
- return buildTypeOracle(logger, resources, generatedUnits, SourceLevel.DEFAULT_SOURCE_LEVEL);
+ return buildCompilationState(logger, resources, generatedUnits,
+ SourceLevel.DEFAULT_SOURCE_LEVEL).getTypeOracle();
+ }
+
+ public static TypeOracle buildStandardTypeOracleWith(TreeLogger logger,
+ Set<Resource> resources, Set<GeneratedUnit> generatedUnits, SourceLevel sourceLevel) {
+ return buildCompilationState(logger, standardBuildersPlus(resources),
+ generatedUnits, sourceLevel).getTypeOracle();
+ }
+
+ public static TypeOracle buildStandardTypeOracleWith(TreeLogger logger,
+ Set<Resource> resources) {
+ return buildTypeOracle(logger, standardBuildersPlus(resources));
+ }
+
+ public static TypeOracle buildStandardTypeOracleWith(TreeLogger logger,
+ Resource... resources) {
+ return buildStandardTypeOracleWith(logger, Sets.newHashSet(
+ Arrays.asList(resources)));
}
/**
diff --git a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
index cdd6c99..0023311 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
@@ -17,7 +17,7 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.dev.PrecompileTaskOptions;
+import com.google.gwt.dev.CompilerContext;
import com.google.gwt.dev.cfg.ConfigurationProperties;
import com.google.gwt.dev.javac.CompilationState;
import com.google.gwt.dev.javac.testing.impl.JavaResourceBase;
@@ -353,10 +353,10 @@
};
public static JProgram construct(TreeLogger logger, CompilationState state,
- PrecompileTaskOptions options, ConfigurationProperties config,
+ CompilerContext compilerContext, ConfigurationProperties config,
String... entryPoints) throws UnableToCompleteException {
- options.setEnableAssertions(true);
- JProgram jprogram = AstConstructor.construct(logger, state, options, config);
+ compilerContext.getOptions().setEnableAssertions(true);
+ JProgram jprogram = AstConstructor.construct(logger, state, compilerContext, config);
// Add entry methods for entry points.
for (String entryPoint : entryPoints) {
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/ComputeExhaustiveCastabilityInformationTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/ComputeExhaustiveCastabilityInformationTest.java
index 7bb5d26..92ad1e4 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/ComputeExhaustiveCastabilityInformationTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/ComputeExhaustiveCastabilityInformationTest.java
@@ -40,7 +40,7 @@
registerCompilableResources();
// Compiles and gets a reference to the String[] type.
- JProgram program = compileSnippet("void", "", "", false, true);
+ JProgram program = compileSnippet(null, "void", "", "", true);
ComputeExhaustiveCastabilityInformation.exec(program);
JDeclaredType stringType = program.getIndexedType("String");
JArrayType stringArrayType = program.getTypeArray(stringType);
@@ -84,7 +84,7 @@
private void assertSourceCastsToTargets(String sourceTypeName,
Set<String> expectedTargetTypeNames) throws UnableToCompleteException {
- JProgram program = compileSnippet("void", "", "", false, true);
+ JProgram program = compileSnippet(null, "void", "", "", true);
ComputeExhaustiveCastabilityInformation.exec(program);
JDeclaredType sourceType = program.getIndexedType(sourceTypeName);
assertSourceCastsToTargets(program, sourceType, expectedTargetTypeNames);
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/FullCompileTestBase.java b/dev/core/test/com/google/gwt/dev/jjs/impl/FullCompileTestBase.java
index 11ac8cc..35af944 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/FullCompileTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/FullCompileTestBase.java
@@ -82,7 +82,7 @@
configurationProperties));
jProgram =
- JavaAstConstructor.construct(logger, state, compilerContext.getOptions(), config,
+ JavaAstConstructor.construct(logger, state, compilerContext, config,
"test.EntryPoint", "com.google.gwt.lang.Exceptions");
jProgram.addEntryMethod(findMethod(jProgram, "onModuleLoad"));
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/GwtAstBuilderTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/GwtAstBuilderTest.java
index 6460ffa..f93ca29 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/GwtAstBuilderTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/GwtAstBuilderTest.java
@@ -262,18 +262,11 @@
}
private JProgram compileProgram(String entryType) throws UnableToCompleteException {
- CompilerContext compilerContext =
- new CompilerContext.Builder().options(new PrecompileTaskOptionsImpl() {
- @Override
- public boolean shouldJDTInlineCompileTimeConstants() {
- return false;
- }
- }).build();
- compilerContext.getOptions().setSourceLevel(sourceLevel);
- compilerContext.getOptions().setStrict(true);
+ CompilerContext compilerContext = provideCompilerContext();
+;
CompilationState state = CompilationStateBuilder.buildFrom(logger, compilerContext, sources,
getAdditionalTypeProviderDelegate());
- JProgram program = JavaAstConstructor.construct(logger, state, compilerContext.getOptions(),
+ JProgram program = JavaAstConstructor.construct(logger, state, compilerContext,
null, entryType, "com.google.gwt.lang.Exceptions");
return program;
}
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java b/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java
index a36ee47..7e53200 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java
@@ -19,6 +19,8 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.CompilerContext;
import com.google.gwt.dev.PrecompileTaskOptionsImpl;
+import com.google.gwt.dev.cfg.MockModuleDef;
+import com.google.gwt.dev.javac.CheckerTestCase;
import com.google.gwt.dev.javac.CompilationState;
import com.google.gwt.dev.javac.CompilationStateBuilder;
import com.google.gwt.dev.javac.JdtCompiler.AdditionalTypeProviderDelegate;
@@ -51,8 +53,6 @@
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import com.google.gwt.thirdparty.guava.common.collect.Sets;
-import junit.framework.TestCase;
-
import java.util.Arrays;
import java.util.List;
import java.util.Set;
@@ -62,7 +62,7 @@
/**
* A useful base class for tests that build JJS ASTs.
*/
-public abstract class JJSTestBase extends TestCase {
+public abstract class JJSTestBase extends CheckerTestCase {
public static final String MAIN_METHOD_NAME = "onModuleLoad";
@@ -245,42 +245,68 @@
/**
* Returns the program that results from compiling the specified code snippet
* as the body of an entry point method.
- * @param returnType the return type of the method to compile; use "void" if
+ * @param logger a logger where to log, the default logger will be used if null.
+ * @param returnType the return type of the method to compile; use "void" if
* the code snippet has no return statement
* @param codeSnippet the body of the entry method
*/
- protected JProgram compileSnippet(final String returnType,
+ protected JProgram compileSnippet(TreeLogger logger, final String returnType,
final String codeSnippet) throws UnableToCompleteException {
- return compileSnippet(returnType, "", codeSnippet, true, false);
+ return compileSnippet(logger, returnType, "", codeSnippet, false);
}
/**
* Returns the program that results from compiling the specified code snippet
* as the body of an entry point method.
- * @param returnType the return type of the method to compile; use "void" if
+ * @param logger a logger where to log, the default logger will be used if null.
+ * @param returnType the return type of the method to compile; use "void" if
+ * the code snippet has no return statement
+ * @param codeSnippet the body of the entry method
+ * @param staticMethod whether to make the method static
+ */
+ protected JProgram compileSnippet(TreeLogger logger, final String returnType,
+ final String codeSnippet, boolean staticMethod) throws UnableToCompleteException {
+ return compileSnippet(logger, returnType, "", codeSnippet, staticMethod);
+ }
+
+ /**
+ * Returns the program that results from compiling the specified code snippet
+ * as the body of an entry point method.
+ * @param returnType the return type of the method to compile; use "void" if
* the code snippet has no return statement
* @param codeSnippet the body of the entry method
* @param staticMethod whether to make the method static
*/
protected JProgram compileSnippet(final String returnType,
final String codeSnippet, boolean staticMethod) throws UnableToCompleteException {
- return compileSnippet(returnType, "", codeSnippet, true, staticMethod);
+ return compileSnippet(logger, returnType, "", codeSnippet, staticMethod);
+ }
+
+ /**
+ * Returns the program that results from compiling the specified code snippet
+ * as the body of an entry point method.
+ * @param returnType the return type of the method to compile; use "void" if
+ * the code snippet has no return statement
+ * @param codeSnippet the body of the entry method
+ */
+ protected JProgram compileSnippet(final String returnType,
+ final String codeSnippet) throws UnableToCompleteException {
+ return compileSnippet(logger, returnType, "", codeSnippet, false);
}
/**
* Returns the program that results from compiling the specified code snippet
* as the body of an entry point method.
*
+ * @param logger a logger where to log, the default logger will be used if null.
* @param returnType the return type of the method to compile; use "void" if
* the code snippet has no return statement
* @param params the parameter list of the method to compile
* @param codeSnippet the body of the entry method
- * @param compileMonolithic whether the compile is monolithic
* @param staticMethod whether the entryPoint should be static
*/
- protected JProgram compileSnippet(final String returnType,
- final String params, final String codeSnippet, boolean compileMonolithic,
- final boolean staticMethod)
+ protected JProgram compileSnippet(TreeLogger logger, final String returnType,
+ final String params, final String codeSnippet, final boolean staticMethod)
throws UnableToCompleteException {
sourceOracle.addOrReplace(new MockJavaResource("test.EntryPoint") {
@Override
@@ -302,26 +328,40 @@
return code;
}
});
- CompilerContext compilerContext =
- new CompilerContext.Builder().options(new PrecompileTaskOptionsImpl() {
- @Override
- public boolean shouldJDTInlineCompileTimeConstants() {
- return false;
- }
- }).build();
- compilerContext.getOptions().setSourceLevel(sourceLevel);
- compilerContext.getOptions().setStrict(true);
- compilerContext.getOptions().setJsInteropMode(OptionJsInteropMode.Mode.JS);
+ CompilerContext compilerContext = provideCompilerContext();
+
+ if (logger == null) {
+ logger = this.logger;
+ }
CompilationState state =
CompilationStateBuilder.buildFrom(logger, compilerContext,
sourceOracle.getResources(), getAdditionalTypeProviderDelegate());
JProgram program =
- JavaAstConstructor.construct(logger, state, compilerContext.getOptions(),
+ JavaAstConstructor.construct(logger, state, compilerContext,
null, "test.EntryPoint", "com.google.gwt.lang.Exceptions");
return program;
}
/**
+ * Returns a compiler context to be used for compiling code within the test.
+ */
+ protected CompilerContext provideCompilerContext() {
+ CompilerContext compilerContext = new CompilerContext.Builder().module(new MockModuleDef())
+ .options(new PrecompileTaskOptionsImpl() {
+ @Override
+ public boolean shouldJDTInlineCompileTimeConstants() {
+ return false;
+ }
+ }
+ ).build();
+
+ compilerContext.getOptions().setSourceLevel(sourceLevel);
+ compilerContext.getOptions().setStrict(true);
+ compilerContext.getOptions().setJsInteropMode(OptionJsInteropMode.Mode.JS);
+ return compilerContext;
+ }
+
+ /**
* Return an AdditionalTypeProviderDelegate that will be able to provide
* new sources for unknown classnames.
*/
@@ -420,7 +460,9 @@
protected void addAll(Resource... sourceFiles) {
for (Resource sourceFile : sourceFiles) {
- sourceOracle.addOrReplace(sourceFile);
+ if (sourceFile != null) {
+ sourceOracle.addOrReplace(sourceFile);
+ }
}
}
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java b/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
index 2242d49..660210d 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
@@ -476,14 +476,17 @@
protected final Result optimizeMethod(final String methodName,
final String mainMethodReturnType, final String... mainMethodSnippet)
throws UnableToCompleteException {
- return optimizeMethod(TreeLogger.NULL, methodName, mainMethodReturnType, mainMethodSnippet);
+ return optimizeMethod(null, methodName, mainMethodReturnType, mainMethodSnippet);
}
protected final Result optimizeMethod(TreeLogger logger, final String methodName,
final String mainMethodReturnType, final String... mainMethodSnippet)
throws UnableToCompleteException {
+ if (logger == null) {
+ logger = this.logger;
+ }
String snippet = Joiner.on("\n").join(mainMethodSnippet);
- JProgram program = compileSnippet(mainMethodReturnType, snippet, true);
+ JProgram program = compileSnippet(logger, mainMethodReturnType, snippet, true);
JMethod method = findMethod(program, methodName);
boolean madeChanges = doOptimizeMethod(logger, program, method);
if (madeChanges && runDeadCodeElimination) {
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/UnifyAstTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/UnifyAstTest.java
index a2161c9..9042d39 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/UnifyAstTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/UnifyAstTest.java
@@ -14,7 +14,9 @@
package com.google.gwt.dev.jjs.impl;
import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.CompilerContext;
import com.google.gwt.dev.javac.testing.impl.JavaResourceBase;
import com.google.gwt.dev.javac.testing.impl.MockJavaResource;
import com.google.gwt.dev.jjs.ast.JClassType;
@@ -480,12 +482,102 @@
.typeOracle.getInstanceMethodBySignature(testImplClass, mSignature));
}
+ public void testGetProperty_error_undefinedProperty()
+ throws UnableToCompleteException {
+
+ final MockJavaResource someClass =
+ JavaResourceBase.createMockJavaResource("test.SomeClass",
+ "package test;",
+ "public class SomeClass {",
+ " public void m() { String a = System.getProperty(\"undefined\"); }",
+ "}");
+
+ shouldGenerateError(someClass, 3, "Property 'undefined' is not defined.");
+ }
+
+ public void testGetProperty_error_multivalued()
+ throws UnableToCompleteException {
+
+ final MockJavaResource someClass =
+ JavaResourceBase.createMockJavaResource("test.SomeClass",
+ "package test;",
+ "public class SomeClass {",
+ " public void m() { String a = System.getProperty(\"multivalued\"); }",
+ "}");
+
+ shouldGenerateError(someClass, 3, "Property 'multivalued' is multivalued." +
+ " Multivalued properties are not supported by System.getProperty().");
+ }
+
+ public void testGetPropertyWithDefault_error_multivalued()
+ throws UnableToCompleteException {
+
+ final MockJavaResource someClass =
+ JavaResourceBase.createMockJavaResource("test.SomeClass",
+ "package test;",
+ "public class SomeClass {",
+ " public void m() { String a = System.getProperty(\"multivalued\", \"somevalue\"); }",
+ "}");
+
+ shouldGenerateError(someClass, 3, "Property 'multivalued' is multivalued." +
+ " Multivalued properties are not supported by System.getProperty().");
+ }
+
+ public void testGetPropertyWithDefault_success_undefined()
+ throws UnableToCompleteException {
+
+ final MockJavaResource someClass =
+ JavaResourceBase.createMockJavaResource("test.SomeClass",
+ "package test;",
+ "public class SomeClass {",
+ " public void m() { String a = System.getProperty(\"undefined\", \"somevalue\"); }",
+ "}");
+
+ shouldGenerateNoError(someClass);
+ }
+
@Override
protected boolean doOptimizeMethod(TreeLogger logger, JProgram program, JMethod method) {
program.addEntryMethod(findMainMethod(program));
return false;
}
+ @Override
+ protected CompilerContext provideCompilerContext() {
+ CompilerContext context = super.provideCompilerContext();
+ context.getModule().getProperties().createConfiguration("multivalued", true);
+ return context;
+ }
+
+ @Override
+ protected Pass providePass() {
+ return new Pass() {
+ private Result result = null;
+ @Override
+ public boolean run(TreeLogger logger, MockJavaResource buggyResource,
+ MockJavaResource extraResource) {
+ addAll(buggyResource, extraResource);
+ try {
+ result = optimize(logger, "void", "new SomeClass().m();");
+ } catch (UnableToCompleteException e) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean classAvailable(String className) {
+ return result != null && result.findClass(className) != null;
+ }
+
+ @Override
+ public String getTopErrorMessage(Type logLevel, MockJavaResource resource) {
+ return (logLevel == Type.WARN ? "Warnings" : "Errors") +
+ " in '" + resource.getPath() + "'";
+ }
+ };
+ }
+
private static final MockJavaResource A_A =
JavaResourceBase.createMockJavaResource("a.A",
"package a;",
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/CfgAnalysisTestBase.java b/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/CfgAnalysisTestBase.java
index 8ba8fd2..9d17cf6 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/CfgAnalysisTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/CfgAnalysisTestBase.java
@@ -42,7 +42,7 @@
protected AnalysisResult analyzeWithParams(String returnType, String params,
String... codeSnippet) throws UnableToCompleteException {
- JProgram program = compileSnippet(returnType, params, Joiner.on("\n").join(codeSnippet), true,
+ JProgram program = compileSnippet(null, returnType, params, Joiner.on("\n").join(codeSnippet),
true);
JMethodBody body = (JMethodBody) findMainMethod(program).getBody();
Cfg cfgGraph = CfgBuilder.build(program, body.getBlock());
diff --git a/user/test/com/google/gwt/dev/jjs/test/SystemGetPropertyTest.java b/user/test/com/google/gwt/dev/jjs/test/SystemGetPropertyTest.java
index 4d96a90..2604e5e 100644
--- a/user/test/com/google/gwt/dev/jjs/test/SystemGetPropertyTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/SystemGetPropertyTest.java
@@ -27,7 +27,7 @@
return "com.google.gwt.dev.jjs.SystemGetPropertyTest";
}
- // TODO(rluble): Remove DoNotRun here is System.getProperty is ever implemented for devmode.
+ // In DevMode System.getProperty is routed to the standard Java implementation.
@DoNotRunWith(Platform.Devel)
public void testBindingProperties() {
assertEquals("two", System.getProperty("collapsedProperty"));
@@ -40,7 +40,6 @@
@DoNotRunWith(Platform.Devel)
public void testConfigurationProperties() {
- assertNull(System.getProperty("nonExistent"));
assertEquals("conf", System.getProperty("someConfigurationProperty"));
assertEquals("conf", System.getProperty("someConfigurationProperty", "default"));
}