Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
梦境迷离
Scala Macro Tools
提交
004baeff
S
Scala Macro Tools
项目概览
梦境迷离
/
Scala Macro Tools
上一次同步 大约 1 年
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
Scala Macro Tools
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
004baeff
编写于
8月 01, 2021
作者:
梦境迷离
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refactor
上级
43af7786
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
42 addition
and
45 deletion
+42
-45
src/main/scala/io/github/dreamylost/macros/AbstractMacroProcessor.scala
.../io/github/dreamylost/macros/AbstractMacroProcessor.scala
+6
-6
src/main/scala/io/github/dreamylost/macros/builderMacro.scala
...main/scala/io/github/dreamylost/macros/builderMacro.scala
+6
-6
src/main/scala/io/github/dreamylost/macros/constructorMacro.scala
.../scala/io/github/dreamylost/macros/constructorMacro.scala
+21
-21
src/main/scala/io/github/dreamylost/macros/equalsAndHashCodeMacro.scala
.../io/github/dreamylost/macros/equalsAndHashCodeMacro.scala
+7
-11
src/test/scala/io/github/dreamylost/EqualsAndHashCodeTest.scala
...st/scala/io/github/dreamylost/EqualsAndHashCodeTest.scala
+2
-1
未找到文件。
src/main/scala/io/github/dreamylost/macros/AbstractMacroProcessor.scala
浏览文件 @
004baeff
...
...
@@ -198,7 +198,7 @@ abstract class AbstractMacroProcessor(val c: whitebox.Context) {
* @param annotteeClassParams
* @return {{ i: Int}}
*/
def
getConstructor
Field
NameWithType
(
annotteeClassParams
:
Seq
[
Tree
])
:
Seq
[
Tree
]
=
{
def
getConstructor
Params
NameWithType
(
annotteeClassParams
:
Seq
[
Tree
])
:
Seq
[
Tree
]
=
{
annotteeClassParams
.
map
{
case
v
:
ValDef
=>
q
"${v.name}: ${v.tpt}"
}
...
...
@@ -239,11 +239,11 @@ abstract class AbstractMacroProcessor(val c: whitebox.Context) {
*
* @param annotteeClassDefinitions
*/
def
getClassMemberValDefs
(
annotteeClassDefinitions
:
Seq
[
Tree
])
:
Seq
[
Tree
]
=
{
def
getClassMemberValDefs
(
annotteeClassDefinitions
:
Seq
[
Tree
])
:
Seq
[
ValDef
]
=
{
annotteeClassDefinitions
.
filter
(
_
match
{
case
_:
ValDef
=>
true
case
_
=>
false
})
})
.
map
(
_
.
asInstanceOf
[
ValDef
])
}
/**
...
...
@@ -251,11 +251,11 @@ abstract class AbstractMacroProcessor(val c: whitebox.Context) {
*
* @param annotteeClassDefinitions
*/
def
getClassMemberDefDefs
(
annotteeClassDefinitions
:
Seq
[
Tree
])
:
Seq
[
Tree
]
=
{
def
getClassMemberDefDefs
(
annotteeClassDefinitions
:
Seq
[
Tree
])
:
Seq
[
DefDef
]
=
{
annotteeClassDefinitions
.
filter
(
_
match
{
case
_:
DefDef
=>
true
case
_
=>
false
})
})
.
map
(
_
.
asInstanceOf
[
DefDef
])
}
/**
...
...
@@ -293,7 +293,7 @@ abstract class AbstractMacroProcessor(val c: whitebox.Context) {
* @example {{ def apply(int: Int)(j: Int)(k: Option[String])(t: Option[Long]): B3 = new B3(int)(j)(k)(t) }}
*/
def
getApplyMethodWithCurrying
(
typeName
:
TypeName
,
fieldss
:
List
[
List
[
Tree
]],
classTypeParams
:
List
[
Tree
])
:
Tree
=
{
val
allFieldsTermName
=
fieldss
.
map
(
f
=>
getConstructor
Field
NameWithType
(
f
))
val
allFieldsTermName
=
fieldss
.
map
(
f
=>
getConstructor
Params
NameWithType
(
f
))
val
returnTypeParams
=
extractClassTypeParamsTypeName
(
classTypeParams
)
// not currying
val
applyMethod
=
if
(
fieldss
.
isEmpty
||
fieldss
.
size
==
1
)
{
...
...
src/main/scala/io/github/dreamylost/macros/builderMacro.scala
浏览文件 @
004baeff
...
...
@@ -48,13 +48,13 @@ object builderMacro {
private
def
getFieldSetMethod
(
typeName
:
TypeName
,
field
:
Tree
,
classTypeParams
:
List
[
Tree
])
:
Tree
=
{
val
builderClassName
=
getBuilderClassName
(
typeName
)
val
returnTypeParams
=
extractClassTypeParamsTypeName
(
classTypeParams
)
val
valDefMapTo
=
(
v
:
ValDef
)
=>
{
lazy
val
valDefMapTo
=
(
v
:
ValDef
)
=>
{
q
"""
def ${v.name}(${v.name}: ${v.tpt}): $builderClassName[..$returnTypeParams] = {
this.${v.name} = ${v.name}
this
}
"""
def ${v.name}(${v.name}: ${v.tpt}): $builderClassName[..$returnTypeParams] = {
this.${v.name} = ${v.name}
this
}
"""
}
field
match
{
case
v
:
ValDef
=>
valDefMapTo
(
v
)
...
...
src/main/scala/io/github/dreamylost/macros/constructorMacro.scala
浏览文件 @
004baeff
...
...
@@ -45,18 +45,23 @@ object constructorMacro {
}
}
private
def
getMutableValDefAndExcludeFields
(
annotteeClassDefinitions
:
Seq
[
Tree
])
:
Seq
[
c.universe.ValDef
]
=
{
getClassMemberValDefs
(
annotteeClassDefinitions
).
filter
(
v
=>
v
.
mods
.
hasFlag
(
Flag
.
MUTABLE
)
&&
!
extractArgumentsDetail
.
_2
.
contains
(
v
.
name
.
decodedName
.
toString
))
}
/**
* Extract the internal fields of members belonging to the class, but not in primary constructor and only `var`.
*/
private
def
get
ClassMemberVarDefOnlyAssignExpr
(
annotteeClassDefinitions
:
Seq
[
Tree
])
:
Seq
[
Tree
]
=
{
get
ClassMemberValDefs
(
annotteeClassDefinitions
).
filter
(
_
match
{
case
v
:
ValDef
if
v.mods.hasFlag
(
Flag.MUTABLE
)
=>
!
extractArgumentsDetail
.
_2
.
contains
(
v
.
name
.
decodedName
.
toString
)
case
_
=>
false
}).
map
{
case
q
"$mods var $pat = $expr"
=>
// TODO getClass RETURN a java type, maybe we can try use class reflect to get the fields type name.
q
"$pat: ${TypeName(toScalaType(evalTree(expr.asInstanceOf[Tree]).getClass.getTypeName))
}"
case
q
"$mods var $tname: $tpt = $expr"
=>
q
"$tname: $tpt"
private
def
get
MemberVarDefTermNameWithType
(
annotteeClassDefinitions
:
Seq
[
Tree
])
:
Seq
[
Tree
]
=
{
get
MutableValDefAndExcludeFields
(
annotteeClassDefinitions
).
map
{
case
v
:
ValDef
if
v.mods.hasFlag
(
Flag.MUTABLE
)
=>
if
(
v
.
tpt
.
isEmpty
)
{
// val i = 1, tpt is `<type ?>`
// 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
}"
}
}
}
...
...
@@ -64,18 +69,13 @@ object constructorMacro {
* We generate this method with currying, and we have to deal with the first layer of currying alone.
*/
private
def
getThisMethodWithCurrying
(
annotteeClassParams
:
List
[
List
[
Tree
]],
annotteeClassDefinitions
:
Seq
[
Tree
])
:
Tree
=
{
val
class
FieldDefinitionsOnlyAssignExpr
=
getClassMemberVarDefOnlyAssignExpr
(
annotteeClassDefinitions
)
val
class
InternalFieldsWithType
=
getMemberVarDefTermNameWithType
(
annotteeClassDefinitions
)
if
(
class
FieldDefinitionsOnlyAssignExpr
.
isEmpty
)
{
if
(
class
InternalFieldsWithType
.
isEmpty
)
{
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
classFieldDefinitions
=
getClassMemberValDefs
(
annotteeClassDefinitions
)
val
annotteeClassFieldNames
=
classFieldDefinitions
.
filter
(
_
match
{
case
v
:
ValDef
if
v.mods.hasFlag
(
Flag.MUTABLE
)
=>
!
extractArgumentsDetail
.
_2
.
contains
(
v
.
name
.
decodedName
.
toString
)
case
_
=>
false
}).
map
{
val
annotteeClassFieldNames
=
getMutableValDefAndExcludeFields
(
annotteeClassDefinitions
).
map
{
case
v
:
ValDef
if
v.mods.hasFlag
(
Flag.MUTABLE
)
=>
v
.
name
}
...
...
@@ -85,19 +85,19 @@ object constructorMacro {
})
// Extract the field of the primary constructor.
val
classParams
AssignExpr
=
getConstructorField
NameWithType
(
annotteeClassParams
.
flatten
)
val
classParams
NameWithType
=
getConstructorParams
NameWithType
(
annotteeClassParams
.
flatten
)
val
applyMethod
=
if
(
annotteeClassParams
.
isEmpty
||
annotteeClassParams
.
size
==
1
)
{
q
"""
def this(..${classParams
AssignExpr ++ classFieldDefinitionsOnlyAssignExpr
}) = {
def this(..${classParams
NameWithType ++ classInternalFieldsWithType
}) = {
this(..${allFieldsTermName.flatten})
..${annotteeClassFieldNames.map(f => q"this.$f = $f")}
}
"""
}
else
{
// NOTE: currying constructor overload must be placed in the first bracket block.
val
allClass
ParamsAssignExpr
=
annotteeClassParams
.
map
(
cc
=>
getConstructorField
NameWithType
(
cc
))
val
allClass
CtorParamsNameWithType
=
annotteeClassParams
.
map
(
cc
=>
getConstructorParams
NameWithType
(
cc
))
q
"""
def this(..${allClass
ParamsAssignExpr.head ++ classFieldDefinitionsOnlyAssignExpr})(...${allClassParamsAssignExpr
.tail}) = {
def this(..${allClass
CtorParamsNameWithType.head ++ classInternalFieldsWithType})(...${allClassCtorParamsNameWithType
.tail}) = {
this(..${allFieldsTermName.head})(...${allFieldsTermName.tail})
..${annotteeClassFieldNames.map(f => q"this.$f = $f")}
}
...
...
src/main/scala/io/github/dreamylost/macros/equalsAndHashCodeMacro.scala
浏览文件 @
004baeff
...
...
@@ -67,22 +67,18 @@ object equalsAndHashCodeMacro {
/**
* Extract the internal fields of members belonging to the class.
*/
private
def
getInternalFieldTermNameExcludeLocal
(
annotteeClassDefinitions
:
Seq
[
Tree
])
:
Seq
[
TermName
]
=
{
getClassMemberValDefs
(
annotteeClassDefinitions
).
filter
(
p
=>
isNotLocalClassMember
(
p
)
&&
(
p
match
{
case
v
:
ValDef
=>
!
extractArgumentsDetail
.
_2
.
contains
(
v
.
name
.
decodedName
.
toString
)
case
_
=>
false
})).
map
{
case
v
:
ValDef
=>
v
.
name
.
toTermName
private
def
getInternalFieldsTermNameExcludeLocal
(
annotteeClassDefinitions
:
Seq
[
Tree
])
:
Seq
[
TermName
]
=
{
if
(
annotteeClassDefinitions
.
exists
(
f
=>
isNotLocalClassMember
(
f
)))
{
c
.
info
(
c
.
enclosingPosition
,
s
"There is a non private class definition inside the class"
,
extractArgumentsDetail
.
_1
)
}
getClassMemberValDefs
(
annotteeClassDefinitions
).
filter
(
p
=>
isNotLocalClassMember
(
p
)
&&
!
extractArgumentsDetail
.
_2
.
contains
(
p
.
name
.
decodedName
.
toString
)).
map
(
_
.
name
.
toTermName
)
}
// equals method
private
def
getEqualsMethod
(
className
:
TypeName
,
termNames
:
Seq
[
TermName
],
superClasses
:
Seq
[
Tree
],
annotteeClassDefinitions
:
Seq
[
Tree
])
:
Tree
=
{
val
existsCanEqual
=
getClassMemberDefDefs
(
annotteeClassDefinitions
)
exists
{
val
existsCanEqual
=
getClassMemberDefDefs
(
annotteeClassDefinitions
)
.
exists
{
case
tree
@
q
"$mods def $tname[..$tparams](...$paramss): $tpt = $expr"
if
tname
.
asInstanceOf
[
TermName
].
decodedName
.
toString
==
"canEqual"
&&
paramss
.
nonEmpty
=>
if
(!
isNotLocalClassMember
(
tree
))
{
c
.
info
(
c
.
enclosingPosition
,
"The canEqual method has been found in class, and method mods exists private[this] or protected[this]"
,
extractArgumentsDetail
.
_1
)
}
val
params
=
paramss
.
asInstanceOf
[
List
[
List
[
Tree
]]].
flatten
.
map
(
pp
=>
getMethodParamName
(
pp
))
params
.
exists
(
p
=>
p
.
decodedName
.
toString
==
"Any"
)
case
_
=>
false
...
...
@@ -135,7 +131,7 @@ object equalsAndHashCodeMacro {
val
allFieldsTermName
=
ctorFieldNames
.
map
{
case
v
:
ValDef
=>
v
.
name
.
toTermName
}
val
allTernNames
=
allFieldsTermName
++
getInternalFieldTermNameExcludeLocal
(
annotteeClassDefinitions
)
val
allTernNames
=
allFieldsTermName
++
getInternalField
s
TermNameExcludeLocal
(
annotteeClassDefinitions
)
val
hash
=
getHashcodeMethod
(
allTernNames
,
superClasses
)
val
equals
=
getEqualsMethod
(
className
,
allTernNames
,
superClasses
,
annotteeClassDefinitions
)
c
.
Expr
(
...
...
src/test/scala/io/github/dreamylost/EqualsAndHashCodeTest.scala
浏览文件 @
004baeff
...
...
@@ -100,7 +100,8 @@ class EqualsAndHashCodeTest extends AnyFlatSpec with Matchers {
"equals3"
should
"ok even if exists a canEqual"
in
{
@equalsAndHashCode
class
Employee1
(
name
:
String
,
age
:
Int
,
var
role
:
String
)
extends
Person
(
name
,
age
)
{
override
def
canEqual
(
that
:
Any
)
=
that
.
getClass
==
classOf
[
Employee1
];
class
A
{}
override
def
canEqual
(
that
:
Any
)
=
that
.
getClass
==
classOf
[
Employee1
]
}
"""
| @equalsAndHashCode
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录