From 70061aee2ea2c86c34c5adfaf53a803f5cbf3200 Mon Sep 17 00:00:00 2001 From: ryuukk Date: Sat, 29 Jul 2023 18:36:00 +0200 Subject: [PATCH 01/21] Fix deprecation warning --- common/src/dcd/common/messages.d | 55 +++++++++++++++++--------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/common/src/dcd/common/messages.d b/common/src/dcd/common/messages.d index e0e7a8f..f5958bc 100644 --- a/common/src/dcd/common/messages.d +++ b/common/src/dcd/common/messages.d @@ -260,36 +260,39 @@ AutocompleteResponse getResponse(Socket socket) */ bool serverIsRunning(bool useTCP, string socketFile, ushort port) { - scope (failure) - return false; - AutocompleteRequest request; - request.kind = RequestKind.query; - Socket socket; - scope (exit) - { - socket.shutdown(SocketShutdown.BOTH); - socket.close(); - } - version(Windows) useTCP = true; - if (useTCP) - { - socket = new TcpSocket(AddressFamily.INET); - socket.connect(new InternetAddress("localhost", port)); - } - else - { - version(Windows) {} else + try { + AutocompleteRequest request; + request.kind = RequestKind.query; + Socket socket; + scope (exit) { - socket = new Socket(AddressFamily.UNIX, SocketType.STREAM); - socket.connect(new UnixAddress(socketFile)); + socket.shutdown(SocketShutdown.BOTH); + socket.close(); } + version(Windows) useTCP = true; + if (useTCP) + { + socket = new TcpSocket(AddressFamily.INET); + socket.connect(new InternetAddress("localhost", port)); + } + else + { + version(Windows) {} else + { + socket = new Socket(AddressFamily.UNIX, SocketType.STREAM); + socket.connect(new UnixAddress(socketFile)); + } + } + socket.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(5)); + socket.blocking = true; + if (sendRequest(socket, request)) + return getResponse(socket).completionType == "ack"; + else + return false; } - socket.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(5)); - socket.blocking = true; - if (sendRequest(socket, request)) - return getResponse(socket).completionType == "ack"; - else + catch (Exception _) { return false; + } } /// Escapes \n, \t and \ in the string. If `single` is true \t won't be escaped. From 0dd4c7898584c5e217af9d65a66787747c37af22 Mon Sep 17 00:00:00 2001 From: ryuukk Date: Sat, 29 Jul 2023 18:59:23 +0200 Subject: [PATCH 02/21] Use latest version of msgpack-d to get rid of deprecate warning --- msgpack-d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msgpack-d b/msgpack-d index 480f3bf..26ef07e 160000 --- a/msgpack-d +++ b/msgpack-d @@ -1 +1 @@ -Subproject commit 480f3bf9ee80ccf6695ed900cfcc1850ba8da991 +Subproject commit 26ef07e16023483ad93e3f86374b19d0e541c924 From 2e84d9d76a86c3561216de92e75af90b798ee6e6 Mon Sep 17 00:00:00 2001 From: ryuukk <44361234+ryuukk@users.noreply.github.com> Date: Sun, 13 Aug 2023 01:56:46 +0200 Subject: [PATCH 03/21] Ensure type is not null for symbols not yet fully resolved --- dsymbol/src/dsymbol/symbol.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsymbol/src/dsymbol/symbol.d b/dsymbol/src/dsymbol/symbol.d index c70be9e..6b506a2 100644 --- a/dsymbol/src/dsymbol/symbol.d +++ b/dsymbol/src/dsymbol/symbol.d @@ -234,7 +234,7 @@ struct DSymbol // pointers are implicitly dereferenced on members (a single layer) if (qualifier == SymbolQualifier.pointer - && this.type.qualifier != SymbolQualifier.pointer) + && (this.type && this.type.qualifier != SymbolQualifier.pointer)) return type.getParts!OR(name, app, visited, onlyOne); if (name is null) From 60ccfd520e7b9253ae9b232bf802a0ec0858c83c Mon Sep 17 00:00:00 2001 From: brianush1 Date: Sat, 15 Jul 2023 21:07:31 +0300 Subject: [PATCH 04/21] fix parameters in constructors being treated as fields --- dsymbol/src/dsymbol/conversion/first.d | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dsymbol/src/dsymbol/conversion/first.d b/dsymbol/src/dsymbol/conversion/first.d index c9ac1b6..e56a523 100644 --- a/dsymbol/src/dsymbol/conversion/first.d +++ b/dsymbol/src/dsymbol/conversion/first.d @@ -908,7 +908,6 @@ private: CompletionKind.functionName, symbolFile, location); symbol.parent = currentSymbol; currentSymbol.addChild(symbol, true); - processParameters(symbol, null, THIS_SYMBOL_NAME, parameters, templateParameters); symbol.acSymbol.protection = protection.current; symbol.acSymbol.doc = makeDocumentation(doc); @@ -921,9 +920,16 @@ private: pushFunctionScope(functionBody, location + 4); // 4 == "this".length scope(exit) popScope(); currentSymbol = symbol; + processParameters(symbol, null, THIS_SYMBOL_NAME, parameters, templateParameters); functionBody.accept(this); currentSymbol = currentSymbol.parent; } + else + { + currentSymbol = symbol; + processParameters(symbol, null, THIS_SYMBOL_NAME, parameters, templateParameters); + currentSymbol = currentSymbol.parent; + } } void visitDestructor(size_t location, const FunctionBody functionBody, string doc) From 8a693954d31c09fdfea3887b9bc75a6b66cfe9e7 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Fri, 11 Aug 2023 16:42:29 +0200 Subject: [PATCH 05/21] add test for ctors not tainting fields --- tests/tc_ctors/expected.txt | 3 +++ tests/tc_ctors/file.d | 19 +++++++++++++++++++ tests/tc_ctors/run.sh | 8 ++++++++ 3 files changed, 30 insertions(+) create mode 100644 tests/tc_ctors/expected.txt create mode 100644 tests/tc_ctors/file.d create mode 100755 tests/tc_ctors/run.sh diff --git a/tests/tc_ctors/expected.txt b/tests/tc_ctors/expected.txt new file mode 100644 index 0000000..a68b5ef --- /dev/null +++ b/tests/tc_ctors/expected.txt @@ -0,0 +1,3 @@ +identifiers +mangleof k +member1 v diff --git a/tests/tc_ctors/file.d b/tests/tc_ctors/file.d new file mode 100644 index 0000000..3679e23 --- /dev/null +++ b/tests/tc_ctors/file.d @@ -0,0 +1,19 @@ +struct Foo { + this(int mCtor) {} + int member1; +} + +class Bar { + this(int mCtor) {} + int member1; +} + +unittest { + Foo f; + f.m +} + +unittest { + Bar b = new Bar(1); + b.m +} \ No newline at end of file diff --git a/tests/tc_ctors/run.sh b/tests/tc_ctors/run.sh new file mode 100755 index 0000000..4afdf99 --- /dev/null +++ b/tests/tc_ctors/run.sh @@ -0,0 +1,8 @@ +set -e +set -u + +../../bin/dcd-client $1 file.d -c122 > actual.txt +diff actual.txt expected.txt --strip-trailing-cr + +../../bin/dcd-client $1 file.d -c162 > actual.txt +diff actual.txt expected.txt --strip-trailing-cr From dc11cf704d881d340ee2a0b36f212e1ecbe1042d Mon Sep 17 00:00:00 2001 From: drpriver Date: Sat, 30 Sep 2023 16:54:09 -0700 Subject: [PATCH 06/21] Fix out of bounds access in complete.d when there is no paren. (#754) --- src/dcd/server/autocomplete/complete.d | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/dcd/server/autocomplete/complete.d b/src/dcd/server/autocomplete/complete.d index cf3825c..6622890 100644 --- a/src/dcd/server/autocomplete/complete.d +++ b/src/dcd/server/autocomplete/complete.d @@ -361,7 +361,12 @@ CalltipHint getCalltipHint(T)(T beforeTokens, out size_t parenIndex) // evaluate at comma case if (beforeTokens.isComma) { - parenIndex = beforeTokens.goBackToOpenParen; + size_t tmp = beforeTokens.goBackToOpenParen; + if(tmp == size_t.max){ + return CalltipHint.regularArguments; + } + parenIndex = tmp; + // check if we are actually a "!(" if (beforeTokens[0 .. parenIndex].isTemplateBangParen) { From f15ca10acfcde7dcce60acaab39b13ffcaa50eac Mon Sep 17 00:00:00 2001 From: imrying Date: Tue, 7 Nov 2023 08:29:47 +0100 Subject: [PATCH 07/21] fix(env): change the environment to be /usr/bin/env bash --- makefile | 2 +- tests/extra/tc_ufcs_all_kinds/run.sh | 2 +- tests/run_tests.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/makefile b/makefile index 74c0b57..90e0587 100644 --- a/makefile +++ b/makefile @@ -13,7 +13,7 @@ LDC := ldc2 DPARSE_DIR := libdparse DSYMBOL_DIR := dsymbol -SHELL:=/bin/bash +SHELL:=/usr/bin/env bash githash: @mkdir -p bin diff --git a/tests/extra/tc_ufcs_all_kinds/run.sh b/tests/extra/tc_ufcs_all_kinds/run.sh index 4c548a4..2c5e79c 100755 --- a/tests/extra/tc_ufcs_all_kinds/run.sh +++ b/tests/extra/tc_ufcs_all_kinds/run.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if [ -z "${DC:-}" ]; then DC=dmd diff --git a/tests/run_tests.sh b/tests/run_tests.sh index aa64ce8..1d4b62b 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -1,4 +1,4 @@ -#! /bin/bash +#! /usr/bin/env bash RED="\033[31m" GREEN="\033[32m" YELLOW="\033[33m" From 5244f8136736eee3f7b6d9433754c6cce7f88e31 Mon Sep 17 00:00:00 2001 From: ryuukk <44361234+ryuukk@users.noreply.github.com> Date: Tue, 14 Nov 2023 14:59:08 +0100 Subject: [PATCH 08/21] Add support for extended output when requesting symbol's documentation (#757) --- src/dcd/client/client.d | 12 ++++++++---- src/dcd/server/autocomplete/doc.d | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/dcd/client/client.d b/src/dcd/client/client.d index e0be61d..bd619d9 100644 --- a/src/dcd/client/client.d +++ b/src/dcd/client/client.d @@ -250,7 +250,7 @@ int runClient(string[] args) else if (getIdentifier) printIdentifierResponse(response); else if (doc) - printDocResponse(response); + printDocResponse(response, fullOutput); else if (search !is null) printSearchResponse(response); else if (localUse) @@ -359,10 +359,14 @@ Socket createSocket(string socketFile, ushort port) return socket; } -void printDocResponse(ref const AutocompleteResponse response) +void printDocResponse(ref const AutocompleteResponse response, bool extended) { - import std.algorithm : each; - response.completions.each!(a => a.documentation.escapeConsoleOutputString(true).writeln); + foreach (ref completion; response.completions) + { + if (extended) + writeln(completion.definition); + writeln(completion.documentation.escapeConsoleOutputString(true)); + } } void printIdentifierResponse(ref const AutocompleteResponse response) diff --git a/src/dcd/server/autocomplete/doc.d b/src/dcd/server/autocomplete/doc.d index 060ba30..c3dbc1d 100644 --- a/src/dcd/server/autocomplete/doc.d +++ b/src/dcd/server/autocomplete/doc.d @@ -62,7 +62,7 @@ public AutocompleteResponse getDoc(const AutocompleteRequest request, continue; firstSymbol = false; - AutocompleteResponse.Completion c; + AutocompleteResponse.Completion c = makeSymbolCompletionInfo(symbol, symbol.kind); c.documentation = symbol.doc; response.completions ~= c; } From 09f4e7e932c9568ea1585982116bac6145c326bd Mon Sep 17 00:00:00 2001 From: ryuukk <44361234+ryuukk@users.noreply.github.com> Date: Tue, 14 Nov 2023 14:27:10 +0100 Subject: [PATCH 09/21] Add proper symbol qualifier to function symbols --- dsymbol/src/dsymbol/conversion/first.d | 1 + 1 file changed, 1 insertion(+) diff --git a/dsymbol/src/dsymbol/conversion/first.d b/dsymbol/src/dsymbol/conversion/first.d index e56a523..a211469 100644 --- a/dsymbol/src/dsymbol/conversion/first.d +++ b/dsymbol/src/dsymbol/conversion/first.d @@ -131,6 +131,7 @@ final class FirstPass : ASTVisitor scope (exit) popSymbol(); currentSymbol.acSymbol.protection = protection.current; currentSymbol.acSymbol.doc = makeDocumentation(dec.comment); + currentSymbol.acSymbol.qualifier = SymbolQualifier.func; istring lastComment = this.lastComment; this.lastComment = istring.init; From 6d635923f75b07bf920bba0ce37acaa16b8a1a4f Mon Sep 17 00:00:00 2001 From: ryuukk <44361234+ryuukk@users.noreply.github.com> Date: Wed, 22 Nov 2023 21:45:23 +0100 Subject: [PATCH 10/21] Save memory by removing argNames from DSymbol (#763) --- dsymbol/src/dsymbol/conversion/first.d | 1 - dsymbol/src/dsymbol/symbol.d | 5 ----- 2 files changed, 6 deletions(-) diff --git a/dsymbol/src/dsymbol/conversion/first.d b/dsymbol/src/dsymbol/conversion/first.d index a211469..8ba1d6d 100644 --- a/dsymbol/src/dsymbol/conversion/first.d +++ b/dsymbol/src/dsymbol/conversion/first.d @@ -1006,7 +1006,6 @@ private: break; } } - currentSymbol.acSymbol.argNames.insert(parameter.acSymbol.name); currentSymbol.acSymbol.functionParameters ~= parameter.acSymbol; diff --git a/dsymbol/src/dsymbol/symbol.d b/dsymbol/src/dsymbol/symbol.d index 6b506a2..9350709 100644 --- a/dsymbol/src/dsymbol/symbol.d +++ b/dsymbol/src/dsymbol/symbol.d @@ -386,11 +386,6 @@ struct DSymbol // Is alias this symbols DSymbol*[] aliasThisSymbols; - /** - * Names of function arguments - */ - // TODO: remove since we have function arguments - UnrolledList!(istring) argNames; /** * Function parameter symbols From b79982d5097de49b5308f71523b552dddf4f550c Mon Sep 17 00:00:00 2001 From: Jan Jurzitza Date: Mon, 4 Dec 2023 10:38:58 +0100 Subject: [PATCH 11/21] Add a new request to get inlay hints (#764) Co-authored-by: ryuukk --- README.md | 13 +++ common/src/dcd/common/messages.d | 4 +- src/dcd/client/client.d | 27 +++++- src/dcd/server/autocomplete/inlayhints.d | 108 +++++++++++++++++++++++ src/dcd/server/autocomplete/package.d | 1 + src/dcd/server/main.d | 5 ++ tests/tc_inlay_hints/expected.txt | 1 + tests/tc_inlay_hints/file.d | 17 ++++ tests/tc_inlay_hints/run.sh | 5 ++ 9 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 src/dcd/server/autocomplete/inlayhints.d create mode 100644 tests/tc_inlay_hints/expected.txt create mode 100644 tests/tc_inlay_hints/file.d create mode 100755 tests/tc_inlay_hints/run.sh diff --git a/README.md b/README.md index 20e74d6..1bc4397 100644 --- a/README.md +++ b/README.md @@ -314,6 +314,19 @@ Otherwise the client outputs _00000_ so that the length of the answer is guarant 45 133 +## Inlay Hints + +Build a list of extra annoations for your IDE to display. +You must submit the content of the current file displayed in your editor. + + dcd-client --inlayHints + +This is a W.I.P., currently it only provide annoatations about aliases for your variables, +more is planned. + +#### Example output + + l ->MyAlias->MyType 42 # Server diff --git a/common/src/dcd/common/messages.d b/common/src/dcd/common/messages.d index f5958bc..11c71d6 100644 --- a/common/src/dcd/common/messages.d +++ b/common/src/dcd/common/messages.d @@ -78,10 +78,12 @@ enum RequestKind : ushort localUse = 0b00000010_00000000, /// Remove import directory from server removeImport = 0b00000100_00000000, + /// Get inlay hints + inlayHints = 0b00001000_00000000, /// These request kinds require source code and won't be executed if there /// is no source sent - requiresSourceCode = autocomplete | doc | symbolLocation | search | localUse, + requiresSourceCode = autocomplete | doc | symbolLocation | search | localUse | inlayHints, // dfmt on } diff --git a/src/dcd/client/client.d b/src/dcd/client/client.d index bd619d9..207264e 100644 --- a/src/dcd/client/client.d +++ b/src/dcd/client/client.d @@ -62,6 +62,7 @@ int runClient(string[] args) bool clearCache; bool symbolLocation; bool doc; + bool inlayHints; bool query; bool printVersion; bool listImports; @@ -86,6 +87,7 @@ int runClient(string[] args) "R", &removedImportPaths, "port|p", &port, "help|h", &help, "shutdown", &shutdown, "clearCache", &clearCache, "symbolLocation|l", &symbolLocation, "doc|d", &doc, + "inlayHints", &inlayHints, "query|status|q", &query, "search|s", &search, "version", &printVersion, "listImports", &listImports, "tcp", &useTCP, "socketFile", &socketFile, @@ -181,7 +183,7 @@ int runClient(string[] args) printImportList(response); return 0; } - else if (search == null && cursorPos == size_t.max) + else if (search == null && !inlayHints && cursorPos == size_t.max) { // cursor position is a required argument printHelp(args[0]); @@ -234,6 +236,8 @@ int runClient(string[] args) request.kind |= RequestKind.search; else if(localUse) request.kind |= RequestKind.localUse; + else if (inlayHints) + request.kind |= RequestKind.inlayHints; else request.kind |= RequestKind.autocomplete; @@ -255,6 +259,8 @@ int runClient(string[] args) printSearchResponse(response); else if (localUse) printLocalUse(response); + else if (inlayHints) + printInlayHintsResponse(response); else printCompletionResponse(response, fullOutput); @@ -295,6 +301,10 @@ Options: Gets documentation comments associated with the symbol at the cursor location. + --inlayHints + For all supported variable usages, show value types. Currently shows + alias definitions. + --search | -s symbolName Searches for symbolName in both stdin / the given file name as well as others files cached by the server. @@ -384,6 +394,21 @@ void printLocationResponse(ref const AutocompleteResponse response) writeln(makeTabSeparated(response.symbolFilePath, response.symbolLocation.to!string)); } +void printInlayHintsResponse(ref const AutocompleteResponse response) +{ + auto app = appender!(string[])(); + foreach (ref completion; response.completions) + { + app.put(makeTabSeparated( + completion.kind == char.init ? "" : "" ~ completion.kind, + completion.identifier, + completion.symbolLocation.to!string + )); + } + foreach (line; app.data) + writeln(line); +} + void printCompletionResponse(ref const AutocompleteResponse response, bool extended) { if (response.completions.length > 0) diff --git a/src/dcd/server/autocomplete/inlayhints.d b/src/dcd/server/autocomplete/inlayhints.d new file mode 100644 index 0000000..b5cd466 --- /dev/null +++ b/src/dcd/server/autocomplete/inlayhints.d @@ -0,0 +1,108 @@ +/** + * This file is part of DCD, a development tool for the D programming language. + * Copyright (C) 2014 Brian Schott + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +module dcd.server.autocomplete.inlayhints; + +import std.stdio; +import std.algorithm; +import std.array; +import std.experimental.allocator; +import std.experimental.logger; +import std.typecons; + +import dcd.server.autocomplete.util; + +import dparse.lexer; +import dparse.rollback_allocator; + +import dsymbol.modulecache; +import dsymbol.symbol; +import dsymbol.scope_; +import dsymbol.conversion; +import dsymbol.string_interning; + +import dcd.common.messages; + +import containers.hashset; + +public AutocompleteResponse getInlayHints(const AutocompleteRequest request, + ref ModuleCache moduleCache) +{ +// trace("Getting inlay hints comments"); + AutocompleteResponse response; + + LexerConfig config; + config.fileName = ""; + auto cache = StringCache(request.sourceCode.length.optimalBucketCount); + auto tokenArray = getTokensForParser(cast(ubyte[]) request.sourceCode, config, &cache); + RollbackAllocator rba; + auto pair = generateAutocompleteTrees(tokenArray, &rba, -1, moduleCache); + scope(exit) pair.destroy(); + + void check(DSymbol* it, ref HashSet!size_t visited) + { + if (visited.contains(cast(size_t) it)) + return; + if (it.symbolFile != "stdin") return; + visited.insert(cast(size_t) it); + + //writeln("sym: ", it.name," ", it.location, " kind: ", it.kind," qualifier: ", it.qualifier); + //if (auto type = it.type) + //{ + // writeln(" ", type.name, " kind: ", type.kind, " qualifier", type.qualifier); + // if (auto ttype = type.type) + // writeln(" ", ttype.name, " kind: ", ttype.kind, " qualifier", ttype.qualifier); + //} + + + // aliases + // struct Data {} + // alias Alias1 = Data; + // Alias1 var; becomes: Alias1 [-> Data] var; + if (it.kind == CompletionKind.variableName && it.type && it.type.kind == CompletionKind.aliasName) + { + AutocompleteResponse.Completion c; + c.symbolLocation = it.location - 1; + c.kind = CompletionKind.aliasName; + + DSymbol* type = it.type; + + while (type) + { + if (type.kind == CompletionKind.aliasName && type.type) + c.identifier ~= "->" ~ type.type.name; + if (type.type && type.type.kind != CompletionKind.aliasName) break; + type = type.type; + } + + response.completions ~= c; + } + + foreach(part; it.opSlice()) + check(part, visited); + } + + HashSet!size_t visited; + foreach (symbol; pair.scope_.symbols) + { + check(symbol, visited); + foreach(part; symbol.opSlice()) + check(part, visited); + } + return response; +} diff --git a/src/dcd/server/autocomplete/package.d b/src/dcd/server/autocomplete/package.d index ee7811c..8e36e47 100644 --- a/src/dcd/server/autocomplete/package.d +++ b/src/dcd/server/autocomplete/package.d @@ -24,3 +24,4 @@ import dcd.server.autocomplete.complete; import dcd.server.autocomplete.doc; import dcd.server.autocomplete.localuse; import dcd.server.autocomplete.symbols; +import dcd.server.autocomplete.inlayhints; diff --git a/src/dcd/server/main.d b/src/dcd/server/main.d index 3f3828d..7dbfd78 100644 --- a/src/dcd/server/main.d +++ b/src/dcd/server/main.d @@ -347,6 +347,11 @@ int runServer(string[] args) s.trySendResponse(symbolSearch(request, cache), "Could not perform symbol search"); else if (request.kind & RequestKind.localUse) s.trySendResponse(findLocalUse(request, cache), "Couldnot find local usage"); + else if (request.kind & RequestKind.inlayHints) + { + info("Getting inlay hints"); + s.trySendResponse(getInlayHints(request, cache), "Could not get inlay hints"); + } else if (needResponse) s.trySendResponse(AutocompleteResponse.ack, "Could not send ack"); } diff --git a/tests/tc_inlay_hints/expected.txt b/tests/tc_inlay_hints/expected.txt new file mode 100644 index 0000000..a01907c --- /dev/null +++ b/tests/tc_inlay_hints/expected.txt @@ -0,0 +1 @@ +l ->Point 208 diff --git a/tests/tc_inlay_hints/file.d b/tests/tc_inlay_hints/file.d new file mode 100644 index 0000000..8df2e2f --- /dev/null +++ b/tests/tc_inlay_hints/file.d @@ -0,0 +1,17 @@ +// when extending the inlayHints capabilities, don't forget to update the --help +// text inside client.d + +import point; +import point : P = Point; + +void foo(int x, int y) {} +void foo(Point point) {} +void bar(P point, int z = 1) {} + +void main() +{ + P p; + foo(1, 2); + foo(p); + bar(p, 3); +} diff --git a/tests/tc_inlay_hints/run.sh b/tests/tc_inlay_hints/run.sh new file mode 100755 index 0000000..c35089d --- /dev/null +++ b/tests/tc_inlay_hints/run.sh @@ -0,0 +1,5 @@ +set -e +set -u + +../../bin/dcd-client $1 --inlayHints file.d > actual.txt +diff actual.txt expected.txt --strip-trailing-cr From 2bb03265cc872f4464890ce81bc0410dc96a6051 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Mon, 4 Dec 2023 10:40:07 +0100 Subject: [PATCH 12/21] support inlay hints inside functions remake of #759 Co-authored-by: ryuukk --- dsymbol/src/dsymbol/conversion/package.d | 1 + tests/tc_inlay_hints/expected.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/dsymbol/src/dsymbol/conversion/package.d b/dsymbol/src/dsymbol/conversion/package.d index 6b0df50..57e6626 100644 --- a/dsymbol/src/dsymbol/conversion/package.d +++ b/dsymbol/src/dsymbol/conversion/package.d @@ -115,6 +115,7 @@ class AutocompleteParser : Parser { if (!currentIs(tok!"{")) return null; + if (cursorPosition == -1) return super.parseBlockStatement(); if (current.index > cursorPosition) { BlockStatement bs = allocator.make!(BlockStatement); diff --git a/tests/tc_inlay_hints/expected.txt b/tests/tc_inlay_hints/expected.txt index a01907c..26f4596 100644 --- a/tests/tc_inlay_hints/expected.txt +++ b/tests/tc_inlay_hints/expected.txt @@ -1 +1,2 @@ l ->Point 208 +l ->Point 247 From 25139a8833e0f651da4182d760723f400e5a380c Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Mon, 4 Dec 2023 10:49:24 +0100 Subject: [PATCH 13/21] fix inlayHints ordering --- src/dcd/server/autocomplete/inlayhints.d | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dcd/server/autocomplete/inlayhints.d b/src/dcd/server/autocomplete/inlayhints.d index b5cd466..41db78b 100644 --- a/src/dcd/server/autocomplete/inlayhints.d +++ b/src/dcd/server/autocomplete/inlayhints.d @@ -104,5 +104,8 @@ public AutocompleteResponse getInlayHints(const AutocompleteRequest request, foreach(part; symbol.opSlice()) check(part, visited); } + + response.completions.sort!"a.symbolLocation < b.symbolLocation"; + return response; } From fe6ce047203ecbf95c751606581f1848587c8af8 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sat, 24 Jun 2023 20:58:54 +0200 Subject: [PATCH 14/21] implement typeof in types --- dsymbol/src/dsymbol/builtin/names.d | 14 +++++ dsymbol/src/dsymbol/conversion/first.d | 37 ++++++------ dsymbol/src/dsymbol/conversion/second.d | 75 +++++++++++++++++-------- dsymbol/src/dsymbol/conversion/third.d | 2 - dsymbol/src/dsymbol/type_lookup.d | 1 - tests/tc_typeof/expected1.txt | 20 +++++++ tests/tc_typeof/expected2.txt | 2 + tests/tc_typeof/expected3.txt | 8 +++ tests/tc_typeof/run.sh | 14 +++++ tests/tc_typeof/test1.d | 32 +++++++++++ tests/tc_typeof/test2.d | 15 +++++ tests/tc_typeof/test3.d | 10 ++++ 12 files changed, 187 insertions(+), 43 deletions(-) create mode 100644 tests/tc_typeof/expected1.txt create mode 100644 tests/tc_typeof/expected2.txt create mode 100644 tests/tc_typeof/expected3.txt create mode 100755 tests/tc_typeof/run.sh create mode 100644 tests/tc_typeof/test1.d create mode 100644 tests/tc_typeof/test2.d create mode 100644 tests/tc_typeof/test3.d diff --git a/dsymbol/src/dsymbol/builtin/names.d b/dsymbol/src/dsymbol/builtin/names.d index b91739f..9b87334 100644 --- a/dsymbol/src/dsymbol/builtin/names.d +++ b/dsymbol/src/dsymbol/builtin/names.d @@ -165,6 +165,20 @@ package istring[24] builtinTypeNames; * class. DSymbol child of the class type, with the baseClass as its child type. */ @("super") istring SUPER_SYMBOL_NAME; +/** + * This symbol name may appear at the start of breadcrumbs meaning the remaining + * breadcrumbs up until the matching $(LREF TYPEOF_END_SYMBOL_NAME) are an + * initializer or typeof expression. Pointer/Array suffixes are parsed + * beforehand, using popBack to remove them from the breadcrumbs. + * + * See_Also: $(LREF TYPEOF_END_SYMBOL_NAME) + */ +@("typeof(") istring TYPEOF_SYMBOL_NAME; +/** + * This symbol always appears in pairs with TYPEOF_SYMBOL_NAME, designates the + * end of the typeof expression in the breadcrumbs. + */ +@(")/*typeof*/") istring TYPEOF_END_SYMBOL_NAME; /** * Breadcrumb part in initializer type generation for literal values in the diff --git a/dsymbol/src/dsymbol/conversion/first.d b/dsymbol/src/dsymbol/conversion/first.d index 8ba1d6d..600d542 100644 --- a/dsymbol/src/dsymbol/conversion/first.d +++ b/dsymbol/src/dsymbol/conversion/first.d @@ -271,7 +271,7 @@ final class FirstPass : ASTVisitor part.identifier.text, CompletionKind.variableName, symbolFile, part.identifier.index); symbol.parent = currentSymbol; - populateInitializer(symbol, part.initializer); + populateInitializer(symbol.typeLookups, part.initializer); symbol.acSymbol.protection = protection.current; symbol.acSymbol.doc = makeDocumentation(dec.comment); currentSymbol.addChild(symbol, true); @@ -719,7 +719,7 @@ final class FirstPass : ASTVisitor currentSymbol.addChild(symbol, true); currentScope.addSymbol(symbol.acSymbol, true); if (symbol.typeLookups.empty && feExpression !is null) - populateInitializer(symbol, feExpression, true); + populateInitializer(symbol.typeLookups, feExpression, true); } } @@ -738,7 +738,7 @@ final class FirstPass : ASTVisitor currentSymbol.addChild(symbol, true); currentScope.addSymbol(symbol.acSymbol, true); if (symbol.typeLookups.empty && ifs.condition !is null && ifs.condition.expression !is null) - populateInitializer(symbol, ifs.condition.expression, false); + populateInitializer(symbol.typeLookups, ifs.condition.expression, false); } ifs.accept(this); } @@ -756,7 +756,7 @@ final class FirstPass : ASTVisitor currentScope.startLocation, null); scope(exit) popSymbol(); - populateInitializer(currentSymbol, withStatement.expression, false); + populateInitializer(currentSymbol.typeLookups, withStatement.expression, false); withStatement.accept(this); } @@ -1127,12 +1127,19 @@ private: return istring(app.data); } - void populateInitializer(T)(SemanticSymbol* symbol, const T initializer, - bool appendForeach = false) + void populateInitializer(T)(ref TypeLookups lookups, const T initializer, + bool appendForeach = false, TypeLookup* l = null) { - auto lookup = TypeLookupsAllocator.instance.make!TypeLookup(TypeLookupKind.initializer); + auto lookup = l ? l : TypeLookupsAllocator.instance.make!TypeLookup(TypeLookupKind.varOrFunType); + + lookup.breadcrumbs.insert(TYPEOF_SYMBOL_NAME); + scope (exit) + lookup.breadcrumbs.insert(TYPEOF_END_SYMBOL_NAME); scope visitor = new InitializerVisitor(lookup, appendForeach, this); - symbol.typeLookups.insert(lookup); + + if (l is null) + lookups.insert(lookup); + static if (is(T == typeof(feExpression))) visitor.dynamicDispatch(initializer); else @@ -1155,22 +1162,20 @@ private: auto lookup = l !is null ? l : TypeLookupsAllocator.instance.make!TypeLookup( TypeLookupKind.varOrFunType); auto t2 = type.type2; - if (t2.type !is null) - addTypeToLookups(lookups, t2.type, lookup); + if (t2.typeofExpression !is null) + populateInitializer(lookups, t2.typeofExpression, false, lookup); else if (t2.superOrThis is tok!"this") lookup.breadcrumbs.insert(internString("this")); else if (t2.superOrThis is tok!"super") lookup.breadcrumbs.insert(internString("super")); + + if (t2.type !is null) + addTypeToLookups(lookups, t2.type, lookup); else if (t2.builtinType !is tok!"") lookup.breadcrumbs.insert(getBuiltinTypeName(t2.builtinType)); else if (t2.typeIdentifierPart !is null) writeIotcTo(t2.typeIdentifierPart, lookup.breadcrumbs); - else - { - // TODO: Add support for typeof expressions - // TODO: Add support for __vector -// warning("typeof() and __vector are not yet supported"); - } + // TODO: support __vector, traits and mixin foreach (suffix; type.typeSuffixes) { diff --git a/dsymbol/src/dsymbol/conversion/second.d b/dsymbol/src/dsymbol/conversion/second.d index a7b3580..d1220b0 100644 --- a/dsymbol/src/dsymbol/conversion/second.d +++ b/dsymbol/src/dsymbol/conversion/second.d @@ -237,10 +237,27 @@ do } // Follow all the names and try to resolve them - size_t i = 0; - foreach (part; lookup.breadcrumbs[]) + bool first = true; + auto breadcrumbs = lookup.breadcrumbs[]; + + while (!breadcrumbs.empty) { - if (i == 0) + auto part = breadcrumbs.front; + breadcrumbs.popFront(); + scope (exit) + first = false; + + if (part == TYPEOF_SYMBOL_NAME) + { + if (currentSymbol !is null) + { + warning("Invalid breadcrumbs, found `Type.typeof(...)`"); + return; + } + resolveTypeFromInitializer(symbol, lookup, moduleScope, cache, + breadcrumbs, currentSymbol); + } + else if (first) { if (moduleScope is null) getSymbolFromImports(imports, part); @@ -273,7 +290,6 @@ do return; currentSymbol = currentSymbol.getFirstPartNamed(part); } - ++i; if (currentSymbol is null) return; } @@ -311,19 +327,32 @@ do } } -void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup, - Scope* moduleScope, ref ModuleCache cache) +private void resolveTypeFromInitializer(R)(DSymbol* symbol, TypeLookup* lookup, + Scope* moduleScope, ref ModuleCache cache, + ref R breadcrumbs, ref DSymbol* currentSymbol) { - if (lookup.breadcrumbs.length == 0) + if (breadcrumbs.empty) return; - DSymbol* currentSymbol = null; - size_t i = 0; - auto crumbs = lookup.breadcrumbs[]; - foreach (crumb; crumbs) + bool first = true; + while (!breadcrumbs.empty) { - if (i == 0) + auto crumb = breadcrumbs.front; + breadcrumbs.popFront(); + if (crumb == TYPEOF_SYMBOL_NAME) { + resolveTypeFromInitializer(symbol, lookup, moduleScope, cache, + breadcrumbs, currentSymbol); + if (currentSymbol is null) + return; + continue; + } + if (crumb == TYPEOF_END_SYMBOL_NAME) + break; + + if (first) + { + first = false; currentSymbol = moduleScope.getFirstSymbolByNameAndCursor( symbolNameToTypeName(crumb), symbol.location); @@ -348,18 +377,21 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup, || currentSymbol.qualifier == SymbolQualifier.pointer || currentSymbol.kind == CompletionKind.aliasName) { - if (currentSymbol.type !is null) - currentSymbol = currentSymbol.type; - else - return; + // may become null, returns later + currentSymbol = currentSymbol.type; } else { auto opIndex = currentSymbol.getFirstPartNamed(internString("opIndex")); if (opIndex !is null) + { currentSymbol = opIndex.type; + } else + { + currentSymbol = null; return; + } } } else if (crumb == "foreach") @@ -371,19 +403,19 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup, || currentSymbol.qualifier == SymbolQualifier.assocArray) { currentSymbol = currentSymbol.type; - break; + continue; } auto front = currentSymbol.getFirstPartNamed(internString("front")); if (front !is null) { currentSymbol = front.type; - break; + continue; } auto opApply = currentSymbol.getFirstPartNamed(internString("opApply")); if (opApply !is null) { currentSymbol = opApply.type; - break; + continue; } } else @@ -393,13 +425,10 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup, return; currentSymbol = currentSymbol.getFirstPartNamed(crumb); } - ++i; if (currentSymbol is null) return; } typeSwap(currentSymbol); - symbol.type = currentSymbol; - symbol.ownType = false; } private: @@ -506,8 +535,6 @@ void resolveType(DSymbol* symbol, ref TypeLookups typeLookups, foreach(lookup; typeLookups) { if (lookup.kind == TypeLookupKind.varOrFunType) resolveTypeFromType(symbol, lookup, moduleScope, cache, null); - else if (lookup.kind == TypeLookupKind.initializer) - resolveTypeFromInitializer(symbol, lookup, moduleScope, cache); // issue 94 else if (lookup.kind == TypeLookupKind.inherit) resolveInheritance(symbol, typeLookups, moduleScope, cache); diff --git a/dsymbol/src/dsymbol/conversion/third.d b/dsymbol/src/dsymbol/conversion/third.d index 1148dac..29aa91c 100644 --- a/dsymbol/src/dsymbol/conversion/third.d +++ b/dsymbol/src/dsymbol/conversion/third.d @@ -64,8 +64,6 @@ void checkMissingTypes(SemanticSymbol* currentSymbol, Scope* moduleScope, ref Mo auto lookup = currentSymbol.typeLookups.front; if (lookup.kind == TypeLookupKind.varOrFunType) resolveTypeFromType(currentSymbol.acSymbol, lookup, moduleScope, cache, null); - else if (lookup.kind == TypeLookupKind.initializer) - resolveTypeFromInitializer(currentSymbol.acSymbol, lookup, moduleScope, cache); } break; default: diff --git a/dsymbol/src/dsymbol/type_lookup.d b/dsymbol/src/dsymbol/type_lookup.d index 2260e57..8f69ceb 100644 --- a/dsymbol/src/dsymbol/type_lookup.d +++ b/dsymbol/src/dsymbol/type_lookup.d @@ -10,7 +10,6 @@ enum TypeLookupKind : ubyte { inherit, aliasThis, - initializer, mixinTemplate, varOrFunType, selectiveImport, diff --git a/tests/tc_typeof/expected1.txt b/tests/tc_typeof/expected1.txt new file mode 100644 index 0000000..3301724 --- /dev/null +++ b/tests/tc_typeof/expected1.txt @@ -0,0 +1,20 @@ +identifiers +getMember f typeof(member) getMember() stdin 78 Result +identifiers +staticMember f typeof(S.member) staticMember() stdin 133 Result +identifiers +alignof k +expected v int expected stdin 21 int +init k +mangleof k +sizeof k +stringof k +tupleof k +identifiers +alignof k +expected v int expected stdin 21 int +init k +mangleof k +sizeof k +stringof k +tupleof k diff --git a/tests/tc_typeof/expected2.txt b/tests/tc_typeof/expected2.txt new file mode 100644 index 0000000..293e517 --- /dev/null +++ b/tests/tc_typeof/expected2.txt @@ -0,0 +1,2 @@ +identifiers +test v Enum test stdin 121 Enum diff --git a/tests/tc_typeof/expected3.txt b/tests/tc_typeof/expected3.txt new file mode 100644 index 0000000..bcfd9d8 --- /dev/null +++ b/tests/tc_typeof/expected3.txt @@ -0,0 +1,8 @@ +identifiers +alignof k +init k +mangleof k +ok v bool ok stdin 16 bool +sizeof k +stringof k +tupleof k diff --git a/tests/tc_typeof/run.sh b/tests/tc_typeof/run.sh new file mode 100755 index 0000000..3fd2acd --- /dev/null +++ b/tests/tc_typeof/run.sh @@ -0,0 +1,14 @@ +set -e +set -u + +../../bin/dcd-client $1 test1.d -x -c213 > actual1.txt +../../bin/dcd-client $1 test1.d -x -c239 >> actual1.txt +../../bin/dcd-client $1 test1.d -x -c254 >> actual1.txt +../../bin/dcd-client $1 test1.d -x -c265 >> actual1.txt +diff actual1.txt expected1.txt --strip-trailing-cr + +../../bin/dcd-client $1 test2.d -x -c132 > actual2.txt +diff actual2.txt expected2.txt --strip-trailing-cr + +../../bin/dcd-client $1 test3.d -x -c83 > actual3.txt +diff actual3.txt expected3.txt --strip-trailing-cr diff --git a/tests/tc_typeof/test1.d b/tests/tc_typeof/test1.d new file mode 100644 index 0000000..7fe98a0 --- /dev/null +++ b/tests/tc_typeof/test1.d @@ -0,0 +1,32 @@ +struct Result +{ + int expected; +} + +struct S +{ + Result member; + + typeof(member) getMember() + { + return member; + } +} + +typeof(S.member) staticMember() +{ + return S.init.member; +} + +void test() +{ + S s; + auto a = S.getMember(); + auto b = staticMember(); + { + a. + } + { + b. + } +} diff --git a/tests/tc_typeof/test2.d b/tests/tc_typeof/test2.d new file mode 100644 index 0000000..9bc2f15 --- /dev/null +++ b/tests/tc_typeof/test2.d @@ -0,0 +1,15 @@ +struct MyTemplate(T) +{ + enum Enum { a, b } + + T member1; +} + +MyTemplate!long global2; + +void main() +{ + typeof(global2).Enum test; + test +} + diff --git a/tests/tc_typeof/test3.d b/tests/tc_typeof/test3.d new file mode 100644 index 0000000..9b85483 --- /dev/null +++ b/tests/tc_typeof/test3.d @@ -0,0 +1,10 @@ +struct S { bool ok; } + +S global3; + +void main() +{ + typeof(global3)[] test; + test[0]. +} + From dcffd378e16b39474d86f171886361eb70c6f06e Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Mon, 4 Dec 2023 11:54:11 +0100 Subject: [PATCH 15/21] support casts in initializers rework of #710, reuses the existing type construction Co-authored-by: ryuukk --- dsymbol/src/dsymbol/conversion/first.d | 25 +++++++++++++++++++++++-- tests/tc_casts/expected1.txt | 8 ++++++++ tests/tc_casts/expected2.txt | 0 tests/tc_casts/file.d | 26 ++++++++++++++++++++++++++ tests/tc_casts/run.sh | 8 ++++++++ 5 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 tests/tc_casts/expected1.txt create mode 100644 tests/tc_casts/expected2.txt create mode 100644 tests/tc_casts/file.d create mode 100755 tests/tc_casts/run.sh diff --git a/dsymbol/src/dsymbol/conversion/first.d b/dsymbol/src/dsymbol/conversion/first.d index 600d542..26f366f 100644 --- a/dsymbol/src/dsymbol/conversion/first.d +++ b/dsymbol/src/dsymbol/conversion/first.d @@ -1133,9 +1133,10 @@ private: auto lookup = l ? l : TypeLookupsAllocator.instance.make!TypeLookup(TypeLookupKind.varOrFunType); lookup.breadcrumbs.insert(TYPEOF_SYMBOL_NAME); - scope (exit) - lookup.breadcrumbs.insert(TYPEOF_END_SYMBOL_NAME); scope visitor = new InitializerVisitor(lookup, appendForeach, this); + scope (exit) + if (!visitor.isCast) + lookup.breadcrumbs.insert(TYPEOF_END_SYMBOL_NAME); if (l is null) lookups.insert(lookup); @@ -1586,6 +1587,25 @@ class InitializerVisitor : ASTVisitor on = false; } + override void visit(const CastExpression expression) + { + if (expression.type) + { + if (lookup.breadcrumbs.empty || lookup.breadcrumbs.back != TYPEOF_SYMBOL_NAME) + return; + + isCast = true; + lookup.breadcrumbs.popBack(); + TypeLookups none; + fp.addTypeToLookups(none, expression.type, lookup); + } + else + { + // we don't care about non-type casts (e.g. `cast()` or `cast(const)`) yet + expression.accept(this); + } + } + override void dynamicDispatch(const ExpressionNode expression) { on = true; @@ -1599,6 +1619,7 @@ class InitializerVisitor : ASTVisitor bool on = false; const bool appendForeach; FirstPass fp; + bool isCast; } class ArgumentListVisitor : ASTVisitor diff --git a/tests/tc_casts/expected1.txt b/tests/tc_casts/expected1.txt new file mode 100644 index 0000000..52a2264 --- /dev/null +++ b/tests/tc_casts/expected1.txt @@ -0,0 +1,8 @@ +identifiers +alignof k +init k +inside_c v +mangleof k +sizeof k +stringof k +tupleof k diff --git a/tests/tc_casts/expected2.txt b/tests/tc_casts/expected2.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/tc_casts/file.d b/tests/tc_casts/file.d new file mode 100644 index 0000000..3fa9bce --- /dev/null +++ b/tests/tc_casts/file.d @@ -0,0 +1,26 @@ +struct A +{ + struct B + { + struct C + { + int inside_c; + } + int inside_b; + } + int inside_a; +} + +unittest +{ + auto from_cast = cast(A.B.C) nonExist; + from_cast. +} + +unittest +{ + struct A {} + + auto from_cast = cast(A.B.C) nonExist; + from_cast. +} diff --git a/tests/tc_casts/run.sh b/tests/tc_casts/run.sh new file mode 100755 index 0000000..bacdbad --- /dev/null +++ b/tests/tc_casts/run.sh @@ -0,0 +1,8 @@ +set -e +set -u + +../../bin/dcd-client $1 file.d -c159 > actual1.txt +diff actual1.txt expected1.txt --strip-trailing-cr + +../../bin/dcd-client $1 file.d -c239 > actual2.txt +diff actual2.txt expected2.txt --strip-trailing-cr From 584b245c8b7d4d8f12c2802b889cbb7321ad8fb0 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Mon, 4 Dec 2023 12:45:04 +0100 Subject: [PATCH 16/21] support `.Type` syntax for module type lookup --- dsymbol/src/dsymbol/builtin/names.d | 9 +++++++++ dsymbol/src/dsymbol/conversion/first.d | 4 ++++ dsymbol/src/dsymbol/conversion/second.d | 9 ++++++++- tests/tc_casts/file.d | 8 ++++++++ tests/tc_casts/run.sh | 3 +++ 5 files changed, 32 insertions(+), 1 deletion(-) diff --git a/dsymbol/src/dsymbol/builtin/names.d b/dsymbol/src/dsymbol/builtin/names.d index 9b87334..5bd5fb4 100644 --- a/dsymbol/src/dsymbol/builtin/names.d +++ b/dsymbol/src/dsymbol/builtin/names.d @@ -27,6 +27,15 @@ package istring[24] builtinTypeNames; * or the child type for single index access. */ @("*arr*") istring ARRAY_SYMBOL_NAME; +/** + * In breadcrumbs this is a single entry meaning that the type following this + * started with a dot `.`, so module scope instead of local scope is to be used + * for type resolution. + * + * Note that auto-completion does not rely on this symbol, only type / symbol + * lookup relies on this. + */ +@("*arr*") istring MODULE_SYMBOL_NAME; /** * Type suffix, in breadcrumbs this is a single entry. * diff --git a/dsymbol/src/dsymbol/conversion/first.d b/dsymbol/src/dsymbol/conversion/first.d index 26f366f..6cad7ff 100644 --- a/dsymbol/src/dsymbol/conversion/first.d +++ b/dsymbol/src/dsymbol/conversion/first.d @@ -1358,6 +1358,10 @@ void writeIotcTo(T)(const TypeIdentifierPart tip, ref T output) nothrow { if (!tip.identifierOrTemplateInstance) return; + + if (tip.dot) + output.insert(MODULE_SYMBOL_NAME); + if (tip.identifierOrTemplateInstance.identifier != tok!"") output.insert(internString(tip.identifierOrTemplateInstance.identifier.text)); else diff --git a/dsymbol/src/dsymbol/conversion/second.d b/dsymbol/src/dsymbol/conversion/second.d index d1220b0..bac4b50 100644 --- a/dsymbol/src/dsymbol/conversion/second.d +++ b/dsymbol/src/dsymbol/conversion/second.d @@ -263,7 +263,14 @@ do getSymbolFromImports(imports, part); else { - auto symbols = moduleScope.getSymbolsByNameAndCursor(part, symbol.location); + auto symbols = part == MODULE_SYMBOL_NAME + ? { + assert(!breadcrumbs.empty); + part = breadcrumbs.front; + breadcrumbs.popFront(); + return moduleScope.getSymbolsByName(part); + }() + : moduleScope.getSymbolsByNameAndCursor(part, symbol.location); if (symbols.length > 0) currentSymbol = symbols[0]; else diff --git a/tests/tc_casts/file.d b/tests/tc_casts/file.d index 3fa9bce..43834b1 100644 --- a/tests/tc_casts/file.d +++ b/tests/tc_casts/file.d @@ -24,3 +24,11 @@ unittest auto from_cast = cast(A.B.C) nonExist; from_cast. } + +unittest +{ + struct A {} + + auto from_cast = cast(.A.B.C) nonExist; + from_cast. +} diff --git a/tests/tc_casts/run.sh b/tests/tc_casts/run.sh index bacdbad..a45085f 100755 --- a/tests/tc_casts/run.sh +++ b/tests/tc_casts/run.sh @@ -6,3 +6,6 @@ diff actual1.txt expected1.txt --strip-trailing-cr ../../bin/dcd-client $1 file.d -c239 > actual2.txt diff actual2.txt expected2.txt --strip-trailing-cr + +../../bin/dcd-client $1 file.d -c320 > actual3.txt +diff actual3.txt expected1.txt --strip-trailing-cr From 15ea4b37b82b2f5adbdeb933cb532567ae0a3ce3 Mon Sep 17 00:00:00 2001 From: brianush1 Date: Mon, 11 Dec 2023 00:51:41 -0500 Subject: [PATCH 17/21] avoid unnecessary O(n^2) work in localuse (#768) Co-authored-by: WebFreak001 --- src/dcd/server/autocomplete/localuse.d | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/dcd/server/autocomplete/localuse.d b/src/dcd/server/autocomplete/localuse.d index 5974cfb..86f042b 100644 --- a/src/dcd/server/autocomplete/localuse.d +++ b/src/dcd/server/autocomplete/localuse.d @@ -57,12 +57,14 @@ public AutocompleteResponse findLocalUse(AutocompleteRequest request, config.fileName = ""; const(Token)[] tokenArray = getTokensForParser(cast(ubyte[]) request.sourceCode, config, &cache); + auto sortedTokens = assumeSorted(tokenArray); + ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, + &rba, request.cursorPosition, moduleCache); + scope(exit) pair.destroy(); + SymbolStuff getSymbolsAtCursor(size_t cursorPosition) { - auto sortedTokens = assumeSorted(tokenArray); auto beforeTokens = sortedTokens.lowerBound(cursorPosition); - ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, - &rba, request.cursorPosition, moduleCache); auto expression = getExpression(beforeTokens); return SymbolStuff(getSymbolsByTokenChain(pair.scope_, expression, cursorPosition, CompletionType.location), pair.symbol, pair.scope_); @@ -70,7 +72,6 @@ public AutocompleteResponse findLocalUse(AutocompleteRequest request, // gets the symbol matching to cursor pos SymbolStuff stuff = getSymbolsAtCursor(cast(size_t)request.cursorPosition); - scope(exit) stuff.destroy(); // starts searching only if no ambiguity with the symbol if (stuff.symbols.length == 1) @@ -100,7 +101,6 @@ public AutocompleteResponse findLocalUse(AutocompleteRequest request, { size_t pos = cast(size_t) t.index + 1; // place cursor inside the token SymbolStuff candidate = getSymbolsAtCursor(pos); - scope(exit) candidate.destroy(); if (candidate.symbols.length == 1 && candidate.symbols[0].location == sourceSymbol.location && candidate.symbols[0].symbolFile == sourceSymbol.symbolFile) From 57794ca8759ef7ecea640908d7caa03966504e7b Mon Sep 17 00:00:00 2001 From: Jeremy Baxter Date: Fri, 22 Dec 2023 13:39:37 +1300 Subject: [PATCH 18/21] Fix build on BSD Added extra version statements for OpenBSD, NetBSD and DragonflyBSD, as these are not included in the BSD version identifier. Also removed the line `SHELL:=/usr/bin/env bash' from the top of the makefile because most BSDs don't include bash in the base system, and the build doesn't need it anyway. On OpenBSD, using -inline with dmd causes the compiler to crash because of insufficient memory (with 8 GB), so I added a couple of ifneq's to use -inline only if the build is not running on OpenBSD. --- common/src/dcd/common/socket.d | 3 +++ makefile | 12 ++++++++---- src/dcd/server/server.d | 3 +++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/common/src/dcd/common/socket.d b/common/src/dcd/common/socket.d index 9be4246..9e00837 100644 --- a/common/src/dcd/common/socket.d +++ b/common/src/dcd/common/socket.d @@ -27,6 +27,9 @@ version (OSX) version = haveUnixSockets; version (linux) version = haveUnixSockets; version (BSD) version = haveUnixSockets; version (FreeBSD) version = haveUnixSockets; +version (OpenBSD) version = haveUnixSockets; +version (NetBSD) version = haveUnixSockets; +version (DragonflyBSD) version = haveUnixSockets; enum DEFAULT_PORT_NUMBER = 9166; diff --git a/makefile b/makefile index 90e0587..eb9e46c 100644 --- a/makefile +++ b/makefile @@ -13,8 +13,6 @@ LDC := ldc2 DPARSE_DIR := libdparse DSYMBOL_DIR := dsymbol -SHELL:=/usr/bin/env bash - githash: @mkdir -p bin git describe --tags > bin/githash.txt @@ -37,7 +35,6 @@ CLIENT_SRC := \ DMD_CLIENT_FLAGS := -Imsgpack-d/src\ -Imsgpack-d/src\ -Jbin\ - -inline\ -O\ -wi\ -ofbin/dcd-client @@ -56,6 +53,10 @@ LDC_CLIENT_FLAGS := -Imsgpack-d/src\ -oq\ -of=bin/dcd-client +ifneq ($(shell uname), OpenBSD) + override DMD_CLIENT_FLAGS += -inline +endif + override DMD_CLIENT_FLAGS += $(DFLAGS) override LDC_CLIENT_FLAGS += $(DFLAGS) override GDC_CLIENT_FLAGS += $(DFLAGS) @@ -76,7 +77,6 @@ DMD_SERVER_FLAGS := -Icontainers/src\ -wi\ -O\ -release\ - -inline\ -ofbin/dcd-server DEBUG_SERVER_FLAGS := -Icontainers/src\ @@ -106,6 +106,10 @@ LDC_SERVER_FLAGS := -Icontainers/src\ -O5\ -release +ifneq ($(shell uname), OpenBSD) + DMD_SERVER_FLAGS += -inline +endif + override DMD_SERVER_FLAGS += $(DFLAGS) override LDC_SERVER_FLAGS += $(DFLAGS) override GDC_SERVER_FLAGS += $(DFLAGS) diff --git a/src/dcd/server/server.d b/src/dcd/server/server.d index 10b3651..0095ffe 100644 --- a/src/dcd/server/server.d +++ b/src/dcd/server/server.d @@ -35,6 +35,9 @@ enum CONFIG_FILE_NAME = "dcd.conf"; version(linux) version = useXDG; version(BSD) version = useXDG; version(FreeBSD) version = useXDG; +version(OpenBSD) version = useXDG; +version(NetBSD) version = useXDG; +version(DragonflyBSD) version = useXDG; version(OSX) version = useXDG; /** From 27b1042959c4d1a27787cf502da14970ab821149 Mon Sep 17 00:00:00 2001 From: electricface Date: Wed, 17 Apr 2024 12:20:03 +0800 Subject: [PATCH 19/21] fix getSymbolsForCompletion raise exception should first check if the range `beforeTokens` is empty. --- src/dcd/server/autocomplete/util.d | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dcd/server/autocomplete/util.d b/src/dcd/server/autocomplete/util.d index 2f618f4..976e4a1 100644 --- a/src/dcd/server/autocomplete/util.d +++ b/src/dcd/server/autocomplete/util.d @@ -147,7 +147,8 @@ SymbolStuff getSymbolsForCompletion(const AutocompleteRequest request, auto expression = getExpression(beforeTokens); auto symbols = getSymbolsByTokenChain(pair.scope_, expression, request.cursorPosition, type); - if (symbols.length == 0 && doUFCSSearch(stringToken(beforeTokens.front), stringToken(beforeTokens.back))) { + if (symbols.length == 0 && !beforeTokens.empty && + doUFCSSearch(stringToken(beforeTokens.front), stringToken(beforeTokens.back))) { // Let search for UFCS, since we got no hit symbols ~= getSymbolsByTokenChain(pair.scope_, getExpression([beforeTokens.back]), request.cursorPosition, type); } From d85e752427528709435d5c164c2a8af2d4aaf4e9 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sat, 1 Mar 2025 02:02:52 +0100 Subject: [PATCH 20/21] update action --- .github/workflows/pr_info_untrusted.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr_info_untrusted.yml b/.github/workflows/pr_info_untrusted.yml index f72c0de..9e8be32 100644 --- a/.github/workflows/pr_info_untrusted.yml +++ b/.github/workflows/pr_info_untrusted.yml @@ -61,7 +61,7 @@ jobs: echo ${{ github.event.number }} > ./pr/NR - name: upload comment to high-trust action making the comment - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: pr path: pr/ From e48216e4a8da81c100b84d8dcba02fc714fa2585 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sat, 1 Mar 2025 02:04:03 +0100 Subject: [PATCH 21/21] upgrade libdparse --- dub.json | 2 +- dub.selections.json | 4 ++-- libdparse | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dub.json b/dub.json index f5bade8..5868c76 100644 --- a/dub.json +++ b/dub.json @@ -8,7 +8,7 @@ "license": "GPL-3.0", "dependencies": { ":dsymbol": "*", - "libdparse": ">=0.23.0 <0.24.0", + "libdparse": ">=0.23.0 <0.26.0", ":common": "*", "emsi_containers": "~>0.9.0" }, diff --git a/dub.selections.json b/dub.selections.json index 6513ec2..f9773e7 100644 --- a/dub.selections.json +++ b/dub.selections.json @@ -3,8 +3,8 @@ "versions": { "dsymbol": "0.14.1", "emsi_containers": "0.9.0", - "libdparse": "0.23.0", - "msgpack-d": "1.0.4", + "libdparse": "0.25.0", + "msgpack-d": "1.0.5", "stdx-allocator": "2.77.5" } } diff --git a/libdparse b/libdparse index 86c9bf4..f8a6c28 160000 --- a/libdparse +++ b/libdparse @@ -1 +1 @@ -Subproject commit 86c9bf44c96e1666eb175c749cc26f62c2008979 +Subproject commit f8a6c28589aae180532fb460a1b22e92a0978292