From 4c86117b797174eb39cf5c249cec32f68053b290 Mon Sep 17 00:00:00 2001 From: fkorotkov Date: Wed, 15 Jul 2015 14:49:12 -0400 Subject: [PATCH] Line content from diagnostic classes if available --- build.sbt | 2 +- .../compiler/javac/DiagnosticsReporter.scala | 41 ++++++++++++++----- .../sbt/compiler/javac/JavaCompilerSpec.scala | 27 ++++++++---- 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/build.sbt b/build.sbt index 1569ec94e..6d4dde762 100644 --- a/build.sbt +++ b/build.sbt @@ -573,7 +573,7 @@ lazy val safeUnitTests = taskKey[Unit]("Known working tests (for both 2.10 and 2 lazy val safeProjects: ScopeFilter = ScopeFilter( inProjects(mainSettingsProj, mainProj, ivyProj, completeProj, actionsProj, classpathProj, collectionProj, compileIncrementalProj, - logProj, runProj, stdTaskProj), + logProj, runProj, stdTaskProj, compilerProj), inConfigurations(Test) ) lazy val otherUnitTests = taskKey[Unit]("Unit test other projects") diff --git a/compile/src/main/scala/sbt/compiler/javac/DiagnosticsReporter.scala b/compile/src/main/scala/sbt/compiler/javac/DiagnosticsReporter.scala index 20ecb48b7..d7abef74c 100644 --- a/compile/src/main/scala/sbt/compiler/javac/DiagnosticsReporter.scala +++ b/compile/src/main/scala/sbt/compiler/javac/DiagnosticsReporter.scala @@ -69,18 +69,37 @@ final class DiagnosticsReporter(reporter: Reporter) extends DiagnosticListener[J def startPosition: Option[Long] = checkNoPos(d.getStartPosition) def endPosition: Option[Long] = checkNoPos(d.getEndPosition) override val offset: Maybe[Integer] = Logger.o2m(checkNoPos(d.getPosition) map { x => new Integer(x.toInt) }) - // TODO - Is this pulling contents of the line correctly? - // Would be ok to just return null if this version of the JDK doesn't support grabbing - // source lines? - override def lineContent: String = - Option(d.getSource) match { - case Some(source: JavaFileObject) => - (Option(source.getCharContent(true)), startPosition, endPosition) match { - case (Some(cc), Some(start), Some(end)) => cc.subSequence(start.toInt, end.toInt).toString - case _ => "" + override def lineContent: String = { + def getDiagnosticLine: Option[String] = + try { + // See com.sun.tools.javac.api.ClientCodeWrapper.DiagnosticSourceUnwrapper + val diagnostic = d.getClass.getField("d").get(d) + // See com.sun.tools.javac.util.JCDiagnostic#getDiagnosticSource + val getDiagnosticSourceMethod = diagnostic.getClass.getDeclaredMethod("getDiagnosticSource") + Option(getDiagnosticSourceMethod.invoke(diagnostic)) match { + case Some(diagnosticSource) => + // See com.sun.tools.javac.util.DiagnosticSource + val getLineMethod = diagnosticSource.getClass.getMethod("getLine", Integer.TYPE) + Option(getLineMethod.invoke(diagnosticSource, line.get())).map(_.toString) + case _ => None } - case _ => "" - } + } catch { + case ignored: NoSuchMethodException => None + case ignored: NoSuchFieldException => None + } + + def getExpression: String = + Option(d.getSource) match { + case Some(source: JavaFileObject) => + (Option(source.getCharContent(true)), startPosition, endPosition) match { + case (Some(cc), Some(start), Some(end)) => cc.subSequence(start.toInt, end.toInt).toString + case _ => "" + } + case _ => "" + } + + getDiagnosticLine.getOrElse(getExpression) + } private val sourceUri = fixSource(d.getSource) override val sourcePath = Logger.o2m(sourceUri) override val sourceFile = Logger.o2m(sourceUri.map(new File(_))) diff --git a/compile/src/test/scala/sbt/compiler/javac/JavaCompilerSpec.scala b/compile/src/test/scala/sbt/compiler/javac/JavaCompilerSpec.scala index 4eef68b22..a2bd1141c 100644 --- a/compile/src/test/scala/sbt/compiler/javac/JavaCompilerSpec.scala +++ b/compile/src/test/scala/sbt/compiler/javac/JavaCompilerSpec.scala @@ -60,7 +60,8 @@ object JavaCompilerSpec extends Specification { val (result, problems) = compile(compiler, Seq(knownSampleErrorFile), Seq("-deprecation")) val errored = result must beFalse val foundErrorAndWarning = problems must haveSize(5) - val hasKnownErrors = problems.toSeq must contain(errorOnLine(1), warnOnLine(7)) + val importWarn = warnOnLine(lineno = 1, lineContent = Some("import java.rmi.RMISecurityException;")) + val hasKnownErrors = problems.toSeq must contain(importWarn, errorOnLine(3), warnOnLine(7)) errored and foundErrorAndWarning and hasKnownErrors } @@ -107,20 +108,28 @@ object JavaCompilerSpec extends Specification { leftCompiled and rightCompiled and apisExpectedMatch } - def lineMatches(p: Problem, lineno: Int): Boolean = - p.position.line.isDefined && (p.position.line.get == lineno) + def lineMatches(p: Problem, lineno: Int, lineContent: Option[String] = None): Boolean = { + def lineContentCheck = + lineContent match { + case Some(content) => content.equalsIgnoreCase(p.position.lineContent()) + case _ => true + } + def lineNumberCheck = p.position.line.isDefined && (p.position.line.get == lineno) + lineNumberCheck && lineContentCheck + } + def isError(p: Problem): Boolean = p.severity == Severity.Error def isWarn(p: Problem): Boolean = p.severity == Severity.Warn - def errorOnLine(lineno: Int) = + def errorOnLine(lineno: Int, lineContent: Option[String] = None) = beLike[Problem]({ - case p if lineMatches(p, lineno) && isError(p) => ok - case _ => ko + case p if lineMatches(p, lineno, lineContent) && isError(p) => ok + case _ => ko }) - def warnOnLine(lineno: Int) = + def warnOnLine(lineno: Int, lineContent: Option[String] = None) = beLike[Problem]({ - case p if lineMatches(p, lineno) && isWarn(p) => ok - case _ => ko + case p if lineMatches(p, lineno, lineContent) && isWarn(p) => ok + case _ => ko }) def forkSameAsLocal = {