Add options for wrapping local variable and property annotations

#KT-14950 Fixed
This commit is contained in:
Dmitry Jemerov
2017-07-18 19:36:08 +02:00
parent 050ff03b07
commit 951392005b
11 changed files with 94 additions and 15 deletions
@@ -42,6 +42,7 @@ private val KDOC_CONTENT = TokenSet.create(KDocTokens.KDOC, KDocElementTypes.KDO
private val CODE_BLOCKS = TokenSet.create(KtNodeTypes.BLOCK, KtNodeTypes.CLASS_BODY, KtNodeTypes.FUNCTION_LITERAL) private val CODE_BLOCKS = TokenSet.create(KtNodeTypes.BLOCK, KtNodeTypes.CLASS_BODY, KtNodeTypes.FUNCTION_LITERAL)
private val ALIGN_FOR_BINARY_OPERATIONS = TokenSet.create(MUL, DIV, PERC, PLUS, MINUS, ELVIS, LT, GT, LTEQ, GTEQ, ANDAND, OROR) private val ALIGN_FOR_BINARY_OPERATIONS = TokenSet.create(MUL, DIV, PERC, PLUS, MINUS, ELVIS, LT, GT, LTEQ, GTEQ, ANDAND, OROR)
private val ANNOTATIONS = TokenSet.create(KtNodeTypes.ANNOTATION_ENTRY, KtNodeTypes.ANNOTATION)
val CodeStyleSettings.kotlinSettings val CodeStyleSettings.kotlinSettings
get() = getCustomSettings(KotlinCodeStyleSettings::class.java) get() = getCustomSettings(KotlinCodeStyleSettings::class.java)
@@ -322,6 +323,7 @@ abstract class KotlinCommonBlock(
private fun getWrappingStrategy(): WrappingStrategy { private fun getWrappingStrategy(): WrappingStrategy {
val commonSettings = settings.getCommonSettings(KotlinLanguage.INSTANCE) val commonSettings = settings.getCommonSettings(KotlinLanguage.INSTANCE)
val elementType = node.elementType val elementType = node.elementType
val nodePsi = node.psi
when { when {
elementType === KtNodeTypes.VALUE_ARGUMENT_LIST -> elementType === KtNodeTypes.VALUE_ARGUMENT_LIST ->
@@ -355,29 +357,44 @@ abstract class KotlinCommonBlock(
elementType === KtNodeTypes.CLASS_BODY -> elementType === KtNodeTypes.CLASS_BODY ->
return getWrappingStrategyForItemList(commonSettings.ENUM_CONSTANTS_WRAP, KtNodeTypes.ENUM_ENTRY) return getWrappingStrategyForItemList(commonSettings.ENUM_CONSTANTS_WRAP, KtNodeTypes.ENUM_ENTRY)
elementType === KtNodeTypes.MODIFIER_LIST -> elementType === KtNodeTypes.MODIFIER_LIST -> {
when (node.treeParent.psi) { val parent = node.treeParent.psi
when (parent) {
is KtParameter -> is KtParameter ->
return getWrappingStrategyForItemList(commonSettings.PARAMETER_ANNOTATION_WRAP, return getWrappingStrategyForItemList(commonSettings.PARAMETER_ANNOTATION_WRAP,
KtNodeTypes.ANNOTATION_ENTRY, ANNOTATIONS,
!node.treeParent.isFirstParameter()) !node.treeParent.isFirstParameter())
is KtClassOrObject -> is KtClassOrObject ->
return getWrappingStrategyForItemList(commonSettings.CLASS_ANNOTATION_WRAP, return getWrappingStrategyForItemList(commonSettings.CLASS_ANNOTATION_WRAP,
KtNodeTypes.ANNOTATION_ENTRY) ANNOTATIONS)
is KtNamedFunction -> is KtNamedFunction ->
return getWrappingStrategyForItemList(commonSettings.METHOD_ANNOTATION_WRAP, return getWrappingStrategyForItemList(commonSettings.METHOD_ANNOTATION_WRAP,
KtNodeTypes.ANNOTATION_ENTRY) ANNOTATIONS)
is KtProperty ->
return getWrappingStrategyForItemList(if (parent.isLocal)
commonSettings.VARIABLE_ANNOTATION_WRAP
else
commonSettings.FIELD_ANNOTATION_WRAP,
ANNOTATIONS)
} }
}
elementType === KtNodeTypes.VALUE_PARAMETER -> elementType === KtNodeTypes.VALUE_PARAMETER ->
return wrapAfterAnnotation(commonSettings.PARAMETER_ANNOTATION_WRAP) return wrapAfterAnnotation(commonSettings.PARAMETER_ANNOTATION_WRAP)
node.psi is KtClassOrObject -> nodePsi is KtClassOrObject ->
return wrapAfterAnnotation(commonSettings.CLASS_ANNOTATION_WRAP) return wrapAfterAnnotation(commonSettings.CLASS_ANNOTATION_WRAP)
node.psi is KtNamedFunction -> nodePsi is KtNamedFunction ->
return wrapAfterAnnotation(commonSettings.METHOD_ANNOTATION_WRAP) return wrapAfterAnnotation(commonSettings.METHOD_ANNOTATION_WRAP)
nodePsi is KtProperty ->
return wrapAfterAnnotation(if (nodePsi.isLocal)
commonSettings.VARIABLE_ANNOTATION_WRAP
else
commonSettings.FIELD_ANNOTATION_WRAP)
} }
return WrappingStrategy.NoWrapping return WrappingStrategy.NoWrapping
@@ -391,12 +408,13 @@ private fun ASTNode.isFirstParameter(): Boolean = treePrev.elementType == KtToke
private fun wrapAfterAnnotation(wrapType: Int): WrappingStrategy { private fun wrapAfterAnnotation(wrapType: Int): WrappingStrategy {
return object : WrappingStrategy { return object : WrappingStrategy {
override fun getWrap(childElement: ASTNode): Wrap? { override fun getWrap(childElement: ASTNode): Wrap? {
if (childElement.elementType in KtTokens.COMMENTS) return null
var prevLeaf = childElement.treePrev var prevLeaf = childElement.treePrev
while (prevLeaf?.elementType == TokenType.WHITE_SPACE) { while (prevLeaf?.elementType == TokenType.WHITE_SPACE) {
prevLeaf = prevLeaf.treePrev prevLeaf = prevLeaf.treePrev
} }
if (prevLeaf?.elementType == KtNodeTypes.MODIFIER_LIST) { if (prevLeaf?.elementType == KtNodeTypes.MODIFIER_LIST) {
if (prevLeaf?.lastChildNode?.elementType == KtNodeTypes.ANNOTATION_ENTRY) { if (prevLeaf?.lastChildNode?.elementType in ANNOTATIONS) {
return Wrap.createWrap(wrapType, true) return Wrap.createWrap(wrapType, true)
} }
} }
@@ -579,6 +597,15 @@ private fun getWrappingStrategyForItemList(wrapType: Int, itemType: IElementType
} }
} }
private fun getWrappingStrategyForItemList(wrapType: Int, itemTypes: TokenSet, wrapFirstElement: Boolean = false): WrappingStrategy {
val itemWrap = Wrap.createWrap(wrapType, wrapFirstElement)
return object : WrappingStrategy {
override fun getWrap(childElement: ASTNode): Wrap? {
return if (childElement.elementType in itemTypes) itemWrap else null
}
}
}
private fun findNodeBlockIndex(blocks: List<Block>, tokenSet: TokenSet): Int { private fun findNodeBlockIndex(blocks: List<Block>, tokenSet: TokenSet): Int {
return blocks.indexOfFirst { block -> return blocks.indexOfFirst { block ->
if (block !is ASTBlock) return@indexOfFirst false if (block !is ASTBlock) return@indexOfFirst false
@@ -49,9 +49,12 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
fun longMethod(@Named("param1") param1: Int, fun longMethod(@Named("param1") param1: Int,
param2: String) { param2: String) {
@Deprecated val foo = 1
} }
} }
@Deprecated val bar = 1
enum class Enumeration { enum class Enumeration {
A, B A, B
} }
@@ -238,6 +241,8 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
"METHOD_ANNOTATION_WRAP", "METHOD_ANNOTATION_WRAP",
"CLASS_ANNOTATION_WRAP", "CLASS_ANNOTATION_WRAP",
"PARAMETER_ANNOTATION_WRAP", "PARAMETER_ANNOTATION_WRAP",
"VARIABLE_ANNOTATION_WRAP",
"FIELD_ANNOTATION_WRAP",
"METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE", "METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE",
"METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE", "METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE",
"CALL_PARAMETERS_LPAREN_ON_NEXT_LINE", "CALL_PARAMETERS_LPAREN_ON_NEXT_LINE",
@@ -245,6 +250,7 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
"ENUM_CONSTANTS_WRAP" "ENUM_CONSTANTS_WRAP"
) )
consumer.renameStandardOption(CodeStyleSettingsCustomizable.WRAPPING_SWITCH_STATEMENT, "'when' statements") consumer.renameStandardOption(CodeStyleSettingsCustomizable.WRAPPING_SWITCH_STATEMENT, "'when' statements")
consumer.renameStandardOption("FIELD_ANNOTATION_WRAP", "Property annotations")
showCustomOption(KotlinCodeStyleSettings::ALIGN_IN_COLUMNS_CASE_BRANCH, showCustomOption(KotlinCodeStyleSettings::ALIGN_IN_COLUMNS_CASE_BRANCH,
"Align 'when' branches in columns", "Align 'when' branches in columns",
CodeStyleSettingsCustomizable.WRAPPING_SWITCH_STATEMENT) CodeStyleSettingsCustomizable.WRAPPING_SWITCH_STATEMENT)
@@ -0,0 +1,7 @@
fun foo() {
@Deprecated
@Named("foo")
val bar = 1
}
// SET_INT: VARIABLE_ANNOTATION_WRAP = 2
@@ -0,0 +1,5 @@
fun foo() {
@Deprecated @Named("foo") val bar = 1
}
// SET_INT: VARIABLE_ANNOTATION_WRAP = 2
@@ -0,0 +1,5 @@
@Deprecated
@Named("foo")
val bar = 1
// SET_INT: FIELD_ANNOTATION_WRAP = 2
+3
View File
@@ -0,0 +1,3 @@
@Deprecated @Named("foo") val bar = 1
// SET_INT: FIELD_ANNOTATION_WRAP = 2
+15 -4
View File
@@ -67,7 +67,12 @@ annotation class A1
annotation class A2 annotation class A2
private @[A1 A2 A1] @A1 @A2 @[A1 A2 A2] @[A1] val fooProp1 = 1 private @[A1 A2 A1]
@A1
@A2
@[A1 A2 A2]
@[A1]
val fooProp1 = 1
private @[ private @[
@@ -75,17 +80,23 @@ private @[
A1 A1
A2 A1] @A1 @A2 @[A1 A2 A1]
@A1
@A2
@[A1
A2 A2
A2 A2
] @[A1] val fooProp1 = 1 ]
@[A1]
val fooProp1 = 1
private @A1 private @A1
@A2 val @A2
val
fooProp2 = 1 fooProp2 = 1
@@ -4,7 +4,8 @@ annotation class X(val s: String)
class A(val n: Int) { class A(val n: Int) {
val t = 1 val t = 1
internal @X("1") val <T : Number> T.foo: Boolean internal @X("1")
val <T : Number> T.foo: Boolean
get() = toInt() - n > 1 get() = toInt() - n > 1
val u = 2 val u = 2
} }
@@ -4,5 +4,6 @@ annotation class Annotation3(val a: Int = 0)
class TestClass(@Annotation1(42) @Annotation3(42) text: String = "LoremIpsum") { class TestClass(@Annotation1(42) @Annotation3(42) text: String = "LoremIpsum") {
private @Annotation1(42) @field:Annotation2(42) val text = text private @Annotation1(42) @field:Annotation2(42)
val text = text
} }
@@ -3,5 +3,6 @@
annotation class PropertyAnnotation(val a: Int = 0) annotation class PropertyAnnotation(val a: Int = 0)
class TestClass(text: String = "LoremIpsum") { class TestClass(text: String = "LoremIpsum") {
private @PropertyAnnotation(42) val text = text private @PropertyAnnotation(42)
val text = text
} }
@@ -500,6 +500,12 @@ public class FormatterTestGenerated extends AbstractFormatterTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("LocalVariableAnnotationWrap.after.kt")
public void testLocalVariableAnnotationWrap() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/LocalVariableAnnotationWrap.after.kt");
doTest(fileName);
}
@TestMetadata("LoopParameterWithExplicitType.after.kt") @TestMetadata("LoopParameterWithExplicitType.after.kt")
public void testLoopParameterWithExplicitType() throws Exception { public void testLoopParameterWithExplicitType() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/LoopParameterWithExplicitType.after.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/LoopParameterWithExplicitType.after.kt");
@@ -614,6 +620,12 @@ public class FormatterTestGenerated extends AbstractFormatterTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("PropertyAnnotationWrap.after.kt")
public void testPropertyAnnotationWrap() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/PropertyAnnotationWrap.after.kt");
doTest(fileName);
}
@TestMetadata("PropertyTypeParameterList.after.kt") @TestMetadata("PropertyTypeParameterList.after.kt")
public void testPropertyTypeParameterList() throws Exception { public void testPropertyTypeParameterList() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/PropertyTypeParameterList.after.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/PropertyTypeParameterList.after.kt");