Include relevant compiler options in SDM cache key.

Changing options that affect javascript output would not force
a clean minimal rebuild cache nor use a different key ending up with
incosistent resutls.

Now the relevant compiler options are part of the key to the minimal
rebuild cache.

Bug: #9390
Bug-Link: https://github.com/gwtproject/gwt/issues/9390
Change-Id: Idd216d6eba2a21ddedf161d80d8276efb3ac04fc
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
index ab3c996..742e8c6 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
@@ -24,6 +24,7 @@
 import com.google.gwt.dev.javac.UnitCacheSingleton;
 import com.google.gwt.dev.util.DiskCachingUtil;
 import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+import com.google.gwt.thirdparty.guava.common.collect.ImmutableMap;
 import com.google.gwt.util.tools.Utility;
 
 import java.io.File;
@@ -69,7 +70,8 @@
             DiskCachingUtil.computePreferredCacheDir(options.getModuleNames(), logger);
         UnitCache unitCache = UnitCacheSingleton.get(logger, null, baseCacheDir);
         MinimalRebuildCacheManager minimalRebuildCacheManager =
-            new MinimalRebuildCacheManager(logger, baseCacheDir);
+            createMinimalRebuildCacheManager(logger, options, baseCacheDir);
+
         outboxTable = makeOutboxTable(options, logger, unitCache, minimalRebuildCacheManager);
       } catch (Throwable t) {
         t.printStackTrace();
@@ -112,6 +114,21 @@
     }
   }
 
+  private static MinimalRebuildCacheManager createMinimalRebuildCacheManager(
+      PrintWriterTreeLogger logger, Options options,File baseCacheDir) {
+    return new MinimalRebuildCacheManager(
+        logger,
+        baseCacheDir,
+        ImmutableMap.of(
+            "style", options.getOutput().name(),
+            "closureFormattedOutput",
+                Boolean.valueOf(options.isClosureFormattedOutput()).toString(),
+            "generateJsInteropExports",
+                Boolean.valueOf(options.shouldGenerateJsInteropExports()).toString(),
+            "methodDisplayMode", options.getMethodNameDisplayMode().name())
+    );
+  }
+
   /**
    * Starts the code server with the given command line options. To shut it down, see
    * {@link WebServer#stop}.
@@ -128,7 +145,7 @@
         DiskCachingUtil.computePreferredCacheDir(options.getModuleNames(), startupLogger);
     UnitCache unitCache = UnitCacheSingleton.get(startupLogger, null, baseCacheDir);
     MinimalRebuildCacheManager minimalRebuildCacheManager =
-        new MinimalRebuildCacheManager(topLogger, baseCacheDir);
+        createMinimalRebuildCacheManager(topLogger, options, baseCacheDir);
     OutboxTable outboxTable =
         makeOutboxTable(options, startupLogger, unitCache, minimalRebuildCacheManager);
 
diff --git a/dev/codeserver/javatests/com/google/gwt/dev/codeserver/RecompilerTest.java b/dev/codeserver/javatests/com/google/gwt/dev/codeserver/RecompilerTest.java
index 737030e..c63e949 100644
--- a/dev/codeserver/javatests/com/google/gwt/dev/codeserver/RecompilerTest.java
+++ b/dev/codeserver/javatests/com/google/gwt/dev/codeserver/RecompilerTest.java
@@ -26,6 +26,7 @@
 import com.google.gwt.dev.javac.testing.impl.MockResource;
 import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
 import com.google.gwt.thirdparty.guava.common.base.Charsets;
+import com.google.gwt.thirdparty.guava.common.collect.ImmutableMap;
 import com.google.gwt.thirdparty.guava.common.collect.Lists;
 import com.google.gwt.thirdparty.guava.common.io.Files;
 
@@ -176,7 +177,7 @@
     File baseCacheDir = Files.createTempDir();
     UnitCache unitCache = UnitCacheSingleton.get(logger, null, baseCacheDir);
     MinimalRebuildCacheManager minimalRebuildCacheManager =
-        new MinimalRebuildCacheManager(logger, baseCacheDir);
+        new MinimalRebuildCacheManager(logger, baseCacheDir, ImmutableMap.<String, String>of());
     Recompiler recompiler = new Recompiler(OutboxDir.create(Files.createTempDir(), logger), null,
         "com.foo.SimpleModule", options, unitCache, minimalRebuildCacheManager);
     Outbox outbox = new Outbox("Transactional Cache", recompiler, options, logger);
@@ -222,7 +223,7 @@
     File baseCacheDir = Files.createTempDir();
     UnitCache unitCache = UnitCacheSingleton.get(logger, null, baseCacheDir);
     MinimalRebuildCacheManager minimalRebuildCacheManager =
-        new MinimalRebuildCacheManager(logger, baseCacheDir);
+        new MinimalRebuildCacheManager(logger, baseCacheDir, ImmutableMap.<String, String>of());
     Recompiler recompiler = new Recompiler(OutboxDir.create(Files.createTempDir(), logger), null,
         "com.foo.PropertyModule", options, unitCache, minimalRebuildCacheManager);
     Outbox outbox = new Outbox("Transactional Cache", recompiler, options, logger);
diff --git a/dev/core/src/com/google/gwt/dev/MinimalRebuildCacheManager.java b/dev/core/src/com/google/gwt/dev/MinimalRebuildCacheManager.java
index 6df1f53..9cdb468 100644
--- a/dev/core/src/com/google/gwt/dev/MinimalRebuildCacheManager.java
+++ b/dev/core/src/com/google/gwt/dev/MinimalRebuildCacheManager.java
@@ -33,6 +33,8 @@
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -57,9 +59,12 @@
   private final File minimalRebuildCacheDir;
   private final Cache<String, MinimalRebuildCache> minimalRebuildCachesByName =
       CacheBuilder.newBuilder().maximumSize(MEMORY_CACHE_COUNT_LIMIT).build();
+  private final Map<String, String> options = new LinkedHashMap<>();
 
-  public MinimalRebuildCacheManager(TreeLogger logger, File baseCacheDir) {
+  public MinimalRebuildCacheManager(
+      TreeLogger logger, File baseCacheDir, Map<String, String> options) {
     this.logger = logger;
+    this.options.putAll(options);
     if (baseCacheDir != null) {
       minimalRebuildCacheDir = new File(baseCacheDir, REBUILD_CACHE_PREFIX);
       minimalRebuildCacheDir.mkdir();
@@ -88,7 +93,8 @@
    */
   public synchronized MinimalRebuildCache getCache(String moduleName,
       PermutationDescription permutationDescription) {
-    String cacheName = computeMinimalRebuildCacheName(moduleName, permutationDescription);
+    String cacheName =
+        computeMinimalRebuildCacheName(moduleName, permutationDescription);
 
     MinimalRebuildCache minimalRebuildCache = minimalRebuildCachesByName.getIfPresent(cacheName);
 
@@ -269,9 +275,21 @@
     String currentWorkingDirectory = System.getProperty("user.dir");
     String compilerVersionHash = CompilerVersion.getHash();
     String permutationDescriptionString = permutationDescription.toString();
+    String optionsDescriptionString = " Options [";
+    String separator = "";
+    for (Map.Entry entry : options.entrySet()) {
+      optionsDescriptionString +=
+          String.format("%s%s = %s", separator, entry.getKey(), entry.getValue());
+      separator = ",";
+    }
+    optionsDescriptionString += "]";
 
     String consistentHash = StringUtils.toHexString(Md5Utils.getMd5Digest((
-        compilerVersionHash + moduleName + currentWorkingDirectory + permutationDescriptionString)
+        compilerVersionHash
+            + moduleName
+            + currentWorkingDirectory
+            + permutationDescriptionString
+            + optionsDescriptionString)
         .getBytes()));
     return REBUILD_CACHE_PREFIX + "-" + consistentHash;
   }
diff --git a/dev/core/test/com/google/gwt/dev/MinimalRebuildCacheManagerTest.java b/dev/core/test/com/google/gwt/dev/MinimalRebuildCacheManagerTest.java
index c0ab6b0..11aae8b 100644
--- a/dev/core/test/com/google/gwt/dev/MinimalRebuildCacheManagerTest.java
+++ b/dev/core/test/com/google/gwt/dev/MinimalRebuildCacheManagerTest.java
@@ -30,22 +30,73 @@
  */
 public class MinimalRebuildCacheManagerTest extends TestCase {
 
-  public void testNoSuchCache() {
+  public void testCacheChange() throws InterruptedException {
+    String moduleName = "com.google.FooModule";
+    Map<String, String> initialCompilerOptions = ImmutableMap.of("option", "oldvalue");
+    PermutationDescription permutationDescription = new PermutationDescription();
+    File cacheDir = Files.createTempDir();
+
     MinimalRebuildCacheManager minimalRebuildCacheManager =
-        new MinimalRebuildCacheManager(TreeLogger.NULL, Files.createTempDir());
+        new MinimalRebuildCacheManager(
+            TreeLogger.NULL, cacheDir, initialCompilerOptions);
 
     // Make sure we start with a blank slate.
     minimalRebuildCacheManager.deleteCaches();
 
     // Construct and empty cache and also ask the manager to get a cache which does not exist.
     MinimalRebuildCache emptyCache = new MinimalRebuildCache();
-    MinimalRebuildCache noSuchCache = minimalRebuildCacheManager.getCache("com.google.FooModule",
-        new PermutationDescription());
+    MinimalRebuildCache fooCacheOld = minimalRebuildCacheManager.getCache(moduleName,
+        permutationDescription);
+
+    // Show that the manager created a new empty cache for the request of a cache that does not
+    // exist. Do not test instnace equality as getCache always returns a copy.
+    assertTrue(emptyCache.hasSameContent(fooCacheOld));
+
+    // Set some data into the cache
+    fooCacheOld.addTypeReference("Type1", "Type2");
+    assertFalse(emptyCache.hasSameContent(fooCacheOld));
+
+    // Set the cache back and shut down the manager to wait for the cache to be written to disk.
+    minimalRebuildCacheManager.enqueueAsyncWriteDiskCache(
+        moduleName, permutationDescription, fooCacheOld);
+    minimalRebuildCacheManager.shutdown();
+
+    // Change compiler options and get a new cache manager.
+    Map<String, String> newCompilerOptions = ImmutableMap.of("option", "newvalue");
+    minimalRebuildCacheManager =
+        new MinimalRebuildCacheManager(
+            TreeLogger.NULL, cacheDir, newCompilerOptions);
+
+    // Now get the cache for FooModule under different compiler flags
+    MinimalRebuildCache fooCacheNew = minimalRebuildCacheManager.getCache(moduleName,
+        permutationDescription);
 
     // Show that the manager created a new empty cache for the request of a cache that does not
     // exist.
-    assertFalse(emptyCache == noSuchCache);
-    assertTrue(emptyCache.hasSameContent(noSuchCache));
+    assertTrue(emptyCache.hasSameContent(fooCacheNew));
+    assertFalse(fooCacheOld.hasSameContent(fooCacheNew));
+
+    // Set the cache back and shut down the manager to wait for the cache to be written to disk.
+    minimalRebuildCacheManager.enqueueAsyncWriteDiskCache(
+        moduleName, permutationDescription, fooCacheNew);
+    minimalRebuildCacheManager.shutdown();
+
+    // Switch back to the initial option values and verify you get the same old cache.
+    minimalRebuildCacheManager =
+        new MinimalRebuildCacheManager(
+            TreeLogger.NULL, cacheDir, initialCompilerOptions);
+
+    // Now get the cache for FooModule under different under initial options values.
+    MinimalRebuildCache fooCacheResetOptions = minimalRebuildCacheManager.getCache(
+        moduleName,
+        permutationDescription);
+
+    // Show that the manager retrieved the already existing cache for FooModule under initial
+    // compiler options.
+    assertTrue(fooCacheOld.hasSameContent(fooCacheResetOptions));
+    minimalRebuildCacheManager.deleteCaches();
+    minimalRebuildCacheManager.shutdown();
+    cacheDir.delete();
   }
 
   public void testReload() throws InterruptedException {
@@ -53,7 +104,8 @@
 
     String moduleName = "com.google.FooModule";
     MinimalRebuildCacheManager minimalRebuildCacheManager =
-        new MinimalRebuildCacheManager(TreeLogger.NULL, cacheDir);
+        new MinimalRebuildCacheManager(
+            TreeLogger.NULL, cacheDir, ImmutableMap.<String, String>of());
     PermutationDescription permutationDescription = new PermutationDescription();
 
     // Make sure we start with a blank slate.
@@ -96,7 +148,8 @@
 
     // Start a new cache manager in the same folder.
     MinimalRebuildCacheManager reloadedMinimalRebuildCacheManager =
-        new MinimalRebuildCacheManager(TreeLogger.NULL, cacheDir);
+        new MinimalRebuildCacheManager(
+            TreeLogger.NULL, cacheDir, ImmutableMap.<String, String>of());
 
     // Reread the previously saved cache.
     MinimalRebuildCache reloadedCache =