added ufcs completion for string and string literal
This commit is contained in:
parent
fbd79b258f
commit
9e4c70ce15
|
@ -21,14 +21,20 @@ enum CompletionContext
|
|||
ParenCompletion,
|
||||
}
|
||||
|
||||
|
||||
struct TokenCursorResult
|
||||
{
|
||||
CompletionContext completionContext;
|
||||
istring functionName;
|
||||
istring symbolIdentifierName;
|
||||
Token significantToken;
|
||||
string partialIdentifier;
|
||||
}
|
||||
|
||||
struct DeducedSymbolTypeResult{
|
||||
const(DSymbol)* deducedSymbolType;
|
||||
bool success = false;
|
||||
}
|
||||
|
||||
// https://dlang.org/spec/type.html#implicit-conversions
|
||||
enum string[string] INTEGER_PROMOTIONS = [
|
||||
"bool": "int",
|
||||
|
@ -43,15 +49,31 @@ enum string[string] INTEGER_PROMOTIONS = [
|
|||
|
||||
enum MAX_NUMBER_OF_MATCHING_RUNS = 50;
|
||||
|
||||
private const(DSymbol)* deduceSymbolType(const(DSymbol)* symbol)
|
||||
private DeducedSymbolTypeResult deduceSymbolTypeByToken(Scope* completionScope, scope ref const(Token) significantToken, size_t cursorPosition)
|
||||
{
|
||||
DeducedSymbolTypeResult result;
|
||||
//Literal type deduction
|
||||
if (significantToken.type is tok!"stringLiteral"){
|
||||
result.deducedSymbolType = completionScope.getFirstSymbolByNameAndCursor(istring("string"), cursorPosition);
|
||||
result.success = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
const(DSymbol)* symbol = completionScope.getFirstSymbolByNameAndCursor(istring(significantToken.text), cursorPosition);
|
||||
|
||||
if (symbol is null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const(DSymbol)* symbolType = symbol.type;
|
||||
while (symbolType !is null && (symbolType.qualifier == SymbolQualifier.func
|
||||
|| symbolType.kind == CompletionKind.functionName
|
||||
|| symbolType.kind == CompletionKind.importSymbol
|
||||
|| symbolType.kind == CompletionKind.aliasName))
|
||||
{
|
||||
if (symbolType.type is null || symbolType.type is symbolType)
|
||||
if (symbolType.type is null
|
||||
|| symbolType.type is symbolType
|
||||
|| symbolType.name.data == "string") // special case for string
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -59,7 +81,10 @@ private const(DSymbol)* deduceSymbolType(const(DSymbol)* symbol)
|
|||
symbolType = symbolType.type;
|
||||
}
|
||||
|
||||
return symbolType;
|
||||
|
||||
result.deducedSymbolType = symbolType;
|
||||
result.success = true;
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
@ -90,13 +115,13 @@ private TokenCursorResult getCursorToken(const(Token)[] tokens, size_t cursorPos
|
|||
sortedBeforeTokens = sortedBeforeTokens[0 .. $ - 1];
|
||||
}
|
||||
|
||||
if (sortedBeforeTokens.length >= 2
|
||||
if (sortedBeforeTokens.length >= 2
|
||||
&& sortedBeforeTokens[$ - 1].type is tok!"."
|
||||
&& sortedBeforeTokens[$ - 2].type is tok!"identifier")
|
||||
&& (sortedBeforeTokens[$ - 2].type is tok!"identifier" || sortedBeforeTokens[$ - 2].type is tok!"stringLiteral"))
|
||||
{
|
||||
// Check if it's UFCS dot completion
|
||||
tokenCursorResult.completionContext = CompletionContext.DotCompletion;
|
||||
tokenCursorResult.symbolIdentifierName = istring(sortedBeforeTokens[$ - 2].text);
|
||||
tokenCursorResult.significantToken = sortedBeforeTokens[$ - 2];
|
||||
return tokenCursorResult;
|
||||
}
|
||||
else if (!tokenCursorResult.partialIdentifier.length)
|
||||
|
@ -117,7 +142,7 @@ private TokenCursorResult getCursorToken(const(Token)[] tokens, size_t cursorPos
|
|||
&& slicedAtParen[$ - 1].type is tok!"(")
|
||||
{
|
||||
tokenCursorResult.completionContext = CompletionContext.ParenCompletion;
|
||||
tokenCursorResult.symbolIdentifierName = istring(slicedAtParen[$ - 4].text);
|
||||
tokenCursorResult.significantToken = slicedAtParen[$ - 4];
|
||||
tokenCursorResult.functionName = istring(slicedAtParen[$ - 2].text);
|
||||
return tokenCursorResult;
|
||||
}
|
||||
|
@ -187,29 +212,14 @@ DSymbol*[] getUFCSSymbolsForCursor(Scope* completionScope, scope ref const(Token
|
|||
return [];
|
||||
}
|
||||
|
||||
const(DSymbol)* cursorSymbol = completionScope.getFirstSymbolByNameAndCursor(
|
||||
tokenCursorResult.symbolIdentifierName, cursorPosition);
|
||||
DeducedSymbolTypeResult deducedSymbolTypeResult = deduceSymbolTypeByToken(completionScope, tokenCursorResult.significantToken, cursorPosition);
|
||||
|
||||
if (cursorSymbol is null)
|
||||
{
|
||||
warning("Coudn't find symbol ", tokenCursorResult.symbolIdentifierName);
|
||||
return [];
|
||||
}
|
||||
|
||||
if (cursorSymbol.isInvalidForUFCSCompletion)
|
||||
{
|
||||
trace("CursorSymbol is invalid for UFCS");
|
||||
return [];
|
||||
}
|
||||
|
||||
const(DSymbol)* cursorSymbolType = deduceSymbolType(cursorSymbol);
|
||||
|
||||
if (cursorSymbolType is null)
|
||||
if (deducedSymbolTypeResult.deducedSymbolType is null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
if (cursorSymbolType.isInvalidForUFCSCompletion)
|
||||
if (deducedSymbolTypeResult.deducedSymbolType.isInvalidForUFCSCompletion)
|
||||
{
|
||||
trace("CursorSymbolType isn't valid for UFCS completion");
|
||||
return [];
|
||||
|
@ -217,11 +227,11 @@ DSymbol*[] getUFCSSymbolsForCursor(Scope* completionScope, scope ref const(Token
|
|||
|
||||
if (tokenCursorResult.completionContext == CompletionContext.ParenCompletion)
|
||||
{
|
||||
return getUFCSSymbolsForParenCompletion(cursorSymbolType, completionScope, tokenCursorResult.functionName, cursorPosition);
|
||||
return getUFCSSymbolsForParenCompletion(deducedSymbolTypeResult.deducedSymbolType, completionScope, tokenCursorResult.functionName, cursorPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
return getUFCSSymbolsForDotCompletion(cursorSymbolType, completionScope, cursorPosition, tokenCursorResult.partialIdentifier);
|
||||
return getUFCSSymbolsForDotCompletion(deducedSymbolTypeResult.deducedSymbolType, completionScope, cursorPosition, tokenCursorResult.partialIdentifier);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -205,14 +205,21 @@ AutocompleteResponse dotCompletion(T)(T beforeTokens, const(Token)[] tokenArray,
|
|||
significantTokenType = beforeTokens[$ - 2].type;
|
||||
else
|
||||
return response;
|
||||
|
||||
switch (significantTokenType)
|
||||
{
|
||||
mixin(STRING_LITERAL_CASES);
|
||||
foreach (symbol; arraySymbols)
|
||||
{
|
||||
foreach (symbol; arraySymbols){
|
||||
response.completions ~= makeSymbolCompletionInfo(symbol, symbol.kind);
|
||||
}
|
||||
response.completionType = CompletionType.identifiers;
|
||||
RollbackAllocator rba;
|
||||
ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, &rba, cursorPosition, moduleCache);
|
||||
scope(exit) pair.destroy();
|
||||
response.completions ~= pair.ufcsSymbols.map!(s => makeSymbolCompletionInfo(s, CompletionKind.ufcsName)).array;
|
||||
break;
|
||||
}
|
||||
|
||||
mixin(TYPE_IDENT_CASES);
|
||||
case tok!")":
|
||||
case tok!"]":
|
||||
|
@ -221,7 +228,11 @@ AutocompleteResponse dotCompletion(T)(T beforeTokens, const(Token)[] tokenArray,
|
|||
scope(exit) pair.destroy();
|
||||
response.setCompletions(pair.scope_, getExpression(beforeTokens),
|
||||
cursorPosition, CompletionType.identifiers, false, partial);
|
||||
response.completions ~= pair.ufcsSymbols.map!(s => makeSymbolCompletionInfo(s, CompletionKind.ufcsName)).array;
|
||||
if (!pair.ufcsSymbols.empty) {
|
||||
response.completions ~= pair.ufcsSymbols.map!(s => makeSymbolCompletionInfo(s, CompletionKind.ufcsName)).array;
|
||||
// Setting CompletionType in case of none symbols are found via setCompletions, but we have UFCS symbols.
|
||||
response.completionType = CompletionType.identifiers;
|
||||
}
|
||||
break;
|
||||
// these tokens before a "." mean "Module Scope Operator"
|
||||
case tok!":":
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
identifiers
|
||||
alignof k
|
||||
dup k
|
||||
idup k
|
||||
init k
|
||||
length k
|
||||
mangleof k
|
||||
ptr k
|
||||
sizeof k
|
||||
stringof k
|
||||
testUfcs F
|
||||
ufcsString F
|
||||
ufcsStringBar F
|
|
@ -0,0 +1,4 @@
|
|||
identifiers
|
||||
testUfcs F
|
||||
ufcsString F
|
||||
ufcsStringBar F
|
|
@ -0,0 +1,6 @@
|
|||
void ufcsString(string input){}
|
||||
void ufcsStringBar(string input){}
|
||||
void testUfcs(string x){
|
||||
"foo".
|
||||
x.
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
set -e
|
||||
set -u
|
||||
|
||||
#TEST CASE 0
|
||||
SOURCE_FILE_0=file.d
|
||||
ACTUAL_FILE_NAME_0=actual_string_literal_test.txt
|
||||
EXPECTED_FILE_NAME_0=expected_string_literal_test.txt
|
||||
|
||||
../../bin/dcd-client $1 -c99 $SOURCE_FILE_0 > $ACTUAL_FILE_NAME_0
|
||||
diff $ACTUAL_FILE_NAME_0 $EXPECTED_FILE_NAME_0 --strip-trailing-cr
|
||||
|
||||
ACTUAL_FILE_NAME_1=actual_string_test.txt
|
||||
EXPECTED_FILE_NAME_1=expected_string_test.txt
|
||||
../../bin/dcd-client $1 -c103 $SOURCE_FILE_0 > $ACTUAL_FILE_NAME_1
|
||||
diff $ACTUAL_FILE_NAME_1 $EXPECTED_FILE_NAME_1 --strip-trailing-cr
|
Loading…
Reference in New Issue