@AutoCodec File{State}Value.

PiperOrigin-RevId: 188085895
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileContentsProxy.java b/src/main/java/com/google/devtools/build/lib/skyframe/FileContentsProxy.java
index 8dca37c..2b845ed 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/FileContentsProxy.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/FileContentsProxy.java
@@ -13,21 +13,23 @@
 // limitations under the License.
 package com.google.devtools.build.lib.skyframe;
 
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
 import com.google.devtools.build.lib.vfs.FileStatus;
 import java.io.IOException;
 import java.io.Serializable;
 import java.util.Objects;
 
 /**
- * In case we can't get a fast digest from the filesystem, we store this metadata as a proxy to
- * the file contents. Currently it is a pair of a relevant timestamp and a "node id". On Linux the
- * former is the ctime and the latter is the inode number. We might want to add the device number
- * in the future.
+ * In case we can't get a fast digest from the filesystem, we store this metadata as a proxy to the
+ * file contents. Currently it is a pair of a relevant timestamp and a "node id". On Linux the
+ * former is the ctime and the latter is the inode number. We might want to add the device number in
+ * the future.
  *
  * <p>For a Linux example of why mtime alone is insufficient, note that 'mv' preserves timestamps.
  * So if files 'a' and 'b' initially have the same timestamp, then we would think 'b' is unchanged
  * after the user executes `mv a b` between two builds.
  */
+@AutoCodec
 public final class FileContentsProxy implements Serializable {
   private final long ctime;
   private final long nodeId;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileStateValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/FileStateValue.java
index 56988b8..f92e561 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/FileStateValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/FileStateValue.java
@@ -58,8 +58,11 @@
 @VisibleForTesting
 public abstract class FileStateValue implements SkyValue {
 
+  @AutoCodec
   public static final DirectoryFileStateValue DIRECTORY_FILE_STATE_NODE =
       new DirectoryFileStateValue();
+
+  @AutoCodec
   public static final NonexistentFileStateValue NONEXISTENT_FILE_STATE_NODE =
       new NonexistentFileStateValue();
 
@@ -151,10 +154,11 @@
    *
    * <p>A union of (digest, mtime). We use digests only if a fast digest lookup is available from
    * the filesystem. If not, we fall back to mtime-based digests. This avoids the case where Blaze
-   * must read all files involved in the build in order to check for modifications in the case
-   * where fast digest lookups are not available.
+   * must read all files involved in the build in order to check for modifications in the case where
+   * fast digest lookups are not available.
    */
   @ThreadSafe
+  @AutoCodec
   public static final class RegularFileStateValue extends FileStateValue {
     private final long size;
     @Nullable private final byte[] digest;
@@ -270,6 +274,7 @@
   }
 
   /** Implementation of {@link FileStateValue} for special files that exist. */
+  @AutoCodec
   public static final class SpecialFileStateValue extends FileStateValue {
     private final FileContentsProxy contentsProxy;
 
@@ -330,7 +335,8 @@
   }
 
   /** Implementation of {@link FileStateValue} for directories that exist. */
-  public static final class DirectoryFileStateValue extends FileStateValue {
+  @AutoCodec.VisibleForSerialization
+  static final class DirectoryFileStateValue extends FileStateValue {
 
     private DirectoryFileStateValue() {
     }
@@ -358,6 +364,7 @@
   }
 
   /** Implementation of {@link FileStateValue} for symlinks. */
+  @AutoCodec
   public static final class SymlinkFileStateValue extends FileStateValue {
 
     private final PathFragment symlinkTarget;
@@ -397,7 +404,8 @@
   }
 
   /** Implementation of {@link FileStateValue} for nonexistent files. */
-  public static final class NonexistentFileStateValue extends FileStateValue {
+  @AutoCodec.VisibleForSerialization
+  static final class NonexistentFileStateValue extends FileStateValue {
 
     private NonexistentFileStateValue() {
     }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/FileValue.java
index a0fe84d..46e75ce 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/FileValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/FileValue.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.skyframe;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Interner;
 import com.google.devtools.build.lib.actions.FileStateType;
@@ -168,14 +169,16 @@
    * requested path. For example, this is the case for the path "foo/bar/baz" if neither 'foo' nor
    * 'foo/bar' nor 'foo/bar/baz' are symlinks.
    */
+  @VisibleForTesting
+  @AutoCodec
   public static final class RegularFileValue extends FileValue {
 
     private final RootedPath rootedPath;
     private final FileStateValue fileStateValue;
 
-    public RegularFileValue(RootedPath rootedPath, FileStateValue fileState) {
+    public RegularFileValue(RootedPath rootedPath, FileStateValue fileStateValue) {
       this.rootedPath = Preconditions.checkNotNull(rootedPath);
-      this.fileStateValue = Preconditions.checkNotNull(fileState);
+      this.fileStateValue = Preconditions.checkNotNull(fileStateValue);
     }
 
     @Override
@@ -216,13 +219,15 @@
    * requested path. For example, this is the case for the path "foo/bar/baz" if at least one of
    * 'foo', 'foo/bar', or 'foo/bar/baz' is a symlink.
    */
-  public static class DifferentRealPathFileValue extends FileValue {
+  @AutoCodec.VisibleForSerialization
+  @AutoCodec
+  static class DifferentRealPathFileValue extends FileValue {
 
     protected final RootedPath realRootedPath;
     protected final FileStateValue realFileStateValue;
 
-    public DifferentRealPathFileValue(RootedPath realRootedPath,
-                                      FileStateValue realFileStateValue) {
+    @AutoCodec.VisibleForSerialization
+    DifferentRealPathFileValue(RootedPath realRootedPath, FileStateValue realFileStateValue) {
       this.realRootedPath = Preconditions.checkNotNull(realRootedPath);
       this.realFileStateValue = Preconditions.checkNotNull(realFileStateValue);
     }
@@ -262,13 +267,16 @@
   }
 
   /** Implementation of {@link FileValue} for files that are symlinks. */
-  public static final class SymlinkFileValue extends DifferentRealPathFileValue {
-    private final PathFragment linkValue;
+  @VisibleForTesting
+  @AutoCodec
+  static final class SymlinkFileValue extends DifferentRealPathFileValue {
+    private final PathFragment linkTarget;
 
-    public SymlinkFileValue(RootedPath realRootedPath, FileStateValue realFileState,
-                            PathFragment linkTarget) {
-      super(realRootedPath, realFileState);
-      this.linkValue = linkTarget;
+    @VisibleForTesting
+    SymlinkFileValue(
+        RootedPath realRootedPath, FileStateValue realFileStateValue, PathFragment linkTarget) {
+      super(realRootedPath, realFileStateValue);
+      this.linkTarget = linkTarget;
     }
 
     @Override
@@ -278,7 +286,7 @@
 
     @Override
     public PathFragment getUnresolvedLinkTarget() {
-      return linkValue;
+      return linkTarget;
     }
 
     @Override
@@ -292,19 +300,19 @@
       SymlinkFileValue other = (SymlinkFileValue) obj;
       return realRootedPath.equals(other.realRootedPath)
           && realFileStateValue.equals(other.realFileStateValue)
-          && linkValue.equals(other.linkValue);
+          && linkTarget.equals(other.linkTarget);
     }
 
     @Override
     public int hashCode() {
-      return Objects.hash(
-          realRootedPath, realFileStateValue, linkValue, Boolean.TRUE);
+      return Objects.hash(realRootedPath, realFileStateValue, linkTarget, Boolean.TRUE);
     }
 
     @Override
     public String toString() {
-      return String.format("symlink (real_path=%s, real_state=%s, link_value=%s)",
-          realRootedPath, realFileStateValue, linkValue);
+      return String.format(
+          "symlink (real_path=%s, real_state=%s, link_value=%s)",
+          realRootedPath, realFileStateValue, linkTarget);
     }
   }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/FileStateValueTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/FileStateValueTest.java
new file mode 100644
index 0000000..36f8d24
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/FileStateValueTest.java
@@ -0,0 +1,45 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.skyframe;
+
+import com.google.devtools.build.lib.skyframe.serialization.testutils.SerializationTester;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link FileStateValue}. */
+@RunWith(JUnit4.class)
+public class FileStateValueTest {
+  @Test
+  public void testCodec() throws Exception {
+    new SerializationTester(
+            new FileStateValue.RegularFileStateValue(
+                /*size=*/ 1, /*digest=*/ new byte[] {1, 2, 3}, /*contentsProxy=*/ null),
+            new FileStateValue.RegularFileStateValue(
+                /*size=*/ 1, /*digest=*/ new byte[0], /*contentsProxy=*/ null),
+            new FileStateValue.RegularFileStateValue(
+                /*size=*/ 1,
+                /*digest=*/ null,
+                new FileContentsProxy(/* ctime= */ 2, /* nodeId= */ 42)),
+            new FileStateValue.SpecialFileStateValue(
+                new FileContentsProxy(/* ctime= */ 4, /* nodeId= */ 84)),
+            FileStateValue.DIRECTORY_FILE_STATE_NODE,
+            new FileStateValue.SymlinkFileStateValue(PathFragment.create("somewhere/elses")),
+            FileStateValue.NONEXISTENT_FILE_STATE_NODE)
+        .runTests();
+  }
+
+}
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/FileValueTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/FileValueTest.java
new file mode 100644
index 0000000..c6d0a34
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/FileValueTest.java
@@ -0,0 +1,44 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.skyframe;
+
+import com.google.devtools.build.lib.skyframe.serialization.testutils.FsUtils;
+import com.google.devtools.build.lib.skyframe.serialization.testutils.SerializationTester;
+import com.google.devtools.build.lib.vfs.FileSystem;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link FileValue}. */
+@RunWith(JUnit4.class)
+public class FileValueTest {
+  @Test
+  public void testCodec() throws Exception {
+    new SerializationTester(
+            // Assume we have adequate coverage for FileStateValue serialization.
+            new FileValue.RegularFileValue(
+                FsUtils.TEST_ROOT, FileStateValue.NONEXISTENT_FILE_STATE_NODE),
+            new FileValue.DifferentRealPathFileValue(
+                FsUtils.TEST_ROOT, FileStateValue.DIRECTORY_FILE_STATE_NODE),
+            new FileValue.SymlinkFileValue(
+                FsUtils.TEST_ROOT,
+                new FileStateValue.RegularFileStateValue(
+                    /*size=*/ 100, /*digest=*/ new byte[] {1, 2, 3, 4, 5}, /*contentsProxy=*/ null),
+                PathFragment.create("somewhere/else")))
+        .addDependency(FileSystem.class, FsUtils.TEST_FILESYSTEM)
+        .runTests();
+  }
+}