Implement the strictfp modifier

MOE_MIGRATED_REVID=139271575
diff --git a/java/com/google/turbine/binder/TypeBinder.java b/java/com/google/turbine/binder/TypeBinder.java
index a1feb37..d332a43 100644
--- a/java/com/google/turbine/binder/TypeBinder.java
+++ b/java/com/google/turbine/binder/TypeBinder.java
@@ -129,15 +129,34 @@
     return new TypeBinder(env, sym, base).bind();
   }
 
+  private final boolean isStrictFp;
   private final Env<ClassSymbol, HeaderBoundClass> env;
   private final ClassSymbol owner;
   private final SourceHeaderBoundClass base;
 
-  public TypeBinder(
+  private TypeBinder(
       Env<ClassSymbol, HeaderBoundClass> env, ClassSymbol owner, SourceHeaderBoundClass base) {
     this.env = env;
     this.owner = owner;
     this.base = base;
+    this.isStrictFp = isStrictFp(env, owner);
+  }
+
+  private boolean isStrictFp(Env<ClassSymbol, HeaderBoundClass> env, ClassSymbol sym) {
+    while (sym != null) {
+      HeaderBoundClass info = env.get(sym);
+      switch (info.kind()) {
+        case ANNOTATION:
+          return false;
+        default:
+          break;
+      }
+      if ((info.access() & TurbineFlag.ACC_STRICT) == TurbineFlag.ACC_STRICT) {
+        return true;
+      }
+      sym = info.owner();
+    }
+    return false;
   }
 
   private SourceTypeBoundClass bind() {
@@ -216,7 +235,7 @@
         interfaceTypes.build(),
         superClassType,
         typeParameterTypes,
-        base.access(),
+        base.access() & ~TurbineFlag.ACC_STRICT,
         ImmutableList.copyOf(methods),
         fields,
         base.owner(),
@@ -261,6 +280,9 @@
       formals = ImmutableList.of();
     }
     int access = TurbineVisibility.fromAccess(base.access()).flag();
+    if (isStrictFp) {
+      access |= TurbineFlag.ACC_STRICT;
+    }
     access |= TurbineFlag.ACC_SYNTH_CTOR;
     methods.add(
         new MethodInfo(
@@ -277,6 +299,11 @@
   }
 
   private void addEnumMethods(List<MethodInfo> methods) {
+    int access = 0;
+    if (isStrictFp) {
+      access |= TurbineFlag.ACC_STRICT;
+    }
+
     if (!hasConstructor(methods)) {
       methods.add(
           new MethodInfo(
@@ -290,7 +317,7 @@
                       ImmutableList.of(),
                       true)),
               ImmutableList.of(),
-              TurbineFlag.ACC_PRIVATE | TurbineFlag.ACC_SYNTH_CTOR,
+              access | TurbineFlag.ACC_PRIVATE | TurbineFlag.ACC_SYNTH_CTOR,
               null,
               null,
               ImmutableList.of(),
@@ -304,7 +331,7 @@
             Type.ClassTy.asNonParametricClassTy(owner),
             ImmutableList.of(new ParamInfo(Type.ClassTy.STRING, ImmutableList.of(), false)),
             ImmutableList.of(),
-            TurbineFlag.ACC_PUBLIC | TurbineFlag.ACC_STATIC,
+            access | TurbineFlag.ACC_PUBLIC | TurbineFlag.ACC_STATIC,
             null,
             null,
             ImmutableList.of(),
@@ -317,7 +344,7 @@
             new Type.ArrayTy(Type.ClassTy.asNonParametricClassTy(owner), ImmutableList.of()),
             ImmutableList.of(),
             ImmutableList.of(),
-            TurbineFlag.ACC_PUBLIC | TurbineFlag.ACC_STATIC,
+            access | TurbineFlag.ACC_PUBLIC | TurbineFlag.ACC_STATIC,
             null,
             null,
             ImmutableList.of(),
@@ -458,6 +485,10 @@
         break;
     }
 
+    if (isStrictFp && (access & TurbineFlag.ACC_ABSTRACT) == 0) {
+      access |= TurbineFlag.ACC_STRICT;
+    }
+    
     ImmutableList<AnnoInfo> annotations = bindAnnotations(scope, t.annos());
     return new MethodInfo(
         sym,
diff --git a/javatests/com/google/turbine/lower/LowerIntegrationTest.java b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
index 8d30eca..05db806 100644
--- a/javatests/com/google/turbine/lower/LowerIntegrationTest.java
+++ b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
@@ -270,6 +270,7 @@
       "const_boxed.test",
       "interface_member_public.test",
       "javadoc_deprecated.test",
+      "strictfp.test",
     };
     List<Object[]> tests =
         ImmutableList.copyOf(testCases).stream().map(x -> new Object[] {x}).collect(toList());
diff --git a/javatests/com/google/turbine/lower/testdata/strictfp.test b/javatests/com/google/turbine/lower/testdata/strictfp.test
new file mode 100644
index 0000000..6d50176
--- /dev/null
+++ b/javatests/com/google/turbine/lower/testdata/strictfp.test
@@ -0,0 +1,44 @@
+=== Test.java ===
+strictfp abstract class Test {
+  abstract void a();
+  strictfp void f() {}
+  class Inner {
+    void g() {}
+  }
+  enum E {
+    ;
+    void h() {}
+  }
+  @interface A {
+    int value() default 0;
+  }
+  interface I {
+    default int j() {
+      return 1;
+    }
+  }
+  final double x = 1.0 / 2;
+}
+
+=== I.java ===
+strictfp interface I {
+  void f();
+  abstract void a();
+  abstract class N {
+    void g() {}
+    abstract void a();
+  }
+}
+
+=== E.java ===
+strictfp enum E {
+  I {
+    void a() {}
+  };
+  void f() {}
+  abstract void a();
+  abstract class N {
+    void g() {}
+    abstract void a();
+  }
+}