PR changes

This commit is contained in:
davu 2023-03-26 11:50:50 +02:00 committed by Jan Jurzitza
parent 9e4c70ce15
commit 218d047760
14 changed files with 125 additions and 141 deletions

View file

@ -30,11 +30,6 @@ struct TokenCursorResult
string partialIdentifier; string partialIdentifier;
} }
struct DeducedSymbolTypeResult{
const(DSymbol)* deducedSymbolType;
bool success = false;
}
// https://dlang.org/spec/type.html#implicit-conversions // https://dlang.org/spec/type.html#implicit-conversions
enum string[string] INTEGER_PROMOTIONS = [ enum string[string] INTEGER_PROMOTIONS = [
"bool": "int", "bool": "int",
@ -49,20 +44,17 @@ enum string[string] INTEGER_PROMOTIONS = [
enum MAX_NUMBER_OF_MATCHING_RUNS = 50; enum MAX_NUMBER_OF_MATCHING_RUNS = 50;
private DeducedSymbolTypeResult deduceSymbolTypeByToken(Scope* completionScope, scope ref const(Token) significantToken, size_t cursorPosition) private const(DSymbol)* deduceSymbolTypeByToken(Scope* completionScope, scope ref const(Token) significantToken, size_t cursorPosition)
{ {
DeducedSymbolTypeResult result;
//Literal type deduction //Literal type deduction
if (significantToken.type is tok!"stringLiteral"){ if (significantToken.type is tok!"stringLiteral"){
result.deducedSymbolType = completionScope.getFirstSymbolByNameAndCursor(istring("string"), cursorPosition); return completionScope.getFirstSymbolByNameAndCursor(symbolNameToTypeName(STRING_LITERAL_SYMBOL_NAME), cursorPosition);
result.success = true;
return result;
} }
const(DSymbol)* symbol = completionScope.getFirstSymbolByNameAndCursor(istring(significantToken.text), cursorPosition); const(DSymbol)* symbol = completionScope.getFirstSymbolByNameAndCursor(istring(significantToken.text), cursorPosition);
if (symbol is null) { if (symbol is null) {
return result; return null;
} }
const(DSymbol)* symbolType = symbol.type; const(DSymbol)* symbolType = symbol.type;
@ -82,9 +74,7 @@ private DeducedSymbolTypeResult deduceSymbolTypeByToken(Scope* completionScope,
} }
result.deducedSymbolType = symbolType; return symbolType;
result.success = true;
return result;
} }
@ -120,8 +110,14 @@ private TokenCursorResult getCursorToken(const(Token)[] tokens, size_t cursorPos
&& (sortedBeforeTokens[$ - 2].type is tok!"identifier" || sortedBeforeTokens[$ - 2].type is tok!"stringLiteral")) && (sortedBeforeTokens[$ - 2].type is tok!"identifier" || sortedBeforeTokens[$ - 2].type is tok!"stringLiteral"))
{ {
// Check if it's UFCS dot completion // Check if it's UFCS dot completion
tokenCursorResult.completionContext = CompletionContext.DotCompletion; auto expressionTokens = getExpression(sortedBeforeTokens);
if(expressionTokens[0] !is sortedBeforeTokens[$ - 2]){
// If the expression is invalid as a dot token we return
return tokenCursorResult;
}
tokenCursorResult.significantToken = sortedBeforeTokens[$ - 2]; tokenCursorResult.significantToken = sortedBeforeTokens[$ - 2];
tokenCursorResult.completionContext = CompletionContext.DotCompletion;
return tokenCursorResult; return tokenCursorResult;
} }
else if (!tokenCursorResult.partialIdentifier.length) else if (!tokenCursorResult.partialIdentifier.length)
@ -212,14 +208,14 @@ DSymbol*[] getUFCSSymbolsForCursor(Scope* completionScope, scope ref const(Token
return []; return [];
} }
DeducedSymbolTypeResult deducedSymbolTypeResult = deduceSymbolTypeByToken(completionScope, tokenCursorResult.significantToken, cursorPosition); const(DSymbol)* deducedSymbolType = deduceSymbolTypeByToken(completionScope, tokenCursorResult.significantToken, cursorPosition);
if (deducedSymbolTypeResult.deducedSymbolType is null) if (deducedSymbolType is null)
{ {
return []; return [];
} }
if (deducedSymbolTypeResult.deducedSymbolType.isInvalidForUFCSCompletion) if (deducedSymbolType.isInvalidForUFCSCompletion)
{ {
trace("CursorSymbolType isn't valid for UFCS completion"); trace("CursorSymbolType isn't valid for UFCS completion");
return []; return [];
@ -227,11 +223,11 @@ DSymbol*[] getUFCSSymbolsForCursor(Scope* completionScope, scope ref const(Token
if (tokenCursorResult.completionContext == CompletionContext.ParenCompletion) if (tokenCursorResult.completionContext == CompletionContext.ParenCompletion)
{ {
return getUFCSSymbolsForParenCompletion(deducedSymbolTypeResult.deducedSymbolType, completionScope, tokenCursorResult.functionName, cursorPosition); return getUFCSSymbolsForParenCompletion(deducedSymbolType, completionScope, tokenCursorResult.functionName, cursorPosition);
} }
else else
{ {
return getUFCSSymbolsForDotCompletion(deducedSymbolTypeResult.deducedSymbolType, completionScope, cursorPosition, tokenCursorResult.partialIdentifier); return getUFCSSymbolsForDotCompletion(deducedSymbolType, completionScope, cursorPosition, tokenCursorResult.partialIdentifier);
} }
} }

View file

@ -153,3 +153,91 @@ unittest
i = skipParenReverseBefore(t, i, tok!")", tok!"("); i = skipParenReverseBefore(t, i, tok!")", tok!"(");
assert(i == 1); assert(i == 1);
} }
T getExpression(T)(T beforeTokens)
{
enum EXPRESSION_LOOP_BREAK = q{
if (i + 1 < beforeTokens.length) switch (beforeTokens[i + 1].type)
{
mixin (TYPE_IDENT_AND_LITERAL_CASES);
i++;
break expressionLoop;
default:
break;
}
};
if (beforeTokens.length == 0)
return beforeTokens[0 .. 0];
size_t i = beforeTokens.length - 1;
size_t sliceEnd = beforeTokens.length;
IdType open;
IdType close;
uint skipCount = 0;
expressionLoop: while (true)
{
switch (beforeTokens[i].type)
{
case tok!"import":
i++;
break expressionLoop;
mixin (TYPE_IDENT_AND_LITERAL_CASES);
mixin (EXPRESSION_LOOP_BREAK);
break;
case tok!".":
break;
case tok!")":
open = tok!")";
close = tok!"(";
goto skip;
case tok!"]":
open = tok!"]";
close = tok!"[";
skip:
mixin (EXPRESSION_LOOP_BREAK);
immutable bookmark = i;
i = beforeTokens.skipParenReverse(i, open, close);
skipCount++;
// check the current token after skipping parens to the left.
// if it's a loop keyword, pretend we never skipped the parens.
if (i > 0) switch (beforeTokens[i - 1].type)
{
case tok!"scope":
case tok!"if":
case tok!"while":
case tok!"for":
case tok!"foreach":
case tok!"foreach_reverse":
case tok!"do":
case tok!"cast":
case tok!"catch":
i = bookmark + 1;
break expressionLoop;
case tok!"!":
// only break if the bang is for a template instance
if (i - 2 >= 0 && beforeTokens[i - 2].type == tok!"identifier" && skipCount == 1)
{
sliceEnd = i - 1;
i -= 2;
break expressionLoop;
}
break;
default:
break;
}
break;
default:
i++;
break expressionLoop;
}
if (i == 0)
break;
else
i--;
}
return beforeTokens[i .. sliceEnd];
}

View file

@ -208,18 +208,9 @@ AutocompleteResponse dotCompletion(T)(T beforeTokens, const(Token)[] tokenArray,
switch (significantTokenType) switch (significantTokenType)
{ {
mixin(STRING_LITERAL_CASES); mixin(STRING_LITERAL_CASES);
{ foreach (symbol; arraySymbols)
foreach (symbol; arraySymbols){
response.completions ~= makeSymbolCompletionInfo(symbol, symbol.kind); response.completions ~= makeSymbolCompletionInfo(symbol, symbol.kind);
} goto case;
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); mixin(TYPE_IDENT_CASES);
case tok!")": case tok!")":
case tok!"]": case tok!"]":

View file

@ -31,6 +31,7 @@ import dparse.rollback_allocator;
import dsymbol.conversion; import dsymbol.conversion;
import dsymbol.modulecache; import dsymbol.modulecache;
import dsymbol.symbol; import dsymbol.symbol;
import dsymbol.utils;
import dcd.common.messages; import dcd.common.messages;

View file

@ -422,96 +422,6 @@ DSymbol*[] getSymbolsByTokenChain(T)(Scope* completionScope,
return symbols; return symbols;
} }
/**
*
*/
T getExpression(T)(T beforeTokens)
{
enum EXPRESSION_LOOP_BREAK = q{
if (i + 1 < beforeTokens.length) switch (beforeTokens[i + 1].type)
{
mixin (TYPE_IDENT_AND_LITERAL_CASES);
i++;
break expressionLoop;
default:
break;
}
};
if (beforeTokens.length == 0)
return beforeTokens[0 .. 0];
size_t i = beforeTokens.length - 1;
size_t sliceEnd = beforeTokens.length;
IdType open;
IdType close;
uint skipCount = 0;
expressionLoop: while (true)
{
switch (beforeTokens[i].type)
{
case tok!"import":
i++;
break expressionLoop;
mixin (TYPE_IDENT_AND_LITERAL_CASES);
mixin (EXPRESSION_LOOP_BREAK);
break;
case tok!".":
break;
case tok!")":
open = tok!")";
close = tok!"(";
goto skip;
case tok!"]":
open = tok!"]";
close = tok!"[";
skip:
mixin (EXPRESSION_LOOP_BREAK);
immutable bookmark = i;
i = beforeTokens.skipParenReverse(i, open, close);
skipCount++;
// check the current token after skipping parens to the left.
// if it's a loop keyword, pretend we never skipped the parens.
if (i > 0) switch (beforeTokens[i - 1].type)
{
case tok!"scope":
case tok!"if":
case tok!"while":
case tok!"for":
case tok!"foreach":
case tok!"foreach_reverse":
case tok!"do":
case tok!"cast":
case tok!"catch":
i = bookmark + 1;
break expressionLoop;
case tok!"!":
// only break if the bang is for a template instance
if (i - 2 >= 0 && beforeTokens[i - 2].type == tok!"identifier" && skipCount == 1)
{
sliceEnd = i - 1;
i -= 2;
break expressionLoop;
}
break;
default:
break;
}
break;
default:
i++;
break expressionLoop;
}
if (i == 0)
break;
else
i--;
}
return beforeTokens[i .. sliceEnd];
}
/** /**
* Determines if an import is selective, whole-module, or neither. * Determines if an import is selective, whole-module, or neither.
*/ */

View file

@ -8,6 +8,5 @@ mangleof k
ptr k ptr k
sizeof k sizeof k
stringof k stringof k
testUfcs F
ufcsString F ufcsString F
ufcsStringBar F ufcsStringBar F

View file

@ -1,4 +0,0 @@
identifiers
testUfcs F
ufcsString F
ufcsStringBar F

View file

@ -1,6 +1,7 @@
struct Hello { void hi(){} }
void ufcsString(string input){} void ufcsString(string input){}
void ufcsStringBar(string input){} void ufcsStringBar(string input){}
void testUfcs(string x){ void testUfcs(Hello x){
"foo". "foo".
x. x.
} }

View file

@ -1,15 +1,8 @@
set -e set -e
set -u set -u
#TEST CASE 0 ../../bin/dcd-client $1 -c127 file.d > actual_string_literal_test.txt
SOURCE_FILE_0=file.d diff actual_string_literal_test.txt expected_string_literal_test.txt --strip-trailing-cr
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 ../../bin/dcd-client $1 -c131 file.d > actual_string_test.txt
diff $ACTUAL_FILE_NAME_0 $EXPECTED_FILE_NAME_0 --strip-trailing-cr diff actual_string_test.txt expected_string_test.txt --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

View file

@ -1,4 +1,5 @@
identifiers identifiers
aliasStruct F
alignof k alignof k
fooHey f fooHey f
hasArgname F hasArgname F

View file

@ -8,7 +8,9 @@ void main()
foo. foo.
} }
void aliasStruct() { void aliasStruct(Foo f) {
auto intAliased = IntAliased(); auto intAliased = IntAliased();
intAliased. intAliased.
f.
f.
} }

View file

@ -4,5 +4,11 @@ set -u
../../bin/dcd-client $1 -c82 -I"$PWD"/fooutils file.d > actual_struct_test.txt ../../bin/dcd-client $1 -c82 -I"$PWD"/fooutils file.d > actual_struct_test.txt
diff actual_struct_test.txt expected_struct_test.txt diff actual_struct_test.txt expected_struct_test.txt
../../bin/dcd-client $1 -c152 -I"$PWD"/fooutils file.d > actual_aliased_struct_test.txt ../../bin/dcd-client $1 -c157 -I"$PWD"/fooutils file.d > actual_aliased_struct_test.txt
diff actual_aliased_struct_test.txt expected_aliased_struct_test.txt diff actual_aliased_struct_test.txt expected_aliased_struct_test.txt
../../bin/dcd-client $1 -c161 -I"$PWD"/fooutils file.d > actual_should_not_complete_test.txt
diff actual_should_not_complete_test.txt expected_should_not_complete_test.txt
../../bin/dcd-client $1 -c165 -I"$PWD"/fooutils file.d > actual_should_not_complete_test2.txt
diff actual_should_not_complete_test2.txt expected_should_not_complete_test2.txt