@@ -3,9 +3,12 @@ package test
33import dotty .partest .DPConfig
44import dotty .tools .dotc .{Main , Bench , Driver }
55import dotty .tools .dotc .reporting .Reporter
6+ import dotty .tools .dotc .util .SourcePosition
7+ import dotty .tools .dotc .config .CompilerCommand
68import scala .collection .mutable .ListBuffer
7- import scala .reflect .io .{ Path , Directory , File => SFile }
9+ import scala .reflect .io .{ Path , Directory , File => SFile , AbstractFile }
810import scala .tools .partest .nest .{ FileManager , NestUI }
11+ import scala .annotation .tailrec
912import java .io .{ RandomAccessFile , File => JFile }
1013
1114import org .junit .Test
@@ -178,13 +181,81 @@ abstract class CompilerTest extends DottyTest {
178181
179182 // ========== HELPERS =============
180183
181- private def compileArgs (args : Array [String ], xerrors : Int = 0 )(implicit defaultOptions : List [String ]): Unit = {
184+ private def compileArgs (args : Array [String ], xerrors : Int = 0 )
185+ (implicit defaultOptions : List [String ]): Unit = {
182186 val allArgs = args ++ defaultOptions
183187 val processor = if (allArgs.exists(_.startsWith(" #" ))) Bench else Main
184- val nerrors = processor.process(allArgs, ctx).errorCount
188+ val reporter = processor.process(allArgs, ctx)
189+
190+ val nerrors = reporter.errorCount
185191 assert(nerrors == xerrors, s " Wrong # of errors. Expected: $xerrors, found: $nerrors" )
192+
193+ // is neg test, check errors occur on right line
194+ if (xerrors > 0 ) {
195+ val errorLines = reporter.allErrors.map(_.pos)
196+ // reporter didn't record as many errors as its errorCount says
197+ assert(errorLines.length == nerrors, s " Not enough errors recorded. " )
198+ val (byFile, noPos) = errorLines.groupBy(_.source.file).partition(_._1.toString != " <no source>" )
199+
200+ // check the compiler errors that have a source position
201+ val noPosErrFiles = byFile.foldLeft(0 )(_ + checkErrorsInFile(_))
202+
203+ // check that files without compiler errors don't contain error markers
204+ val allFiles = CompilerCommand .distill(allArgs)(ctx).arguments
205+ val checkedFiles = byFile.keys.toList.map(_.toString)
206+ val noPosExpected = noPosErrFiles + checkNoErrorMissing(allFiles.filter(! checkedFiles.contains(_)))
207+
208+ // check compiler errors without source position, their number should
209+ // correspond to all "// nopos-error" markers in any files
210+ val noPosFound = noPos.foldLeft(0 )(_ + _._2.length)
211+ assert(noPosFound == noPosExpected,
212+ s " Wrong # of errors without source position. Expected (all files): $noPosExpected, found (compiler): $noPosFound" )
213+ }
186214 }
187215
216+ /** For neg tests, check that all errors thrown by compiler have a "// error"
217+ * on the corresponding line in the source file.
218+ */
219+ def checkErrorsInFile (errors : (AbstractFile , List [SourcePosition ])): Int = {
220+ errors match {
221+ case (fileName, pos@ (first :: rest)) =>
222+ val content = first.source.content.mkString
223+ val (line, rest) = content.span(_ != '\n ' )
224+ val byLine = scala.collection.mutable.Map (errors._2.groupBy(_.line).toSeq: _* )
225+
226+ @ tailrec
227+ def checkLine (line : String , rest : String , index : Int ): Unit = {
228+ val expected = countErrors(line)
229+ byLine.remove(index) match {
230+ case Some (pos) => checkErrors(fileName.toString, Some (index), expected, pos.length)
231+ case None => checkErrors(fileName.toString, Some (index), expected, 0 )
232+ }
233+ val (newLine, newRest) = rest.span(_ != '\n ' )
234+ if (! newRest.isEmpty)
235+ checkLine(newLine, newRest.drop(1 ), index + 1 )
236+ }
237+
238+ checkLine(line, rest.drop(1 ), 0 )
239+ assert(byLine.isEmpty, " Some compiler errors don't correspond to any line in the source file: " + fileName + " : " + byLine)
240+ countNoPosErrors(content)
241+ case (fileName, Nil ) => assert(false , " impossible: empty groupBy value in file: " + fileName); 0
242+ }
243+ }
244+
245+ def countErrors (s : String ) = " // ?error" .r.findAllIn(s).length
246+ def countNoPosErrors (s : String ) = " // ?nopos-error" .r.findAllIn(s).length
247+
248+ def checkErrors (fileName : String , index : Option [Int ], exp : Int , found : Int ) = {
249+ val i = index.map({ i => " :" + (i + 1 ) }).getOrElse(" " )
250+ assert(found == exp, s " Wrong # of errors for $fileName$i. Expected (file): $exp, found (compiler): $found" )
251+ }
252+
253+ def checkNoErrorMissing (files : List [String ]) = files.foldLeft(0 )({ case (sum, fileName) =>
254+ val content = SFile (fileName).slurp
255+ checkErrors(fileName, None , countErrors(content), 0 )
256+ sum + countNoPosErrors(content)
257+ })
258+
188259 // In particular, don't copy flags from scalac tests
189260 private val extensionsToCopy = scala.collection.immutable.HashSet (" scala" , " java" )
190261
0 commit comments