1%M for Members 2============== 3 4Similar to types, KotlinPoet has a special placeholder for **members** (functions and properties), 5which comes handy when your code needs to access top-level members and members declared inside 6objects. Use **`%M`** to reference members, pass an instance of `MemberName` as the argument for the 7placeholder, and KotlinPoet will handle imports automatically: 8 9```kotlin 10val createTaco = MemberName("com.squareup.tacos", "createTaco") 11val isVegan = MemberName("com.squareup.tacos", "isVegan") 12val file = FileSpec.builder("com.squareup.example", "TacoTest") 13 .addFunction( 14 FunSpec.builder("main") 15 .addStatement("val taco = %M()", createTaco) 16 .addStatement("println(taco.%M)", isVegan) 17 .build() 18 ) 19 .build() 20println(file) 21``` 22 23The code above generates the following file: 24 25```kotlin 26package com.squareup.example 27 28import com.squareup.tacos.createTaco 29import com.squareup.tacos.isVegan 30 31fun main() { 32 val taco = createTaco() 33 println(taco.isVegan) 34} 35``` 36 37As you can see, it's also possible to use `%M` to reference extension functions and properties. You 38just need to make sure the member can be imported without simple name collisions, otherwise 39importing will fail and the code generator output will not pass compilation. There's a way to work 40around such cases though - use `FileSpec.addAliasedImport()` to create an alias for a clashing 41`MemberName`: 42 43```kotlin 44val createTaco = MemberName("com.squareup.tacos", "createTaco") 45val createCake = MemberName("com.squareup.cakes", "createCake") 46val isTacoVegan = MemberName("com.squareup.tacos", "isVegan") 47val isCakeVegan = MemberName("com.squareup.cakes", "isVegan") 48val file = FileSpec.builder("com.squareup.example", "Test") 49 .addAliasedImport(isTacoVegan, "isTacoVegan") 50 .addAliasedImport(isCakeVegan, "isCakeVegan") 51 .addFunction( 52 FunSpec.builder("main") 53 .addStatement("val taco = %M()", createTaco) 54 .addStatement("val cake = %M()", createCake) 55 .addStatement("println(taco.%M)", isTacoVegan) 56 .addStatement("println(cake.%M)", isCakeVegan) 57 .build() 58 ) 59 .build() 60println(file) 61``` 62 63KotlinPoet will produce an aliased import for `com.squareup.tacos2.isVegan`: 64 65```kotlin 66package com.squareup.example 67 68import com.squareup.cakes.createCake 69import com.squareup.tacos.createTaco 70import com.squareup.cakes.isVegan as isCakeVegan 71import com.squareup.tacos.isVegan as isTacoVegan 72 73fun main() { 74 val taco = createTaco() 75 val cake = createCake() 76 println(taco.isTacoVegan) 77 println(cake.isCakeVegan) 78} 79``` 80 81## MemberName and operators 82 83MemberName also supports operators, you can use `MemberName(String, KOperator)` 84or `MemberName(ClassName, KOperator)` to import and reference operators. 85 86```kotlin 87val taco = ClassName("com.squareup.tacos", "Taco") 88val meat = ClassName("com.squareup.tacos.ingredient", "Meat") 89val iterator = MemberName("com.squareup.tacos.internal", KOperator.ITERATOR) 90val minusAssign = MemberName("com.squareup.tacos.internal", KOperator.MINUS_ASSIGN) 91val file = FileSpec.builder("com.example", "Test") 92 .addFunction( 93 FunSpec.builder("makeTacoHealthy") 94 .addParameter("taco", taco) 95 .beginControlFlow("for (ingredient %M taco)", iterator) 96 .addStatement("if (ingredient is %T) taco %M ingredient", meat, minusAssign) 97 .endControlFlow() 98 .addStatement("return taco") 99 .build() 100 ) 101 .build() 102println(file) 103``` 104 105KotlinPoet will import the extension operator functions and emit the operator. 106 107```kotlin 108package com.example 109 110import com.squareup.tacos.Taco 111import com.squareup.tacos.ingredient.Meat 112import com.squareup.tacos.internal.iterator 113import com.squareup.tacos.internal.minusAssign 114 115fun makeTacoHealthy(taco: Taco) { 116 for (ingredient in taco) { 117 if (ingredient is Meat) taco -= ingredient 118 } 119 return taco 120} 121 122``` 123