@@ -4,13 +4,17 @@ import java.util
4
4
import java .util .Objects
5
5
6
6
import com .intellij .lang .javascript .dialects .JSDialectSpecificHandlersFactory
7
+ import com .intellij .lang .javascript .documentation .JSDocumentationUtils
7
8
import com .intellij .lang .javascript .psi .impl .{JSDefinitionExpressionImpl , JSFunctionImpl , JSReferenceExpressionImpl }
8
9
import com .intellij .lang .javascript .psi ._
10
+ import com .intellij .lang .javascript .psi .jsdoc .JSDocTag
11
+ import com .intellij .lang .javascript .psi .jsdoc .impl .JSDocCommentImpl
9
12
import com .intellij .lang .javascript .psi .resolve .JSResolveUtil
10
13
import com .intellij .lang .javascript .psi .types ._
11
14
import com .intellij .psi .impl .source .resolve .ResolveCache .PolyVariantResolver
12
- import com .intellij .psi .{PsiElement , PsiFile }
15
+ import com .intellij .psi .{PsiElement , PsiFile , PsiWhiteSpace }
13
16
import com .intellij .psi .impl .source .resolve .reference .impl .providers .{FileReference , FileReferenceSet }
17
+ import com .intellij .psi .impl .source .tree .LeafPsiElement
14
18
import com .intellij .psi .util .PsiTreeUtil
15
19
import org .klesun .deep_js_completion .entry .PathStrGoToDecl
16
20
import org .klesun .deep_js_completion .helpers .{ICtx , MultiType }
@@ -19,6 +23,9 @@ import org.klesun.lang.Lang
19
23
import scala .collection .JavaConverters ._
20
24
import org .klesun .lang .Lang ._
21
25
26
+ import scala .collection .GenTraversable
27
+ import scala .collection .mutable .ListBuffer
28
+
22
29
/**
23
30
* resolves variable type
24
31
*/
@@ -79,9 +86,70 @@ case class VarRes(ctx: ICtx) {
79
86
.flatMap(file => resolveRequireJsFormatDef(file))
80
87
.flatMap(clsT => ensureFunc(clsT))
81
88
89
+ private def getDocTagComment (docTag : JSDocTag ) = {
90
+ var next = docTag.getNextSibling
91
+ val tokens = new ListBuffer [PsiElement ]
92
+ while (next != null && (
93
+ next.isInstanceOf [LeafPsiElement ] ||
94
+ next.isInstanceOf [PsiWhiteSpace ]
95
+ )) {
96
+ tokens.append(next)
97
+ next = next.getNextSibling
98
+ }
99
+ tokens.map(t => t.getText).mkString(" " )
100
+ .replaceAll(""" \n\s*\* """ , " \n " )
101
+ }
102
+
103
+ private def findVarDecl (caretPsi : PsiElement , varName : String ): Option [JSType ] = {
104
+ Lang .findParent[JSBlockStatement ](caretPsi)
105
+ .toList.flatMap(b => b.getStatements
106
+ .flatMap(st => st match {
107
+ case varSt : JSVarStatement =>
108
+ varSt.getDeclarations
109
+ .filter(own => varName.equals(own.getName))
110
+ .map(own => own.getInitializer)
111
+ .flatMap(expr => ctx.findExprType(expr))
112
+ case func : JSFunctionDeclaration =>
113
+ if (varName.equals(func.getName)) {
114
+ val rts = MainRes .getReturns(func)
115
+ .flatMap(ret => ctx.findExprType(ret))
116
+ val rt = MultiType .mergeTypes(rts).getOrElse(JSUnknownType .JS_INSTANCE )
117
+ Some (new JSFunctionTypeImpl (JSTypeSource .EMPTY , new util.ArrayList , rt))
118
+ } else {
119
+ None
120
+ }
121
+ case _ => None
122
+ })
123
+ .++ (findVarDecl(b, varName))
124
+ )
125
+ .lift(0 )
126
+ }
127
+
128
+ private def parseDocExpr (caretPsi : PsiElement , expr : String ): Option [JSType ] = {
129
+ """ ^\s*=\s*(\w+)(\([^\)]*\)|)\s*$""" .r.findFirstMatchIn(expr)
130
+ .flatMap(found => {
131
+ val varName = found.group(1 )
132
+ val isFuncCall = ! found.group(2 ).equals(" " )
133
+ findVarDecl(caretPsi, varName)
134
+ .flatMap(t => if (isFuncCall) MultiType .getReturnType(t) else Some (t))
135
+ })
136
+ }
137
+
138
+ private def getArgDocExprType (func : JSFunction , para : JSParameter ): List [JSType ] = {
139
+ Option (JSDocumentationUtils .findDocComment(para))
140
+ .flatMap(cast[JSDocCommentImpl ](_)).toList
141
+ .flatMap(tag => tag.getTags)
142
+ .filter(tag => " param" .equals(tag.getName))
143
+ .filter(tag => Option (tag.getDocCommentData)
144
+ .exists(data => Objects .equals(para.getName, data.getText)))
145
+ .map(tag => getDocTagComment(tag))
146
+ .flatMap(expr => parseDocExpr(para, expr))
147
+ }
148
+
82
149
private def resolveArg (para : JSParameter ): Option [JSType ] = {
83
150
val types = Option (para.getDeclaringFunction)
84
151
.toList.flatMap(func => List [JSType ]()
152
+ ++ getArgDocExprType(func, para)
85
153
++ getInlineFuncArgType(func)
86
154
++ getKlesunRequiresArgType(func))
87
155
MultiType .mergeTypes(types)
0 commit comments