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")); }