From 40ae7eee109a3c8a3a125c1ec4a2167bba2acd9c Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 7 Dec 2021 18:35:00 +0100 Subject: [PATCH 1/2] Allow `import ` to show completions Previously, there would be no completions after simple `import annot`. Now, we make sure that the completions mode is set correctly for that case. Additionally, whenever both `java.lang` and `scala` imports conflict we choose scala one. --- .../tools/dotc/interactive/Completion.scala | 24 +++++++++++++++++++ .../tools/languageserver/CompletionTest.scala | 9 +++++++ 2 files changed, 33 insertions(+) diff --git a/compiler/src/dotty/tools/dotc/interactive/Completion.scala b/compiler/src/dotty/tools/dotc/interactive/Completion.scala index b57c300defae..8c0e5f7bd8f5 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Completion.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Completion.scala @@ -61,6 +61,8 @@ object Completion { */ def completionMode(path: List[Tree], pos: SourcePosition): Mode = path match { + case Ident(_) :: Import(_, _) :: _ => + Mode.Import case (ref: RefTree) :: _ => if (ref.name.isTermName) Mode.Term else if (ref.name.isTypeName) Mode.Type @@ -211,6 +213,22 @@ object Completion { // import a.C def isSameSymbolImportedDouble = denotss.forall(_.denots == first.denots) + def isScalaPackage(scopedDenots: ScopedDenotations) = + scopedDenots.denots.exists(_.info.typeSymbol.owner == defn.ScalaPackageClass) + + def isJavaLangPackage(scopedDenots: ScopedDenotations) = + scopedDenots.denots.exists(_.info.typeSymbol.owner == defn.JavaLangPackageClass) + + // For example + // import java.lang.annotation + // is shadowed by + // import scala.annotation + def isJavaLangAndScala = denotss match + case List(first, second) => + isScalaPackage(first) && isJavaLangPackage(second) || + isScalaPackage(second) && isJavaLangPackage(first) + case _ => false + denotss.find(!_.ctx.isImportContext) match { // most deeply nested member or local definition if not shadowed by an import case Some(local) if local.ctx.scope == first.ctx.scope => @@ -218,6 +236,12 @@ object Completion { case None if isSingleImport || isImportedInDifferentScope || isSameSymbolImportedDouble => resultMappings += name -> first.denots + case None if isJavaLangAndScala => + denotss.foreach{ + denots => + if isScalaPackage(denots) then + resultMappings += name -> denots.denots + } case _ => } diff --git a/language-server/test/dotty/tools/languageserver/CompletionTest.scala b/language-server/test/dotty/tools/languageserver/CompletionTest.scala index bc870e329f4f..c9ebdaf8e5d2 100644 --- a/language-server/test/dotty/tools/languageserver/CompletionTest.scala +++ b/language-server/test/dotty/tools/languageserver/CompletionTest.scala @@ -976,4 +976,13 @@ class CompletionTest { ("main", Module, "main") ) ) + + @Test def i13623_annotation : Unit = + code"""import annot${m1}""" + .withSource + .completion(m1, + Set( + ("annotation", Module, "scala.annotation") + ) + ) } From ed1f39990a34e479516562b157a3eaaae9979e2f Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Fri, 10 Dec 2021 19:28:45 +0100 Subject: [PATCH 2/2] Fix issues with multiple java.lang and scala shadowing improts --- .../src/dotty/tools/dotc/interactive/Completion.scala | 11 ++++++----- .../dotty/tools/languageserver/CompletionTest.scala | 9 +++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/interactive/Completion.scala b/compiler/src/dotty/tools/dotc/interactive/Completion.scala index 8c0e5f7bd8f5..1f26b50b6cce 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Completion.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Completion.scala @@ -24,6 +24,7 @@ import dotty.tools.dotc.printing.Texts._ import dotty.tools.dotc.util.{NameTransformer, NoSourcePosition, SourcePosition} import scala.collection.mutable +import scala.util.control.NonFatal /** * One of the results of a completion query. @@ -223,11 +224,11 @@ object Completion { // import java.lang.annotation // is shadowed by // import scala.annotation - def isJavaLangAndScala = denotss match - case List(first, second) => - isScalaPackage(first) && isJavaLangPackage(second) || - isScalaPackage(second) && isJavaLangPackage(first) - case _ => false + def isJavaLangAndScala = + try + denotss.forall(denots => isScalaPackage(denots) || isJavaLangPackage(denots)) + catch + case NonFatal(_) => false denotss.find(!_.ctx.isImportContext) match { // most deeply nested member or local definition if not shadowed by an import diff --git a/language-server/test/dotty/tools/languageserver/CompletionTest.scala b/language-server/test/dotty/tools/languageserver/CompletionTest.scala index c9ebdaf8e5d2..afee53328857 100644 --- a/language-server/test/dotty/tools/languageserver/CompletionTest.scala +++ b/language-server/test/dotty/tools/languageserver/CompletionTest.scala @@ -985,4 +985,13 @@ class CompletionTest { ("annotation", Module, "scala.annotation") ) ) + + @Test def importAnnotationAfterImport : Unit = + code"""import java.lang.annotation; import annot${m1}""" + .withSource + .completion(m1, + Set( + ("annotation", Module, "scala.annotation") + ) + ) }