diff --git a/compiler/src/dotty/tools/dotc/Run.scala b/compiler/src/dotty/tools/dotc/Run.scala index bcab1c50db65..85e253cadcd8 100644 --- a/compiler/src/dotty/tools/dotc/Run.scala +++ b/compiler/src/dotty/tools/dotc/Run.scala @@ -19,9 +19,10 @@ import transform.TreeChecker import rewrite.Rewrites import java.io.{BufferedWriter, OutputStreamWriter} -import dotty.tools.dotc.profile.Profiler +import profile.Profiler import printing.XprintMode import parsing.Parsers.Parser +import parsing.JavaParsers.JavaParser import typer.ImplicitRunInfo import collection.mutable @@ -209,7 +210,9 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint lateFiles += file val unit = new CompilationUnit(getSource(file.path)) def process()(implicit ctx: Context) = { - unit.untpdTree = new Parser(unit.source).parse() + unit.untpdTree = + if (unit.isJava) new JavaParser(unit.source).parse() + else new Parser(unit.source).parse() ctx.typer.lateEnter(unit.untpdTree) def typeCheckUnit() = unit.tpdTree = ctx.typer.typedExpr(unit.untpdTree) if (typeCheck) diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index fc3acef8c826..87d810e9cb5e 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -16,6 +16,7 @@ import Decorators._ import scala.util.control.NonFatal import ast.Trees._ import ast.tpd +import parsing.JavaParsers.OutlineJavaParser import parsing.Parsers.OutlineParser import reporting.trace @@ -154,7 +155,10 @@ object SymbolLoaders { case _ => } - traverse(new OutlineParser(unit.source).parse(), Nil) + traverse( + if (unit.isJava) new OutlineJavaParser(unit.source).parse() + else new OutlineParser(unit.source).parse(), + Nil) } val unit = new CompilationUnit(ctx.run.getSource(src.path)) diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala index 5c203d123f4a..f22afb941c73 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -907,4 +907,18 @@ object JavaParsers { unit } } + + + /** OutlineJavaParser parses top-level declarations in `source` to find declared classes, ignoring their bodies (which + * must only have balanced braces). This is used to map class names to defining sources. + * This is necessary even for Java, because the filename defining a non-public classes cannot be determined from the + * classname alone. + */ + class OutlineJavaParser(source: SourceFile)(implicit ctx: Context) extends JavaParser(source) with OutlineParserCommon { + override def skipBracesHook() = None + override def typeBody(leadingToken: Int, parentName: Name, parentTParams: List[TypeDef]): (List[Tree], List[Tree]) = { + skipBraces() + (List(EmptyValDef), List(EmptyTree)) + } + } } diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index ee83866d48c9..991255e913fa 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -130,6 +130,23 @@ object Parsers { ctx.error(msg, source atPos pos) } + trait OutlineParserCommon extends ParserCommon { + def accept(token: Int): Int + + def skipBracesHook(): Option[Tree] + def skipBraces(): Unit = { + accept(LBRACE) + var openBraces = 1 + while (in.token != EOF && openBraces > 0) { + skipBracesHook() getOrElse { + if (in.token == LBRACE) openBraces += 1 + else if (in.token == RBRACE) openBraces -= 1 + in.nextToken() + } + } + } + } + class Parser(source: SourceFile)(implicit ctx: Context) extends ParserCommon(source) { val in: Scanner = new Scanner(source) @@ -2638,24 +2655,22 @@ object Parsers { } - class OutlineParser(source: SourceFile)(implicit ctx: Context) extends Parser(source) { + /** OutlineParser parses top-level declarations in `source` to find declared classes, ignoring their bodies (which + * must only have balanced braces). This is used to map class names to defining sources. + */ + class OutlineParser(source: SourceFile)(implicit ctx: Context) extends Parser(source) with OutlineParserCommon { - def skipBraces[T](body: T): T = { - accept(LBRACE) - var openBraces = 1 - while (in.token != EOF && openBraces > 0) { - if (in.token == XMLSTART) xmlLiteral() - else { - if (in.token == LBRACE) openBraces += 1 - else if (in.token == RBRACE) openBraces -= 1 - in.nextToken() - } - } - body - } + def skipBracesHook(): Option[Tree] = + if (in.token == XMLSTART) Some(xmlLiteral()) else None - override def blockExpr(): Tree = skipBraces(EmptyTree) + override def blockExpr(): Tree = { + skipBraces() + EmptyTree + } - override def templateBody() = skipBraces((EmptyValDef, List(EmptyTree))) + override def templateBody() = { + skipBraces() + (EmptyValDef, List(EmptyTree)) + } } } diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 7aa2dc4d36eb..694386cef3b3 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -57,6 +57,7 @@ object Scanners { abstract class ScannerCommon(source: SourceFile)(implicit ctx: Context) extends CharArrayReader with TokenData { val buf = source.content + def nextToken(): Unit // Errors ----------------------------------------------------------------- diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 90521d3acca4..7dc338710a6c 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -47,6 +47,7 @@ class CompilationTests extends ParallelTesting { compileFile("tests/pos-special/completeFromSource/Test.scala", defaultOptions.and("-sourcepath", "tests/pos-special")) + compileFile("tests/pos-special/completeFromSource/Test2.scala", defaultOptions.and("-sourcepath", "tests/pos-special")) + compileFile("tests/pos-special/completeFromSource/Test3.scala", defaultOptions.and("-sourcepath", "tests/pos-special", "-scansource")) + + compileFile("tests/pos-special/completeFromSource/nested/Test4.scala", defaultOptions.and("-sourcepath", "tests/pos-special", "-scansource")) + compileFilesInDir("tests/pos-special/fatal-warnings", defaultOptions.and("-Xfatal-warnings")) + compileList( "compileMixed", @@ -158,7 +159,8 @@ class CompilationTests extends ParallelTesting { compileFile("tests/neg-custom-args/i4372.scala", allowDeepSubtypes) + compileFile("tests/neg-custom-args/i1754.scala", allowDeepSubtypes) + compileFilesInDir("tests/neg-custom-args/isInstanceOf", allowDeepSubtypes and "-Xfatal-warnings") + - compileFile("tests/neg-custom-args/i3627.scala", allowDeepSubtypes) + compileFile("tests/neg-custom-args/i3627.scala", allowDeepSubtypes) + + compileFile("tests/neg-custom-args/completeFromSource/nested/Test1.scala", defaultOptions.and("-sourcepath", "tests/neg-custom-args", "-scansource")) }.checkExpectedErrors() // Run tests ----------------------------------------------------------------- diff --git a/tests/neg-custom-args/completeFromSource/nested/D.java b/tests/neg-custom-args/completeFromSource/nested/D.java new file mode 100644 index 000000000000..e437b32ed0b2 --- /dev/null +++ b/tests/neg-custom-args/completeFromSource/nested/D.java @@ -0,0 +1,18 @@ +package completeFromSource.nested; + +public class D { + public D(int i) { + + } + public String thisIsD(int i) { + return java.lang.Integer.toString(i); + } +} + +class E { + public E(String s) {} + + public String thisIsE(int i) { + return java.lang.Integer.toString(i); + } +} diff --git a/tests/neg-custom-args/completeFromSource/nested/Test1.scala b/tests/neg-custom-args/completeFromSource/nested/Test1.scala new file mode 100644 index 000000000000..baac82e3234c --- /dev/null +++ b/tests/neg-custom-args/completeFromSource/nested/Test1.scala @@ -0,0 +1,10 @@ +package completeFromSource.nested + +class Test4 { + + val d = new D(1) + val e = new E("xx") + + d.thisIsD(1) + e.thisIsE() // error +} diff --git a/tests/pos-special/completeFromSource/nested/D.java b/tests/pos-special/completeFromSource/nested/D.java new file mode 100644 index 000000000000..e437b32ed0b2 --- /dev/null +++ b/tests/pos-special/completeFromSource/nested/D.java @@ -0,0 +1,18 @@ +package completeFromSource.nested; + +public class D { + public D(int i) { + + } + public String thisIsD(int i) { + return java.lang.Integer.toString(i); + } +} + +class E { + public E(String s) {} + + public String thisIsE(int i) { + return java.lang.Integer.toString(i); + } +} diff --git a/tests/pos-special/completeFromSource/nested/Test4.scala b/tests/pos-special/completeFromSource/nested/Test4.scala new file mode 100644 index 000000000000..daa06d12c426 --- /dev/null +++ b/tests/pos-special/completeFromSource/nested/Test4.scala @@ -0,0 +1,10 @@ +package completeFromSource.nested + +class Test4 { + + val d = new D(1) + val e = new E("xx") + + d.thisIsD(1) + e.thisIsE(2) +}