Skip to content

Commit

Permalink
Support namespacedRClass gradle option (#126)
Browse files Browse the repository at this point in the history
* Use annotation r reference for generated code

* add readme

* use r class name

* Don't use attribute for r finder if namespaced resources

* remove nesting

* Fix typo

* Make tests work both in android studio and gradle

* Validate default style

* Change to new test method

* revert gradle change

* revert project gradle

* add documentation

* add documentation

* Update gradle.properties

Co-authored-by: Nathanael Silverman <[email protected]>
  • Loading branch information
Ben Schwab and ngsilverman authored Feb 3, 2020
1 parent e068f2c commit bb5fc67
Show file tree
Hide file tree
Showing 33 changed files with 660 additions and 45 deletions.
1 change: 1 addition & 0 deletions .idea/codeStyles/codeStyleConfig.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@
String defaultStyleNameFormat() default "";

Class<?> rClass() default Void.class;

/**
* This is an experimental gradle flag (android.namespacedRClass=true). Setting to true allows Paris to generate code compatible
* with R files that only have resources from the module the resource was declared in.
*/
boolean namespacedResourcesEnabled() default false;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
package com.airbnb.paris.annotations

/**
* @param value The name of the styleable resource.
* @param emptyDefaultStyle Set to true if the view does not have a default style.
* Will only be used if [ParisConfig.namespacedResourcesEnabled] is true. Default: false.
*/
@Target(AnnotationTarget.CLASS)
annotation class Styleable(val value: String = "")
annotation class Styleable(val value: String = "", val emptyDefaultStyle: Boolean = false)
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class ParisProcessor : SkyProcessor(), WithParisProcessor {

override var defaultStyleNameFormat: String = ""

override var namespacedResourcesEnabled: Boolean = false

private var beforeStyleInfoExtractor = BeforeStyleInfoExtractor(this)

private var afterStyleInfoExtractor = AfterStyleInfoExtractor(this)
Expand Down Expand Up @@ -72,6 +74,7 @@ class ParisProcessor : SkyProcessor(), WithParisProcessor {
?.getAnnotation(ParisConfig::class.java)
?.let {
defaultStyleNameFormat = it.defaultStyleNameFormat
namespacedResourcesEnabled = it.namespacedResourcesEnabled
rFinder.processConfig(it)
}

Expand Down Expand Up @@ -110,30 +113,30 @@ class ParisProcessor : SkyProcessor(), WithParisProcessor {
externalStyleablesInfo = BaseStyleableInfoExtractor(this).fromEnvironment()

val allStyleables = styleablesInfo + externalStyleablesInfo
if (allStyleables.isNotEmpty() && rFinder.element == null) {
logError {
"Unable to locate R class. Please annotate an arbitrary package with @ParisConfig and set the rClass parameter to the R class."
}
return
}
val styleablesTree = StyleablesTree(this, allStyleables)
for (styleableInfo in styleablesInfo) {
StyleApplierJavaClass(this, styleablesTree, styleableInfo).write()
StyleExtensionsKotlinFile(this, RElement?.className?.toKPoet(), styleableInfo).write()
StyleExtensionsKotlinFile(this, styleableInfo).write()
}

if (styleablesInfo.isNotEmpty()) {
ModuleJavaClass(this, styleablesInfo).write()
}

if (allStyleables.isNotEmpty()) {
if (rFinder.element == null) {
logError {
"Unable to locate R class. Please annotate an arbitrary package with @ParisConfig and set the rClass parameter to the R class."
}
} else {
val parisClassPackageName = rFinder.element!!.packageName
ParisJavaClass(
this,
parisClassPackageName,
styleablesInfo,
externalStyleablesInfo
).write()
}
val parisClassPackageName = rFinder.element!!.packageName
ParisJavaClass(
this,
parisClassPackageName,
styleablesInfo,
externalStyleablesInfo
).write()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ internal class RFinder(override val processor: ParisProcessor) : WithParisProces
styleableChildrenInfo: List<StyleableChildInfo>,
attrsInfo: List<AttrInfo>
) {
if (element != null) {
// If using namespacedResources, an attribute might reference another module's R2 file, so we
// skip this method of determining the R file.
if (element != null || processor.namespacedResourcesEnabled) {
return
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ internal interface WithParisProcessor : WithSkyProcessor {

val defaultStyleNameFormat get() = processor.defaultStyleNameFormat

val namespacedResourcesEnabled get() = processor.namespacedResourcesEnabled

fun getResourceId(annotation: Class<out Annotation>, element: Element, value: Int): AndroidResourceId? {
val resourceId = processor.resourceScanner.getId(annotation, element, value)
if (resourceId == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import com.squareup.javapoet.ClassName

internal class AndroidResourceId(val value: Int, val className: ClassName, val resourceName: String) {

val code: JavaCodeBlock = if (className.topLevelClassName() == AndroidClassNames.R) {
val rClassName: ClassName = className.topLevelClassName()

val code: JavaCodeBlock = if (rClassName == AndroidClassNames.R) {
JavaCodeBlock.of("\$L.\$N", className, resourceName)
} else {
JavaCodeBlock.of("\$T.\$N", className, resourceName)
}

val kotlinCode: KotlinCodeBlock = if (className.topLevelClassName() == AndroidClassNames.R) {
val kotlinCode: KotlinCodeBlock = if (rClassName == AndroidClassNames.R) {
KotlinCodeBlock.of("%L.%N", className.toKPoet(), resourceName)
} else {
KotlinCodeBlock.of("%T.%N", className.toKPoet(), resourceName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ interface WithSkyProcessor {
}

fun logWarning(element: Element, lazyMessage: () -> String) {
logError { "${element.toStringId()}: ${lazyMessage()}" }
logWarning { "${element.toStringId()}: ${lazyMessage()}" }
}

fun logWarning(lazyMessage: () -> String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ internal class StyleInfoExtractor(override val processor: ParisProcessor) : With
if (defaultNameFormatStyle != null) {
styles + defaultNameFormatStyle
} else {
if (processor.namespacedResourcesEnabled && !styleableElement.getAnnotation(Styleable::class.java).emptyDefaultStyle) {
logError { "No default style found for ${styleableElement.simpleName}. Link an appropriate default style, " +
"or set @Styleable(emptyDefaultStyle = true) for this element if none exist." }
}
styles + EmptyStyleInfo(styleableElement, true)
}
}
Expand All @@ -100,7 +104,7 @@ internal class StyleInfoExtractor(override val processor: ParisProcessor) : With
val defaultStyleName = String.format(Locale.US, defaultStyleNameFormat, elementName)

val rStyleTypeElement = elements.getTypeElement("${RElement!!.qualifiedName}.style")
val defaultStyleExists = elements.getAllMembers(rStyleTypeElement).any {
val defaultStyleExists = rStyleTypeElement != null && elements.getAllMembers(rStyleTypeElement).any {
it.simpleName.toString() == defaultStyleName
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.airbnb.paris.processor.models
import com.airbnb.paris.annotations.Styleable
import com.airbnb.paris.processor.ParisProcessor
import com.airbnb.paris.processor.framework.WithSkyProcessor
import com.squareup.javapoet.ClassName
import javax.annotation.processing.RoundEnvironment
import javax.lang.model.element.Element
import javax.lang.model.element.TypeElement
Expand Down Expand Up @@ -68,7 +69,7 @@ internal class StyleableInfoExtractor(override val processor: ParisProcessor) :
}

if (baseStyleableInfo.styleableResourceName.isNotEmpty() && styleableChildren.isEmpty() && attrs.isEmpty()) {
logWarning {
logWarning(element) {
"No need to specify the @Styleable value parameter if no class members are annotated with @Attr."
}
}
Expand Down Expand Up @@ -101,6 +102,12 @@ internal class StyleableInfo(
baseStyleableInfo: BaseStyleableInfo
) : BaseStyleableInfo(baseStyleableInfo), WithSkyProcessor {

/**
* A styleable declaration is guaranteed to be in the same R file as any attribute or styleable child.
* `min` is used to ensure in the case there are multiple R files, a consistent one is chosen.
*/
val styleableRClassName = (attrs.map { it.styleableResId.rClassName } + styleableChildren.map { it.styleableResId.rClassName }).min()

/**
* Applies lower camel case formatting
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import com.squareup.javapoet.*
internal class BaseStyleBuilderJavaClass(
override val processor: ParisProcessor,
parentStyleApplierClassName: ClassName?,
rClassName: ClassName?,
styleablesTree: StyleablesTree,
styleableInfo: StyleableInfo
) : SkyJavaClass(processor), WithSkyProcessor {
Expand Down Expand Up @@ -84,7 +83,6 @@ internal class BaseStyleBuilderJavaClass(
val distinctStyleableChildren =
styleableInfo.styleableChildren.distinctBy { it.styleableResId.resourceName }
for (styleableChildInfo in distinctStyleableChildren) {
rClassName!!

val methodName =
styleableInfo.attrResourceNameToCamelCase(styleableChildInfo.styleableResId.resourceName)
Expand All @@ -99,7 +97,7 @@ internal class BaseStyleBuilderJavaClass(
returns(TypeVariableName.get("B"))
addStatement(
"getBuilder().putStyle(\$T.styleable.\$L[\$L], resId)",
rClassName,
styleableChildInfo.styleableResId.rClassName,
styleableInfo.styleableResourceName,
styleableChildInfo.styleableResId.code
)
Expand All @@ -112,7 +110,7 @@ internal class BaseStyleBuilderJavaClass(
returns(TypeVariableName.get("B"))
addStatement(
"getBuilder().putStyle(\$T.styleable.\$L[\$L], style)",
rClassName,
styleableChildInfo.styleableResId.rClassName,
styleableInfo.styleableResourceName,
styleableChildInfo.styleableResId.code
)
Expand Down Expand Up @@ -142,7 +140,7 @@ internal class BaseStyleBuilderJavaClass(
addStatement("function.invoke(subBuilder)")
addStatement(
"getBuilder().putStyle(\$T.styleable.\$L[\$L], subBuilder.build())",
rClassName,
styleableChildInfo.styleableResId.rClassName,
styleableInfo.styleableResourceName,
styleableChildInfo.styleableResId.code
)
Expand All @@ -152,7 +150,6 @@ internal class BaseStyleBuilderJavaClass(

val groupedAttrInfos = styleableInfo.attrs.groupBy { it.styleableResId.resourceName }
for (groupedAttrs in groupedAttrInfos.values) {
rClassName!!

val nonResTargetAttrs = groupedAttrs.filter { it.targetFormat != Format.RESOURCE_ID }

Expand Down Expand Up @@ -188,7 +185,7 @@ internal class BaseStyleBuilderJavaClass(
returns(TypeVariableName.get("B"))
addStatement(
"getBuilder().put(\$T.styleable.\$L[\$L], value)",
rClassName,
attr.styleableResId.rClassName,
styleableInfo.styleableResourceName,
attr.styleableResId.code
)
Expand All @@ -208,7 +205,7 @@ internal class BaseStyleBuilderJavaClass(
returns(TypeVariableName.get("B"))
addStatement(
"getBuilder().putRes(\$T.styleable.\$L[\$L], resId)",
rClassName,
attr.styleableResId.rClassName,
styleableInfo.styleableResourceName,
attr.styleableResId.code
)
Expand All @@ -233,7 +230,7 @@ internal class BaseStyleBuilderJavaClass(
returns(TypeVariableName.get("B"))
addStatement(
"getBuilder().putDp(\$T.styleable.\$L[\$L], value)",
rClassName,
attr.styleableResId.rClassName,
styleableInfo.styleableResourceName,
attr.styleableResId.code
)
Expand All @@ -255,7 +252,7 @@ internal class BaseStyleBuilderJavaClass(
returns(TypeVariableName.get("B"))
addStatement(
"getBuilder().putColor(\$T.styleable.\$L[\$L], color)",
rClassName,
attr.styleableResId.rClassName,
styleableInfo.styleableResourceName,
attr.styleableResId.code
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ internal class StyleApplierJavaClass(
}
}

if (!styleableInfo.styleableResourceName.isEmpty()) {
if (styleableInfo.styleableResourceName.isNotEmpty()) {
method("attributes") {
override()
protected()
returns(ArrayTypeName.of(Integer.TYPE))
addStatement("return \$T.styleable.\$L", RElement, styleableInfo.styleableResourceName)
addStatement("return \$T.styleable.\$L", styleableInfo.styleableRClassName ?: RElement, styleableInfo.styleableResourceName)
}

val attrsWithDefaultValue = styleableInfo.attrs
Expand Down Expand Up @@ -189,7 +189,6 @@ internal class StyleApplierJavaClass(
BaseStyleBuilderJavaClass(
processor,
parentStyleApplierClassName,
RElement?.className,
styleablesTree,
styleableInfo
).build()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.airbnb.paris.processor.writers

import androidx.annotation.RequiresApi
import androidx.annotation.StyleRes
import com.airbnb.paris.processor.*
import com.airbnb.paris.processor.framework.*
import com.airbnb.paris.processor.framework.AndroidClassNames.ATTRIBUTE_SET
Expand All @@ -27,7 +28,6 @@ import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
*/
internal class StyleExtensionsKotlinFile(
override val processor: ParisProcessor,
rClassName: KotlinClassName?,
styleable: StyleableInfo
) : SkyKotlinFile(processor) {

Expand Down Expand Up @@ -156,7 +156,6 @@ internal class StyleExtensionsKotlinFile(
*/
val distinctStyleableChildren = styleable.styleableChildren.distinctBy { it.styleableResId.resourceName }
for (styleableChildInfo in distinctStyleableChildren) {
rClassName!!

val functionName = styleable.attrResourceNameToCamelCase(styleableChildInfo.styleableResId.resourceName)

Expand All @@ -168,7 +167,7 @@ internal class StyleExtensionsKotlinFile(
}
addStatement(
"builder.putStyle(%T.styleable.%L[%L], resId)",
rClassName,
styleableChildInfo.styleableResId.rClassName.toKPoet(),
styleable.styleableResourceName,
styleableChildInfo.styleableResId.kotlinCode
)
Expand All @@ -180,7 +179,7 @@ internal class StyleExtensionsKotlinFile(
parameter("style", STYLE_CLASS_NAME.toKPoet())
addStatement(
"builder.putStyle(%T.styleable.%L[%L], style)",
rClassName,
styleableChildInfo.styleableResId.rClassName.toKPoet(),
styleable.styleableResourceName,
styleableChildInfo.styleableResId.kotlinCode
)
Expand Down Expand Up @@ -208,7 +207,7 @@ internal class StyleExtensionsKotlinFile(
)
addStatement(
"builder.putStyle(%T.styleable.%L[%L], %T().apply(%N).build())",
rClassName,
styleableChildInfo.styleableResId.rClassName.toKPoet(),
styleable.styleableResourceName,
styleableChildInfo.styleableResId.kotlinCode,
subExtendableStyleBuilderTypeName,
Expand All @@ -226,7 +225,6 @@ internal class StyleExtensionsKotlinFile(
*/
val attrGroups = styleable.attrs.groupBy { it.styleableResId.resourceName }
for (groupedAttrs in attrGroups.values) {
rClassName!!

val nonResTargetAttrs = groupedAttrs.filter { it.targetFormat != Format.RESOURCE_ID }

Expand Down Expand Up @@ -256,7 +254,7 @@ internal class StyleExtensionsKotlinFile(

addStatement(
"builder.put(%T.styleable.%L[%L], value)",
rClassName,
attr.styleableResId.rClassName.toKPoet(),
styleable.styleableResourceName,
attr.styleableResId.kotlinCode
)
Expand All @@ -276,7 +274,7 @@ internal class StyleExtensionsKotlinFile(

addStatement(
"builder.putRes(%T.styleable.%L[%L], resId)",
rClassName,
attr.styleableResId.rClassName.toKPoet(),
styleable.styleableResourceName,
attr.styleableResId.kotlinCode
)
Expand All @@ -300,7 +298,7 @@ internal class StyleExtensionsKotlinFile(

addStatement(
"builder.putDp(%T.styleable.%L[%L], value)",
rClassName,
attr.styleableResId.rClassName.toKPoet(),
styleable.styleableResourceName,
attr.styleableResId.kotlinCode
)
Expand All @@ -321,7 +319,7 @@ internal class StyleExtensionsKotlinFile(

addStatement(
"builder.putColor(%T.styleable.%L[%L], color)",
rClassName,
attr.styleableResId.rClassName.toKPoet(),
styleable.styleableResourceName,
attr.styleableResId.kotlinCode
)
Expand Down
1 change: 1 addition & 0 deletions paris-test-lib/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
2 changes: 2 additions & 0 deletions paris-test-lib/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This module is used to test accessing resources from another module. In particular, with namespaced resources turned on Paris must generate
references to R files that contain the resource definition.
Loading

0 comments on commit bb5fc67

Please sign in to comment.