mirror of
https://github.com/dlang-community/DCD.git
synced 2025-05-07 11:15:51 +03:00
PR changes
This commit is contained in:
parent
9e4c70ce15
commit
218d047760
14 changed files with 125 additions and 141 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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!"]":
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
identifiers
|
|
||||||
testUfcs F
|
|
||||||
ufcsString F
|
|
||||||
ufcsStringBar F
|
|
|
@ -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.
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
|
@ -1,4 +1,5 @@
|
||||||
identifiers
|
identifiers
|
||||||
|
aliasStruct F
|
||||||
alignof k
|
alignof k
|
||||||
fooHey f
|
fooHey f
|
||||||
hasArgname F
|
hasArgname F
|
||||||
|
|
|
@ -8,7 +8,9 @@ void main()
|
||||||
foo.
|
foo.
|
||||||
}
|
}
|
||||||
|
|
||||||
void aliasStruct() {
|
void aliasStruct(Foo f) {
|
||||||
auto intAliased = IntAliased();
|
auto intAliased = IntAliased();
|
||||||
intAliased.
|
intAliased.
|
||||||
|
f.
|
||||||
|
f.
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue