diff --git a/src/main/scala/io/github/dreamylost/macros/AbstractMacroProcessor.scala b/src/main/scala/io/github/dreamylost/macros/AbstractMacroProcessor.scala index 67019c32b366a49354d71303c2c952569a8b0382..fe21275c360f1b0a8b56a699886f2fd9134e356e 100644 --- a/src/main/scala/io/github/dreamylost/macros/AbstractMacroProcessor.scala +++ b/src/main/scala/io/github/dreamylost/macros/AbstractMacroProcessor.scala @@ -176,8 +176,8 @@ abstract class AbstractMacroProcessor(val c: whitebox.Context) { /** * Check whether the mods of the fields has a `private[this]` or `protected[this]`, because it cannot be used out of class. * - * @param tree a field or method - * @return + * @param tree Tree is a field or method? + * @return false if mods exists private[this] or protected[this] */ def isNotLocalClassMember(tree: Tree): Boolean = { lazy val modifierNotLocal = (mods: Modifiers) => { @@ -246,6 +246,26 @@ abstract class AbstractMacroProcessor(val c: whitebox.Context) { }).map(_.asInstanceOf[ValDef]) } + /** + * Extract the constructor params ValDef and flatten for currying. + * + * @param annotteeClassParams + * @return {{ Seq(ValDef) }} + */ + def getClassConstructorValDefsFlatten(annotteeClassParams: List[List[Tree]]): Seq[ValDef] = { + annotteeClassParams.flatten.map(_.asInstanceOf[ValDef]) + } + + /** + * Extract the constructor params ValDef not flatten. + * + * @param annotteeClassParams + * @return {{ Seq(Seq(ValDef)) }} + */ + def getClassConstructorValDefsNotFlatten(annotteeClassParams: List[List[Tree]]): Seq[Seq[ValDef]] = { + annotteeClassParams.map(_.map(_.asInstanceOf[ValDef])) + } + /** * Extract the methods belonging to the class, contains Secondary Constructor. * @@ -268,9 +288,8 @@ abstract class AbstractMacroProcessor(val c: whitebox.Context) { * @example {{ new TestClass12(i)(j)(k)(t) }} */ def getConstructorWithCurrying(typeName: TypeName, fieldss: List[List[Tree]], isCase: Boolean): Tree = { - val allFieldsTermName = fieldss.map(f => f.map { - case v: ValDef => v.name.toTermName - }) + val fieldssValDefNotFlatten = getClassConstructorValDefsNotFlatten(fieldss) + val allFieldsTermName = fieldssValDefNotFlatten.map(_.map(_.name.toTermName)) // not currying val constructor = if (fieldss.isEmpty || fieldss.size == 1) { q"${if (isCase) q"${typeName.toTermName}(..${allFieldsTermName.flatten})" else q"new $typeName(..${allFieldsTermName.flatten})"}" @@ -280,7 +299,6 @@ abstract class AbstractMacroProcessor(val c: whitebox.Context) { if (isCase) q"${typeName.toTermName}(...$first)(...${allFieldsTermName.tail})" else q"new $typeName(..$first)(...${allFieldsTermName.tail})" } - c.info(c.enclosingPosition, s"getConstructorWithCurrying constructor: $constructor, paramss: $fieldss", force = true) constructor } @@ -303,7 +321,6 @@ abstract class AbstractMacroProcessor(val c: whitebox.Context) { val first = allFieldsTermName.head q"def apply[..$classTypeParams](..$first)(...${allFieldsTermName.tail}): $typeName[..$returnTypeParams] = ${getConstructorWithCurrying(typeName, fieldss, isCase = false)}" } - c.info(c.enclosingPosition, s"getApplyMethodWithCurrying constructor: $applyMethod, paramss: $fieldss", force = true) applyMethod } diff --git a/src/main/scala/io/github/dreamylost/macros/builderMacro.scala b/src/main/scala/io/github/dreamylost/macros/builderMacro.scala index 96a2fe598bdf10e820b860f373299e0c9f965cf4..98a38ae4987438b8781fd8d5aeb5f5e21ad3e979 100644 --- a/src/main/scala/io/github/dreamylost/macros/builderMacro.scala +++ b/src/main/scala/io/github/dreamylost/macros/builderMacro.scala @@ -82,14 +82,14 @@ object builderMacro { } override def modifiedDeclaration(classDecl: ClassDef, compDeclOpt: Option[ModuleDef] = None): Any = { - val (className, fieldss, classTypeParams) = classDecl match { + val (className, annotteeClassParams, classTypeParams) = classDecl match { // @see https://scala-lang.org/files/archive/spec/2.13/05-classes-and-objects.html case q"$mods class $tpname[..$tparams](...$paramss) extends ..$bases { ..$body }" => (tpname.asInstanceOf[TypeName], paramss.asInstanceOf[List[List[Tree]]], tparams.asInstanceOf[List[Tree]]) case _ => c.abort(c.enclosingPosition, s"${ErrorMessage.ONLY_CLASS} classDef: $classDecl") } - val builder = getBuilderClassAndMethod(className, fieldss, classTypeParams, isCaseClass(classDecl)) + val builder = getBuilderClassAndMethod(className, annotteeClassParams, classTypeParams, isCaseClass(classDecl)) val compDecl = modifiedCompanion(compDeclOpt, builder, className) // Return both the class and companion object declarations c.Expr( diff --git a/src/main/scala/io/github/dreamylost/macros/constructorMacro.scala b/src/main/scala/io/github/dreamylost/macros/constructorMacro.scala index 58f15b8a000a093e418972f6f1d304123f9f1cca..7be74af2eb6c674fc33ec8112a60b33cc0df9e5e 100644 --- a/src/main/scala/io/github/dreamylost/macros/constructorMacro.scala +++ b/src/main/scala/io/github/dreamylost/macros/constructorMacro.scala @@ -54,14 +54,13 @@ object constructorMacro { * Extract the internal fields of members belonging to the class, but not in primary constructor and only `var`. */ private def getMemberVarDefTermNameWithType(annotteeClassDefinitions: Seq[Tree]): Seq[Tree] = { - getMutableValDefAndExcludeFields(annotteeClassDefinitions).map { - case v: ValDef if v.mods.hasFlag(Flag.MUTABLE) => - if (v.tpt.isEmpty) { // val i = 1, tpt is `` - // TODO getClass RETURN a java type, maybe we can try use class reflect to get the fields type name. - q"${v.name}: ${TypeName(toScalaType(evalTree(v.rhs).getClass.getTypeName))}" - } else { - q"${v.name}: ${v.tpt}" - } + getMutableValDefAndExcludeFields(annotteeClassDefinitions).map { v => + if (v.tpt.isEmpty) { // val i = 1, tpt is `` + // TODO getClass RETURN a java type, maybe we can try use class reflect to get the fields type name. + q"${v.name}: ${TypeName(toScalaType(evalTree(v.rhs).getClass.getTypeName))}" + } else { + q"${v.name}: ${v.tpt}" + } } } @@ -75,15 +74,8 @@ object constructorMacro { c.abort(c.enclosingPosition, s"${ErrorMessage.ONLY_CLASS} and the internal fields (declare as 'var') should not be Empty.") } // Extract the internal fields of members belonging to the class, but not in primary constructor. - val annotteeClassFieldNames = getMutableValDefAndExcludeFields(annotteeClassDefinitions).map { - case v: ValDef if v.mods.hasFlag(Flag.MUTABLE) => v.name - } - - // Extract the field of the primary constructor. - val allFieldsTermName = annotteeClassParams.map(f => f.map { - case v: ValDef => v.name.toTermName - }) - + val annotteeClassFieldNames = getMutableValDefAndExcludeFields(annotteeClassDefinitions).map(_.name) + val allFieldsTermName = getClassConstructorValDefsNotFlatten(annotteeClassParams).map(_.map(_.name.toTermName)) // Extract the field of the primary constructor. val classParamsNameWithType = getConstructorParamsNameWithType(annotteeClassParams.flatten) val applyMethod = if (annotteeClassParams.isEmpty || annotteeClassParams.size == 1) { diff --git a/src/main/scala/io/github/dreamylost/macros/equalsAndHashCodeMacro.scala b/src/main/scala/io/github/dreamylost/macros/equalsAndHashCodeMacro.scala index 92efe1a02f0754494545721c45d5a26694a0f897..4bf76b9679fe09a6da829ee08dae73d7dfd520fe 100644 --- a/src/main/scala/io/github/dreamylost/macros/equalsAndHashCodeMacro.scala +++ b/src/main/scala/io/github/dreamylost/macros/equalsAndHashCodeMacro.scala @@ -127,10 +127,7 @@ object equalsAndHashCodeMacro { (tpname.asInstanceOf[TypeName], paramss.asInstanceOf[List[List[Tree]]], stats.asInstanceOf[Seq[Tree]], parents.asInstanceOf[Seq[Tree]]) case _ => c.abort(c.enclosingPosition, s"${ErrorMessage.ONLY_CLASS} classDef: $classDecl") } - val ctorFieldNames = annotteeClassParams.flatten.filter(cf => isNotLocalClassMember(cf)) - val allFieldsTermName = ctorFieldNames.map { - case v: ValDef => v.name.toTermName - } + val allFieldsTermName = getClassConstructorValDefsFlatten(annotteeClassParams).filter(cf => isNotLocalClassMember(cf)).map(_.name.toTermName) val allTernNames = allFieldsTermName ++ getInternalFieldsTermNameExcludeLocal(annotteeClassDefinitions) val hash = getHashcodeMethod(allTernNames, superClasses) val equals = getEqualsMethod(className, allTernNames, superClasses, annotteeClassDefinitions)