1
- package dotty .tools .languageserver
1
+ package dotty .tools .dotc . util
2
2
3
- import dotty .tools .dotc .ast .tpd ._
3
+ import dotty .tools .dotc .ast .Trees ._
4
+ import dotty .tools .dotc .ast .tpd
4
5
import dotty .tools .dotc .core .Constants .Constant
5
6
import dotty .tools .dotc .core .Contexts .Context
6
7
import dotty .tools .dotc .core .Denotations .SingleDenotation
8
+ import dotty .tools .dotc .core .Flags .Implicit
9
+ import dotty .tools .dotc .core .Names .TermName
7
10
import 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 }
9
12
import dotty .tools .dotc .reporting .diagnostic .messages
10
13
11
- import org .eclipse .lsp4j .{ParameterInformation , SignatureInformation }
12
-
13
14
import scala .collection .JavaConverters ._
14
15
15
16
object Signatures {
16
17
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 ]) = {
18
52
path match {
19
53
case Apply (fun, params) :: _ =>
20
54
val alreadyAppliedCount = Signatures .countParams(fun)
21
55
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
23
57
case n => n + alreadyAppliedCount
24
58
}
25
59
@@ -42,6 +76,56 @@ object Signatures {
42
76
}
43
77
}
44
78
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
+
45
129
/**
46
130
* The number of parameters that are applied in `tree`.
47
131
*
@@ -51,7 +135,7 @@ object Signatures {
51
135
* @param tree The tree to inspect.
52
136
* @return The number of parameters that are passed.
53
137
*/
54
- private def countParams (tree : Tree ): Int = {
138
+ private def countParams (tree : tpd. Tree ): Int = {
55
139
tree match {
56
140
case Apply (fun, params) => countParams(fun) + params.length
57
141
case _ => 0
@@ -71,7 +155,7 @@ object Signatures {
71
155
* @return A pair composed of the index of the best alternative (0 if no alternatives
72
156
* were found), and the list of alternatives.
73
157
*/
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 ]) = {
75
159
val alternatives =
76
160
err.msg match {
77
161
case messages.AmbiguousOverload (_, alternatives, _) =>
@@ -96,7 +180,7 @@ object Signatures {
96
180
val alternativesScores = alternatives.map { alt =>
97
181
alt.info.stripPoly match {
98
182
case tpe : MethodType =>
99
- userParamsTypes.zip(tpe.paramInfos).takeWhile(_ <:< _) .size
183
+ userParamsTypes.zip(tpe.paramInfos).takeWhile{ case (t0, t1) => t0 <:< t1 } .size
100
184
case _ =>
101
185
0
102
186
}
@@ -108,36 +192,5 @@ object Signatures {
108
192
(bestAlternative, alternatives)
109
193
}
110
194
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
- }
143
195
}
196
+
0 commit comments