diff --git a/sonar-zpa-plugin/src/main/kotlin/org/sonar/plsqlopen/symbols/MappedObject.kt b/sonar-zpa-plugin/src/main/kotlin/org/sonar/plsqlopen/symbols/MappedObject.kt index e75c0e38..3ea819cd 100644 --- a/sonar-zpa-plugin/src/main/kotlin/org/sonar/plsqlopen/symbols/MappedObject.kt +++ b/sonar-zpa-plugin/src/main/kotlin/org/sonar/plsqlopen/symbols/MappedObject.kt @@ -29,7 +29,9 @@ data class MappedObject( val objectType: AstNodeType, val fileType: PlSqlFile.Type, val path: Path, - val inputFile: InputFile + val inputFile: InputFile, + val firstLine: Int = -1, + val lastLine: Int = -1 ) { val isMain: Boolean get() = fileType === PlSqlFile.Type.MAIN diff --git a/sonar-zpa-plugin/src/main/kotlin/org/sonar/plsqlopen/symbols/ObjectLocator.kt b/sonar-zpa-plugin/src/main/kotlin/org/sonar/plsqlopen/symbols/ObjectLocator.kt index bc62476a..c629f891 100644 --- a/sonar-zpa-plugin/src/main/kotlin/org/sonar/plsqlopen/symbols/ObjectLocator.kt +++ b/sonar-zpa-plugin/src/main/kotlin/org/sonar/plsqlopen/symbols/ObjectLocator.kt @@ -33,7 +33,9 @@ class ObjectLocator { val plSqlFile = it.plSqlFile as SonarQubePlSqlFile? ?: return@map null val identifier = it.identifier ?: return@map null val type = it.type ?: return@map null - MappedObject(identifier, type, plSqlFile.type(), plSqlFile.path(), plSqlFile.inputFile) + val firstLine = it.tree?.tokenLine ?: return@map null + val lastLine = it.tree?.lastTokenOrNull?.endLine ?: return@map null + MappedObject(identifier, type, plSqlFile.type(), plSqlFile.path(), plSqlFile.inputFile, firstLine, lastLine) }.filterNotNull() fun setScope(scope: Scope) { diff --git a/sonar-zpa-plugin/src/main/kotlin/org/sonar/plsqlopen/utplsql/CoverageResultImporter.kt b/sonar-zpa-plugin/src/main/kotlin/org/sonar/plsqlopen/utplsql/CoverageResultImporter.kt index 2539eb51..fac1d272 100644 --- a/sonar-zpa-plugin/src/main/kotlin/org/sonar/plsqlopen/utplsql/CoverageResultImporter.kt +++ b/sonar-zpa-plugin/src/main/kotlin/org/sonar/plsqlopen/utplsql/CoverageResultImporter.kt @@ -42,6 +42,8 @@ class CoverageResultImporter(private val objectLocator: ObjectLocator, var inputFile = context.fileSystem() .inputFile(context.fileSystem().predicates().hasPath(filePath)) + var lineOffset = 0 + if (inputFile == null) { val objectType = when (filePath.substringBeforeLast(' ')) { "package body" -> PlSqlGrammar.CREATE_PACKAGE_BODY @@ -53,16 +55,19 @@ class CoverageResultImporter(private val objectLocator: ObjectLocator, } val objectName = filePath.substringAfterLast('.') - val mappedFile = objectLocator.findMainObject(objectName, objectType) - - inputFile = mappedFile?.inputFile + val mappedObject = objectLocator.findMainObject(objectName, objectType) + if (mappedObject != null) { + inputFile = mappedObject.inputFile + lineOffset = mappedObject.firstLine - 1 + } } if (inputFile != null) { val newCoverage = context.newCoverage().onFile(inputFile) file.linesToCover?.forEach { line -> - newCoverage.lineHits(line.lineNumber, if (line.covered) 1 else 0) + val lineNumber = line.lineNumber + lineOffset + newCoverage.lineHits(lineNumber, if (line.covered) 1 else 0) val branchesToCover = line.branchesToCover val coveredBranches = line.coveredBranches ?: 0 @@ -72,7 +77,7 @@ class CoverageResultImporter(private val objectLocator: ObjectLocator, "${line.lineNumber} for file \"$filePath\"" } - newCoverage.conditions(line.lineNumber, branchesToCover, coveredBranches) + newCoverage.conditions(lineNumber, branchesToCover, coveredBranches) } } diff --git a/sonar-zpa-plugin/src/test/kotlin/org/sonar/plsqlopen/utplsql/UtPlSqlSensorTest.kt b/sonar-zpa-plugin/src/test/kotlin/org/sonar/plsqlopen/utplsql/UtPlSqlSensorTest.kt index 1137c2cf..0fdc69ed 100644 --- a/sonar-zpa-plugin/src/test/kotlin/org/sonar/plsqlopen/utplsql/UtPlSqlSensorTest.kt +++ b/sonar-zpa-plugin/src/test/kotlin/org/sonar/plsqlopen/utplsql/UtPlSqlSensorTest.kt @@ -145,17 +145,25 @@ class UtPlSqlSensorTest { context.fileSystem().add(mainFile) whenever(objectLocator.findMainObject(any(), any())).thenReturn( - MappedObject("", PlSqlGrammar.CREATE_FUNCTION, PlSqlFile.Type.MAIN, mainFile.path(), mainFile) + MappedObject( + identifier = "", + objectType = PlSqlGrammar.CREATE_FUNCTION, + fileType = PlSqlFile.Type.MAIN, + path = mainFile.path(), + inputFile = mainFile, + firstLine = 3, + lastLine = 10 + ) ) context.settings().setProperty(UtPlSqlSensor.COVERAGE_REPORT_PATH_KEY, "coverage-report-without-paths.xml") sensor.execute(context) val key = mainFile.key() - assertThat(context.lineHits(key, 2)).isOne() assertThat(context.lineHits(key, 4)).isOne() - assertThat(context.lineHits(key, 5)).isOne() + assertThat(context.lineHits(key, 6)).isOne() assertThat(context.lineHits(key, 7)).isOne() + assertThat(context.lineHits(key, 9)).isOne() } @Test diff --git a/sonar-zpa-plugin/src/test/resources/org/sonar/plsqlopen/utplsql/betwnstr.sql b/sonar-zpa-plugin/src/test/resources/org/sonar/plsqlopen/utplsql/betwnstr.sql index 71cb9399..2cf64cd4 100644 --- a/sonar-zpa-plugin/src/test/resources/org/sonar/plsqlopen/utplsql/betwnstr.sql +++ b/sonar-zpa-plugin/src/test/resources/org/sonar/plsqlopen/utplsql/betwnstr.sql @@ -1,3 +1,5 @@ +/* comment before the code + so the lines in the coverage report don't match the file */ create or replace function betwnstr(a_string varchar2, a_start_pos integer, a_end_pos integer) return varchar2 is l_start_pos pls_integer := a_start_pos; begin