diff --git a/internal/zinc-compile-core/src/main/scala/sbt/internal/inc/javac/JavaErrorParser.scala b/internal/zinc-compile-core/src/main/scala/sbt/internal/inc/javac/JavaErrorParser.scala index 91db8658fa..8eb0382f45 100644 --- a/internal/zinc-compile-core/src/main/scala/sbt/internal/inc/javac/JavaErrorParser.scala +++ b/internal/zinc-compile-core/src/main/scala/sbt/internal/inc/javac/JavaErrorParser.scala @@ -83,6 +83,33 @@ class JavaErrorParser(relativeDir: File = new File(new File(".").getAbsolutePath }) ^^ { case xs => xs.mkString("\n") } + val nonPathLine: Parser[String] = { + val nonPathLine0 = new Parser[String] { + def isStopChar(c: Char): Boolean = c == '\n' || c == '\r' + + def apply(in: Input) = { + val source = in.source + val offset = in.offset + var i = offset + while (i < source.length && !isStopChar(source.charAt(i))) { + i += 1 + } + val line = source.subSequence(offset, i).toString + if ((line.startsWith("/") || line.contains("\\")) && line.contains(".java")) + Failure("Path found", in) + else if (i == offset) Failure("Empty", in) + else Success(line, in.drop(i - offset)) + } + } + nonPathLine0 ~ """[\r]?[\n]?""".r ^^ { + case msg ~ endline => msg + endline + } + } + val nonPathLines: Parser[String] = { + rep(nonPathLine) ^^ { + case lines => lines.mkString("") + } + } // Parses ALL characters until an expected character is met. def allUntilChar(c: Char): Parser[String] = allUntilChars(Array(c)) @@ -148,15 +175,21 @@ class JavaErrorParser(relativeDir: File = new File(new File(".").getAbsolutePath val fileLineMessage = fileAndLineNo ~ SEMICOLON ~ restOfLine ^^ { case (file, line) ~ _ ~ msg => (file, line, msg) } - fileLineMessage ~ allUntilCaret ~ restOfLine ~ (allIndented.?) ^^ { - case (file, line, msg) ~ contents ~ r ~ ind => + fileLineMessage ~ (allUntilCaret ~ '^' ~ restOfLine).? ~ (nonPathLines.?) ^^ { + case (file, line, msg) ~ contentsOpt ~ ind => new JavaProblem( new JavaPosition( findFileSource(file), line, - contents + '^' + r + ind + (contentsOpt match { + case Some(contents ~ _ ~ r) => contents + '^' + r + case _ => "" + }) + ind .getOrElse(""), // TODO - Actually parse caret position out of here. - getOffset(contents) + (contentsOpt match { + case Some(contents ~ _ ~ _) => getOffset(contents) + case _ => 0 + }) ), Severity.Error, msg @@ -169,14 +202,20 @@ class JavaErrorParser(relativeDir: File = new File(new File(".").getAbsolutePath val fileLineMessage = fileAndLineNo ~ SEMICOLON ~ WARNING ~ SEMICOLON ~ restOfLine ^^ { case (file, line) ~ _ ~ _ ~ _ ~ msg => (file, line, msg) } - fileLineMessage ~ allUntilCaret ~ restOfLine ~ (allIndented.?) ^^ { - case (file, line, msg) ~ contents ~ r ~ ind => + fileLineMessage ~ (allUntilCaret ~ '^' ~ restOfLine).? ~ (nonPathLines.?) ^^ { + case (file, line, msg) ~ contentsOpt ~ ind => new JavaProblem( new JavaPosition( findFileSource(file), line, - contents + "^" + r + ind.getOrElse(""), - getOffset(contents) + (contentsOpt match { + case Some(contents ~ _ ~ r) => contents + '^' + r + case _ => "" + }) + ind.getOrElse(""), + (contentsOpt match { + case Some(contents ~ _ ~ _) => getOffset(contents) + case _ => 0 + }) ), Severity.Warn, msg @@ -201,9 +240,15 @@ class JavaErrorParser(relativeDir: File = new File(new File(".").getAbsolutePath ) } + val outputSumamry: Parser[Unit] = + """(\s*)(\d+) (\w+)""".r ~ restOfLine ^^ { + case a ~ b => + () + } + val potentialProblem: Parser[Problem] = warningMessage | errorMessage | noteMessage | javacError - val javacOutput: Parser[Seq[Problem]] = rep(potentialProblem) + val javacOutput: Parser[Seq[Problem]] = rep(potentialProblem) <~ opt(outputSumamry) /** * Example: diff --git a/internal/zinc-compile-core/src/test/resources/sbt/internal/inc/javac/test2.java b/internal/zinc-compile-core/src/test/resources/sbt/internal/inc/javac/test2.java new file mode 100644 index 0000000000..e69de29bb2 diff --git a/internal/zinc-compile-core/src/test/scala/sbt/internal/inc/javac/javaErrorParserSpec.scala b/internal/zinc-compile-core/src/test/scala/sbt/internal/inc/javac/javaErrorParserSpec.scala index b786c7d193..d2672fc475 100644 --- a/internal/zinc-compile-core/src/test/scala/sbt/internal/inc/javac/javaErrorParserSpec.scala +++ b/internal/zinc-compile-core/src/test/scala/sbt/internal/inc/javac/javaErrorParserSpec.scala @@ -3,33 +3,35 @@ package internal package inc package javac +import org.scalatest.DiagrammedAssertions import sbt.util.Logger +import sbt.internal.util.ConsoleLogger -class JavaErrorParserSpec extends UnitSpec { +class JavaErrorParserSpec extends UnitSpec with DiagrammedAssertions { - "The JavaErrorParser" should "be able to parse linux errors" in parseSampleLinux() + "The JavaErrorParser" should "be able to parse Linux errors" in parseSampleLinux() it should "be able to parse windows file names" in parseWindowsFile() it should "be able to parse windows errors" in parseSampleWindows() it should "be able to parse javac errors" in parseSampleJavac() it should "register the position of errors" in parseErrorPosition() it should "be able to parse multiple errors" in parseMultipleErrors() + it should "be able to parse multiple errors without carrets or indentation" in parseMultipleErrors2() def parseSampleLinux() = { val parser = new JavaErrorParser() - val logger = Logger.Null + val logger = ConsoleLogger() val problems = parser.parseProblems(sampleLinuxMessage, logger) - problems should have size (1) - problems(0).position.sourcePath.get shouldBe ("/home/me/projects/sample/src/main/Test.java") - + assert(problems.size == 1) + assert(problems(0).position.sourcePath.get == ("/home/me/projects/sample/src/main/Test.java")) } def parseSampleWindows() = { val parser = new JavaErrorParser() - val logger = Logger.Null + val logger = ConsoleLogger() val problems = parser.parseProblems(sampleWindowsMessage, logger) - problems should have size (1) + assert(problems.size == 1) problems(0).position.sourcePath.get shouldBe (windowsFile) } @@ -47,35 +49,62 @@ class JavaErrorParserSpec extends UnitSpec { def parseSampleJavac() = { val parser = new JavaErrorParser() - val logger = Logger.Null + val logger = ConsoleLogger() val problems = parser.parseProblems(sampleJavacMessage, logger) - problems should have size (1) + assert(problems.size == 1) problems(0).message shouldBe (sampleJavacMessage) } def parseErrorPosition() = { val parser = new JavaErrorParser() - val logger = Logger.Null + val logger = ConsoleLogger() val problems = parser.parseProblems(sampleErrorPosition, logger) - problems should have size (1) + assert(problems.size == 1) problems(0).position.offset.isPresent shouldBe true problems(0).position.offset.get shouldBe 23 } def parseMultipleErrors() = { val parser = new JavaErrorParser() - val logger = Logger.Null + val logger = ConsoleLogger() val problems = parser.parseProblems(sampleMultipleErrors, logger) - problems should have size (5) + assert(problems.size == 5) + } + + def parseMultipleErrors2() = { + val parser = new JavaErrorParser() + val logger = ConsoleLogger() + val problems = parser.parseProblems(sampleLinuxMessage2, logger) + + assert(problems.size == 3) + assert(problems(0).position.sourcePath.get == ("/home/me/projects/sample/src/main/Test.java")) } def sampleLinuxMessage = """ - |/home/me/projects/sample/src/main/Test.java:4: cannot find symbol - |symbol : method baz() - |location: class Foo - |return baz(); - """.stripMargin + |/home/me/projects/sample/src/main/Test.java:18: error: cannot find symbol + | baz(); + | ^ + | symbol: method baz() + | location: class AbstractActorRef + |1 error. + |""".stripMargin + + def sampleLinuxMessage2 = + """ + |/home/me/projects/sample/src/main/Test.java:100:1: cannot find symbol + |symbol: method isBar() + |location: variable x of type com.example.List + |if (x.isBar()) { + |/home/me/projects/sample/src/main/Test.java:200:1: cannot find symbol + |symbol: method isBar() + |location: variable x of type com.example.List + |} else if (x.isBar()) { + |/home/me/projects/sample/src/main/Test.java:300:1: cannot find symbol + |symbol: method isBar() + |location: variable x of type com.example.List + |foo.baz(runtime, x.isBar()); + |""".stripMargin def sampleWindowsMessage = s""" @@ -117,5 +146,6 @@ class JavaErrorParserSpec extends UnitSpec { |/home/foo/sbt/internal/inc/javac/test1.java:7: warning: [deprecation] RMISecurityException(String) in RMISecurityException has been deprecated | throw new RMISecurityException("O NOES"); | ^ + |5 errors. |""".stripMargin }