ufcs function chaining
This commit is contained in:
parent
c409670da8
commit
e969d2b158
|
|
@ -36,8 +36,9 @@ the issue.)
|
|||
* *auto* declarations (Mostly)
|
||||
* *with* statements
|
||||
* Simple UFCS suggestions for concrete types.
|
||||
* UFCS '.' function chaining with concrete types except string type.
|
||||
* 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
|
||||
* 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
|
||||
|
|
@ -157,6 +158,7 @@ tab character, followed by a completion kind
|
|||
resolvedType v
|
||||
calltip v
|
||||
getPartByName f
|
||||
ufcsFunction F
|
||||
|
||||
#### Extended output mode
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ import std.experimental.allocator;
|
|||
import std.experimental.allocator.gc_allocator : GCAllocator;
|
||||
import std.experimental.logger;
|
||||
import std.typecons : Rebindable;
|
||||
import std.array : appender;
|
||||
import std.range : empty;
|
||||
|
||||
/**
|
||||
* 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,
|
||||
string functionName, const Parameters parameters,
|
||||
const TemplateParameters templateParameters)
|
||||
{
|
||||
setFunctionReturnType(returnType, *symbol.acSymbol);
|
||||
processTemplateParameters(symbol, templateParameters);
|
||||
if (parameters !is null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -386,6 +386,12 @@ struct DSymbol
|
|||
*/
|
||||
DSymbol*[] functionParameters;
|
||||
|
||||
/**
|
||||
*
|
||||
* Return type of the function
|
||||
*/
|
||||
DSymbol* functionReturnType;
|
||||
|
||||
private uint _location;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -558,8 +558,10 @@ void setCompletions(T)(ref AutocompleteResponse response,
|
|||
DSymbol*[] symbols = getSymbolsByTokenChain(completionScope, tokens,
|
||||
cursorPosition, completionType);
|
||||
|
||||
if (symbols.length == 0)
|
||||
if (symbols.length == 0){
|
||||
lookupUFCSForDotChaining(completionScope, tokens, cursorPosition, response);
|
||||
return;
|
||||
}
|
||||
|
||||
if (completionType == CompletionType.identifiers)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,11 +14,15 @@ import dparse.lexer : tok;
|
|||
import std.regex;
|
||||
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);
|
||||
if (ufcsSymbols.empty)
|
||||
return false;
|
||||
response.completions ~= map!(s => createCompletionForUFCS(s))(ufcsSymbols).array;
|
||||
return true;
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
ufcsBarReturnScope F
|
||||
ufcsBarScope F
|
||||
ufcsGetNumber 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;
|
||||
|
||||
void hasArgname(Foo f){
|
||||
|
|
@ -7,4 +6,9 @@ void main()
|
|||
{
|
||||
auto 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) {}
|
||||
Foo ufcsSelf(ref Foo foo) { return foo; }
|
||||
int ufcsGetNumber(ref Foo foo, int number) { return number; }
|
||||
void ufcsHello(ref Foo foo) {}
|
||||
void ufcsBar(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 ufcsBarReturnScope(return scope Foo foo, string mama) {}
|
||||
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 -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 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