Skip to content

Commit f462f7f

Browse files
Fix directive error handling
1 parent e43844d commit f462f7f

File tree

5 files changed

+128
-124
lines changed

5 files changed

+128
-124
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package scala.build.errors
2+
3+
import scala.build.Position
4+
5+
final class MalformedDirectiveError(message: String, positions: Seq[Position])
6+
extends BuildException(message, positions)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package scala.build.preprocessing
2+
3+
import com.virtuslab.using_directives.custom.utils.{Position => DirectivePosition}
4+
import com.virtuslab.using_directives.reporter.Reporter
5+
6+
import scala.build.Position
7+
import scala.build.errors.{Diagnostic, Severity}
8+
9+
class CustomDirectivesReporter(path: Either[String, os.Path], onDiagnostic: Diagnostic => Unit)
10+
extends Reporter {
11+
12+
private var errorCount = 0
13+
14+
private def toScalaCliPosition(position: DirectivePosition): Position = {
15+
val coords = (position.getLine, position.getColumn)
16+
Position.File(path, coords, coords)
17+
}
18+
19+
override def error(msg: String): Unit =
20+
onDiagnostic {
21+
errorCount += 1
22+
Diagnostic(msg, Severity.Error)
23+
}
24+
override def error(position: DirectivePosition, msg: String): Unit =
25+
onDiagnostic {
26+
errorCount += 1
27+
Diagnostic(msg, Severity.Error, Seq(toScalaCliPosition(position)))
28+
}
29+
override def warning(msg: String): Unit =
30+
onDiagnostic {
31+
Diagnostic(msg, Severity.Warning)
32+
}
33+
override def warning(position: DirectivePosition, msg: String): Unit =
34+
onDiagnostic {
35+
Diagnostic(msg, Severity.Warning, Seq(toScalaCliPosition(position)))
36+
}
37+
38+
override def hasErrors(): Boolean =
39+
errorCount != 0
40+
41+
override def reset(): Unit = {
42+
errorCount = 0
43+
}
44+
}
45+
46+
object CustomDirectivesReporter {
47+
def create(path: Either[String, os.Path])(onDiagnostic: Diagnostic => Unit)
48+
: CustomDirectivesReporter =
49+
new CustomDirectivesReporter(path, onDiagnostic)
50+
}

modules/build/src/main/scala/scala/build/preprocessing/DirectivesOutputStreamReporter.scala

Lines changed: 0 additions & 37 deletions
This file was deleted.

modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala

Lines changed: 71 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,12 @@ import java.nio.charset.StandardCharsets
1515

1616
import scala.build.EitherCps.{either, value}
1717
import scala.build.Ops._
18-
import scala.build.errors.{
19-
BuildException,
20-
CompositeBuildException,
21-
DependencyFormatError,
22-
UnusedDirectiveError
23-
}
18+
import scala.build.errors._
2419
import scala.build.internal.{AmmUtil, Util}
2520
import scala.build.options.{BuildOptions, BuildRequirements, ClassPathOptions, ShadowingSeq}
2621
import scala.build.preprocessing.directives._
2722
import scala.build.{Inputs, Logger, Position, Positioned}
23+
import scala.collection.mutable
2824
import scala.jdk.CollectionConverters._
2925

3026
case object ScalaPreprocessor extends Preprocessor {
@@ -362,76 +358,88 @@ case object ScalaPreprocessor extends Preprocessor {
362358
path: Either[String, os.Path],
363359
logger: Logger
364360
): Either[BuildException, ExtractedDirectives] = {
361+
val errors = new mutable.ListBuffer[Diagnostic]
362+
val reporter = CustomDirectivesReporter.create(path) { diag =>
363+
if (diag.severity == Severity.Warning)
364+
logger.log(Seq(diag))
365+
else
366+
errors += diag
367+
}
365368
val processor = {
366-
val reporter = new DirectivesOutputStreamReporter(System.err) // TODO Get that via a logger
367369
val settings = new Settings
368370
settings.setAllowStartWithoutAt(true)
369371
settings.setAllowRequire(false)
370372
val context = new Context(reporter, settings)
371373
new UsingDirectivesProcessor(context)
372374
}
373375
val all = processor.extract(contentChars, true, true).asScala
376+
if (errors.isEmpty) {
374377

375-
def byKind(kind: UsingDirectiveKind) = all.find(_.getKind == kind).get
378+
def byKind(kind: UsingDirectiveKind) = all.find(_.getKind == kind).get
376379

377-
def getDirectives(directives: UsingDirectives) =
378-
directives.getAst() match {
379-
case ud: UsingDefs =>
380-
ud.getUsingDefs().asScala
381-
case _ =>
382-
Nil
383-
}
380+
def getDirectives(directives: UsingDirectives) =
381+
directives.getAst() match {
382+
case ud: UsingDefs =>
383+
ud.getUsingDefs().asScala
384+
case _ =>
385+
Nil
386+
}
384387

385-
val codeDirectives = byKind(UsingDirectiveKind.Code)
386-
val specialCommentDirectives = byKind(UsingDirectiveKind.SpecialComment)
387-
val plainCommentDirectives = byKind(UsingDirectiveKind.PlainComment)
388-
389-
def reportWarning(msg: String, values: Seq[UsingDef], before: Boolean = true): Unit =
390-
values.foreach { v =>
391-
val astPos = v.getPosition()
392-
val (start, end) =
393-
if (before) (0, astPos.getColumn())
394-
else (astPos.getColumn(), astPos.getColumn() + v.getSyntax.getKeyword.size)
395-
val position = Position.File(path, (astPos.getLine(), start), (astPos.getLine(), end))
396-
logger.diagnostic(msg, positions = Seq(position))
397-
}
388+
val codeDirectives = byKind(UsingDirectiveKind.Code)
389+
val specialCommentDirectives = byKind(UsingDirectiveKind.SpecialComment)
390+
val plainCommentDirectives = byKind(UsingDirectiveKind.PlainComment)
391+
392+
def reportWarning(msg: String, values: Seq[UsingDef], before: Boolean = true): Unit =
393+
values.foreach { v =>
394+
val astPos = v.getPosition()
395+
val (start, end) =
396+
if (before) (0, astPos.getColumn())
397+
else (astPos.getColumn(), astPos.getColumn() + v.getSyntax.getKeyword.size)
398+
val position = Position.File(path, (astPos.getLine(), start), (astPos.getLine(), end))
399+
logger.diagnostic(msg, positions = Seq(position))
400+
}
398401

399-
val usedDirectives =
400-
if (!codeDirectives.getFlattenedMap().isEmpty()) {
401-
val msg =
402-
"This using directive is ignored. File contains directives outside comments and those have higher precedence."
403-
reportWarning(
404-
msg,
405-
getDirectives(plainCommentDirectives) ++ getDirectives(specialCommentDirectives)
406-
)
407-
codeDirectives
408-
}
409-
else if (!specialCommentDirectives.getFlattenedMap().isEmpty()) {
410-
val msg =
411-
s"This using directive is ignored. $changeToSpecialCommentMsg"
412-
reportWarning(msg, getDirectives(plainCommentDirectives))
413-
specialCommentDirectives
414-
}
415-
else {
416-
reportWarning(changeToSpecialCommentMsg, getDirectives(plainCommentDirectives))
417-
plainCommentDirectives
418-
}
402+
val usedDirectives =
403+
if (!codeDirectives.getFlattenedMap().isEmpty()) {
404+
val msg =
405+
"This using directive is ignored. File contains directives outside comments and those have higher precedence."
406+
reportWarning(
407+
msg,
408+
getDirectives(plainCommentDirectives) ++ getDirectives(specialCommentDirectives)
409+
)
410+
codeDirectives
411+
}
412+
else if (!specialCommentDirectives.getFlattenedMap().isEmpty()) {
413+
val msg =
414+
s"This using directive is ignored. $changeToSpecialCommentMsg"
415+
reportWarning(msg, getDirectives(plainCommentDirectives))
416+
specialCommentDirectives
417+
}
418+
else {
419+
reportWarning(changeToSpecialCommentMsg, getDirectives(plainCommentDirectives))
420+
plainCommentDirectives
421+
}
422+
423+
// All using directives should use just `using` keyword, no @using or require
424+
reportWarning(
425+
"Deprecated using directive syntax, please use keyword `using`.",
426+
getDirectives(usedDirectives).filter(_.getSyntax() != UsingDirectiveSyntax.Using),
427+
before = false
428+
)
429+
430+
val flattened = usedDirectives.getFlattenedMap.asScala.toSeq
431+
val strictDirectives =
432+
flattened.map { case (k, l) => StrictDirective(k.getPath.asScala.mkString("."), l.asScala) }
419433

420-
// All using directives should use just `using` keyword, no @using or require
421-
reportWarning(
422-
"Deprecated using directive syntax, please use keyword `using`.",
423-
getDirectives(usedDirectives).filter(_.getSyntax() != UsingDirectiveSyntax.Using),
424-
before = false
425-
)
426-
427-
val flattened = usedDirectives.getFlattenedMap.asScala.toSeq
428-
val strictDirectives =
429-
flattened.map { case (k, l) => StrictDirective(k.getPath.asScala.mkString("."), l.asScala) }
430-
431-
val offset =
432-
if (usedDirectives.getKind() != UsingDirectiveKind.Code) 0
433-
else usedDirectives.getCodeOffset()
434-
Right(ExtractedDirectives(offset, strictDirectives))
434+
val offset =
435+
if (usedDirectives.getKind() != UsingDirectiveKind.Code) 0
436+
else usedDirectives.getCodeOffset()
437+
Right(ExtractedDirectives(offset, strictDirectives))
438+
}
439+
else {
440+
val errors0 = errors.map(diag => new MalformedDirectiveError(diag.message, diag.positions))
441+
Left(CompositeBuildException(errors0))
442+
}
435443
}
436444

437445
private def parseDependency(str: String, pos: Position): Either[BuildException, AnyDependency] =

modules/build/src/test/scala/scala/build/tests/BuildTests.scala

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -334,14 +334,6 @@ class BuildTests extends munit.FunSuite {
334334
|pprint.log(g)
335335
|""".stripMargin,
336336
os.rel / "simple2.sc" ->
337-
"""//> using
338-
|// lib "com.lihaoyi::geny:0.6.5"
339-
|// lib "com.lihaoyi::pprint:0.6.6"
340-
|import geny.Generator
341-
|val g = Generator("Hel", "lo")
342-
|pprint.log(g)
343-
|""".stripMargin,
344-
os.rel / "simple3.sc" ->
345337
"""//> using lib "com.lihaoyi::geny:0.6.5", "com.lihaoyi::pprint:0.6.6"
346338
|import geny.Generator
347339
|val g = Generator("Hel", "lo")
@@ -357,11 +349,7 @@ class BuildTests extends munit.FunSuite {
357349
"simple2.class",
358350
"simple2_sc.class",
359351
"simple2$.class",
360-
"simple2_sc$.class",
361-
"simple3.class",
362-
"simple3_sc.class",
363-
"simple3$.class",
364-
"simple3_sc$.class"
352+
"simple2_sc$.class"
365353
)
366354
maybeBuild.orThrow.assertNoDiagnostics
367355
}
@@ -595,17 +583,6 @@ class BuildTests extends munit.FunSuite {
595583
|for {
596584
| (x, y) <- getCounts
597585
|} yield x + y
598-
|""".stripMargin,
599-
os.rel / "p2.sc" ->
600-
"""//> using
601-
|// scala "2.13"
602-
|// plugins "com.olegpy::better-monadic-for:0.3.1"
603-
|
604-
|def getCounts: Either[String, (Int, Int)] = ???
605-
|
606-
|for {
607-
| (x, y) <- getCounts
608-
|} yield x + y
609586
|""".stripMargin
610587
)
611588
val buildOptions = defaultOptions.copy(

0 commit comments

Comments
 (0)