mirror of
https://github.com/BetterAndroid/Hikage.git
synced 2025-09-07 19:14:22 +08:00
refactor: merge to BetterAndroid new usage
This commit is contained in:
@@ -39,15 +39,20 @@ fun KSDeclaration.getSimpleNameString(): String {
|
||||
fun KSClassDeclaration.isSubclassOf(superType: KSType?): Boolean {
|
||||
if (superType == null) return false
|
||||
if (this == superType.declaration) return true
|
||||
|
||||
superTypes.forEach { parent ->
|
||||
val resolvedParent = parent.resolve()
|
||||
// Direct match.
|
||||
if (resolvedParent == superType) return true
|
||||
|
||||
val parentDeclaration = resolvedParent.declaration as? KSClassDeclaration
|
||||
?: return@forEach
|
||||
|
||||
// Recursively check the parent class.
|
||||
if (parentDeclaration.isSubclassOf(superType)) return true
|
||||
}; return false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun KSClassDeclaration.asType() = asType(emptyList())
|
||||
|
@@ -71,6 +71,7 @@ class HikageViewGenerator(override val environment: SymbolProcessorEnvironment)
|
||||
|
||||
override fun startProcess(resolver: Resolver) {
|
||||
Processor.init(logger, resolver)
|
||||
|
||||
val dependencies = Dependencies(aggregating = true, *resolver.getAllFiles().toList().toTypedArray())
|
||||
resolver.getSymbolsWithAnnotation(HikageViewSpec.CLASS)
|
||||
.filterIsInstance<KSClassDeclaration>()
|
||||
@@ -79,9 +80,11 @@ class HikageViewGenerator(override val environment: SymbolProcessorEnvironment)
|
||||
ksClass.annotations.forEach {
|
||||
// Get annotation parameters.
|
||||
val (annotation, declaration) = HikageViewSpec.create(resolver, it, ksClass)
|
||||
|
||||
performers += Performer(annotation, declaration)
|
||||
}
|
||||
}
|
||||
|
||||
resolver.getSymbolsWithAnnotation(HikageViewDeclarationSpec.CLASS)
|
||||
.filterIsInstance<KSClassDeclaration>()
|
||||
.distinctBy { it.qualifiedName }
|
||||
@@ -89,14 +92,17 @@ class HikageViewGenerator(override val environment: SymbolProcessorEnvironment)
|
||||
ksClass.annotations.forEach {
|
||||
// Get annotation parameters.
|
||||
val (annotation, declaration) = HikageViewDeclarationSpec.create(resolver, it, ksClass)
|
||||
|
||||
performers += Performer(annotation, declaration)
|
||||
}
|
||||
}
|
||||
|
||||
processPerformer(dependencies)
|
||||
}
|
||||
|
||||
private fun processPerformer(dependencies: Dependencies) {
|
||||
val duplicatedItems = performers.groupBy { it.declaration.key }.filter { it.value.size > 1 }.flatMap { it.value }
|
||||
|
||||
require(duplicatedItems.isEmpty()) {
|
||||
"Discover duplicate @HikageView or @HikageViewDeclaration's class name or alias definitions, " +
|
||||
"you can re-specify the class name using the `alias` parameter.\n" +
|
||||
@@ -109,25 +115,30 @@ class HikageViewGenerator(override val environment: SymbolProcessorEnvironment)
|
||||
private fun generateCodeFile(dependencies: Dependencies, performer: Performer) {
|
||||
val classNameSet = performer.declaration.alias ?: performer.declaration.className
|
||||
val fileName = "_$classNameSet"
|
||||
|
||||
val viewClass = performer.declaration.toClassName().let {
|
||||
val packageName = it.packageName
|
||||
val simpleName = it.simpleName
|
||||
val topClassName = if (simpleName.contains(".")) simpleName.split(".")[0] else null
|
||||
|
||||
// com.example.MyViewScope
|
||||
// com.example.MyViewScope.MyView
|
||||
topClassName?.let { name -> ClassName(packageName, name) } to it
|
||||
}
|
||||
|
||||
val lparamsClass = performer.annotation.lparams?.let {
|
||||
val packageName = it.packageName.asString()
|
||||
val subClassName = it.getSimpleNameString()
|
||||
val simpleName = it.simpleName.asString()
|
||||
val topClassName = subClassName.replace(".$simpleName", "")
|
||||
|
||||
// android.view.ViewGroup
|
||||
// android.view.ViewGroup.LayoutParams
|
||||
(if (topClassName != subClassName)
|
||||
ClassName(packageName, topClassName)
|
||||
else null) to ClassName(packageName, subClassName)
|
||||
}
|
||||
|
||||
val packageName = "$PACKAGE_NAME_PREFIX.${performer.declaration.packageName}"
|
||||
val fileSpec = FileSpec.builder(packageName, fileName).apply {
|
||||
addFileComment(
|
||||
@@ -140,6 +151,7 @@ class HikageViewGenerator(override val environment: SymbolProcessorEnvironment)
|
||||
**DO NOT EDIT THIS FILE MANUALLY**
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
addAnnotation(
|
||||
AnnotationSpec.builder(Suppress::class)
|
||||
.addMember("%S, %S, %S", "unused", "FunctionName", "DEPRECATION")
|
||||
@@ -150,17 +162,22 @@ class HikageViewGenerator(override val environment: SymbolProcessorEnvironment)
|
||||
.addMember("%S", "${classNameSet}Performer")
|
||||
.build()
|
||||
)
|
||||
|
||||
addImport(DeclaredSymbol.ANDROID_VIEW_PACKAGE_NAME, DeclaredSymbol.ANDROID_VIEW_GROUP_CLASS_NAME)
|
||||
addImport(DeclaredSymbol.HIKAGE_CORE_PACKAGE_NAME, DeclaredSymbol.HIKAGE_CLASS_NAME)
|
||||
|
||||
// Kotlin's import rule is to introduce the parent class that also needs to be introduced at the same time.
|
||||
// If a child class exists, it needs to import the parent class,
|
||||
// and kotlinpoet will not perform this operation automatically.
|
||||
viewClass.first?.let { addImport(it.packageName, it.simpleName) }
|
||||
lparamsClass?.first?.let { addImport(it.packageName, it.simpleName) }
|
||||
|
||||
// May conflict with other [LayoutParams].
|
||||
lparamsClass?.second?.let { addAliasedImport(it, it.getTypedSimpleName()) }
|
||||
|
||||
addAliasedImport(ViewGroupLpClass, ViewGroupLpClass.getTypedSimpleName())
|
||||
addAliasedImport(HikageLparamClass, HikageLparamClass.getTypedSimpleName())
|
||||
|
||||
addFunction(FunSpec.builder(classNameSet).apply {
|
||||
addKdoc(
|
||||
"""
|
||||
@@ -170,10 +187,12 @@ class HikageViewGenerator(override val environment: SymbolProcessorEnvironment)
|
||||
@return [${performer.declaration.className}]
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
addAnnotation(HikageableClass)
|
||||
addModifiers(KModifier.INLINE)
|
||||
addTypeVariable(TypeVariableName(name = "LP", ViewGroupLpClass).copy(reified = true))
|
||||
receiver(PerformerClass.parameterizedBy(TypeVariableName("LP")))
|
||||
|
||||
addParameter(
|
||||
ParameterSpec.builder(name = "lparams", HikageLparamClass.copy(nullable = true))
|
||||
.defaultValue("null")
|
||||
@@ -203,9 +222,11 @@ class HikageViewGenerator(override val environment: SymbolProcessorEnvironment)
|
||||
)
|
||||
addStatement("return ViewGroup<${performer.declaration.className}, ${it.simpleName}>(lparams, id, init, performer)")
|
||||
} ?: addStatement("return View<${performer.declaration.className}>(lparams, id, init)")
|
||||
|
||||
returns(viewClass.second)
|
||||
}.build())
|
||||
}.build()
|
||||
|
||||
// May already exists, no need to generate.
|
||||
runCatching {
|
||||
fileSpec.writeTo(codeGenerator, dependencies)
|
||||
@@ -239,6 +260,7 @@ class HikageViewGenerator(override val environment: SymbolProcessorEnvironment)
|
||||
ksType.declaration.qualifiedName?.asString() != Any::class.qualifiedName
|
||||
}
|
||||
var resolvedLparams = lparamsType?.declaration?.getClassDeclaration(resolver)
|
||||
|
||||
when {
|
||||
// If the current view is not a view group but the lparams parameter is declared,
|
||||
// remove the lparams parameter.
|
||||
@@ -253,6 +275,7 @@ class HikageViewGenerator(override val environment: SymbolProcessorEnvironment)
|
||||
// set the default type parameter for it.
|
||||
declaration.isViewGroup && resolvedLparams == null -> resolvedLparams = lparamsDeclaration
|
||||
}
|
||||
|
||||
// Verify layout parameter class.
|
||||
if (resolvedLparams != null) require(resolvedLparams.isSubclassOf(lparamsDeclaration.asType())) {
|
||||
val resolvedLparamsName = resolvedLparams.qualifiedName?.asString()
|
||||
@@ -271,17 +294,21 @@ class HikageViewGenerator(override val environment: SymbolProcessorEnvironment)
|
||||
val packageName = ksClass.packageName.asString()
|
||||
val className = ksClass.getSimpleNameString()
|
||||
val isViewGroup = ksClass.isSubclassOf(viewGroupDeclaration.asType())
|
||||
|
||||
var _alias = alias
|
||||
// If no alias name is set, if the class name contains a subclass,
|
||||
// replace it with an underscore and use it as an alias name.
|
||||
if (_alias.isNullOrBlank() && className.contains("."))
|
||||
_alias = className.replace(".", "_")
|
||||
_alias = _alias?.takeIf { it.isNotBlank() }
|
||||
|
||||
val declaration = ViewDeclaration(packageName, className, _alias, isViewGroup, baseType)
|
||||
|
||||
// Verify the legality of the class name.
|
||||
if (!_alias.isNullOrBlank()) require(ClassDetector.verify(_alias)) {
|
||||
"Declares @$tagName's alias \"$_alias\" is illegal.\n${declaration.locateDesc}"
|
||||
}
|
||||
|
||||
// [ViewGroup] cannot be new instance.
|
||||
require(ksClass != viewGroupDeclaration) {
|
||||
"Declares @$tagName's class must not be a directly \"${DeclaredSymbol.ANDROID_VIEW_GROUP_CLASS}\".\n${declaration.locateDesc}"
|
||||
@@ -290,6 +317,7 @@ class HikageViewGenerator(override val environment: SymbolProcessorEnvironment)
|
||||
require(ksClass.isSubclassOf(viewDeclaration.asType())) {
|
||||
"Declares @$tagName's class must be subclass of \"${DeclaredSymbol.ANDROID_VIEW_CLASS}\".\n${declaration.locateDesc}"
|
||||
}
|
||||
|
||||
return declaration
|
||||
}
|
||||
}
|
||||
@@ -332,9 +360,11 @@ class HikageViewGenerator(override val environment: SymbolProcessorEnvironment)
|
||||
val alias = annotation.arguments.getOrNull<String>("alias")
|
||||
val requireInit = annotation.arguments.getOrNull<Boolean>("requireInit") ?: false
|
||||
val requirePerformer = annotation.arguments.getOrNull<Boolean>("requirePerformer") ?: false
|
||||
|
||||
// Solve the actual content of the annotation parameters.
|
||||
val declaration = Processor.createViewDeclaration(NAME, alias, ksClass)
|
||||
val resolvedLparams = Processor.resolvedLparamsDeclaration(NAME, resolver, declaration, lparams)
|
||||
|
||||
return HikageViewSpec(resolvedLparams, alias, requireInit, requirePerformer) to declaration
|
||||
}
|
||||
}
|
||||
@@ -363,9 +393,11 @@ class HikageViewGenerator(override val environment: SymbolProcessorEnvironment)
|
||||
val alias = annotation.arguments.getOrNull<String>("alias")
|
||||
val requireInit = annotation.arguments.getOrNull<Boolean>("requireInit") ?: false
|
||||
val requirePerformer = annotation.arguments.getOrNull<Boolean>("requirePerformer") ?: false
|
||||
|
||||
// Solve the actual content of the annotation parameters.
|
||||
val resolvedView = view?.declaration?.getClassDeclaration(resolver) ?: error("Internal error.")
|
||||
val declaration = Processor.createViewDeclaration(NAME, alias, resolvedView, ksClass)
|
||||
|
||||
// Only object classes can be used as view declarations.
|
||||
require(ksClass.classKind == ClassKind.OBJECT) {
|
||||
"Declares @$NAME's class must be an object.\n${declaration.locateDesc}"
|
||||
@@ -373,6 +405,7 @@ class HikageViewGenerator(override val environment: SymbolProcessorEnvironment)
|
||||
require(!ksClass.isCompanionObject) {
|
||||
"Declares @$NAME's class must not be a companion object.\n${declaration.locateDesc}"
|
||||
}
|
||||
|
||||
val resolvedLparams = Processor.resolvedLparamsDeclaration(NAME, resolver, declaration, lparams)
|
||||
return HikageViewDeclarationSpec(resolvedView, resolvedLparams, alias, requireInit, requirePerformer) to declaration
|
||||
}
|
||||
|
Reference in New Issue
Block a user