Compare commits
21 Commits
v0.16.0-be
...
master
Author | SHA1 | Date |
---|---|---|
|
e48216e4a8 | |
|
d85e752427 | |
|
27b1042959 | |
|
57794ca875 | |
|
15ea4b37b8 | |
|
584b245c8b | |
|
dcffd378e1 | |
|
fe6ce04720 | |
|
25139a8833 | |
|
2bb03265cc | |
|
b79982d509 | |
|
6d635923f7 | |
|
09f4e7e932 | |
|
5244f81367 | |
|
f15ca10acf | |
|
dc11cf704d | |
|
8a693954d3 | |
|
60ccfd520e | |
|
2e84d9d76a | |
|
0dd4c78985 | |
|
70061aee2e |
|
@ -61,7 +61,7 @@ jobs:
|
||||||
echo ${{ github.event.number }} > ./pr/NR
|
echo ${{ github.event.number }} > ./pr/NR
|
||||||
|
|
||||||
- name: upload comment to high-trust action making the comment
|
- name: upload comment to high-trust action making the comment
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: pr
|
name: pr
|
||||||
path: pr/
|
path: pr/
|
||||||
|
|
13
README.md
13
README.md
|
@ -314,6 +314,19 @@ Otherwise the client outputs _00000_ so that the length of the answer is guarant
|
||||||
45
|
45
|
||||||
133
|
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
|
# Server
|
||||||
|
|
||||||
|
|
|
@ -78,10 +78,12 @@ enum RequestKind : ushort
|
||||||
localUse = 0b00000010_00000000,
|
localUse = 0b00000010_00000000,
|
||||||
/// Remove import directory from server
|
/// Remove import directory from server
|
||||||
removeImport = 0b00000100_00000000,
|
removeImport = 0b00000100_00000000,
|
||||||
|
/// Get inlay hints
|
||||||
|
inlayHints = 0b00001000_00000000,
|
||||||
|
|
||||||
/// These request kinds require source code and won't be executed if there
|
/// These request kinds require source code and won't be executed if there
|
||||||
/// is no source sent
|
/// is no source sent
|
||||||
requiresSourceCode = autocomplete | doc | symbolLocation | search | localUse,
|
requiresSourceCode = autocomplete | doc | symbolLocation | search | localUse | inlayHints,
|
||||||
// dfmt on
|
// dfmt on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,36 +262,39 @@ AutocompleteResponse getResponse(Socket socket)
|
||||||
*/
|
*/
|
||||||
bool serverIsRunning(bool useTCP, string socketFile, ushort port)
|
bool serverIsRunning(bool useTCP, string socketFile, ushort port)
|
||||||
{
|
{
|
||||||
scope (failure)
|
try {
|
||||||
return false;
|
AutocompleteRequest request;
|
||||||
AutocompleteRequest request;
|
request.kind = RequestKind.query;
|
||||||
request.kind = RequestKind.query;
|
Socket socket;
|
||||||
Socket socket;
|
scope (exit)
|
||||||
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
|
|
||||||
{
|
{
|
||||||
socket = new Socket(AddressFamily.UNIX, SocketType.STREAM);
|
socket.shutdown(SocketShutdown.BOTH);
|
||||||
socket.connect(new UnixAddress(socketFile));
|
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));
|
catch (Exception _) {
|
||||||
socket.blocking = true;
|
|
||||||
if (sendRequest(socket, request))
|
|
||||||
return getResponse(socket).completionType == "ack";
|
|
||||||
else
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Escapes \n, \t and \ in the string. If `single` is true \t won't be escaped.
|
/// Escapes \n, \t and \ in the string. If `single` is true \t won't be escaped.
|
||||||
|
|
|
@ -27,6 +27,9 @@ version (OSX) version = haveUnixSockets;
|
||||||
version (linux) version = haveUnixSockets;
|
version (linux) version = haveUnixSockets;
|
||||||
version (BSD) version = haveUnixSockets;
|
version (BSD) version = haveUnixSockets;
|
||||||
version (FreeBSD) version = haveUnixSockets;
|
version (FreeBSD) version = haveUnixSockets;
|
||||||
|
version (OpenBSD) version = haveUnixSockets;
|
||||||
|
version (NetBSD) version = haveUnixSockets;
|
||||||
|
version (DragonflyBSD) version = haveUnixSockets;
|
||||||
|
|
||||||
enum DEFAULT_PORT_NUMBER = 9166;
|
enum DEFAULT_PORT_NUMBER = 9166;
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,15 @@ package istring[24] builtinTypeNames;
|
||||||
* or the child type for single index access.
|
* or the child type for single index access.
|
||||||
*/
|
*/
|
||||||
@("*arr*") istring ARRAY_SYMBOL_NAME;
|
@("*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.
|
* Type suffix, in breadcrumbs this is a single entry.
|
||||||
*
|
*
|
||||||
|
@ -165,6 +174,20 @@ package istring[24] builtinTypeNames;
|
||||||
* class. DSymbol child of the class type, with the baseClass as its child type.
|
* class. DSymbol child of the class type, with the baseClass as its child type.
|
||||||
*/
|
*/
|
||||||
@("super") istring SUPER_SYMBOL_NAME;
|
@("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
|
* Breadcrumb part in initializer type generation for literal values in the
|
||||||
|
|
|
@ -131,6 +131,7 @@ final class FirstPass : ASTVisitor
|
||||||
scope (exit) popSymbol();
|
scope (exit) popSymbol();
|
||||||
currentSymbol.acSymbol.protection = protection.current;
|
currentSymbol.acSymbol.protection = protection.current;
|
||||||
currentSymbol.acSymbol.doc = makeDocumentation(dec.comment);
|
currentSymbol.acSymbol.doc = makeDocumentation(dec.comment);
|
||||||
|
currentSymbol.acSymbol.qualifier = SymbolQualifier.func;
|
||||||
|
|
||||||
istring lastComment = this.lastComment;
|
istring lastComment = this.lastComment;
|
||||||
this.lastComment = istring.init;
|
this.lastComment = istring.init;
|
||||||
|
@ -270,7 +271,7 @@ final class FirstPass : ASTVisitor
|
||||||
part.identifier.text, CompletionKind.variableName,
|
part.identifier.text, CompletionKind.variableName,
|
||||||
symbolFile, part.identifier.index);
|
symbolFile, part.identifier.index);
|
||||||
symbol.parent = currentSymbol;
|
symbol.parent = currentSymbol;
|
||||||
populateInitializer(symbol, part.initializer);
|
populateInitializer(symbol.typeLookups, part.initializer);
|
||||||
symbol.acSymbol.protection = protection.current;
|
symbol.acSymbol.protection = protection.current;
|
||||||
symbol.acSymbol.doc = makeDocumentation(dec.comment);
|
symbol.acSymbol.doc = makeDocumentation(dec.comment);
|
||||||
currentSymbol.addChild(symbol, true);
|
currentSymbol.addChild(symbol, true);
|
||||||
|
@ -718,7 +719,7 @@ final class FirstPass : ASTVisitor
|
||||||
currentSymbol.addChild(symbol, true);
|
currentSymbol.addChild(symbol, true);
|
||||||
currentScope.addSymbol(symbol.acSymbol, true);
|
currentScope.addSymbol(symbol.acSymbol, true);
|
||||||
if (symbol.typeLookups.empty && feExpression !is null)
|
if (symbol.typeLookups.empty && feExpression !is null)
|
||||||
populateInitializer(symbol, feExpression, true);
|
populateInitializer(symbol.typeLookups, feExpression, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -737,7 +738,7 @@ final class FirstPass : ASTVisitor
|
||||||
currentSymbol.addChild(symbol, true);
|
currentSymbol.addChild(symbol, true);
|
||||||
currentScope.addSymbol(symbol.acSymbol, true);
|
currentScope.addSymbol(symbol.acSymbol, true);
|
||||||
if (symbol.typeLookups.empty && ifs.condition !is null && ifs.condition.expression !is null)
|
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);
|
ifs.accept(this);
|
||||||
}
|
}
|
||||||
|
@ -755,7 +756,7 @@ final class FirstPass : ASTVisitor
|
||||||
currentScope.startLocation, null);
|
currentScope.startLocation, null);
|
||||||
scope(exit) popSymbol();
|
scope(exit) popSymbol();
|
||||||
|
|
||||||
populateInitializer(currentSymbol, withStatement.expression, false);
|
populateInitializer(currentSymbol.typeLookups, withStatement.expression, false);
|
||||||
withStatement.accept(this);
|
withStatement.accept(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -908,7 +909,6 @@ private:
|
||||||
CompletionKind.functionName, symbolFile, location);
|
CompletionKind.functionName, symbolFile, location);
|
||||||
symbol.parent = currentSymbol;
|
symbol.parent = currentSymbol;
|
||||||
currentSymbol.addChild(symbol, true);
|
currentSymbol.addChild(symbol, true);
|
||||||
processParameters(symbol, null, THIS_SYMBOL_NAME, parameters, templateParameters);
|
|
||||||
symbol.acSymbol.protection = protection.current;
|
symbol.acSymbol.protection = protection.current;
|
||||||
symbol.acSymbol.doc = makeDocumentation(doc);
|
symbol.acSymbol.doc = makeDocumentation(doc);
|
||||||
|
|
||||||
|
@ -921,9 +921,16 @@ private:
|
||||||
pushFunctionScope(functionBody, location + 4); // 4 == "this".length
|
pushFunctionScope(functionBody, location + 4); // 4 == "this".length
|
||||||
scope(exit) popScope();
|
scope(exit) popScope();
|
||||||
currentSymbol = symbol;
|
currentSymbol = symbol;
|
||||||
|
processParameters(symbol, null, THIS_SYMBOL_NAME, parameters, templateParameters);
|
||||||
functionBody.accept(this);
|
functionBody.accept(this);
|
||||||
currentSymbol = currentSymbol.parent;
|
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)
|
void visitDestructor(size_t location, const FunctionBody functionBody, string doc)
|
||||||
|
@ -999,7 +1006,6 @@ private:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentSymbol.acSymbol.argNames.insert(parameter.acSymbol.name);
|
|
||||||
|
|
||||||
currentSymbol.acSymbol.functionParameters ~= parameter.acSymbol;
|
currentSymbol.acSymbol.functionParameters ~= parameter.acSymbol;
|
||||||
|
|
||||||
|
@ -1121,12 +1127,20 @@ private:
|
||||||
return istring(app.data);
|
return istring(app.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void populateInitializer(T)(SemanticSymbol* symbol, const T initializer,
|
void populateInitializer(T)(ref TypeLookups lookups, const T initializer,
|
||||||
bool appendForeach = false)
|
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 visitor = new InitializerVisitor(lookup, appendForeach, this);
|
scope visitor = new InitializerVisitor(lookup, appendForeach, this);
|
||||||
symbol.typeLookups.insert(lookup);
|
scope (exit)
|
||||||
|
if (!visitor.isCast)
|
||||||
|
lookup.breadcrumbs.insert(TYPEOF_END_SYMBOL_NAME);
|
||||||
|
|
||||||
|
if (l is null)
|
||||||
|
lookups.insert(lookup);
|
||||||
|
|
||||||
static if (is(T == typeof(feExpression)))
|
static if (is(T == typeof(feExpression)))
|
||||||
visitor.dynamicDispatch(initializer);
|
visitor.dynamicDispatch(initializer);
|
||||||
else
|
else
|
||||||
|
@ -1149,22 +1163,20 @@ private:
|
||||||
auto lookup = l !is null ? l : TypeLookupsAllocator.instance.make!TypeLookup(
|
auto lookup = l !is null ? l : TypeLookupsAllocator.instance.make!TypeLookup(
|
||||||
TypeLookupKind.varOrFunType);
|
TypeLookupKind.varOrFunType);
|
||||||
auto t2 = type.type2;
|
auto t2 = type.type2;
|
||||||
if (t2.type !is null)
|
if (t2.typeofExpression !is null)
|
||||||
addTypeToLookups(lookups, t2.type, lookup);
|
populateInitializer(lookups, t2.typeofExpression, false, lookup);
|
||||||
else if (t2.superOrThis is tok!"this")
|
else if (t2.superOrThis is tok!"this")
|
||||||
lookup.breadcrumbs.insert(internString("this"));
|
lookup.breadcrumbs.insert(internString("this"));
|
||||||
else if (t2.superOrThis is tok!"super")
|
else if (t2.superOrThis is tok!"super")
|
||||||
lookup.breadcrumbs.insert(internString("super"));
|
lookup.breadcrumbs.insert(internString("super"));
|
||||||
|
|
||||||
|
if (t2.type !is null)
|
||||||
|
addTypeToLookups(lookups, t2.type, lookup);
|
||||||
else if (t2.builtinType !is tok!"")
|
else if (t2.builtinType !is tok!"")
|
||||||
lookup.breadcrumbs.insert(getBuiltinTypeName(t2.builtinType));
|
lookup.breadcrumbs.insert(getBuiltinTypeName(t2.builtinType));
|
||||||
else if (t2.typeIdentifierPart !is null)
|
else if (t2.typeIdentifierPart !is null)
|
||||||
writeIotcTo(t2.typeIdentifierPart, lookup.breadcrumbs);
|
writeIotcTo(t2.typeIdentifierPart, lookup.breadcrumbs);
|
||||||
else
|
// TODO: support __vector, traits and mixin
|
||||||
{
|
|
||||||
// TODO: Add support for typeof expressions
|
|
||||||
// TODO: Add support for __vector
|
|
||||||
// warning("typeof() and __vector are not yet supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (suffix; type.typeSuffixes)
|
foreach (suffix; type.typeSuffixes)
|
||||||
{
|
{
|
||||||
|
@ -1346,6 +1358,10 @@ void writeIotcTo(T)(const TypeIdentifierPart tip, ref T output) nothrow
|
||||||
{
|
{
|
||||||
if (!tip.identifierOrTemplateInstance)
|
if (!tip.identifierOrTemplateInstance)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (tip.dot)
|
||||||
|
output.insert(MODULE_SYMBOL_NAME);
|
||||||
|
|
||||||
if (tip.identifierOrTemplateInstance.identifier != tok!"")
|
if (tip.identifierOrTemplateInstance.identifier != tok!"")
|
||||||
output.insert(internString(tip.identifierOrTemplateInstance.identifier.text));
|
output.insert(internString(tip.identifierOrTemplateInstance.identifier.text));
|
||||||
else
|
else
|
||||||
|
@ -1575,6 +1591,25 @@ class InitializerVisitor : ASTVisitor
|
||||||
on = false;
|
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)
|
override void dynamicDispatch(const ExpressionNode expression)
|
||||||
{
|
{
|
||||||
on = true;
|
on = true;
|
||||||
|
@ -1588,6 +1623,7 @@ class InitializerVisitor : ASTVisitor
|
||||||
bool on = false;
|
bool on = false;
|
||||||
const bool appendForeach;
|
const bool appendForeach;
|
||||||
FirstPass fp;
|
FirstPass fp;
|
||||||
|
bool isCast;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArgumentListVisitor : ASTVisitor
|
class ArgumentListVisitor : ASTVisitor
|
||||||
|
|
|
@ -115,6 +115,7 @@ class AutocompleteParser : Parser
|
||||||
{
|
{
|
||||||
if (!currentIs(tok!"{"))
|
if (!currentIs(tok!"{"))
|
||||||
return null;
|
return null;
|
||||||
|
if (cursorPosition == -1) return super.parseBlockStatement();
|
||||||
if (current.index > cursorPosition)
|
if (current.index > cursorPosition)
|
||||||
{
|
{
|
||||||
BlockStatement bs = allocator.make!(BlockStatement);
|
BlockStatement bs = allocator.make!(BlockStatement);
|
||||||
|
|
|
@ -237,16 +237,40 @@ do
|
||||||
}
|
}
|
||||||
|
|
||||||
// Follow all the names and try to resolve them
|
// Follow all the names and try to resolve them
|
||||||
size_t i = 0;
|
bool first = true;
|
||||||
foreach (part; lookup.breadcrumbs[])
|
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)
|
if (moduleScope is null)
|
||||||
getSymbolFromImports(imports, part);
|
getSymbolFromImports(imports, part);
|
||||||
else
|
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)
|
if (symbols.length > 0)
|
||||||
currentSymbol = symbols[0];
|
currentSymbol = symbols[0];
|
||||||
else
|
else
|
||||||
|
@ -273,7 +297,6 @@ do
|
||||||
return;
|
return;
|
||||||
currentSymbol = currentSymbol.getFirstPartNamed(part);
|
currentSymbol = currentSymbol.getFirstPartNamed(part);
|
||||||
}
|
}
|
||||||
++i;
|
|
||||||
if (currentSymbol is null)
|
if (currentSymbol is null)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -311,19 +334,32 @@ do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
|
private void resolveTypeFromInitializer(R)(DSymbol* symbol, TypeLookup* lookup,
|
||||||
Scope* moduleScope, ref ModuleCache cache)
|
Scope* moduleScope, ref ModuleCache cache,
|
||||||
|
ref R breadcrumbs, ref DSymbol* currentSymbol)
|
||||||
{
|
{
|
||||||
if (lookup.breadcrumbs.length == 0)
|
if (breadcrumbs.empty)
|
||||||
return;
|
return;
|
||||||
DSymbol* currentSymbol = null;
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
auto crumbs = lookup.breadcrumbs[];
|
bool first = true;
|
||||||
foreach (crumb; crumbs)
|
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(
|
currentSymbol = moduleScope.getFirstSymbolByNameAndCursor(
|
||||||
symbolNameToTypeName(crumb), symbol.location);
|
symbolNameToTypeName(crumb), symbol.location);
|
||||||
|
|
||||||
|
@ -348,18 +384,21 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
|
||||||
|| currentSymbol.qualifier == SymbolQualifier.pointer
|
|| currentSymbol.qualifier == SymbolQualifier.pointer
|
||||||
|| currentSymbol.kind == CompletionKind.aliasName)
|
|| currentSymbol.kind == CompletionKind.aliasName)
|
||||||
{
|
{
|
||||||
if (currentSymbol.type !is null)
|
// may become null, returns later
|
||||||
currentSymbol = currentSymbol.type;
|
currentSymbol = currentSymbol.type;
|
||||||
else
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto opIndex = currentSymbol.getFirstPartNamed(internString("opIndex"));
|
auto opIndex = currentSymbol.getFirstPartNamed(internString("opIndex"));
|
||||||
if (opIndex !is null)
|
if (opIndex !is null)
|
||||||
|
{
|
||||||
currentSymbol = opIndex.type;
|
currentSymbol = opIndex.type;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
currentSymbol = null;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (crumb == "foreach")
|
else if (crumb == "foreach")
|
||||||
|
@ -371,19 +410,19 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
|
||||||
|| currentSymbol.qualifier == SymbolQualifier.assocArray)
|
|| currentSymbol.qualifier == SymbolQualifier.assocArray)
|
||||||
{
|
{
|
||||||
currentSymbol = currentSymbol.type;
|
currentSymbol = currentSymbol.type;
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
auto front = currentSymbol.getFirstPartNamed(internString("front"));
|
auto front = currentSymbol.getFirstPartNamed(internString("front"));
|
||||||
if (front !is null)
|
if (front !is null)
|
||||||
{
|
{
|
||||||
currentSymbol = front.type;
|
currentSymbol = front.type;
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
auto opApply = currentSymbol.getFirstPartNamed(internString("opApply"));
|
auto opApply = currentSymbol.getFirstPartNamed(internString("opApply"));
|
||||||
if (opApply !is null)
|
if (opApply !is null)
|
||||||
{
|
{
|
||||||
currentSymbol = opApply.type;
|
currentSymbol = opApply.type;
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -393,13 +432,10 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
|
||||||
return;
|
return;
|
||||||
currentSymbol = currentSymbol.getFirstPartNamed(crumb);
|
currentSymbol = currentSymbol.getFirstPartNamed(crumb);
|
||||||
}
|
}
|
||||||
++i;
|
|
||||||
if (currentSymbol is null)
|
if (currentSymbol is null)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
typeSwap(currentSymbol);
|
typeSwap(currentSymbol);
|
||||||
symbol.type = currentSymbol;
|
|
||||||
symbol.ownType = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -506,8 +542,6 @@ void resolveType(DSymbol* symbol, ref TypeLookups typeLookups,
|
||||||
foreach(lookup; typeLookups) {
|
foreach(lookup; typeLookups) {
|
||||||
if (lookup.kind == TypeLookupKind.varOrFunType)
|
if (lookup.kind == TypeLookupKind.varOrFunType)
|
||||||
resolveTypeFromType(symbol, lookup, moduleScope, cache, null);
|
resolveTypeFromType(symbol, lookup, moduleScope, cache, null);
|
||||||
else if (lookup.kind == TypeLookupKind.initializer)
|
|
||||||
resolveTypeFromInitializer(symbol, lookup, moduleScope, cache);
|
|
||||||
// issue 94
|
// issue 94
|
||||||
else if (lookup.kind == TypeLookupKind.inherit)
|
else if (lookup.kind == TypeLookupKind.inherit)
|
||||||
resolveInheritance(symbol, typeLookups, moduleScope, cache);
|
resolveInheritance(symbol, typeLookups, moduleScope, cache);
|
||||||
|
|
|
@ -64,8 +64,6 @@ void checkMissingTypes(SemanticSymbol* currentSymbol, Scope* moduleScope, ref Mo
|
||||||
auto lookup = currentSymbol.typeLookups.front;
|
auto lookup = currentSymbol.typeLookups.front;
|
||||||
if (lookup.kind == TypeLookupKind.varOrFunType)
|
if (lookup.kind == TypeLookupKind.varOrFunType)
|
||||||
resolveTypeFromType(currentSymbol.acSymbol, lookup, moduleScope, cache, null);
|
resolveTypeFromType(currentSymbol.acSymbol, lookup, moduleScope, cache, null);
|
||||||
else if (lookup.kind == TypeLookupKind.initializer)
|
|
||||||
resolveTypeFromInitializer(currentSymbol.acSymbol, lookup, moduleScope, cache);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -234,7 +234,7 @@ struct DSymbol
|
||||||
|
|
||||||
// pointers are implicitly dereferenced on members (a single layer)
|
// pointers are implicitly dereferenced on members (a single layer)
|
||||||
if (qualifier == SymbolQualifier.pointer
|
if (qualifier == SymbolQualifier.pointer
|
||||||
&& this.type.qualifier != SymbolQualifier.pointer)
|
&& (this.type && this.type.qualifier != SymbolQualifier.pointer))
|
||||||
return type.getParts!OR(name, app, visited, onlyOne);
|
return type.getParts!OR(name, app, visited, onlyOne);
|
||||||
|
|
||||||
if (name is null)
|
if (name is null)
|
||||||
|
@ -386,11 +386,6 @@ struct DSymbol
|
||||||
|
|
||||||
// Is alias this symbols
|
// Is alias this symbols
|
||||||
DSymbol*[] aliasThisSymbols;
|
DSymbol*[] aliasThisSymbols;
|
||||||
/**
|
|
||||||
* Names of function arguments
|
|
||||||
*/
|
|
||||||
// TODO: remove since we have function arguments
|
|
||||||
UnrolledList!(istring) argNames;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function parameter symbols
|
* Function parameter symbols
|
||||||
|
|
|
@ -10,7 +10,6 @@ enum TypeLookupKind : ubyte
|
||||||
{
|
{
|
||||||
inherit,
|
inherit,
|
||||||
aliasThis,
|
aliasThis,
|
||||||
initializer,
|
|
||||||
mixinTemplate,
|
mixinTemplate,
|
||||||
varOrFunType,
|
varOrFunType,
|
||||||
selectiveImport,
|
selectiveImport,
|
||||||
|
|
2
dub.json
2
dub.json
|
@ -8,7 +8,7 @@
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
":dsymbol": "*",
|
":dsymbol": "*",
|
||||||
"libdparse": ">=0.23.0 <0.24.0",
|
"libdparse": ">=0.23.0 <0.26.0",
|
||||||
":common": "*",
|
":common": "*",
|
||||||
"emsi_containers": "~>0.9.0"
|
"emsi_containers": "~>0.9.0"
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
"versions": {
|
"versions": {
|
||||||
"dsymbol": "0.14.1",
|
"dsymbol": "0.14.1",
|
||||||
"emsi_containers": "0.9.0",
|
"emsi_containers": "0.9.0",
|
||||||
"libdparse": "0.23.0",
|
"libdparse": "0.25.0",
|
||||||
"msgpack-d": "1.0.4",
|
"msgpack-d": "1.0.5",
|
||||||
"stdx-allocator": "2.77.5"
|
"stdx-allocator": "2.77.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 86c9bf44c96e1666eb175c749cc26f62c2008979
|
Subproject commit f8a6c28589aae180532fb460a1b22e92a0978292
|
12
makefile
12
makefile
|
@ -13,8 +13,6 @@ LDC := ldc2
|
||||||
DPARSE_DIR := libdparse
|
DPARSE_DIR := libdparse
|
||||||
DSYMBOL_DIR := dsymbol
|
DSYMBOL_DIR := dsymbol
|
||||||
|
|
||||||
SHELL:=/bin/bash
|
|
||||||
|
|
||||||
githash:
|
githash:
|
||||||
@mkdir -p bin
|
@mkdir -p bin
|
||||||
git describe --tags > bin/githash.txt
|
git describe --tags > bin/githash.txt
|
||||||
|
@ -37,7 +35,6 @@ CLIENT_SRC := \
|
||||||
DMD_CLIENT_FLAGS := -Imsgpack-d/src\
|
DMD_CLIENT_FLAGS := -Imsgpack-d/src\
|
||||||
-Imsgpack-d/src\
|
-Imsgpack-d/src\
|
||||||
-Jbin\
|
-Jbin\
|
||||||
-inline\
|
|
||||||
-O\
|
-O\
|
||||||
-wi\
|
-wi\
|
||||||
-ofbin/dcd-client
|
-ofbin/dcd-client
|
||||||
|
@ -56,6 +53,10 @@ LDC_CLIENT_FLAGS := -Imsgpack-d/src\
|
||||||
-oq\
|
-oq\
|
||||||
-of=bin/dcd-client
|
-of=bin/dcd-client
|
||||||
|
|
||||||
|
ifneq ($(shell uname), OpenBSD)
|
||||||
|
override DMD_CLIENT_FLAGS += -inline
|
||||||
|
endif
|
||||||
|
|
||||||
override DMD_CLIENT_FLAGS += $(DFLAGS)
|
override DMD_CLIENT_FLAGS += $(DFLAGS)
|
||||||
override LDC_CLIENT_FLAGS += $(DFLAGS)
|
override LDC_CLIENT_FLAGS += $(DFLAGS)
|
||||||
override GDC_CLIENT_FLAGS += $(DFLAGS)
|
override GDC_CLIENT_FLAGS += $(DFLAGS)
|
||||||
|
@ -76,7 +77,6 @@ DMD_SERVER_FLAGS := -Icontainers/src\
|
||||||
-wi\
|
-wi\
|
||||||
-O\
|
-O\
|
||||||
-release\
|
-release\
|
||||||
-inline\
|
|
||||||
-ofbin/dcd-server
|
-ofbin/dcd-server
|
||||||
|
|
||||||
DEBUG_SERVER_FLAGS := -Icontainers/src\
|
DEBUG_SERVER_FLAGS := -Icontainers/src\
|
||||||
|
@ -106,6 +106,10 @@ LDC_SERVER_FLAGS := -Icontainers/src\
|
||||||
-O5\
|
-O5\
|
||||||
-release
|
-release
|
||||||
|
|
||||||
|
ifneq ($(shell uname), OpenBSD)
|
||||||
|
DMD_SERVER_FLAGS += -inline
|
||||||
|
endif
|
||||||
|
|
||||||
override DMD_SERVER_FLAGS += $(DFLAGS)
|
override DMD_SERVER_FLAGS += $(DFLAGS)
|
||||||
override LDC_SERVER_FLAGS += $(DFLAGS)
|
override LDC_SERVER_FLAGS += $(DFLAGS)
|
||||||
override GDC_SERVER_FLAGS += $(DFLAGS)
|
override GDC_SERVER_FLAGS += $(DFLAGS)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 480f3bf9ee80ccf6695ed900cfcc1850ba8da991
|
Subproject commit 26ef07e16023483ad93e3f86374b19d0e541c924
|
|
@ -62,6 +62,7 @@ int runClient(string[] args)
|
||||||
bool clearCache;
|
bool clearCache;
|
||||||
bool symbolLocation;
|
bool symbolLocation;
|
||||||
bool doc;
|
bool doc;
|
||||||
|
bool inlayHints;
|
||||||
bool query;
|
bool query;
|
||||||
bool printVersion;
|
bool printVersion;
|
||||||
bool listImports;
|
bool listImports;
|
||||||
|
@ -86,6 +87,7 @@ int runClient(string[] args)
|
||||||
"R", &removedImportPaths, "port|p", &port, "help|h", &help,
|
"R", &removedImportPaths, "port|p", &port, "help|h", &help,
|
||||||
"shutdown", &shutdown, "clearCache", &clearCache,
|
"shutdown", &shutdown, "clearCache", &clearCache,
|
||||||
"symbolLocation|l", &symbolLocation, "doc|d", &doc,
|
"symbolLocation|l", &symbolLocation, "doc|d", &doc,
|
||||||
|
"inlayHints", &inlayHints,
|
||||||
"query|status|q", &query, "search|s", &search,
|
"query|status|q", &query, "search|s", &search,
|
||||||
"version", &printVersion, "listImports", &listImports,
|
"version", &printVersion, "listImports", &listImports,
|
||||||
"tcp", &useTCP, "socketFile", &socketFile,
|
"tcp", &useTCP, "socketFile", &socketFile,
|
||||||
|
@ -181,7 +183,7 @@ int runClient(string[] args)
|
||||||
printImportList(response);
|
printImportList(response);
|
||||||
return 0;
|
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
|
// cursor position is a required argument
|
||||||
printHelp(args[0]);
|
printHelp(args[0]);
|
||||||
|
@ -234,6 +236,8 @@ int runClient(string[] args)
|
||||||
request.kind |= RequestKind.search;
|
request.kind |= RequestKind.search;
|
||||||
else if(localUse)
|
else if(localUse)
|
||||||
request.kind |= RequestKind.localUse;
|
request.kind |= RequestKind.localUse;
|
||||||
|
else if (inlayHints)
|
||||||
|
request.kind |= RequestKind.inlayHints;
|
||||||
else
|
else
|
||||||
request.kind |= RequestKind.autocomplete;
|
request.kind |= RequestKind.autocomplete;
|
||||||
|
|
||||||
|
@ -250,11 +254,13 @@ int runClient(string[] args)
|
||||||
else if (getIdentifier)
|
else if (getIdentifier)
|
||||||
printIdentifierResponse(response);
|
printIdentifierResponse(response);
|
||||||
else if (doc)
|
else if (doc)
|
||||||
printDocResponse(response);
|
printDocResponse(response, fullOutput);
|
||||||
else if (search !is null)
|
else if (search !is null)
|
||||||
printSearchResponse(response);
|
printSearchResponse(response);
|
||||||
else if (localUse)
|
else if (localUse)
|
||||||
printLocalUse(response);
|
printLocalUse(response);
|
||||||
|
else if (inlayHints)
|
||||||
|
printInlayHintsResponse(response);
|
||||||
else
|
else
|
||||||
printCompletionResponse(response, fullOutput);
|
printCompletionResponse(response, fullOutput);
|
||||||
|
|
||||||
|
@ -295,6 +301,10 @@ Options:
|
||||||
Gets documentation comments associated with the symbol at the cursor
|
Gets documentation comments associated with the symbol at the cursor
|
||||||
location.
|
location.
|
||||||
|
|
||||||
|
--inlayHints
|
||||||
|
For all supported variable usages, show value types. Currently shows
|
||||||
|
alias definitions.
|
||||||
|
|
||||||
--search | -s symbolName
|
--search | -s symbolName
|
||||||
Searches for symbolName in both stdin / the given file name as well as
|
Searches for symbolName in both stdin / the given file name as well as
|
||||||
others files cached by the server.
|
others files cached by the server.
|
||||||
|
@ -359,10 +369,14 @@ Socket createSocket(string socketFile, ushort port)
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printDocResponse(ref const AutocompleteResponse response)
|
void printDocResponse(ref const AutocompleteResponse response, bool extended)
|
||||||
{
|
{
|
||||||
import std.algorithm : each;
|
foreach (ref completion; response.completions)
|
||||||
response.completions.each!(a => a.documentation.escapeConsoleOutputString(true).writeln);
|
{
|
||||||
|
if (extended)
|
||||||
|
writeln(completion.definition);
|
||||||
|
writeln(completion.documentation.escapeConsoleOutputString(true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void printIdentifierResponse(ref const AutocompleteResponse response)
|
void printIdentifierResponse(ref const AutocompleteResponse response)
|
||||||
|
@ -380,6 +394,21 @@ void printLocationResponse(ref const AutocompleteResponse response)
|
||||||
writeln(makeTabSeparated(response.symbolFilePath, response.symbolLocation.to!string));
|
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)
|
void printCompletionResponse(ref const AutocompleteResponse response, bool extended)
|
||||||
{
|
{
|
||||||
if (response.completions.length > 0)
|
if (response.completions.length > 0)
|
||||||
|
|
|
@ -361,7 +361,12 @@ CalltipHint getCalltipHint(T)(T beforeTokens, out size_t parenIndex)
|
||||||
// evaluate at comma case
|
// evaluate at comma case
|
||||||
if (beforeTokens.isComma)
|
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 "!("
|
// check if we are actually a "!("
|
||||||
if (beforeTokens[0 .. parenIndex].isTemplateBangParen)
|
if (beforeTokens[0 .. parenIndex].isTemplateBangParen)
|
||||||
{
|
{
|
||||||
|
|
|
@ -62,7 +62,7 @@ public AutocompleteResponse getDoc(const AutocompleteRequest request,
|
||||||
continue;
|
continue;
|
||||||
firstSymbol = false;
|
firstSymbol = false;
|
||||||
|
|
||||||
AutocompleteResponse.Completion c;
|
AutocompleteResponse.Completion c = makeSymbolCompletionInfo(symbol, symbol.kind);
|
||||||
c.documentation = symbol.doc;
|
c.documentation = symbol.doc;
|
||||||
response.completions ~= c;
|
response.completions ~= c;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
/**
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
response.completions.sort!"a.symbolLocation < b.symbolLocation";
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
|
@ -57,12 +57,14 @@ public AutocompleteResponse findLocalUse(AutocompleteRequest request,
|
||||||
config.fileName = "";
|
config.fileName = "";
|
||||||
const(Token)[] tokenArray = getTokensForParser(cast(ubyte[]) request.sourceCode,
|
const(Token)[] tokenArray = getTokensForParser(cast(ubyte[]) request.sourceCode,
|
||||||
config, &cache);
|
config, &cache);
|
||||||
|
auto sortedTokens = assumeSorted(tokenArray);
|
||||||
|
ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray,
|
||||||
|
&rba, request.cursorPosition, moduleCache);
|
||||||
|
scope(exit) pair.destroy();
|
||||||
|
|
||||||
SymbolStuff getSymbolsAtCursor(size_t cursorPosition)
|
SymbolStuff getSymbolsAtCursor(size_t cursorPosition)
|
||||||
{
|
{
|
||||||
auto sortedTokens = assumeSorted(tokenArray);
|
|
||||||
auto beforeTokens = sortedTokens.lowerBound(cursorPosition);
|
auto beforeTokens = sortedTokens.lowerBound(cursorPosition);
|
||||||
ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray,
|
|
||||||
&rba, request.cursorPosition, moduleCache);
|
|
||||||
auto expression = getExpression(beforeTokens);
|
auto expression = getExpression(beforeTokens);
|
||||||
return SymbolStuff(getSymbolsByTokenChain(pair.scope_, expression,
|
return SymbolStuff(getSymbolsByTokenChain(pair.scope_, expression,
|
||||||
cursorPosition, CompletionType.location), pair.symbol, pair.scope_);
|
cursorPosition, CompletionType.location), pair.symbol, pair.scope_);
|
||||||
|
@ -70,7 +72,6 @@ public AutocompleteResponse findLocalUse(AutocompleteRequest request,
|
||||||
|
|
||||||
// gets the symbol matching to cursor pos
|
// gets the symbol matching to cursor pos
|
||||||
SymbolStuff stuff = getSymbolsAtCursor(cast(size_t)request.cursorPosition);
|
SymbolStuff stuff = getSymbolsAtCursor(cast(size_t)request.cursorPosition);
|
||||||
scope(exit) stuff.destroy();
|
|
||||||
|
|
||||||
// starts searching only if no ambiguity with the symbol
|
// starts searching only if no ambiguity with the symbol
|
||||||
if (stuff.symbols.length == 1)
|
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
|
size_t pos = cast(size_t) t.index + 1; // place cursor inside the token
|
||||||
SymbolStuff candidate = getSymbolsAtCursor(pos);
|
SymbolStuff candidate = getSymbolsAtCursor(pos);
|
||||||
scope(exit) candidate.destroy();
|
|
||||||
if (candidate.symbols.length == 1 &&
|
if (candidate.symbols.length == 1 &&
|
||||||
candidate.symbols[0].location == sourceSymbol.location &&
|
candidate.symbols[0].location == sourceSymbol.location &&
|
||||||
candidate.symbols[0].symbolFile == sourceSymbol.symbolFile)
|
candidate.symbols[0].symbolFile == sourceSymbol.symbolFile)
|
||||||
|
|
|
@ -24,3 +24,4 @@ import dcd.server.autocomplete.complete;
|
||||||
import dcd.server.autocomplete.doc;
|
import dcd.server.autocomplete.doc;
|
||||||
import dcd.server.autocomplete.localuse;
|
import dcd.server.autocomplete.localuse;
|
||||||
import dcd.server.autocomplete.symbols;
|
import dcd.server.autocomplete.symbols;
|
||||||
|
import dcd.server.autocomplete.inlayhints;
|
||||||
|
|
|
@ -147,7 +147,8 @@ SymbolStuff getSymbolsForCompletion(const AutocompleteRequest request,
|
||||||
auto expression = getExpression(beforeTokens);
|
auto expression = getExpression(beforeTokens);
|
||||||
auto symbols = getSymbolsByTokenChain(pair.scope_, expression,
|
auto symbols = getSymbolsByTokenChain(pair.scope_, expression,
|
||||||
request.cursorPosition, type);
|
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
|
// Let search for UFCS, since we got no hit
|
||||||
symbols ~= getSymbolsByTokenChain(pair.scope_, getExpression([beforeTokens.back]), request.cursorPosition, type);
|
symbols ~= getSymbolsByTokenChain(pair.scope_, getExpression([beforeTokens.back]), request.cursorPosition, type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -347,6 +347,11 @@ int runServer(string[] args)
|
||||||
s.trySendResponse(symbolSearch(request, cache), "Could not perform symbol search");
|
s.trySendResponse(symbolSearch(request, cache), "Could not perform symbol search");
|
||||||
else if (request.kind & RequestKind.localUse)
|
else if (request.kind & RequestKind.localUse)
|
||||||
s.trySendResponse(findLocalUse(request, cache), "Couldnot find local usage");
|
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)
|
else if (needResponse)
|
||||||
s.trySendResponse(AutocompleteResponse.ack, "Could not send ack");
|
s.trySendResponse(AutocompleteResponse.ack, "Could not send ack");
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,9 @@ enum CONFIG_FILE_NAME = "dcd.conf";
|
||||||
version(linux) version = useXDG;
|
version(linux) version = useXDG;
|
||||||
version(BSD) version = useXDG;
|
version(BSD) version = useXDG;
|
||||||
version(FreeBSD) version = useXDG;
|
version(FreeBSD) version = useXDG;
|
||||||
|
version(OpenBSD) version = useXDG;
|
||||||
|
version(NetBSD) version = useXDG;
|
||||||
|
version(DragonflyBSD) version = useXDG;
|
||||||
version(OSX) version = useXDG;
|
version(OSX) version = useXDG;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
if [ -z "${DC:-}" ]; then
|
if [ -z "${DC:-}" ]; then
|
||||||
DC=dmd
|
DC=dmd
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#! /bin/bash
|
#! /usr/bin/env bash
|
||||||
RED="\033[31m"
|
RED="\033[31m"
|
||||||
GREEN="\033[32m"
|
GREEN="\033[32m"
|
||||||
YELLOW="\033[33m"
|
YELLOW="\033[33m"
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
identifiers
|
||||||
|
alignof k
|
||||||
|
init k
|
||||||
|
inside_c v
|
||||||
|
mangleof k
|
||||||
|
sizeof k
|
||||||
|
stringof k
|
||||||
|
tupleof k
|
|
@ -0,0 +1,34 @@
|
||||||
|
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.
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
struct A {}
|
||||||
|
|
||||||
|
auto from_cast = cast(.A.B.C) nonExist;
|
||||||
|
from_cast.
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
../../bin/dcd-client $1 file.d -c320 > actual3.txt
|
||||||
|
diff actual3.txt expected1.txt --strip-trailing-cr
|
|
@ -0,0 +1,3 @@
|
||||||
|
identifiers
|
||||||
|
mangleof k
|
||||||
|
member1 v
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
||||||
|
l ->Point 208
|
||||||
|
l ->Point 247
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
||||||
|
identifiers
|
||||||
|
test v Enum test stdin 121 Enum
|
|
@ -0,0 +1,8 @@
|
||||||
|
identifiers
|
||||||
|
alignof k
|
||||||
|
init k
|
||||||
|
mangleof k
|
||||||
|
ok v bool ok stdin 16 bool
|
||||||
|
sizeof k
|
||||||
|
stringof k
|
||||||
|
tupleof k
|
|
@ -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
|
|
@ -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.
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
struct MyTemplate(T)
|
||||||
|
{
|
||||||
|
enum Enum { a, b }
|
||||||
|
|
||||||
|
T member1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MyTemplate!long global2;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
typeof(global2).Enum test;
|
||||||
|
test
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
struct S { bool ok; }
|
||||||
|
|
||||||
|
S global3;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
typeof(global3)[] test;
|
||||||
|
test[0].
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue