1- package dotty .tools .languageserver
1+ package dotty .tools .dotc . util
22
3- import dotty .tools .dotc .ast .tpd ._
3+ import dotty .tools .dotc .ast .Trees ._
4+ import dotty .tools .dotc .ast .tpd
45import dotty .tools .dotc .core .Constants .Constant
56import dotty .tools .dotc .core .Contexts .Context
67import dotty .tools .dotc .core .Denotations .SingleDenotation
8+ import dotty .tools .dotc .core .Flags .Implicit
9+ import dotty .tools .dotc .core .Names .TermName
710import dotty .tools .dotc .util .Positions .Position
8- import dotty .tools .dotc .core .Types .{ErrorType , MethodType }
11+ import dotty .tools .dotc .core .Types .{ErrorType , MethodType , PolyType }
912import dotty .tools .dotc .reporting .diagnostic .messages
1013
11- import org .eclipse .lsp4j .{ParameterInformation , SignatureInformation }
12-
1314import scala .collection .JavaConverters ._
1415
1516object Signatures {
1617
17- def callInfo (path : List [Tree ], pos : Position )(implicit ctx : Context ): (Int , Int , List [SingleDenotation ]) = {
18+ /**
19+ * Represent a method signature.
20+ *
21+ * @param name The name of the method
22+ * @param tparams The type parameters and their bounds
23+ * @param paramss The parameter lists of this method
24+ * @param returnType The return type of this method, if this is not a constructor.
25+ * @param doc The documentation for this method.
26+ */
27+ case class Signature (name : String , tparams : List [String ], paramss : List [List [Param ]], returnType : Option [String ], doc : Option [String ] = None ) {
28+ }
29+
30+ /**
31+ * Represent a method's parameter.
32+ *
33+ * @param name The name of the parameter
34+ * @param tpe The type of the parameter
35+ * @param doc The documentation of this parameter
36+ * @param isImplicit Is this parameter implicit?
37+ */
38+ case class Param (name : String , tpe : String , doc : Option [String ] = None , isImplicit : Boolean = false ) {
39+ def show : String =
40+ s " $name: $tpe"
41+ }
42+
43+ /**
44+ * Extract (current parameter index, function index, functions) out of a method call.
45+ *
46+ * @param path The path to the function application
47+ * @param pos The position of the cursor
48+ * @return A triple containing the index of the parameter being edited, the index of the function
49+ * being called, the list of overloads of this function).
50+ */
51+ def callInfo (path : List [tpd.Tree ], pos : Position )(implicit ctx : Context ): (Int , Int , List [SingleDenotation ]) = {
1852 path match {
1953 case Apply (fun, params) :: _ =>
2054 val alreadyAppliedCount = Signatures .countParams(fun)
2155 val paramIndex = params.indexWhere(_.pos.contains(pos)) match {
22- case - 1 => (( params.length - 1 ) max 0 ) + alreadyAppliedCount
56+ case - 1 => (params.length - 1 max 0 ) + alreadyAppliedCount
2357 case n => n + alreadyAppliedCount
2458 }
2559
@@ -42,6 +76,56 @@ object Signatures {
4276 }
4377 }
4478
79+ def toSignature (denot : SingleDenotation )(implicit ctx : Context ): Option [Signature ] = {
80+ val symbol = denot.symbol
81+ val docComment = ParsedComment .docOf(symbol)
82+ val classTree = symbol.topLevelClass.asClass.rootTree
83+ val isImplicit : TermName => Boolean = tpd.defPath(symbol, classTree).lastOption match {
84+ case Some (DefDef (_, _, paramss, _, _)) =>
85+ val flatParams = paramss.flatten
86+ name => flatParams.find(_.name == name).map(_.symbol.is(Implicit )).getOrElse(false )
87+ case _ =>
88+ _ => false
89+ }
90+
91+ denot.info.stripPoly match {
92+ case tpe : MethodType =>
93+ val infos = {
94+ tpe.paramInfoss.zip(tpe.paramNamess).map { case (infos, names) =>
95+ infos.zip(names).map { case (info, name) =>
96+ Signatures .Param (name.show,
97+ info.widenTermRefExpr.show,
98+ docComment.flatMap(_.paramDoc(name)),
99+ isImplicit = isImplicit(name))
100+ }
101+ }
102+ }
103+
104+ val typeParams = denot.info match {
105+ case poly : PolyType =>
106+ poly.paramNames.zip(poly.paramInfos).map { case (x, y) => x.show + y.show }
107+ case _ =>
108+ Nil
109+ }
110+
111+ val (name, returnType) =
112+ if (symbol.isConstructor) (symbol.owner.name.show, None )
113+ else (denot.name.show, Some (tpe.finalResultType.widenTermRefExpr.show))
114+
115+ val signature =
116+ Signatures .Signature (name,
117+ typeParams,
118+ infos,
119+ returnType,
120+ docComment.map(_.mainDoc))
121+
122+ Some (signature)
123+
124+ case other =>
125+ None
126+ }
127+ }
128+
45129 /**
46130 * The number of parameters that are applied in `tree`.
47131 *
@@ -51,7 +135,7 @@ object Signatures {
51135 * @param tree The tree to inspect.
52136 * @return The number of parameters that are passed.
53137 */
54- private def countParams (tree : Tree ): Int = {
138+ private def countParams (tree : tpd. Tree ): Int = {
55139 tree match {
56140 case Apply (fun, params) => countParams(fun) + params.length
57141 case _ => 0
@@ -71,7 +155,7 @@ object Signatures {
71155 * @return A pair composed of the index of the best alternative (0 if no alternatives
72156 * were found), and the list of alternatives.
73157 */
74- private def alternativesFromError (err : ErrorType , params : List [Tree ])(implicit ctx : Context ): (Int , List [SingleDenotation ]) = {
158+ private def alternativesFromError (err : ErrorType , params : List [tpd. Tree ])(implicit ctx : Context ): (Int , List [SingleDenotation ]) = {
75159 val alternatives =
76160 err.msg match {
77161 case messages.AmbiguousOverload (_, alternatives, _) =>
@@ -96,7 +180,7 @@ object Signatures {
96180 val alternativesScores = alternatives.map { alt =>
97181 alt.info.stripPoly match {
98182 case tpe : MethodType =>
99- userParamsTypes.zip(tpe.paramInfos).takeWhile(_ <:< _) .size
183+ userParamsTypes.zip(tpe.paramInfos).takeWhile{ case (t0, t1) => t0 <:< t1 } .size
100184 case _ =>
101185 0
102186 }
@@ -108,36 +192,5 @@ object Signatures {
108192 (bestAlternative, alternatives)
109193 }
110194
111- case class Signature (name : String , tparams : List [String ], paramss : List [List [Param ]], returnType : Option [String ], doc : Option [String ] = None ) {
112- def toSignatureInformation : SignatureInformation = {
113- val paramInfoss = paramss.map(_.map(_.toParameterInformation))
114- val paramLists = paramss.map { paramList =>
115- val labels = paramList.map(_.show)
116- val prefix = if (paramList.exists(_.isImplicit)) " implicit " else " "
117- labels.mkString(prefix, " , " , " " )
118- }.mkString(" (" , " )(" , " )" )
119- val tparamsLabel = if (tparams.isEmpty) " " else tparams.mkString(" [" , " , " , " ]" )
120- val returnTypeLabel = returnType.map(t => s " : $t" ).getOrElse(" " )
121- val label = s " $name$tparamsLabel$paramLists$returnTypeLabel"
122- val documentation = doc.map(DottyLanguageServer .hoverContent)
123- val signature = new SignatureInformation (label)
124- signature.setParameters(paramInfoss.flatten.asJava)
125- documentation.foreach(signature.setDocumentation(_))
126- signature
127- }
128- }
129-
130- case class Param (name : String , tpe : String , doc : Option [String ] = None , isImplicit : Boolean = false ) {
131-
132- def toParameterInformation : ParameterInformation = {
133- val label = s " $name: $tpe"
134- val documentation = doc.map(DottyLanguageServer .hoverContent)
135- val info = new ParameterInformation (label)
136- documentation.foreach(info.setDocumentation(_))
137- info
138- }
139-
140- def show : String =
141- s " $name: $tpe"
142- }
143195}
196+
0 commit comments