@@ -15,9 +15,16 @@ import std.string;
1515import std.regex ;
1616import containers.hashset : HashSet;
1717import std.experimental.logger ;
18-
1918alias SortedTokens = SortedRange! (const (Token )[], " a < b" );
2019
20+ struct ExpressionInfo
21+ {
22+ const (DSymbol)* type;
23+ bool assumingLvalue; // We only assume else we need to do life time analysis.
24+ bool isFromFunction;
25+ string name;
26+ }
27+
2128enum CompletionContext
2229{
2330 UnknownCompletion,
@@ -128,8 +135,8 @@ private const(DSymbol)* deduceExpressionType(
128135 symbolNameToTypeName(STRING_LITERAL_SYMBOL_NAME ), cursorPosition);
129136 }
130137
131- auto currentType =
132- deduceSymbolTypeByToken(completionScope, * firstToken, cursorPosition);
138+ auto currentType = deduceSymbolTypeByToken(completionScope, * firstToken, cursorPosition);
139+
133140
134141 if (currentType is null )
135142 return null ;
@@ -174,8 +181,18 @@ private const(DSymbol)* deduceExpressionType(
174181 auto name = istring(exprTokens[i + 1 ].text);
175182
176183 // Get UFCS candidates for current type
184+ ExpressionInfo beforeDotType;
185+ beforeDotType.type = currentType;
186+ beforeDotType.assumingLvalue = false ;
187+ // check if there it's from a function
188+ auto functionSymbol = completionScope.getFirstSymbolByNameAndCursor(istring(firstToken.text), cursorPosition);
189+ if (functionSymbol) {
190+ beforeDotType.isFromFunction = functionSymbol.qualifier == SymbolQualifier.func;
191+ beforeDotType.name = functionSymbol.name;
192+ }
193+
177194 auto candidates = getUFCSSymbolsForDotCompletion(
178- currentType ,
195+ beforeDotType ,
179196 completionScope,
180197 cursorPosition,
181198 " "
@@ -207,23 +224,6 @@ private const(DSymbol)* deduceExpressionType(
207224 return currentType;
208225}
209226
210- void printTokenType (const (Token )* token)
211- {
212- if (token is null )
213- {
214- return ;
215- }
216- switch (token.type)
217- {
218- case tok! " " :
219-
220- break ;
221-
222- default :
223- break ;
224- }
225- }
226-
227227private const (DSymbol)* deduceSymbolTypeByToken (Scope* completionScope, scope ref const (Token ) significantToken, size_t cursorPosition)
228228{
229229
@@ -429,14 +429,15 @@ DSymbol*[] getUFCSSymbolsForCursor(Scope* completionScope, scope ref const(Token
429429 return [];
430430 }
431431
432- const (DSymbol)* deducedSymbolType = deduceExpressionType(completionScope, tokenCursorResult.expressionTokens, cursorPosition);
432+ ExpressionInfo deducedSymbolType;
433+ deducedSymbolType.type = deduceExpressionType(completionScope, tokenCursorResult.expressionTokens, cursorPosition);
433434
434- if (deducedSymbolType is null )
435+ if (deducedSymbolType.type is null )
435436 {
436437 return [];
437438 }
438439
439- if (deducedSymbolType.isInvalidForUFCSCompletion)
440+ if (deducedSymbolType.type. isInvalidForUFCSCompletion)
440441 {
441442 trace(" CursorSymbolType isn't valid for UFCS completion" );
442443 return [];
@@ -454,7 +455,7 @@ DSymbol*[] getUFCSSymbolsForCursor(Scope* completionScope, scope ref const(Token
454455
455456}
456457
457- private DSymbol* [] getUFCSSymbolsForDotCompletion (const (DSymbol) * symbolType, Scope* completionScope, size_t cursorPosition, string partial)
458+ private DSymbol* [] getUFCSSymbolsForDotCompletion (ExpressionInfo symbolType, Scope* completionScope, size_t cursorPosition, string partial)
458459{
459460 // local appender
460461 FilteredAppender! ((DSymbol* a) =>
@@ -472,7 +473,7 @@ private DSymbol*[] getUFCSSymbolsForDotCompletion(const(DSymbol)* symbolType, Sc
472473 return localAppender.data ~ globalAppender.data;
473474}
474475
475- private DSymbol* [] getUFCSSymbolsForParenCompletion (const (DSymbol) * symbolType, Scope* completionScope, istring searchWord, size_t cursorPosition)
476+ private DSymbol* [] getUFCSSymbolsForParenCompletion (ExpressionInfo symbolType, Scope* completionScope, istring searchWord, size_t cursorPosition)
476477{
477478 // local appender
478479 FilteredAppender! (a => a.isCallableWithArg(symbolType) && a.name.among(searchWord), DSymbol* []) localAppender;
@@ -644,10 +645,10 @@ private bool matchSymbolType(const(DSymbol)* firstParameter, const(DSymbol)* sig
644645 * `true` if `incomingSymbols`' first parameter matches `beforeDotType`
645646 * `false` otherwise
646647 */
647- bool isCallableWithArg (const (DSymbol)* incomingSymbol, const (DSymbol) * beforeDotType, bool isGlobalScope = false )
648+ bool isCallableWithArg (const (DSymbol)* incomingSymbol, ExpressionInfo beforeDotType, bool isGlobalScope = false )
648649{
649650 if (incomingSymbol is null
650- || beforeDotType is null
651+ || beforeDotType.type is null
651652 || isGlobalScope && incomingSymbol.protection is tok! " private" ) // don't show private functions if we are in global scope
652653 {
653654 return false ;
@@ -656,7 +657,8 @@ bool isCallableWithArg(const(DSymbol)* incomingSymbol, const(DSymbol)* beforeDot
656657 if (incomingSymbol.kind is CompletionKind.functionName && ! incomingSymbol.functionParameters.empty && incomingSymbol
657658 .functionParameters.front.type)
658659 {
659- return matchSymbolType (incomingSymbol.functionParameters.front, beforeDotType);
660+ auto firstParam = incomingSymbol.functionParameters.front;
661+ return matchSymbolType (firstParam, beforeDotType.type);
660662 }
661663 return false ;
662664}
0 commit comments