Skip to content

Commit

Permalink
Support inline fixers for fix and warn plugin
Browse files Browse the repository at this point in the history
What's done:
* Added support inline fixers for fix and warn plugin
Closes #221
  • Loading branch information
Cheshiriks committed Sep 2, 2021
1 parent c1237b2 commit 83a18d4
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import org.cqfn.save.core.result.Pass
import org.cqfn.save.core.result.TestResult
import org.cqfn.save.plugin.warn.WarnPlugin
import org.cqfn.save.plugin.warn.WarnPluginConfig
import org.cqfn.save.plugin.warn.utils.getLineNumber
import org.cqfn.save.plugins.fix.FixPlugin
import org.cqfn.save.plugins.fix.FixPluginConfig

Expand All @@ -34,12 +35,12 @@ class FixAndWarnPlugin(
fileSystem,
useInternalRedirections,
redirectTo) {
private val fixPluginConfig: FixPluginConfig =
testConfig.pluginConfigs.filterIsInstance<FixAndWarnPluginConfig>().single().fix
private val warnPluginConfig: WarnPluginConfig =
testConfig.pluginConfigs.filterIsInstance<FixAndWarnPluginConfig>().single().warn
private val fixAndWarnPluginConfig: FixAndWarnPluginConfig = testConfig.pluginConfigs.filterIsInstance<FixAndWarnPluginConfig>().single()
private val fixPluginConfig: FixPluginConfig = fixAndWarnPluginConfig.fix
private val warnPluginConfig: WarnPluginConfig = fixAndWarnPluginConfig.warn
private val generalConfig: GeneralConfig =
testConfig.pluginConfigs.filterIsInstance<GeneralConfig>().single()
private val inlineFixer = fixAndWarnPluginConfig.inlineFixer
private lateinit var fixPlugin: FixPlugin
private lateinit var warnPlugin: WarnPlugin

Expand Down Expand Up @@ -69,12 +70,19 @@ class FixAndWarnPlugin(
// Need to update private fields after validation
initOrUpdateConfigs()
val testFilePattern = warnPluginConfig.resourceNamePattern
val expectedFiles = files.filterTestResources(testFilePattern, match = false)

val newFiles = if (inlineFixer == true) {
replaceFixLine(files)
} else {
files
}

val expectedFiles = newFiles.filterTestResources(testFilePattern, match = false)

// Remove (in place) warnings from test files before fix plugin execution
val filesAndTheirWarningsMap = removeWarningsFromExpectedFiles(expectedFiles)

val fixTestResults = fixPlugin.handleFiles(files).toList()
val fixTestResults = fixPlugin.handleFiles(newFiles).toList()

val (fixTestResultsPassed, fixTestResultsFailed) = fixTestResults.partition { it.status is Pass }

Expand Down Expand Up @@ -168,6 +176,61 @@ class FixAndWarnPlugin(
}
}

@Suppress(
"TOO_LONG_FUNCTION",
"TOO_MANY_LINES_IN_LAMBDA"
)
private fun replaceFixLine(files: Sequence<List<Path>>): Sequence<List<Path>> {
val newFiles: MutableList<List<Path>> = mutableListOf()
files.map { file -> file.single() }.map {
val fileCopy = createTestFile(it)
val fileCopyWarning = createTestFile(it)
val linesFile = fs.readLines(it) as MutableList
linesFile.mapIndexed { index, line ->
if (generalConfig.expectedWarningsPattern!!.matches(line)) {
val lineNumber = line.getLineNumber(
generalConfig.expectedWarningsPattern!!,
warnPluginConfig.lineCaptureGroup,
warnPluginConfig.linePlaceholder!!,
index + 1,
it,
linesFile,
)
val newLine = fixAndWarnPluginConfig.checkFixesPattern!!.find(linesFile[index + 1])?.groups?.get(1)
?.value
newLine?.let {
lineNumber?.let {
linesFile.removeAt(lineNumber - 1)
linesFile.add(lineNumber - 1, newLine)
}
}
}
}
linesFile.map {
if (!generalConfig.expectedWarningsPattern!!.matches(it) && !fixAndWarnPluginConfig.checkFixesPattern!!.matches(it)) {
fs.write(fileCopy) {
write((it + "\n").encodeToByteArray())
}
}
}
linesFile.map {
if (!fixAndWarnPluginConfig.checkFixesPattern!!.matches(it)) {
fs.write(fileCopyWarning) {
write((it + "\n").encodeToByteArray())
}
}
}
newFiles.add(listOf(fileCopy, fileCopyWarning))
}
return newFiles.asSequence()
}

private fun createTestFile(path: Path): Path {
val pathCopy: Path = constructPathForCopyOfTestFile(FixAndWarnPlugin::class.simpleName!!, path)
createTempDir(pathCopy.parent!!)
return pathCopy
}

override fun cleanupTempDir() {
val tmpDir = (FileSystem.SYSTEM_TEMPORARY_DIRECTORY / FixAndWarnPlugin::class.simpleName!!)
if (fs.exists(tmpDir)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
@file:Suppress("HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE")
@file:UseSerializers(RegexSerializer::class)

package org.cqfn.save.plugins.fixandwarn

import org.cqfn.save.core.config.TestConfigSections
import org.cqfn.save.core.plugin.PluginConfig
import org.cqfn.save.core.utils.RegexSerializer
import org.cqfn.save.plugin.warn.WarnPluginConfig
import org.cqfn.save.plugins.fix.FixPluginConfig

Expand All @@ -10,15 +14,20 @@ import okio.Path.Companion.toPath

import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.UseSerializers

/**
* @property fix config for nested [fix] section
* @property warn config for nested [warn] section
* @property inlineFixer
* @property checkFixesPattern
*/
@Serializable
data class FixAndWarnPluginConfig(
val fix: FixPluginConfig,
val warn: WarnPluginConfig
val warn: WarnPluginConfig,
val inlineFixer: Boolean? = null,
val checkFixesPattern: Regex? = null,
) : PluginConfig {
override val type = TestConfigSections.`FIX AND WARN`

Expand All @@ -31,7 +40,9 @@ data class FixAndWarnPluginConfig(
val mergedWarnPluginConfig = warn.mergeWith(other.warn)
return FixAndWarnPluginConfig(
mergedFixPluginConfig as FixPluginConfig,
mergedWarnPluginConfig as WarnPluginConfig
mergedWarnPluginConfig as WarnPluginConfig,
this.inlineFixer ?: otherConfig.inlineFixer,
this.checkFixesPattern ?: other.checkFixesPattern,
)
}

Expand All @@ -43,9 +54,21 @@ data class FixAndWarnPluginConfig(
[warn]: {${warn.testName}, ${warn.batchSize}}
"""
}
val newInlineFixer = inlineFixer ?: false
val newCheckFixerPattern = if (newInlineFixer) (checkFixesPattern ?: defaultCheckFixesPattern) else null
return FixAndWarnPluginConfig(
fix.validateAndSetDefaults(),
warn.validateAndSetDefaults()
warn.validateAndSetDefaults(),
newInlineFixer,
newCheckFixerPattern,
)
}

companion object {
/**
* Default regex for check fixes
* ```CHECK-FIXES: val foo = 42```
*/
internal val defaultCheckFixesPattern = Regex("(.+): (.+)")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ class FixAndWarnPluginTest {
WarnPluginConfig(warnExecutionCmd,
Regex("(.+):(\\d+):(\\d+): (.+)"),
true, true, 1, ", ", 1, 2, 3, 1, 2, 3, 4
)
),
false,
),
GeneralConfig("", listOf(""), "", "", expectedWarningsPattern = Regex("// ;warn:(\\d+):(\\d+): (.*)"))
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,57 @@ data class Warning(
val fileName: String,
)

/**
* @param warningRegex regular expression for warning
* @param lineGroupIdx index of capture group for line number
* @param placeholder placeholder for line
* @param lineNum number of line
* @param file path to test file
* @param linesFile lines of file
* @return a [Warning] or null if [this] string doesn't match [warningRegex]
* @throws ResourceFormatException when parsing a file
*/
@Suppress(
"TooGenericExceptionCaught",
"LongParameterList",
"NestedBlockDepth",
"ReturnCount",
// fixme: add `cause` parameter to `PluginException`
"SwallowedException",
"TOO_MANY_PARAMETERS",
"AVOID_NULL_CHECKS",
)
fun String.getLineNumber(warningRegex: Regex,
lineGroupIdx: Long?,
placeholder: String,
lineNum: Int?,
file: Path?,
linesFile: List<String>?,
): Int? {
if (lineGroupIdx == null) {
// line capture group is not configured in save.toml
return null
}

val groups = warningRegex.find(this)?.groups ?: return null
val lineValue = groups[lineGroupIdx.toInt()]!!.value
return if (lineValue.isEmpty() && lineNum != null && linesFile != null) {
nextLineNotMatchingRegex(file!!, warningRegex, linesFile, lineNum)
} else {
lineValue.toIntOrNull() ?: run {
if (lineValue[0] != placeholder[0]) {
throw ResourceFormatException("The group <$lineValue> is neither a number nor a placeholder.")
}
try {
val adjustment = lineValue.substringAfterLast(placeholder)
lineNum!! + adjustment.ifBlank { "0" }.toInt()
} catch (e: Exception) {
throw ResourceFormatException("Could not extract line number from line [$this], cause: ${e.describe()}")
}
}
}
}

/**
* Extract warning from [this] string using provided parameters
*
Expand Down Expand Up @@ -80,57 +131,6 @@ internal fun String.extractWarning(warningRegex: Regex,
return extractWarning(warningRegex, fileName, line, columnGroupIdx, messageGroupIdx)
}

/**
* @param warningRegex regular expression for warning
* @param lineGroupIdx index of capture group for line number
* @param placeholder placeholder for line
* @param lineNum number of line
* @param file path to test file
* @param linesFile lines of file
* @return a [Warning] or null if [this] string doesn't match [warningRegex]
* @throws ResourceFormatException when parsing a file
*/
@Suppress(
"TooGenericExceptionCaught",
"LongParameterList",
"NestedBlockDepth",
"ReturnCount",
// fixme: add `cause` parameter to `PluginException`
"SwallowedException",
"TOO_MANY_PARAMETERS",
"AVOID_NULL_CHECKS",
)
internal fun String.getLineNumber(warningRegex: Regex,
lineGroupIdx: Long?,
placeholder: String,
lineNum: Int?,
file: Path?,
linesFile: List<String>?,
): Int? {
if (lineGroupIdx == null) {
// line capture group is not configured in save.toml
return null
}

val groups = warningRegex.find(this)?.groups ?: return null
val lineValue = groups[lineGroupIdx.toInt()]!!.value
return if (lineValue.isEmpty() && lineNum != null && linesFile != null) {
nextLineNotMatchingRegex(file!!, warningRegex, linesFile, lineNum)
} else {
lineValue.toIntOrNull() ?: run {
if (lineValue[0] != placeholder[0]) {
throw ResourceFormatException("The group <$lineValue> is neither a number nor a placeholder.")
}
try {
val adjustment = lineValue.substringAfterLast(placeholder)
lineNum!! + adjustment.ifBlank { "0" }.toInt()
} catch (e: Exception) {
throw ResourceFormatException("Could not extract line number from line [$this], cause: ${e.describe()}")
}
}
}
}

/**
* @param warningRegex regular expression for warning
* @param lineGroupIdx index of capture group for line number
Expand Down

0 comments on commit 83a18d4

Please sign in to comment.