Commit f46e20e4 authored by Danny Weinberg's avatar Danny Weinberg Committed by Jacob Potter

Various improvements to make javac lint happy

Add a hashCode implementation in Java when deriving the eq function. This is
also good practice in general.

Avoid referencing rawtypes when deriving the ord function.

Fix nullity annotation of parameter to compareTo method.
parent decd1770
......@@ -26,8 +26,9 @@ import scala.collection.mutable
class JavaGenerator(spec: Spec) extends Generator(spec) {
var javaAnnotationHeader = spec.javaAnnotation.map(pkg => '@' + pkg.split("\\.").last)
val javaAnnotationHeader = spec.javaAnnotation.map(pkg => '@' + pkg.split("\\.").last)
val javaNullableAnnotation = spec.javaNullableAnnotation.map(pkg => '@' + pkg.split("\\.").last)
val javaNonnullAnnotation = spec.javaNonnullAnnotation.map(pkg => '@' + pkg.split("\\.").last)
val marshal = new JavaMarshal(spec)
class JavaRefs() {
......@@ -215,14 +216,9 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
javaAnnotationHeader.foreach(w.wl)
val self = marshal.typename(javaName, r)
// HACK: Use generic base class to correctly implement Comparable interface
val comparableFlag =
if (r.derivingTypes.contains(DerivingType.Ord)) {
if (r.ext.java) {
s"<E extends $self> implements Comparable<E>"
} else {
s" implements Comparable<$self>"
}
s" implements Comparable<$self>"
} else {
""
}
......@@ -295,13 +291,46 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
}
w.wl(";")
}
// Also generate a hashCode function, since you shouldn't override one without the other.
// This hashcode implementation is based off of the apache commons-lang implementation of
// HashCodeBuilder (excluding support for Java arrays) which is in turn based off of the
// the recommendataions made in Effective Java.
w.wl
w.wl("@Override")
w.w("public int hashCode()").braced {
w.wl("// Pick an arbitrary non-zero starting value")
w.wl("int hashCode = 17;")
// Also pick an arbitrary prime to use as the multiplier.
val multiplier = "31"
for (f <- r.fields) {
val fieldHashCode = f.ty.resolved.base match {
case MBinary => s"java.util.Arrays.hashCode(${idJava.field(f.ident)})"
case MList | MSet | MMap | MString | MDate => s"${idJava.field(f.ident)}.hashCode()"
// Need to repeat this case for MDef
case df: MDef => s"${idJava.field(f.ident)}.hashCode()"
case MOptional => s"(${idJava.field(f.ident)} == null ? 0 : ${idJava.field(f.ident)}.hashCode())"
case t: MPrimitive => t.jName match {
case "byte" | "short" | "int" => idJava.field(f.ident)
case "long" => s"((int) (${idJava.field(f.ident)} ^ (${idJava.field(f.ident)} >>> 32)))"
case "float" => s"Float.floatToIntBits(${idJava.field(f.ident)})"
case "double" => s"((int) (Double.doubleToLongBits(${idJava.field(f.ident)}) ^ (Double.doubleToLongBits(${idJava.field(f.ident)}) >>> 32)))"
case "boolean" => s"(${idJava.field(f.ident)} ? 1 : 0)"
case _ => throw new AssertionError("Unreachable")
}
case _ => throw new AssertionError("Unreachable")
}
w.wl(s"hashCode = hashCode * $multiplier + $fieldHashCode;")
}
w.wl(s"return hashCode;")
}
}
if (r.derivingTypes.contains(DerivingType.Ord)) {
w.wl
w.wl("@Override")
val tyName = if (r.ext.java) "E" else self
w.w(s"public int compareTo($tyName other) ").braced {
val nonnullAnnotation = javaNonnullAnnotation.map(_ + " ").getOrElse("")
w.w(s"public int compareTo($nonnullAnnotation$self other) ").braced {
w.wl("int tempResult;")
for (f <- r.fields) {
f.ty.resolved.base match {
......
......@@ -33,7 +33,11 @@ case class Doc(lines: Seq[String])
case class TypeDecl(ident: Ident, params: Seq[TypeParam], body: TypeDef, doc: Doc, origin: String)
case class Ext(java: Boolean, cpp: Boolean, objc: Boolean)
case class Ext(java: Boolean, cpp: Boolean, objc: Boolean) {
def any(): Boolean = {
java || cpp || objc
}
}
case class TypeRef(expr: TypeExpr) {
var resolved: MExpr = null
......
......@@ -211,6 +211,12 @@ private def resolveRecord(scope: Scope, r: Record) {
dupeChecker.check(f.ident)
resolveRef(scope, f.ty)
// Deriving Type Check
if (r.ext.any())
if (r.derivingTypes.contains(DerivingType.Ord)) {
throw new Error(f.ident.loc, "Cannot safely implement Ord on a record that may be extended").toException
} else if (r.derivingTypes.contains(DerivingType.Eq)) {
throw new Error(f.ident.loc, "Cannot safely implement Eq on a record that may be extended").toException
}
f.ty.resolved.base match {
case MBinary | MList | MSet | MMap =>
if (r.derivingTypes.contains(DerivingType.Ord))
......
......@@ -152,4 +152,25 @@ public final class AssortedPrimitives {
((this.mOFthirtytwo == null && other.mOFthirtytwo == null) || (this.mOFthirtytwo != null && this.mOFthirtytwo.equals(other.mOFthirtytwo))) &&
((this.mOFsixtyfour == null && other.mOFsixtyfour == null) || (this.mOFsixtyfour != null && this.mOFsixtyfour.equals(other.mOFsixtyfour)));
}
@Override
public int hashCode() {
// Pick an arbitrary non-zero starting value
int hashCode = 17;
hashCode = hashCode * 31 + (mB ? 1 : 0);
hashCode = hashCode * 31 + mEight;
hashCode = hashCode * 31 + mSixteen;
hashCode = hashCode * 31 + mThirtytwo;
hashCode = hashCode * 31 + ((int) (mSixtyfour ^ (mSixtyfour >>> 32)));
hashCode = hashCode * 31 + Float.floatToIntBits(mFthirtytwo);
hashCode = hashCode * 31 + ((int) (Double.doubleToLongBits(mFsixtyfour) ^ (Double.doubleToLongBits(mFsixtyfour) >>> 32)));
hashCode = hashCode * 31 + (mOB == null ? 0 : mOB.hashCode());
hashCode = hashCode * 31 + (mOEight == null ? 0 : mOEight.hashCode());
hashCode = hashCode * 31 + (mOSixteen == null ? 0 : mOSixteen.hashCode());
hashCode = hashCode * 31 + (mOThirtytwo == null ? 0 : mOThirtytwo.hashCode());
hashCode = hashCode * 31 + (mOSixtyfour == null ? 0 : mOSixtyfour.hashCode());
hashCode = hashCode * 31 + (mOFthirtytwo == null ? 0 : mOFthirtytwo.hashCode());
hashCode = hashCode * 31 + (mOFsixtyfour == null ? 0 : mOFsixtyfour.hashCode());
return hashCode;
}
}
......@@ -40,7 +40,16 @@ public final class RecordWithDerivings implements Comparable<RecordWithDerivings
}
@Override
public int compareTo(RecordWithDerivings other) {
public int hashCode() {
// Pick an arbitrary non-zero starting value
int hashCode = 17;
hashCode = hashCode * 31 + mKey1;
hashCode = hashCode * 31 + mKey2.hashCode();
return hashCode;
}
@Override
public int compareTo(@Nonnull RecordWithDerivings other) {
int tempResult;
if (this.mKey1 < other.mKey1) {
tempResult = -1;
......
......@@ -40,7 +40,16 @@ public final class RecordWithNestedDerivings implements Comparable<RecordWithNes
}
@Override
public int compareTo(RecordWithNestedDerivings other) {
public int hashCode() {
// Pick an arbitrary non-zero starting value
int hashCode = 17;
hashCode = hashCode * 31 + mKey;
hashCode = hashCode * 31 + mRec.hashCode();
return hashCode;
}
@Override
public int compareTo(@Nonnull RecordWithNestedDerivings other) {
int tempResult;
if (this.mKey < other.mKey) {
tempResult = -1;
......
......@@ -29,6 +29,11 @@ public class RecordWithDerivingsTest extends TestCase {
assertFalse(record3.equals(record1));
assertFalse(record2.equals(record3));
assertFalse(record3.equals(record2));
assertTrue(record1.hashCode() == record1A.hashCode());
assertTrue(record1.hashCode() != record2.hashCode());
assertTrue(record1.hashCode() != record3.hashCode());
assertTrue(record2.hashCode() != record3.hashCode());
}
private final RecordWithNestedDerivings nestedRecord1 = new RecordWithNestedDerivings(1, record1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment