mirror of https://github.com/sbt/sbt.git
340 lines
8.7 KiB
Scala
340 lines
8.7 KiB
Scala
/* sbt -- Simple Build Tool
|
|
* Copyright 2009, 2010, 2011 Mark Harrah
|
|
*/
|
|
package xsbt.api
|
|
|
|
import scala.util
|
|
import xsbti.api._
|
|
import util.MurmurHash
|
|
import HashAPI.Hash
|
|
|
|
object HashAPI
|
|
{
|
|
type Hash = Int
|
|
def apply(a: SourceAPI): Hash =
|
|
(new HashAPI(false, true)).hashAPI(a)
|
|
}
|
|
|
|
final class HashAPI(includePrivate: Boolean, includeParamNames: Boolean)
|
|
{
|
|
import scala.collection.mutable
|
|
import MurmurHash._
|
|
|
|
private[this] val visitedStructures = visitedMap[Structure]
|
|
private[this] val visitedClassLike = visitedMap[ClassLike]
|
|
private[this] def visitedMap[T] = new mutable.HashMap[T, List[Hash]]
|
|
private[this] def visit[T](map: mutable.Map[T, List[Hash]], t: T)(hashF: T => Unit)
|
|
{
|
|
map.put(t, hash :: map.getOrElse(t,Nil)) match {
|
|
case Some(x :: _) => extend(x)
|
|
case _ =>
|
|
hashF(t)
|
|
for(hs <- map(t))
|
|
extend(hs)
|
|
map.put(t, hash :: Nil)
|
|
}
|
|
}
|
|
|
|
private[this] final val ValHash = 1
|
|
private[this] final val VarHash = 2
|
|
private[this] final val DefHash = 3
|
|
private[this] final val ClassHash = 4
|
|
private[this] final val TypeDeclHash = 5
|
|
private[this] final val TypeAliasHash = 6
|
|
|
|
private[this] final val PublicHash = 30
|
|
private[this] final val ProtectedHash = 31
|
|
private[this] final val PrivateHash = 32
|
|
private[this] final val UnqualifiedHash = 33
|
|
private[this] final val ThisQualifierHash = 34
|
|
private[this] final val IdQualifierHash = 35
|
|
|
|
private[this] final val IdPathHash = 20
|
|
private[this] final val SuperHash = 21
|
|
private[this] final val ThisPathHash = 22
|
|
|
|
private[this] final val ValueParamsHash = 40
|
|
private[this] final val ClassPendingHash = 41
|
|
private[this] final val StructurePendingHash = 42
|
|
|
|
private[this] final val EmptyTypeHash = 51
|
|
private[this] final val ParameterRefHash = 52
|
|
private[this] final val SingletonHash = 53
|
|
private[this] final val ProjectionHash = 54
|
|
private[this] final val ParameterizedHash = 55
|
|
private[this] final val AnnotatedHash = 56
|
|
private[this] final val PolymorphicHash = 57
|
|
private[this] final val ConstantHash = 58
|
|
private[this] final val ExistentialHash = 59
|
|
private[this] final val StructureHash = 60
|
|
|
|
private[this] final val TrueHash = 97
|
|
private[this] final val FalseHash = 98
|
|
|
|
|
|
private[this] var hash: Hash = startHash(0)
|
|
private[this] var magicA: Hash = startMagicA
|
|
private[this] var magicB: Hash = startMagicB
|
|
|
|
@inline final def hashString(s: String): Unit = extend(stringHash(s))
|
|
@inline final def hashBoolean(b: Boolean): Unit = extend(if(b) TrueHash else FalseHash)
|
|
@inline final def hashSeq[T](s: Seq[T], hashF: T => Unit)
|
|
{
|
|
extend(s.length)
|
|
s foreach hashF
|
|
}
|
|
final def hashSymmetric[T](ts: TraversableOnce[T], hashF: T => Unit)
|
|
{
|
|
val current = hash
|
|
val mA = magicA
|
|
val mB = magicB
|
|
val (hashes, mAs, mBs) = ts.toList.map { t =>
|
|
hash = startHash(1)
|
|
magicA = startMagicA
|
|
magicB = startMagicB
|
|
hashF(t)
|
|
(finalizeHash(hash), magicA, magicB)
|
|
} unzip3;
|
|
hash = current
|
|
magicA = mA
|
|
magicB = mB
|
|
extend(symmetricHash(hashes, 0xb592f7ae)) // constant from MurmurHash3
|
|
}
|
|
|
|
@inline final def extend(a: Hash)
|
|
{
|
|
hash = extendHash(hash, a, magicA, magicB)
|
|
magicA = nextMagicA(magicA)
|
|
magicB = nextMagicB(magicB)
|
|
}
|
|
def hashModifiers(m: Modifiers) = extend(m.raw)
|
|
|
|
def hashAPI(s: SourceAPI): Hash =
|
|
{
|
|
hash = startHash(0)
|
|
hashSymmetric(s.packages, hashPackage)
|
|
hashDefinitions(s.definitions, true)
|
|
finalizeHash(hash)
|
|
}
|
|
|
|
def hashPackage(p: Package) = hashString(p.name)
|
|
|
|
def hashDefinitions(ds: Seq[Definition], topLevel: Boolean): Unit =
|
|
{
|
|
val defs = SameAPI.filterDefinitions(ds, topLevel, includePrivate)
|
|
hashSymmetric(defs, hashDefinition)
|
|
}
|
|
def hashDefinition(d: Definition)
|
|
{
|
|
hashString(d.name)
|
|
hashAnnotations(d.annotations)
|
|
hashModifiers(d.modifiers)
|
|
hashAccess(d.access)
|
|
d match
|
|
{
|
|
case c: ClassLike => hashClass(c)
|
|
case f: FieldLike => hashField(f)
|
|
case d: Def => hashDef(d)
|
|
case t: TypeDeclaration => hashTypeDeclaration(t)
|
|
case t: TypeAlias => hashTypeAlias(t)
|
|
}
|
|
}
|
|
final def hashClass(c: ClassLike): Unit = visit(visitedClassLike, c)(hashClass0)
|
|
def hashClass0(c: ClassLike)
|
|
{
|
|
extend(ClassHash)
|
|
hashParameterizedDefinition(c)
|
|
hashType(c.selfType)
|
|
hashStructure(c.structure)
|
|
}
|
|
def hashField(f: FieldLike)
|
|
{
|
|
f match
|
|
{
|
|
case v: Var => extend(VarHash)
|
|
case v: Val => extend(ValHash)
|
|
}
|
|
hashType(f.tpe)
|
|
}
|
|
def hashDef(d: Def)
|
|
{
|
|
extend(DefHash)
|
|
hashParameterizedDefinition(d)
|
|
hashValueParameters(d.valueParameters)
|
|
hashType(d.returnType)
|
|
}
|
|
def hashAccess(a: Access): Unit =
|
|
a match
|
|
{
|
|
case pub: Public => extend(PublicHash)
|
|
case qual: Qualified => hashQualified(qual)
|
|
}
|
|
def hashQualified(qual: Qualified): Unit =
|
|
{
|
|
qual match
|
|
{
|
|
case p: Protected => extend(ProtectedHash)
|
|
case p: Private => extend(PrivateHash)
|
|
}
|
|
hashQualifier(qual.qualifier)
|
|
}
|
|
def hashQualifier(qual: Qualifier): Unit =
|
|
qual match
|
|
{
|
|
case _: Unqualified => extend(UnqualifiedHash)
|
|
case _: ThisQualifier => extend(ThisQualifierHash)
|
|
case id: IdQualifier =>
|
|
extend(IdQualifierHash)
|
|
hashString(id.value)
|
|
}
|
|
|
|
def hashValueParameters(valueParameters: Seq[ParameterList]) = hashSeq(valueParameters, hashValueParameterList)
|
|
def hashValueParameterList(list: ParameterList) =
|
|
{
|
|
extend(ValueParamsHash)
|
|
hashBoolean(list.isImplicit)
|
|
hashSeq(list.parameters, hashValueParameter)
|
|
}
|
|
def hashValueParameter(parameter: MethodParameter) =
|
|
{
|
|
hashString(parameter.name)
|
|
hashType(parameter.tpe)
|
|
extend(parameter.modifier.ordinal)
|
|
hashBoolean(parameter.hasDefault)
|
|
}
|
|
|
|
def hashParameterizedDefinition[T <: ParameterizedDefinition](d: T)
|
|
{
|
|
hashTypeParameters(d.typeParameters)
|
|
}
|
|
def hashTypeDeclaration(d: TypeDeclaration)
|
|
{
|
|
extend(TypeDeclHash)
|
|
hashParameterizedDefinition(d)
|
|
hashType(d.lowerBound)
|
|
hashType(d.upperBound)
|
|
}
|
|
def hashTypeAlias(d: TypeAlias)
|
|
{
|
|
extend(TypeAliasHash)
|
|
hashParameterizedDefinition(d)
|
|
hashType(d.tpe)
|
|
}
|
|
|
|
def hashTypeParameters(parameters: Seq[TypeParameter]) = hashSeq(parameters, hashTypeParameter)
|
|
def hashTypeParameter(parameter: TypeParameter)
|
|
{
|
|
hashString(parameter.id)
|
|
extend(parameter.variance.ordinal)
|
|
hashTypeParameters(parameter.typeParameters)
|
|
hashType(parameter.lowerBound)
|
|
hashType(parameter.upperBound)
|
|
hashAnnotations(parameter.annotations)
|
|
}
|
|
def hashAnnotations(annotations: Seq[Annotation]) = hashSeq(annotations, hashAnnotation)
|
|
def hashAnnotation(annotation: Annotation) =
|
|
{
|
|
hashType(annotation.base)
|
|
hashAnnotationArguments(annotation.arguments)
|
|
}
|
|
def hashAnnotationArguments(args: Seq[AnnotationArgument]) = hashSeq(args, hashAnnotationArgument)
|
|
def hashAnnotationArgument(arg: AnnotationArgument)
|
|
{
|
|
hashString(arg.name)
|
|
hashString(arg.value)
|
|
}
|
|
|
|
def hashTypes(ts: Seq[Type]) = hashSeq(ts, hashType)
|
|
def hashType(t: Type): Unit =
|
|
t match
|
|
{
|
|
case s: Structure => hashStructure(s)
|
|
case e: Existential => hashExistential(e)
|
|
case c: Constant => hashConstant(c)
|
|
case p: Polymorphic => hashPolymorphic(p)
|
|
case a: Annotated => hashAnnotated(a)
|
|
case p: Parameterized => hashParameterized(p)
|
|
case p: Projection => hashProjection(p)
|
|
case _: EmptyType => extend(EmptyTypeHash)
|
|
case s: Singleton => hashSingleton(s)
|
|
case pr: ParameterRef => hashParameterRef(pr)
|
|
}
|
|
|
|
def hashParameterRef(p: ParameterRef)
|
|
{
|
|
extend(ParameterRefHash)
|
|
hashString(p.id)
|
|
}
|
|
def hashSingleton(s: Singleton)
|
|
{
|
|
extend(SingletonHash)
|
|
hashPath(s.path)
|
|
}
|
|
def hashPath(path: Path) = hashSeq(path.components, hashPathComponent)
|
|
def hashPathComponent(pc: PathComponent) = pc match
|
|
{
|
|
case _: This => extend(ThisPathHash)
|
|
case s: Super => hashSuperPath(s)
|
|
case id: Id => hashIdPath(id)
|
|
}
|
|
def hashSuperPath(s: Super)
|
|
{
|
|
extend(SuperHash)
|
|
hashPath(s.qualifier)
|
|
}
|
|
def hashIdPath(id: Id)
|
|
{
|
|
extend(IdPathHash)
|
|
hashString(id.id)
|
|
}
|
|
|
|
def hashConstant(c: Constant) =
|
|
{
|
|
extend(ConstantHash)
|
|
hashString(c.value)
|
|
hashType(c.baseType)
|
|
}
|
|
def hashExistential(e: Existential) =
|
|
{
|
|
extend(ExistentialHash)
|
|
hashParameters(e.clause, e.baseType)
|
|
}
|
|
def hashPolymorphic(p: Polymorphic) =
|
|
{
|
|
extend(PolymorphicHash)
|
|
hashParameters(p.parameters, p.baseType)
|
|
}
|
|
def hashProjection(p: Projection) =
|
|
{
|
|
extend(ProjectionHash)
|
|
hashString(p.id)
|
|
hashType(p.prefix)
|
|
}
|
|
def hashParameterized(p: Parameterized)
|
|
{
|
|
extend(ParameterizedHash)
|
|
hashType(p.baseType)
|
|
hashTypes(p.typeArguments)
|
|
}
|
|
def hashAnnotated(a: Annotated)
|
|
{
|
|
extend(AnnotatedHash)
|
|
hashType(a.baseType)
|
|
hashAnnotations(a.annotations)
|
|
}
|
|
final def hashStructure(structure: Structure) = visit(visitedStructures, structure)(hashStructure0)
|
|
def hashStructure0(structure: Structure)
|
|
{
|
|
extend(StructureHash)
|
|
hashTypes(structure.parents)
|
|
hashDefinitions(structure.declared, false)
|
|
hashDefinitions(structure.inherited, false)
|
|
}
|
|
def hashParameters(parameters: Seq[TypeParameter], base: Type): Unit =
|
|
{
|
|
hashTypeParameters(parameters)
|
|
hashType(base)
|
|
}
|
|
}
|
|
|