blob: 6bb9297a86713daadafdb815354a029ba8c90514 [file] [log] [blame]
package org.checkerframework.checker.units;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.util.Elements;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.units.qual.N;
import org.checkerframework.checker.units.qual.Prefix;
import org.checkerframework.checker.units.qual.g;
import org.checkerframework.checker.units.qual.h;
import org.checkerframework.checker.units.qual.kg;
import org.checkerframework.checker.units.qual.km2;
import org.checkerframework.checker.units.qual.km3;
import org.checkerframework.checker.units.qual.kmPERh;
import org.checkerframework.checker.units.qual.m;
import org.checkerframework.checker.units.qual.m2;
import org.checkerframework.checker.units.qual.m3;
import org.checkerframework.checker.units.qual.mPERs;
import org.checkerframework.checker.units.qual.mPERs2;
import org.checkerframework.checker.units.qual.mm2;
import org.checkerframework.checker.units.qual.mm3;
import org.checkerframework.checker.units.qual.s;
import org.checkerframework.checker.units.qual.t;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
/** Default relations between SI units. */
public class UnitsRelationsDefault implements UnitsRelations {
/** SI base units. */
protected AnnotationMirror m, km, mm, s, g, kg;
/** Derived SI units without special names */
protected AnnotationMirror m2, km2, mm2, m3, km3, mm3, mPERs, mPERs2;
/** Derived SI units with special names */
protected AnnotationMirror N, kN;
/** Non-SI units */
protected AnnotationMirror h, kmPERh, t;
/** The Element Utilities from the Units Checker's processing environment. */
protected Elements elements;
/**
* Constructs various AnnotationMirrors representing specific checker-framework provided Units
* involved in the rules resolved in this UnitsRelations implementation.
*/
@Override
public UnitsRelations init(ProcessingEnvironment env) {
elements = env.getElementUtils();
m = UnitsRelationsTools.buildAnnoMirrorWithDefaultPrefix(env, m.class);
km = UnitsRelationsTools.buildAnnoMirrorWithSpecificPrefix(env, m.class, Prefix.kilo);
mm = UnitsRelationsTools.buildAnnoMirrorWithSpecificPrefix(env, m.class, Prefix.milli);
m2 = UnitsRelationsTools.buildAnnoMirrorWithNoPrefix(env, m2.class);
km2 = UnitsRelationsTools.buildAnnoMirrorWithNoPrefix(env, km2.class);
mm2 = UnitsRelationsTools.buildAnnoMirrorWithNoPrefix(env, mm2.class);
m3 = UnitsRelationsTools.buildAnnoMirrorWithNoPrefix(env, m3.class);
km3 = UnitsRelationsTools.buildAnnoMirrorWithNoPrefix(env, km3.class);
mm3 = UnitsRelationsTools.buildAnnoMirrorWithNoPrefix(env, mm3.class);
s = UnitsRelationsTools.buildAnnoMirrorWithDefaultPrefix(env, s.class);
h = UnitsRelationsTools.buildAnnoMirrorWithNoPrefix(env, h.class);
mPERs = UnitsRelationsTools.buildAnnoMirrorWithNoPrefix(env, mPERs.class);
kmPERh = UnitsRelationsTools.buildAnnoMirrorWithNoPrefix(env, kmPERh.class);
mPERs2 = UnitsRelationsTools.buildAnnoMirrorWithNoPrefix(env, mPERs2.class);
g = UnitsRelationsTools.buildAnnoMirrorWithDefaultPrefix(env, g.class);
kg = UnitsRelationsTools.buildAnnoMirrorWithSpecificPrefix(env, g.class, Prefix.kilo);
t = UnitsRelationsTools.buildAnnoMirrorWithNoPrefix(env, t.class);
N = UnitsRelationsTools.buildAnnoMirrorWithDefaultPrefix(env, N.class);
kN = UnitsRelationsTools.buildAnnoMirrorWithSpecificPrefix(env, N.class, Prefix.kilo);
return this;
}
/**
* Provides rules for resolving the result Unit of the multiplication of checker-framework
* provided Units.
*/
@Override
public @Nullable AnnotationMirror multiplication(
AnnotatedTypeMirror lht, AnnotatedTypeMirror rht) {
// TODO: does this handle scaling correctly?
// length * length => area
// checking SI units only
if (UnitsRelationsTools.hasSpecificUnitIgnoringPrefix(lht, m)
&& UnitsRelationsTools.hasSpecificUnitIgnoringPrefix(rht, m)) {
if (UnitsRelationsTools.hasNoPrefix(lht) && UnitsRelationsTools.hasNoPrefix(rht)) {
// m * m
return m2;
}
Prefix lhtPrefix = UnitsRelationsTools.getPrefix(lht);
Prefix rhtPrefix = UnitsRelationsTools.getPrefix(rht);
if (bothHaveSpecificPrefix(lhtPrefix, rhtPrefix, Prefix.kilo)) {
// km * km
return km2;
} else if (bothHaveSpecificPrefix(lhtPrefix, rhtPrefix, Prefix.one)) {
// m(Prefix.one) * m(Prefix.one)
return m2;
} else if (bothHaveSpecificPrefix(lhtPrefix, rhtPrefix, Prefix.milli)) {
// mm * mm
return mm2;
} else {
return null;
}
} else if (havePairOfUnitsIgnoringOrder(lht, m, rht, m2)) {
return m3;
} else if (havePairOfUnitsIgnoringOrder(lht, km, rht, km2)) {
return km3;
} else if (havePairOfUnitsIgnoringOrder(lht, mm, rht, mm2)) {
return mm3;
} else if (havePairOfUnitsIgnoringOrder(lht, s, rht, mPERs)) {
// s * mPERs or mPERs * s => m
return m;
} else if (havePairOfUnitsIgnoringOrder(lht, s, rht, mPERs2)) {
// s * mPERs2 or mPERs2 * s => mPERs
return mPERs;
} else if (havePairOfUnitsIgnoringOrder(lht, h, rht, kmPERh)) {
// h * kmPERh or kmPERh * h => km
return km;
} else if (havePairOfUnitsIgnoringOrder(lht, kg, rht, mPERs2)) {
// kg * mPERs2 or mPERs2 * kg = N
return N;
} else if (havePairOfUnitsIgnoringOrder(lht, t, rht, mPERs2)) {
// t * mPERs2 or mPERs2 * t = kN
return kN;
} else {
return null;
}
}
/**
* Provides rules for resolving the result Unit of the division of checker-framework provided
* Units.
*/
@Override
public @Nullable AnnotationMirror division(AnnotatedTypeMirror lht, AnnotatedTypeMirror rht) {
if (havePairOfUnits(lht, m, rht, s)) {
// m / s => mPERs
return mPERs;
} else if (havePairOfUnits(lht, km, rht, h)) {
// km / h => kmPERh
return kmPERh;
} else if (havePairOfUnits(lht, m2, rht, m)) {
// m2 / m => m
return m;
} else if (havePairOfUnits(lht, km2, rht, km)) {
// km2 / km => km
return km;
} else if (havePairOfUnits(lht, mm2, rht, mm)) {
// mm2 / mm => mm
return mm;
} else if (havePairOfUnits(lht, m3, rht, m)) {
// m3 / m => m2
return m2;
} else if (havePairOfUnits(lht, km3, rht, km)) {
// km3 / km => km2
return km2;
} else if (havePairOfUnits(lht, mm3, rht, mm)) {
// mm3 / mm => mm2
return mm2;
} else if (havePairOfUnits(lht, m3, rht, m2)) {
// m3 / m2 => m
return m;
} else if (havePairOfUnits(lht, km3, rht, km2)) {
// km3 / km2 => km
return km;
} else if (havePairOfUnits(lht, mm3, rht, mm2)) {
// mm3 / mm2 => mm
return mm;
} else if (havePairOfUnits(lht, m, rht, mPERs)) {
// m / mPERs => s
return s;
} else if (havePairOfUnits(lht, km, rht, kmPERh)) {
// km / kmPERh => h
return h;
} else if (havePairOfUnits(lht, mPERs, rht, s)) {
// mPERs / s = mPERs2
return mPERs2;
} else if (havePairOfUnits(lht, mPERs, rht, mPERs2)) {
// mPERs / mPERs2 => s (velocity / acceleration == time)
return s;
} else if (UnitsRelationsTools.hasSpecificUnit(lht, N)) {
if (UnitsRelationsTools.hasSpecificUnit(rht, kg)) {
// N / kg => mPERs2
return mPERs2;
} else if (UnitsRelationsTools.hasSpecificUnit(rht, mPERs2)) {
// N / mPERs2 => kg
return kg;
}
return null;
} else if (UnitsRelationsTools.hasSpecificUnit(lht, kN)) {
if (UnitsRelationsTools.hasSpecificUnit(rht, t)) {
// kN / t => mPERs2
return mPERs2;
} else if (UnitsRelationsTools.hasSpecificUnit(rht, mPERs2)) {
// kN / mPERs2 => t
return t;
}
return null;
} else {
return null;
}
}
/**
* Checks to see if both lhtPrefix and rhtPrefix have the same prefix as specificPrefix.
*
* @param lhtPrefix left hand side prefix
* @param rhtPrefix right hand side prefix
* @param specificPrefix specific desired prefix to match
* @return true if all 3 Prefix are the same, false otherwise
*/
protected boolean bothHaveSpecificPrefix(
Prefix lhtPrefix, Prefix rhtPrefix, Prefix specificPrefix) {
if (lhtPrefix == null || rhtPrefix == null || specificPrefix == null) {
return false;
}
return lhtPrefix == rhtPrefix && rhtPrefix == specificPrefix;
}
/**
* Checks to see if lht has the unit ul and if rht has the unit ur all at the same time.
*
* @param lht left hand annotated type
* @param ul left hand unit
* @param rht right hand annotated type
* @param ur right hand unit
* @return true if lht has lu and rht has ru, false otherwise
*/
protected boolean havePairOfUnits(
AnnotatedTypeMirror lht, AnnotationMirror ul, AnnotatedTypeMirror rht, AnnotationMirror ur) {
return UnitsRelationsTools.hasSpecificUnit(lht, ul)
&& UnitsRelationsTools.hasSpecificUnit(rht, ur);
}
/**
* Checks to see if lht and rht have the pair of units u1 and u2 regardless of order.
*
* @param lht left hand annotated type
* @param u1 unit 1
* @param rht right hand annotated type
* @param u2 unit 2
* @return true if lht and rht have the pair of units u1 and u2 regardless of order, false
* otherwise
*/
protected boolean havePairOfUnitsIgnoringOrder(
AnnotatedTypeMirror lht, AnnotationMirror u1, AnnotatedTypeMirror rht, AnnotationMirror u2) {
return havePairOfUnits(lht, u1, rht, u2) || havePairOfUnits(lht, u2, rht, u1);
}
}