diktat
diktat copied to clipboard
False positive findings for `TOP_LEVEL_ORDER` on kdoc comments
This behavior is strange. It reports this warning for almost everything, especially functions. I'm not sure but I guess it's only reported for my util top level functions but I get so many findings, so I can't tell for sure.
[TOP_LEVEL_ORDER] the declaration part of a top level elements should be in the proper order: /**...
One suspicious file:
package de.example.common.jvm.util
private const val INT_MAX_POWER_OF_TWO: Int = 1 shl (Int.SIZE_BITS - 2)
/**
*
*/
fun<T> isEqual(first: Collection<T>, second: Collection<T>): Boolean =
first.zip(second).all { (x, y) -> x == y }
/**
* Returns a [Map] containing the elements from the given collection indexed by the key
* returned from [keySelector] function applied to each non-null element.
*
* If elements have the same key returned by [keySelector] the last one gets added to the map.
*
* The returned map preserves the entry iteration order of the original collection.
*
*/
inline fun <T, K> Iterable<T>.associateByNotNull(keySelector: (T) -> K?): Map<K, T> {
val capacity = mapCapacity(collectionSizeOrDefault(10)).coerceAtLeast(16)
return associateByNotNullTo(LinkedHashMap(capacity), keySelector)
}
/**
* Populates and returns the [destination] mutable map with key-value pairs,
* where key is provided by the [keySelector] function applied to each non-null
* element of the given collection and value is the element itself.
*
* If elements have the same key returned by [keySelector] the last one gets added to the map.
*
*/
inline fun <T, K, M : MutableMap<in K, in T>> Iterable<T>.associateByNotNullTo(
destination: M,
keySelector: (T) -> K?,
): M {
for (element in this) {
val key = keySelector(element) ?: continue
destination.put(key, element)
}
return destination
}
/**
* Populates and returns the [destination] mutable map with key-value pairs,
* where key is provided by the [keySelector] function and
* and value is provided by the [valueTransform] function applied to each
* non-null element of the given collection.
*
* If elements have the same key returned by [keySelector] the last one gets added to the map.
*/
inline fun <T, K, V, M : MutableMap<in K, in V>> Iterable<T>.associateByNotNullTo(
destination: M,
keySelector: (T) -> K?,
valueTransform: (T) -> V?,
): M {
for (element in this) {
val key = keySelector(element)
val transformed = valueTransform(element)
if (key == null || transformed == null) continue
destination.put(key, transformed)
}
return destination
}
/**
* Returns a [Map] where keys are elements from the given collection and values are
* produced by the [valueSelector] function applied to each non-null element.
*
* If elements are equal the last one gets added to the map.
*
* The returned map preserves the entry iteration order of the original collection.
*
*/
inline fun <K, V> Iterable<K>.associateWithNotNull(valueSelector: (K) -> V?): Map<K, V> {
val result = LinkedHashMap<K, V>(
mapCapacity(collectionSizeOrDefault(10)).coerceAtLeast(16),
)
return associateWithNotNullTo(result, valueSelector)
}
/**
* Populates and returns the [destination] mutable map with
* key-value pairs for each non-null element,
* where key is the element itself and value is provided
* by the [valueSelector] function applied to that key.
*
* If elements are equal the last one overwrites the former value in the map.
*
*/
inline fun <K, V, M : MutableMap<in K, in V>> Iterable<K>.associateWithNotNullTo(
destination: M,
valueSelector: (K) -> V?,
): M {
for (element in this) {
val value = valueSelector(element) ?: continue
destination.put(element, value)
}
return destination
}
/**
* Groups elements of the original collection by the key returned by the given [keySelector]
* function applied to each element and returns a map where only non-null group keys are associated
* with a list of corresponding elements.
*
* The returned map preserves the entry iteration order of the keys
* produced from the original collection.
*
*/
inline fun <T, K : Any> Iterable<T>.groupByNotNull(keySelector: (T) -> K?): Map<K, List<T>> =
groupByNotNullTo(LinkedHashMap(), keySelector)
/**
* Groups values returned by the [valueTransform] function applied to each element of the original
* collection by the key returned by the given [keySelector] function applied to the element and
* returns a map where only non-null group keys are associated with a list of corresponding values.
*
* The returned map preserves the entry iteration order of the keys
* produced from the original collection.
*
*/
inline fun <T, K : Any, V> Iterable<T>.groupByNotNull(
keySelector: (T) -> K?,
valueTransform: (T) -> V?,
): Map<K, List<V>> = groupByNotNullTo(LinkedHashMap(), keySelector, valueTransform)
/**
* Groups elements of the original collection by the key returned by the given [keySelector]
* function applied to each element and puts to the [destination] map only non-null group keys
* associated with a list of corresponding elements.
*
* @return The [destination] map.
*
*/
inline fun <T, K : Any, M : MutableMap<in K, MutableList<T>>> Iterable<T>.groupByNotNullTo(
destination: M,
keySelector: (T) -> K?,
): M {
for (element in this) {
val key = keySelector(element) ?: continue
val list = destination.getOrPut(key) { ArrayList() }
list.add(element)
}
return destination
}
/**
* Groups values returned by the [valueTransform] function applied to each element of the original
* collection by the key returned by the given [keySelector] function applied to the element and
* puts to the [destination] map only non-null group keys associated with a list of corresponding
* values.
*
* @return The [destination] map.
*
*/
inline fun <T, K : Any, V, M : MutableMap<in K, MutableList<V>>> Iterable<T>.groupByNotNullTo(
destination: M,
keySelector: (T) -> K?,
valueTransform: (T) -> V?,
): M {
for (element in this) {
val key = keySelector(element)
val transformed = valueTransform(element)
if (key == null || transformed == null) continue
val list = destination.getOrPut(key) { ArrayList() }
list.add(transformed)
}
return destination
}
/**
* Returns the size of this iterable if it is known, or the specified [default] value otherwise.
*/
fun <T> Iterable<T>.collectionSizeOrDefault(default: Int): Int =
if (this is Collection<*>) this.size else default
/**
* Calculate the initial capacity of a map, based on Guava's approach.
*/
fun mapCapacity(expectedSize: Int): Int = when {
// We are not coercing the value to a valid one and not throwing an exception.
// It is up to the caller to properly handle negative values.
expectedSize < 0 -> expectedSize
expectedSize < 3 -> expectedSize + 1
expectedSize < INT_MAX_POWER_OF_TWO -> ((expectedSize / 0.75F) + 1.0F).toInt()
// any large value
else -> Int.MAX_VALUE
}
The ktlint demo is also reporting this rule and WRONG_INDENTATION too.
This is not actually a false positive, it's just a rule with poor wording of its findings :)
According to rule 3.1.5 of the code style, extension functions should be placed before ordinary functions.
Since KDocs are part of the same node of the AST as the function declaration, warning text contains part of the node text starting from KDoc start token. If you run diktat with fix mode on ktlint-demo.herokuapp.com, you can see that all it does is move isEqual function to the bottom of the file.
Damn my bad. You are right. You might want to add a more user friendly message or maybe refer to the guide convention but it's up to you. If I had checked the code convention I wouldn't have opened the issue I guess. Sorry for the inconvenience. You can close the issue.
Damn my bad. You are right.
No, thank you for this, it’s our fault. We made a poor work if we need to describe our inspections. I think @petertrr will need to enhance warning description and warning text