diff --git a/compiler/src/dotty/tools/dotc/interactive/Interactive.scala b/compiler/src/dotty/tools/dotc/interactive/Interactive.scala index 7af27c5eeaf1..7255ce81272b 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Interactive.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Interactive.scala @@ -185,6 +185,7 @@ object Interactive { private def handle(utree: untpd.NameTree): Unit = { val tree = utree.asInstanceOf[tpd.NameTree] if (tree.symbol.exists + && tree.name != StdNames.nme.ERROR && !tree.symbol.is(Synthetic) && !tree.symbol.isPrimaryConstructor && tree.span.exists diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index b8e262d2d239..b596a1bd761f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -587,7 +587,7 @@ class Typer extends Namer case _ => } val x = tpnme.ANON_CLASS - val clsDef = TypeDef(x, templ1).withFlags(Final) + val clsDef = TypeDef(x, templ1).withFlags(Final | Synthetic) typed(cpy.Block(tree)(clsDef :: Nil, New(Ident(x), Nil)), pt) case _ => var tpt1 = typedType(tree.tpt) diff --git a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala index 4d146fb60e48..23891477ea59 100644 --- a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala +++ b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala @@ -489,10 +489,20 @@ class DottyLanguageServer extends LanguageServer val uriTrees = driver.openedTrees(uri) - val defs = Interactive.namedTrees(uriTrees, Include.empty) + // Excludes type and term params from synthetic symbols + val excludeParamsFromSyntheticSymbols = (n: NameTree) => { + val owner = n.symbol.owner + !n.symbol.is(Param) || { + !owner.is(Synthetic) && + !owner.isPrimaryConstructor + } + } + + val defs = Interactive.namedTrees(uriTrees, Include.local, excludeParamsFromSyntheticSymbols) + (for { - d <- defs if !isWorksheetWrapper(d) - info <- symbolInfo(d.tree.symbol, d.namePos) + d <- defs if (!isWorksheetWrapper(d) && !isTopLevelWrapper(d)) + info <- symbolInfo(d.tree.symbol, d.pos) } yield JEither.forLeft(info)).asJava } @@ -808,6 +818,14 @@ object DottyLanguageServer { symbol.owner == ctx.definitions.EmptyPackageClass } + /** + * Is this symbol the wrapper object for top level definitions? + */ + def isTopLevelWrapper(sourceTree: SourceTree)(implicit ctx: Context): Boolean = { + val symbol = sourceTree.tree.symbol + symbol.isPackageObject + } + /** Create an lsp4j.CompletionItem from a completion result */ def completionItem(completion: Completion)(implicit ctx: Context): lsp4j.CompletionItem = { def completionItemKind(sym: Symbol)(implicit ctx: Context): lsp4j.CompletionItemKind = { @@ -883,24 +901,34 @@ object DottyLanguageServer { SK.Constructor else if (sym.is(Module)) SK.Module + else if (sym.isAllOf(EnumCase) || sym.isAllOf(EnumValue)) + SK.EnumMember + else if (sym.is(Enum)) + SK.Enum + else if (sym.is(Trait)) + SK.Interface else if (sym.isClass) SK.Class else if (sym.is(Mutable)) SK.Variable else if (sym.is(Method)) SK.Method + else if (sym.is(TypeParam) || sym.isAbstractOrAliasType) + SK.TypeParameter else SK.Field } + def containerName(sym: Symbol): String = { + val owner = if (sym.owner.exists && sym.owner.isPackageObject) sym.owner.owner else sym.owner + if (owner.exists && !owner.isEmptyPackage) { + owner.name.stripModuleClassSuffix.show + } else + null + } val name = sym.name.stripModuleClassSuffix.show - val containerName = - if (sym.owner.exists && !sym.owner.isEmptyPackage) - sym.owner.name.show - else - null - location(pos).map(l => new lsp4j.SymbolInformation(name, symbolKind(sym), l, containerName)) + location(pos).map(l => new lsp4j.SymbolInformation(name, symbolKind(sym), l, containerName(sym))) } /** Convert `signature` to a `SignatureInformation` */ diff --git a/language-server/test/dotty/tools/languageserver/DocumentSymbolTest.scala b/language-server/test/dotty/tools/languageserver/DocumentSymbolTest.scala index 35cc29d303f9..81e4379c99eb 100644 --- a/language-server/test/dotty/tools/languageserver/DocumentSymbolTest.scala +++ b/language-server/test/dotty/tools/languageserver/DocumentSymbolTest.scala @@ -9,39 +9,86 @@ import dotty.tools.languageserver.util.Code._ class DocumentSymbolTest { @Test def withErroneousTree: Unit = - code"class ${m1}Foo$m2 { def }" + code"${m1}class Foo { def }$m2" .withSource.documentSymbol(m1, (m1 to m2).symInfo("Foo", SymbolKind.Class)) @Test def documentSymbol0: Unit = - code"class ${m1}Foo$m2".withSource.documentSymbol(m1, (m1 to m2).symInfo("Foo", SymbolKind.Class)) + code"${m1}class Foo$m2".withSource.documentSymbol(m1, (m1 to m2).symInfo("Foo", SymbolKind.Class)) @Test def documentSymbol1: Unit = - code"class ${m1}Foo$m2; class ${m3}Bar$m4".withSource + code"${m1}class Foo$m2; ${m3}class Bar$m4".withSource .documentSymbol(m1, (m1 to m2).symInfo("Foo", SymbolKind.Class), (m3 to m4).symInfo("Bar", SymbolKind.Class)) @Test def documentSymbol3: Unit = { withSources( - code"class ${m1}Foo$m2", - code"class ${m3}Bar$m4" + code"${m1}class Foo$m2", + code"${m3}class Bar$m4" ) .documentSymbol(m1, (m1 to m2).symInfo("Foo", SymbolKind.Class)) .documentSymbol(m3, (m3 to m4).symInfo("Bar", SymbolKind.Class)) } @Test def documentSymbolShowModule: Unit = { - code"""object ${m1}Foo${m2}""".withSource + code"""${m1}object Foo${m2}""".withSource .documentSymbol(m1, (m1 to m2).symInfo("Foo", SymbolKind.Module)) } @Test def documentSymbolShowClassAndCompanion: Unit = { - code"""object ${m1}Foo${m2} - |class ${m3}Foo${m4}""".withSource + code"""${m1}object Foo${m2} + |${m3}class Foo${m4}""".withSource .documentSymbol(m1, (m1 to m2).symInfo("Foo", SymbolKind.Module), (m3 to m4).symInfo("Foo", SymbolKind.Class)) } @Test def documentSymbolSynthetic: Unit = { - code"""case class ${m1}Foo${m2}(${m3}x${m4}: Int)""".withSource + code"""${m1}case class Foo(${m3}x: Int${m4})${m2}""".withSource .documentSymbol(m1, (m1 to m2).symInfo("Foo", SymbolKind.Class), (m3 to m4).symInfo("x", SymbolKind.Field, "Foo")) } + + @Test def documentSymbolEnumADT: Unit = { + code"""${m1}enum Option[${m3}+T${m4}] { + ${m5}case Some(${m7}x: T${m8})${m6} + ${m9}case None${m10} + }${m2}""".withSource + .documentSymbol(m1, (m1 to m2).symInfo("Option", SymbolKind.Enum), + (m3 to m4).symInfo("T", SymbolKind.TypeParameter, "Option"), + (m5 to m6).symInfo("Some", SymbolKind.EnumMember, "Option"), + (m7 to m8).symInfo("x", SymbolKind.Field, "Some"), + (m9 to m10).symInfo("None", SymbolKind.EnumMember, "Option")) + } + + @Test def documentSymbolEnum: Unit = { + code"""${m1}enum Color(${m3}val rgb: Int${m4}) { + ${m5}case Red extends Color(0xFF0000)${m6} + ${m7}case Green extends Color(0x00FF00)${m8} + ${m9}case Blue extends Color(0x0000FF)${m10} + }${m2}""".withSource + .documentSymbol(m1, (m1 to m2).symInfo("Color", SymbolKind.Enum), + (m3 to m4).symInfo("rgb", SymbolKind.Field, "Color"), + (m5 to m6).symInfo("Red", SymbolKind.EnumMember, "Color"), + (m7 to m8).symInfo("Green", SymbolKind.EnumMember, "Color"), + (m9 to m10).symInfo("Blue", SymbolKind.EnumMember, "Color")) + } + + @Test def documentSymbolTopLevelDef: Unit = + code"${m1}def foo(): Unit = { }${m2}".withSource.documentSymbol(m1, (m1 to m2).symInfo("foo", SymbolKind.Method)) + + @Test def documentSymbolTrait: Unit = + code"${m1}trait Foo(${m3}val x: Int${m4})${m2}".withSource.documentSymbol(m1, (m1 to m2).symInfo("Foo", SymbolKind.Interface), + (m3 to m4).symInfo("x", SymbolKind.Field, "Foo")) + + @Test def documentSymbolLocalDef: Unit = + code"""${m1}def foo(): Unit = { + ${m3}def bar(): Unit = { }${m4} + ${m5}val x: Int = 0${m6} + }${m2}""".withSource.documentSymbol(m1, (m1 to m2).symInfo("foo", SymbolKind.Method), + (m3 to m4).symInfo("bar", SymbolKind.Method, "foo"), + (m5 to m6).symInfo("x", SymbolKind.Field, "foo") ) + + @Test def documentSymbolTypeFields: Unit = + code"""${m1}class Foo { + ${m3}type T${m4} + }${m2}""".withSource.documentSymbol(m1, (m1 to m2).symInfo("Foo", SymbolKind.Class), + (m3 to m4).symInfo("T", SymbolKind.TypeParameter, "Foo")) + } diff --git a/language-server/test/dotty/tools/languageserver/WorksheetTest.scala b/language-server/test/dotty/tools/languageserver/WorksheetTest.scala index d5a9773a0bc2..1ef272f4517d 100644 --- a/language-server/test/dotty/tools/languageserver/WorksheetTest.scala +++ b/language-server/test/dotty/tools/languageserver/WorksheetTest.scala @@ -189,10 +189,10 @@ class WorksheetTest { } @Test def worksheetDocumentSymbol(): Unit = { - ws"""class ${m1}Foo${m2} { - def ${m3}bar${m4} = 123 - }""".withSource - .documentSymbol(m1, (m1 to m2).symInfo("Foo", SymbolKind.Class, WorksheetWrapper.moduleClassName.toString), + ws"""${m1}class Foo { + ${m3}def bar = 123${m4} + }${m2}""".withSource + .documentSymbol(m1, (m1 to m2).symInfo("Foo", SymbolKind.Class, WorksheetWrapper.moduleClassName.stripModuleClassSuffix.toString), (m3 to m4).symInfo("bar", SymbolKind.Method, "Foo")) } @@ -202,7 +202,7 @@ class WorksheetTest { def ${m3}bar${m4} = 123 }""", code"""class ${m5}Baz${m6}""" - ).symbol("Foo", (m1 to m2).symInfo("Foo", SymbolKind.Class, WorksheetWrapper.moduleClassName.toString)) + ).symbol("Foo", (m1 to m2).symInfo("Foo", SymbolKind.Class, WorksheetWrapper.moduleClassName.stripModuleClassSuffix.toString)) .symbol("bar", (m3 to m4).symInfo("bar", SymbolKind.Method, "Foo")) .symbol("Baz", (m5 to m6).symInfo("Baz", SymbolKind.Class)) }