ufcs function chaining
This commit is contained in:
parent
c409670da8
commit
e969d2b158
|
|
@ -36,8 +36,9 @@ the issue.)
|
||||||
* *auto* declarations (Mostly)
|
* *auto* declarations (Mostly)
|
||||||
* *with* statements
|
* *with* statements
|
||||||
* Simple UFCS suggestions for concrete types.
|
* Simple UFCS suggestions for concrete types.
|
||||||
|
* UFCS '.' function chaining with concrete types except string type.
|
||||||
* Not working:
|
* Not working:
|
||||||
* UFCS completion for templates, literals, UFCS function arguments, and '.' chaining with other UFCS functions.
|
* UFCS completion for templates, literals, UFCS function arguments.
|
||||||
* UFCS calltips
|
* UFCS calltips
|
||||||
* Autocompletion of declarations with template arguments (This will work to some extent, but it won't do things like replace T with int)
|
* Autocompletion of declarations with template arguments (This will work to some extent, but it won't do things like replace T with int)
|
||||||
* Determining the type of an enum member when no base type is specified, but the first member has an initializer
|
* Determining the type of an enum member when no base type is specified, but the first member has an initializer
|
||||||
|
|
@ -157,6 +158,7 @@ tab character, followed by a completion kind
|
||||||
resolvedType v
|
resolvedType v
|
||||||
calltip v
|
calltip v
|
||||||
getPartByName f
|
getPartByName f
|
||||||
|
ufcsFunction F
|
||||||
|
|
||||||
#### Extended output mode
|
#### Extended output mode
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,8 @@ import std.experimental.allocator;
|
||||||
import std.experimental.allocator.gc_allocator : GCAllocator;
|
import std.experimental.allocator.gc_allocator : GCAllocator;
|
||||||
import std.experimental.logger;
|
import std.experimental.logger;
|
||||||
import std.typecons : Rebindable;
|
import std.typecons : Rebindable;
|
||||||
|
import std.array : appender;
|
||||||
|
import std.range : empty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* First Pass handles the following:
|
* First Pass handles the following:
|
||||||
|
|
@ -944,10 +946,23 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setFunctionReturnType(const Type returnType, ref DSymbol acSymbol){
|
||||||
|
if (returnType !is null)
|
||||||
|
{
|
||||||
|
auto app = appender!string();
|
||||||
|
app.formatNode(returnType);
|
||||||
|
auto foundSymbols = currentScope.getSymbolsByName(istring(app.data));
|
||||||
|
if (!foundSymbols.empty){
|
||||||
|
acSymbol.functionReturnType = foundSymbols[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void processParameters(SemanticSymbol* symbol, const Type returnType,
|
void processParameters(SemanticSymbol* symbol, const Type returnType,
|
||||||
string functionName, const Parameters parameters,
|
string functionName, const Parameters parameters,
|
||||||
const TemplateParameters templateParameters)
|
const TemplateParameters templateParameters)
|
||||||
{
|
{
|
||||||
|
setFunctionReturnType(returnType, *symbol.acSymbol);
|
||||||
processTemplateParameters(symbol, templateParameters);
|
processTemplateParameters(symbol, templateParameters);
|
||||||
if (parameters !is null)
|
if (parameters !is null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -386,6 +386,12 @@ struct DSymbol
|
||||||
*/
|
*/
|
||||||
DSymbol*[] functionParameters;
|
DSymbol*[] functionParameters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Return type of the function
|
||||||
|
*/
|
||||||
|
DSymbol* functionReturnType;
|
||||||
|
|
||||||
private uint _location;
|
private uint _location;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -558,8 +558,10 @@ void setCompletions(T)(ref AutocompleteResponse response,
|
||||||
DSymbol*[] symbols = getSymbolsByTokenChain(completionScope, tokens,
|
DSymbol*[] symbols = getSymbolsByTokenChain(completionScope, tokens,
|
||||||
cursorPosition, completionType);
|
cursorPosition, completionType);
|
||||||
|
|
||||||
if (symbols.length == 0)
|
if (symbols.length == 0){
|
||||||
|
lookupUFCSForDotChaining(completionScope, tokens, cursorPosition, response);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (completionType == CompletionType.identifiers)
|
if (completionType == CompletionType.identifiers)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,15 @@ import dparse.lexer : tok;
|
||||||
import std.regex;
|
import std.regex;
|
||||||
import containers.hashset : HashSet;
|
import containers.hashset : HashSet;
|
||||||
|
|
||||||
void lookupUFCS(Scope* completionScope, DSymbol* beforeDotSymbol, size_t cursorPosition, ref AutocompleteResponse response)
|
bool lookupUFCS(Scope* completionScope, DSymbol* beforeDotSymbol, size_t cursorPosition, ref AutocompleteResponse response)
|
||||||
{
|
{
|
||||||
// UFCS completion
|
if (beforeDotSymbol.isInvalidForUFCSCompletion)
|
||||||
|
return false;
|
||||||
DSymbol*[] ufcsSymbols = getSymbolsForUFCS(completionScope, beforeDotSymbol, cursorPosition);
|
DSymbol*[] ufcsSymbols = getSymbolsForUFCS(completionScope, beforeDotSymbol, cursorPosition);
|
||||||
|
if (ufcsSymbols.empty)
|
||||||
|
return false;
|
||||||
response.completions ~= map!(s => createCompletionForUFCS(s))(ufcsSymbols).array;
|
response.completions ~= map!(s => createCompletionForUFCS(s))(ufcsSymbols).array;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutocompleteResponse.Completion createCompletionForUFCS(const DSymbol* symbol)
|
AutocompleteResponse.Completion createCompletionForUFCS(const DSymbol* symbol)
|
||||||
|
|
@ -169,3 +173,32 @@ bool doUFCSSearch(string beforeToken, string lastToken)
|
||||||
// we do the search if they are different from eachother
|
// we do the search if they are different from eachother
|
||||||
return beforeToken != lastToken;
|
return beforeToken != lastToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lookupUFCSForDotChaining(T)(Scope* completionScope, ref T tokens, size_t cursorPosition, ref AutocompleteResponse response)
|
||||||
|
{
|
||||||
|
auto filteredTokens = filter!(t => !t.text.empty)(tokens);
|
||||||
|
|
||||||
|
if (filteredTokens.empty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto foundTokens = filteredTokens.array;
|
||||||
|
auto possibleUFCSSymbols = completionScope.getSymbolsByNameAndCursor(istring(null), cursorPosition);
|
||||||
|
for (auto i = foundTokens.length; i > 0; i--)
|
||||||
|
{
|
||||||
|
// Finding function return value type
|
||||||
|
auto foundSymbols = filter!(s => s.name == foundTokens[i - 1].text && s.kind == CompletionKind
|
||||||
|
.functionName)(possibleUFCSSymbols);
|
||||||
|
if (!foundSymbols.empty)
|
||||||
|
{
|
||||||
|
auto foundFunctionSymbol = foundSymbols.array.back;
|
||||||
|
if (foundFunctionSymbol.functionReturnType)
|
||||||
|
{
|
||||||
|
if (lookupUFCS(completionScope, foundFunctionSymbol.functionReturnType, cursorPosition, response))
|
||||||
|
{
|
||||||
|
response.completionType = CompletionType.identifiers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,4 +15,6 @@ ufcsBarRefConstWrapped F
|
||||||
ufcsBarRefImmuttableWrapped F
|
ufcsBarRefImmuttableWrapped F
|
||||||
ufcsBarReturnScope F
|
ufcsBarReturnScope F
|
||||||
ufcsBarScope F
|
ufcsBarScope F
|
||||||
|
ufcsGetNumber F
|
||||||
ufcsHello F
|
ufcsHello F
|
||||||
|
ufcsSelf F
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
identifiers
|
||||||
|
hasArgname F
|
||||||
|
u F
|
||||||
|
ufcsBar F
|
||||||
|
ufcsBarRef F
|
||||||
|
ufcsBarRefConst F
|
||||||
|
ufcsBarRefConstWrapped F
|
||||||
|
ufcsBarRefImmuttableWrapped F
|
||||||
|
ufcsBarReturnScope F
|
||||||
|
ufcsBarScope F
|
||||||
|
ufcsGetNumber F
|
||||||
|
ufcsHello F
|
||||||
|
ufcsSelf F
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
identifiers
|
||||||
|
helloNumber F
|
||||||
|
isEvenNumber F
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
identifiers
|
||||||
|
getBoolToFloat F
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
identifiers
|
||||||
|
multiply1000 F
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
identifiers
|
||||||
|
helloNumber F
|
||||||
|
isEvenNumber F
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
//import foodata;
|
|
||||||
import fooutils;
|
import fooutils;
|
||||||
|
|
||||||
void hasArgname(Foo f){
|
void hasArgname(Foo f){
|
||||||
|
|
@ -7,4 +6,9 @@ void main()
|
||||||
{
|
{
|
||||||
auto foo = Foo();
|
auto foo = Foo();
|
||||||
foo.
|
foo.
|
||||||
|
foo.ufcsSelf.
|
||||||
|
foo.ufcsSelf.ufcsGetNumber(42).
|
||||||
|
foo.ufcsSelf.ufcsGetNumber(42).isEvenNumber.
|
||||||
|
foo.ufcsSelf.ufcsGetNumber(42).isEvenNumber.getBoolToFloat.
|
||||||
|
foo.ufcsSelf.ufcsGetNumber(42).isEvenNumber.getBoolToFloat.multiply1000.
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ struct Foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
void u(Foo foo) {}
|
void u(Foo foo) {}
|
||||||
|
Foo ufcsSelf(ref Foo foo) { return foo; }
|
||||||
|
int ufcsGetNumber(ref Foo foo, int number) { return number; }
|
||||||
void ufcsHello(ref Foo foo) {}
|
void ufcsHello(ref Foo foo) {}
|
||||||
void ufcsBar(Foo foo, string mama) {}
|
void ufcsBar(Foo foo, string mama) {}
|
||||||
void ufcsBarRef(ref Foo foo, string mama) {}
|
void ufcsBarRef(ref Foo foo, string mama) {}
|
||||||
|
|
@ -14,4 +16,7 @@ void ufcsBarRefImmuttableWrapped(ref immutable(Foo) foo, string mama) {}
|
||||||
void ufcsBarScope(ref scope Foo foo, string mama) {}
|
void ufcsBarScope(ref scope Foo foo, string mama) {}
|
||||||
void ufcsBarReturnScope(return scope Foo foo, string mama) {}
|
void ufcsBarReturnScope(return scope Foo foo, string mama) {}
|
||||||
private void ufcsBarPrivate(Foo foo, string message) {}
|
private void ufcsBarPrivate(Foo foo, string message) {}
|
||||||
void helloBar(string message) {}
|
void helloNumber(int message) {}
|
||||||
|
bool isEvenNumber(int number) { return number % 2 == 0; }
|
||||||
|
float getBoolToFloat(bool result) { return result ? 1.0 : 0.0; }
|
||||||
|
int multiply1000(float x) { return x * 1000; }
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,15 @@
|
||||||
set -e
|
set -e
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
../../bin/dcd-client $1 -c100 -I"$PWD"/fooutils file.d > actual.txt
|
../../bin/dcd-client $1 -c82 -I"$PWD"/fooutils file.d > actual.txt
|
||||||
|
../../bin/dcd-client $1 -c97 -I"$PWD"/fooutils file.d > actual2.txt
|
||||||
|
../../bin/dcd-client $1 -c130 -I"$PWD"/fooutils file.d > actual3.txt
|
||||||
|
../../bin/dcd-client $1 -c176 -I"$PWD"/fooutils file.d > actual4.txt
|
||||||
|
../../bin/dcd-client $1 -c237 -I"$PWD"/fooutils file.d > actual5.txt
|
||||||
|
../../bin/dcd-client $1 -c311 -I"$PWD"/fooutils file.d > actual6.txt
|
||||||
diff actual.txt expected.txt
|
diff actual.txt expected.txt
|
||||||
|
diff actual2.txt expected2.txt
|
||||||
|
diff actual3.txt expected3.txt
|
||||||
|
diff actual4.txt expected4.txt
|
||||||
|
diff actual5.txt expected5.txt
|
||||||
|
diff actual6.txt expected6.txt
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue