diff --git a/idea/idea-android/idea-android-output-parser/src/org/jetbrains/kotlin/android/KotlinOutputParser.java b/idea/idea-android/idea-android-output-parser/src/org/jetbrains/kotlin/android/KotlinOutputParser.java index 7613de9d385..790728f6393 100644 --- a/idea/idea-android/idea-android-output-parser/src/org/jetbrains/kotlin/android/KotlinOutputParser.java +++ b/idea/idea-android/idea-android-output-parser/src/org/jetbrains/kotlin/android/KotlinOutputParser.java @@ -18,13 +18,14 @@ package org.jetbrains.kotlin.android; import com.android.ide.common.blame.parser.PatternAwareOutputParser; import com.android.ide.common.blame.parser.util.OutputLineReader; +import com.android.ide.common.blame.Message; import com.android.utils.ILogger; import java.util.List; public class KotlinOutputParser implements PatternAwareOutputParser { @Override - public boolean parse(String s, OutputLineReader reader, List list, ILogger logger) { - return KotlinOutputParserHelperKt.parse(s, reader, list, logger); + public boolean parse(String s, OutputLineReader reader, List list, ILogger logger) { + return KotlinOutputParserHelperKt.parse(s, reader, list); } } diff --git a/idea/idea-android/idea-android-output-parser/src/org/jetbrains/kotlin/android/KotlinOutputParserHelper.kt b/idea/idea-android/idea-android-output-parser/src/org/jetbrains/kotlin/android/KotlinOutputParserHelper.kt index bd2550c1703..0a72e1a7535 100644 --- a/idea/idea-android/idea-android-output-parser/src/org/jetbrains/kotlin/android/KotlinOutputParserHelper.kt +++ b/idea/idea-android/idea-android-output-parser/src/org/jetbrains/kotlin/android/KotlinOutputParserHelper.kt @@ -16,18 +16,18 @@ package org.jetbrains.kotlin.android +import com.android.ide.common.blame.Message +import com.android.ide.common.blame.SourceFilePosition +import com.android.ide.common.blame.SourcePosition import com.android.ide.common.blame.parser.util.OutputLineReader -import com.android.utils.ILogger +import com.google.common.base.Optional import com.google.common.collect.ImmutableList import com.intellij.openapi.util.io.FileUtilRt import com.intellij.openapi.util.text.StringUtil import java.io.File -import java.lang.reflect.Constructor -import java.util.* import java.util.regex.Pattern -import java.lang.reflect.Array as RArray -fun parse(line: String, reader: OutputLineReader, messages: MutableList, logger: ILogger): Boolean { +fun parse(line: String, reader: OutputLineReader, messages: MutableList): Boolean { val colonIndex1 = line.colon() val severity = if (colonIndex1 >= 0) line.substringBeforeAndTrim(colonIndex1) else return false if (!severity.startsWithSeverityPrefix()) return false @@ -37,8 +37,10 @@ fun parse(line: String, reader: OutputLineReader, messages: MutableList, lo if (colonIndex2 >= 0) { val path = lineWoSeverity.substringBeforeAndTrim(colonIndex2) val file = File(path) - if (!file.isFile && FileUtilRt.getExtension(file.name) != "kt") { - return addMessage(KotlinOutputParserHelper.createMessage(logger, severity, lineWoSeverity.amendNextLinesIfNeeded(reader)), messages) + + val fileExtension = file.extension.toLowerCase() + if (!file.isFile || (fileExtension != "kt" && fileExtension != "java")) { + return addMessage(createMessage(getMessageKind(severity), lineWoSeverity.amendNextLinesIfNeeded(reader)), messages) } val lineWoPath = lineWoSeverity.substringAfterAndTrim(colonIndex2) @@ -51,22 +53,18 @@ fun parse(line: String, reader: OutputLineReader, messages: MutableList, lo if (matcher.matches()) { val lineNumber = matcher.group(1) - val symbolNumber = matcher.group(2) - if (lineNumber != null && symbolNumber != null) { - try { - return addMessage(KotlinOutputParserHelper.createMessage(logger, severity, message, path, lineNumber.toInt(), symbolNumber.toInt(), symbolNumber.toInt()), messages) - } - catch (e: NumberFormatException) { - // ignore - } - + val symbolNumber = if (matcher.groupCount() >= 2) matcher.group(2) else "1" + if (lineNumber != null) { + val symbolNumberText = symbolNumber.toInt() + return addMessage(createMessageWithLocation( + getMessageKind(severity), message, path, lineNumber.toInt(), symbolNumberText, symbolNumberText), messages) } } - return addMessage(KotlinOutputParserHelper.createMessage(logger, severity, message), messages) + return addMessage(createMessage(getMessageKind(severity), message), messages) } else { - return addMessage(KotlinOutputParserHelper.createMessage(logger, severity, lineWoSeverity.amendNextLinesIfNeeded(reader)), messages) + return addMessage(createMessage(getMessageKind(severity), lineWoSeverity.amendNextLinesIfNeeded(reader)), messages) } } @@ -112,11 +110,14 @@ private fun String.isNextMessage(): Boolean { || StringUtil.containsIgnoreCase(this, "FAILED") } -private fun String.startsWithSeverityPrefix(): Boolean { - return when (this.trim()) { - "e", "w", "i", "v" -> true - else -> false - } +private fun String.startsWithSeverityPrefix() = getMessageKind(this) != Message.Kind.UNKNOWN + +private fun getMessageKind(kind: String) = when (kind) { + "e" -> Message.Kind.ERROR + "w" -> Message.Kind.WARNING + "i" -> Message.Kind.INFO + "v" -> Message.Kind.SIMPLE + else -> Message.Kind.UNKNOWN } private fun String.substringAfterAndTrim(index: Int) = substring(index + 1).trim() @@ -126,12 +127,11 @@ private fun Int.skipDriveOnWin(line: String): Int { return if (this == 1) line.indexOf(COLON, this + 1) else this } -private fun addMessage(message: Any?, messages: MutableList): Boolean { - if (message == null) return false +private fun addMessage(message: Message, messages: MutableList): Boolean { var duplicatesPrevious = false val messageCount = messages.size if (messageCount > 0) { - val lastMessage = messages.get(messageCount - 1) + val lastMessage = messages[messageCount - 1] duplicatesPrevious = lastMessage == message } if (!duplicatesPrevious) { @@ -140,168 +140,19 @@ private fun addMessage(message: Any?, messages: MutableList): Boolean { return true } -object KotlinOutputParserHelper { - private val isNewAndroidPlugin: Boolean - private val packagePrefix: String - private val severityObjectMap: HashMap = HashMap() - - init { - isNewAndroidPlugin = try { - Class.forName("com.android.ide.common.blame.Message") - true - } - catch (e: ClassNotFoundException) { - false - } - - packagePrefix = if (isNewAndroidPlugin) "com.android.ide.common.blame" else "com.android.ide.common.blame.output" - - loadSeverityEnums() - } - - private val simpleMessageConstructor: Constructor<*> by lazy { - if (!isNewAndroidPlugin) { - val messageClass = Class.forName("$packagePrefix.GradleMessage") - val messageKindClass = Class.forName("$packagePrefix.GradleMessage\$Kind") - messageClass.getConstructor(messageKindClass, String::class.java) - } - else { - val messageClass = Class.forName("$packagePrefix.Message") - val messageKindClass = Class.forName("$packagePrefix.Message\$Kind") - messageClass.getConstructor( - messageKindClass, - String::class.java, - String::class.java, - ImmutableList::class.java) - } - } - - private val complexMessageConstructor: Constructor<*> by lazy { - if (!isNewAndroidPlugin) { - val messageClass = Class.forName("$packagePrefix.GradleMessage") - val messageKindClass = Class.forName("$packagePrefix.GradleMessage\$Kind") - messageClass.getConstructor( - messageKindClass, - String::class.java, String::class.java, - Int::class.java, Int::class.java) - } - else { - val messageClass = Class.forName("$packagePrefix.Message") - val messageKindClass = Class.forName("$packagePrefix.Message\$Kind") - val sourceFilePositionClass = Class.forName("$packagePrefix.SourceFilePosition") - val sourceFilePositionArrayClass = Class.forName("[L$packagePrefix.SourceFilePosition;") - messageClass.getConstructor( - messageKindClass, - String::class.java, - sourceFilePositionClass, - sourceFilePositionArrayClass) - } - } - - private val sourceFilePositionConstructor: Constructor<*> by lazy { - assert(isNewAndroidPlugin) { "This property should be used only for New Android Plugin" } - val sourcePositionClass = Class.forName("$packagePrefix.SourcePosition") - val sourceFilePositionClass = Class.forName("$packagePrefix.SourceFilePosition") - sourceFilePositionClass.getConstructor(File::class.java, sourcePositionClass) - } - - private val sourcePositionConstructor: Constructor<*> by lazy { - assert(isNewAndroidPlugin) { "This property should be used only for New Android Plugin" } - val sourcePositionClass = Class.forName("$packagePrefix.SourcePosition") - sourcePositionClass.getConstructor(Int::class.java, Int::class.java, Int::class.java) - } - - private val sourcePositionVarargArg: Any by lazy { - assert(isNewAndroidPlugin) { "This property should be used only for New Android Plugin" } - val sourceFilePositionClass = Class.forName("$packagePrefix.SourceFilePosition") - RArray.newInstance(sourceFilePositionClass, 0) - } - - private fun loadSeverityEnums() { - val messageKindClass = if (isNewAndroidPlugin) - Class.forName("$packagePrefix.Message\$Kind") - else - Class.forName("$packagePrefix.GradleMessage\$Kind") - - val messageKindConstants = messageKindClass.enumConstants as Array - for (kind in messageKindConstants) { - when(kind.toString()) { - "ERROR" -> severityObjectMap.put("e", kind) - "WARNING" -> severityObjectMap.put("w", kind) - "INFO" -> severityObjectMap.put("i", kind) - "SIMPLE" -> severityObjectMap.put("v", kind) - } - } - } - - fun createMessage( - logger: ILogger, - severity: String, - text: String, - file: String? = null, - lineNumber: Int? = null, - columnIndex: Int? = null, - offset: Int? = null - ): Any? { - try { - val severityConst: Any = severityObjectMap[severity] ?: return null - - return if (isNewAndroidPlugin) { - createNewMessage(severityConst, text.trim(), file, lineNumber, columnIndex, offset) - } - else { - createOldMessage(severityConst, text.trim(), file, lineNumber, columnIndex) - } - } - catch(e: Throwable) { - logger.error(e, "Exception from KotlinOutputParser") - } - - return null - } - - private fun createNewMessage( - severityConst: Any, - text: String, - file: String?, - lineNumber: Int?, - columnIndex: Int?, - offset: Int? - ): Any? { - if (file == null || lineNumber == null || columnIndex == null || offset == null) { - return simpleMessageConstructor.newInstance( - severityConst, - text, - text, - ImmutableList.of()) - } - else { - val sourcePositionObj = sourcePositionConstructor.newInstance(lineNumber - 1, columnIndex - 1, offset) - val sourceFilePositionObj = sourceFilePositionConstructor.newInstance(File(file), sourcePositionObj) - - return complexMessageConstructor.newInstance( - severityConst, - text, - sourceFilePositionObj, - sourcePositionVarargArg) - } - } - - private fun createOldMessage( - severityConst: Any, - text: String, - file: String?, - lineNumber: Int?, - columnIndex: Int? - ): Any? { - return if (file == null || lineNumber == null || columnIndex == null) { - simpleMessageConstructor.newInstance(severityConst, text) - } - else { - complexMessageConstructor.newInstance( - severityConst, - text, file, - lineNumber, columnIndex) - } - } +private fun createMessage(messageKind: Message.Kind, text: String): Message { + return Message(messageKind, text.trim(), text, Optional.absent(), ImmutableList.of()) +} + +private fun createMessageWithLocation( + messageKind: Message.Kind, + text: String, + file: String, + lineNumber: Int, + columnIndex: Int, + offset: Int +): Message { + val sourcePosition = SourcePosition(lineNumber - 1, columnIndex - 1, offset) + val sourceFilePosition = SourceFilePosition(File(file), sourcePosition) + return Message(messageKind, text.trim(), sourceFilePosition) }