diff --git a/dsymbol/src/dsymbol/builtin/symbols.d b/dsymbol/src/dsymbol/builtin/symbols.d index ac1dd7b..85de956 100644 --- a/dsymbol/src/dsymbol/builtin/symbols.d +++ b/dsymbol/src/dsymbol/builtin/symbols.d @@ -45,6 +45,10 @@ TTree!(DSymbol*, SymbolsAllocator, true, "a < b") enumSymbols; */ TTree!(DSymbol*, SymbolsAllocator, true, "a < b") pointerSymbols; +/** + * Templated properties + */ +TTree!(DSymbol*, SymbolsAllocator, true, "a < b") templatedSymbols; /** * Variadic template parameters properties */ diff --git a/dsymbol/src/dsymbol/conversion/first.d b/dsymbol/src/dsymbol/conversion/first.d index 1ed1aad..048706e 100644 --- a/dsymbol/src/dsymbol/conversion/first.d +++ b/dsymbol/src/dsymbol/conversion/first.d @@ -1041,6 +1041,7 @@ private: continue; SemanticSymbol* templateParameter = allocateSemanticSymbol(name, kind, symbolFile, index); + symbol.acSymbol.qualifier = SymbolQualifier.templated; if (type !is null) addTypeToLookups(templateParameter.typeLookups, type); diff --git a/dsymbol/src/dsymbol/conversion/second.d b/dsymbol/src/dsymbol/conversion/second.d index e6b1d4b..5eb2f97 100644 --- a/dsymbol/src/dsymbol/conversion/second.d +++ b/dsymbol/src/dsymbol/conversion/second.d @@ -203,6 +203,7 @@ do case SymbolQualifier.array: lastSuffix.addChildren(arraySymbols[], false); break; case SymbolQualifier.assocArray: lastSuffix.addChildren(assocArraySymbols[], false); break; case SymbolQualifier.pointer: lastSuffix.addChildren(pointerSymbols[], false); break; + case SymbolQualifier.templated: lastSuffix.addChildren(templatedSymbols[], false); break; } if (suffix is null) diff --git a/dsymbol/src/dsymbol/symbol.d b/dsymbol/src/dsymbol/symbol.d index 3d740c7..c937b1d 100644 --- a/dsymbol/src/dsymbol/symbol.d +++ b/dsymbol/src/dsymbol/symbol.d @@ -133,6 +133,8 @@ enum SymbolQualifier : ubyte selectiveImport, /// The symbol is a pointer pointer, + /// The symbol is templated + templated, } /** diff --git a/src/dcd/server/autocomplete/complete.d b/src/dcd/server/autocomplete/complete.d index e5363c0..d5ec822 100644 --- a/src/dcd/server/autocomplete/complete.d +++ b/src/dcd/server/autocomplete/complete.d @@ -47,6 +47,11 @@ import dsymbol.utils; import dcd.common.constants; import dcd.common.messages; +enum CompletionToken { + none, + bracket, bang +} + /** * Handles autocompletion * Params: @@ -134,9 +139,13 @@ public AutocompleteResponse complete(const AutocompleteRequest request, || beforeTokens[$ - 1] == tok!",") { immutable size_t end = goBackToOpenParen(beforeTokens); - if (end != size_t.max) - return parenCompletion(beforeTokens[0 .. end], tokenArray, + if (end != size_t.max) { + return callTipCompletion(beforeTokens[0 .. end], tokenArray, request.cursorPosition, moduleCache); + } + } + else if (beforeTokens[$ - 1] == tok!"!"){ // Bang completion + return callTipCompletion(beforeTokens, tokenArray, request.cursorPosition, moduleCache); } else { @@ -218,7 +227,7 @@ AutocompleteResponse dotCompletion(T)(T beforeTokens, const(Token)[] tokenArray, ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, &rba, cursorPosition, moduleCache); scope(exit) pair.destroy(); response.setCompletions(pair.scope_, getExpression(beforeTokens), - cursorPosition, CompletionType.identifiers, false, partial); + cursorPosition, CompletionType.identifiers, CompletionToken.none, partial); 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. @@ -237,7 +246,7 @@ AutocompleteResponse dotCompletion(T)(T beforeTokens, const(Token)[] tokenArray, ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, &rba, 1, moduleCache); scope(exit) pair.destroy(); response.setCompletions(pair.scope_, getExpression(beforeTokens), - 1, CompletionType.identifiers, false, partial); + 1, CompletionType.identifiers, CompletionToken.none, partial); break; default: break; @@ -246,7 +255,7 @@ AutocompleteResponse dotCompletion(T)(T beforeTokens, const(Token)[] tokenArray, } /** - * Handles paren completion for function calls and some keywords + * Handles calltip completion for function calls and some keywords * Params: * beforeTokens = the tokens before the cursor * tokenArray = all tokens in the file @@ -254,7 +263,7 @@ AutocompleteResponse dotCompletion(T)(T beforeTokens, const(Token)[] tokenArray, * Returns: * the autocompletion response */ -AutocompleteResponse parenCompletion(T)(T beforeTokens, +AutocompleteResponse callTipCompletion(T)(T beforeTokens, const(Token)[] tokenArray, size_t cursorPosition, ref ModuleCache moduleCache) { AutocompleteResponse response; @@ -309,7 +318,7 @@ AutocompleteResponse parenCompletion(T)(T beforeTokens, scope(exit) pair.destroy(); auto expression = getExpression(beforeTokens[0 .. $ - 1]); response.setCompletions(pair.scope_, expression, - cursorPosition, CompletionType.calltips, beforeTokens[$ - 1] == tok!"["); + cursorPosition, CompletionType.calltips, getCompletionToken(beforeTokens)); 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. @@ -322,6 +331,18 @@ AutocompleteResponse parenCompletion(T)(T beforeTokens, return response; } +CompletionToken getCompletionToken(T)(T beforeTokens) { + if(beforeTokens[$ - 1] == tok!"["){ + return CompletionToken.bracket; + } + + if(beforeTokens[$ - 1] == tok!"!"){ + return CompletionToken.bang; + } + + return CompletionToken.none; +} + /** * Provides autocomplete for selective imports, e.g.: * --- @@ -505,7 +526,7 @@ void setImportCompletions(T)(T tokens, ref AutocompleteResponse response, */ void setCompletions(T)(ref AutocompleteResponse response, Scope* completionScope, T tokens, size_t cursorPosition, - CompletionType completionType, bool isBracket = false, string partial = null) + CompletionType completionType, CompletionToken completionToken = CompletionToken.none, string partial = null) { static void addSymToResponse(const(DSymbol)* s, ref AutocompleteResponse r, string p, Scope* completionScope, size_t[] circularGuard = []) @@ -567,6 +588,11 @@ void setCompletions(T)(ref AutocompleteResponse response, DSymbol*[] symbols = getSymbolsByTokenChain(completionScope, tokens, cursorPosition, completionType); + // If bang completion we check if symbol is also templated + if (completionToken == CompletionToken.bang && symbols.length >= 1 && symbols[0].qualifier != SymbolQualifier.templated){ + return; + } + if (symbols.length == 0) return; @@ -607,7 +633,7 @@ void setCompletions(T)(ref AutocompleteResponse response, symbols = [dumb]; goto setCallTips; } - if (isBracket) + if (completionToken == CompletionToken.bracket) { auto index = dumb.getPartsByName(internString("opIndex")); if (index.length > 0) diff --git a/tests/tc_template_bang_completion/expected.txt b/tests/tc_template_bang_completion/expected.txt new file mode 100644 index 0000000..fe294ca --- /dev/null +++ b/tests/tc_template_bang_completion/expected.txt @@ -0,0 +1,2 @@ +calltips +this(T data) diff --git a/tests/tc_template_bang_completion/expected2.txt b/tests/tc_template_bang_completion/expected2.txt new file mode 100644 index 0000000..9f550bd --- /dev/null +++ b/tests/tc_template_bang_completion/expected2.txt @@ -0,0 +1,2 @@ +calltips +this(T foo, X bar) diff --git a/tests/tc_template_bang_completion/expected3.txt b/tests/tc_template_bang_completion/expected3.txt new file mode 100644 index 0000000..ceaf74f --- /dev/null +++ b/tests/tc_template_bang_completion/expected3.txt @@ -0,0 +1,2 @@ +calltips +void doSomething(T)(T someElement) diff --git a/tests/tc_template_bang_completion/file.d b/tests/tc_template_bang_completion/file.d new file mode 100644 index 0000000..3d19184 --- /dev/null +++ b/tests/tc_template_bang_completion/file.d @@ -0,0 +1,23 @@ +struct Wrapper(T) { + T data; +} + +class Something(T, X){ + this(T foo, X bar){} +} + +void doSomething(T)(T someElement){ + +} + +void instantiateTemp1() { + Wrapper! +} + +void instantiateTemp2() { + Something! +} + +void instantiateTemp3() { + doSomething! +} diff --git a/tests/tc_template_bang_completion/run.sh b/tests/tc_template_bang_completion/run.sh new file mode 100755 index 0000000..82d4629 --- /dev/null +++ b/tests/tc_template_bang_completion/run.sh @@ -0,0 +1,11 @@ +set -e +set -u + +../../bin/dcd-client $1 file.d -c155 > actual.txt +diff actual.txt expected.txt --strip-trailing-cr + +../../bin/dcd-client $1 file.d -c196 > actual2.txt +diff actual2.txt expected2.txt --strip-trailing-cr + +../../bin/dcd-client $1 file.d -c239 > actual3.txt +diff actual3.txt expected3.txt --strip-trailing-cr