Compare commits
No commits in common. "master" and "v0.16.0-beta.2" have entirely different histories.
master
...
v0.16.0-be
|
@ -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@v4
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pr
|
name: pr
|
||||||
path: pr/
|
path: pr/
|
||||||
|
|
13
README.md
13
README.md
|
@ -314,19 +314,6 @@ 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,12 +78,10 @@ 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 | inlayHints,
|
requiresSourceCode = autocomplete | doc | symbolLocation | search | localUse,
|
||||||
// dfmt on
|
// dfmt on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,39 +260,36 @@ AutocompleteResponse getResponse(Socket socket)
|
||||||
*/
|
*/
|
||||||
bool serverIsRunning(bool useTCP, string socketFile, ushort port)
|
bool serverIsRunning(bool useTCP, string socketFile, ushort port)
|
||||||
{
|
{
|
||||||
try {
|
scope (failure)
|
||||||
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
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
catch (Exception _) {
|
|
||||||
return false;
|
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
|
||||||
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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,9 +27,6 @@ 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,15 +27,6 @@ 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.
|
||||||
*
|
*
|
||||||
|
@ -174,20 +165,6 @@ 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,7 +131,6 @@ 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;
|
||||||
|
@ -271,7 +270,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.typeLookups, part.initializer);
|
populateInitializer(symbol, 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);
|
||||||
|
@ -719,7 +718,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.typeLookups, feExpression, true);
|
populateInitializer(symbol, feExpression, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -738,7 +737,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.typeLookups, ifs.condition.expression, false);
|
populateInitializer(symbol, ifs.condition.expression, false);
|
||||||
}
|
}
|
||||||
ifs.accept(this);
|
ifs.accept(this);
|
||||||
}
|
}
|
||||||
|
@ -756,7 +755,7 @@ final class FirstPass : ASTVisitor
|
||||||
currentScope.startLocation, null);
|
currentScope.startLocation, null);
|
||||||
scope(exit) popSymbol();
|
scope(exit) popSymbol();
|
||||||
|
|
||||||
populateInitializer(currentSymbol.typeLookups, withStatement.expression, false);
|
populateInitializer(currentSymbol, withStatement.expression, false);
|
||||||
withStatement.accept(this);
|
withStatement.accept(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -909,6 +908,7 @@ 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,16 +921,9 @@ 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)
|
||||||
|
@ -1006,6 +999,7 @@ private:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
currentSymbol.acSymbol.argNames.insert(parameter.acSymbol.name);
|
||||||
|
|
||||||
currentSymbol.acSymbol.functionParameters ~= parameter.acSymbol;
|
currentSymbol.acSymbol.functionParameters ~= parameter.acSymbol;
|
||||||
|
|
||||||
|
@ -1127,20 +1121,12 @@ private:
|
||||||
return istring(app.data);
|
return istring(app.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void populateInitializer(T)(ref TypeLookups lookups, const T initializer,
|
void populateInitializer(T)(SemanticSymbol* symbol, const T initializer,
|
||||||
bool appendForeach = false, TypeLookup* l = null)
|
bool appendForeach = false)
|
||||||
{
|
{
|
||||||
auto lookup = l ? l : TypeLookupsAllocator.instance.make!TypeLookup(TypeLookupKind.varOrFunType);
|
auto lookup = TypeLookupsAllocator.instance.make!TypeLookup(TypeLookupKind.initializer);
|
||||||
|
|
||||||
lookup.breadcrumbs.insert(TYPEOF_SYMBOL_NAME);
|
|
||||||
scope visitor = new InitializerVisitor(lookup, appendForeach, this);
|
scope visitor = new InitializerVisitor(lookup, appendForeach, this);
|
||||||
scope (exit)
|
symbol.typeLookups.insert(lookup);
|
||||||
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
|
||||||
|
@ -1163,20 +1149,22 @@ 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.typeofExpression !is null)
|
if (t2.type !is null)
|
||||||
populateInitializer(lookups, t2.typeofExpression, false, lookup);
|
addTypeToLookups(lookups, t2.type, 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);
|
||||||
// TODO: support __vector, traits and mixin
|
else
|
||||||
|
{
|
||||||
|
// 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)
|
||||||
{
|
{
|
||||||
|
@ -1358,10 +1346,6 @@ 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
|
||||||
|
@ -1591,25 +1575,6 @@ 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;
|
||||||
|
@ -1623,7 +1588,6 @@ 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,7 +115,6 @@ 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,40 +237,16 @@ do
|
||||||
}
|
}
|
||||||
|
|
||||||
// Follow all the names and try to resolve them
|
// Follow all the names and try to resolve them
|
||||||
bool first = true;
|
size_t i = 0;
|
||||||
auto breadcrumbs = lookup.breadcrumbs[];
|
foreach (part; lookup.breadcrumbs[])
|
||||||
|
|
||||||
while (!breadcrumbs.empty)
|
|
||||||
{
|
{
|
||||||
auto part = breadcrumbs.front;
|
if (i == 0)
|
||||||
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 = part == MODULE_SYMBOL_NAME
|
auto symbols = moduleScope.getSymbolsByNameAndCursor(part, symbol.location);
|
||||||
? {
|
|
||||||
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
|
||||||
|
@ -297,6 +273,7 @@ do
|
||||||
return;
|
return;
|
||||||
currentSymbol = currentSymbol.getFirstPartNamed(part);
|
currentSymbol = currentSymbol.getFirstPartNamed(part);
|
||||||
}
|
}
|
||||||
|
++i;
|
||||||
if (currentSymbol is null)
|
if (currentSymbol is null)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -334,32 +311,19 @@ do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resolveTypeFromInitializer(R)(DSymbol* symbol, TypeLookup* lookup,
|
void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
|
||||||
Scope* moduleScope, ref ModuleCache cache,
|
Scope* moduleScope, ref ModuleCache cache)
|
||||||
ref R breadcrumbs, ref DSymbol* currentSymbol)
|
|
||||||
{
|
{
|
||||||
if (breadcrumbs.empty)
|
if (lookup.breadcrumbs.length == 0)
|
||||||
return;
|
return;
|
||||||
|
DSymbol* currentSymbol = null;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
bool first = true;
|
auto crumbs = lookup.breadcrumbs[];
|
||||||
while (!breadcrumbs.empty)
|
foreach (crumb; crumbs)
|
||||||
{
|
{
|
||||||
auto crumb = breadcrumbs.front;
|
if (i == 0)
|
||||||
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);
|
||||||
|
|
||||||
|
@ -384,21 +348,18 @@ private void resolveTypeFromInitializer(R)(DSymbol* symbol, TypeLookup* lookup,
|
||||||
|| currentSymbol.qualifier == SymbolQualifier.pointer
|
|| currentSymbol.qualifier == SymbolQualifier.pointer
|
||||||
|| currentSymbol.kind == CompletionKind.aliasName)
|
|| currentSymbol.kind == CompletionKind.aliasName)
|
||||||
{
|
{
|
||||||
// may become null, returns later
|
if (currentSymbol.type !is null)
|
||||||
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")
|
||||||
|
@ -410,19 +371,19 @@ private void resolveTypeFromInitializer(R)(DSymbol* symbol, TypeLookup* lookup,
|
||||||
|| currentSymbol.qualifier == SymbolQualifier.assocArray)
|
|| currentSymbol.qualifier == SymbolQualifier.assocArray)
|
||||||
{
|
{
|
||||||
currentSymbol = currentSymbol.type;
|
currentSymbol = currentSymbol.type;
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
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;
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
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;
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -432,10 +393,13 @@ private void resolveTypeFromInitializer(R)(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:
|
||||||
|
@ -542,6 +506,8 @@ 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,6 +64,8 @@ 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 && this.type.qualifier != SymbolQualifier.pointer))
|
&& 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,6 +386,11 @@ 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,6 +10,7 @@ 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.26.0",
|
"libdparse": ">=0.23.0 <0.24.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.25.0",
|
"libdparse": "0.23.0",
|
||||||
"msgpack-d": "1.0.5",
|
"msgpack-d": "1.0.4",
|
||||||
"stdx-allocator": "2.77.5"
|
"stdx-allocator": "2.77.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit f8a6c28589aae180532fb460a1b22e92a0978292
|
Subproject commit 86c9bf44c96e1666eb175c749cc26f62c2008979
|
12
makefile
12
makefile
|
@ -13,6 +13,8 @@ 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
|
||||||
|
@ -35,6 +37,7 @@ 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
|
||||||
|
@ -53,10 +56,6 @@ 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)
|
||||||
|
@ -77,6 +76,7 @@ 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,10 +106,6 @@ 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 26ef07e16023483ad93e3f86374b19d0e541c924
|
Subproject commit 480f3bf9ee80ccf6695ed900cfcc1850ba8da991
|
|
@ -62,7 +62,6 @@ 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;
|
||||||
|
@ -87,7 +86,6 @@ 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,
|
||||||
|
@ -183,7 +181,7 @@ int runClient(string[] args)
|
||||||
printImportList(response);
|
printImportList(response);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (search == null && !inlayHints && cursorPos == size_t.max)
|
else if (search == null && cursorPos == size_t.max)
|
||||||
{
|
{
|
||||||
// cursor position is a required argument
|
// cursor position is a required argument
|
||||||
printHelp(args[0]);
|
printHelp(args[0]);
|
||||||
|
@ -236,8 +234,6 @@ 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;
|
||||||
|
|
||||||
|
@ -254,13 +250,11 @@ int runClient(string[] args)
|
||||||
else if (getIdentifier)
|
else if (getIdentifier)
|
||||||
printIdentifierResponse(response);
|
printIdentifierResponse(response);
|
||||||
else if (doc)
|
else if (doc)
|
||||||
printDocResponse(response, fullOutput);
|
printDocResponse(response);
|
||||||
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);
|
||||||
|
|
||||||
|
@ -301,10 +295,6 @@ 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.
|
||||||
|
@ -369,14 +359,10 @@ Socket createSocket(string socketFile, ushort port)
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printDocResponse(ref const AutocompleteResponse response, bool extended)
|
void printDocResponse(ref const AutocompleteResponse response)
|
||||||
{
|
{
|
||||||
foreach (ref completion; response.completions)
|
import std.algorithm : each;
|
||||||
{
|
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)
|
||||||
|
@ -394,21 +380,6 @@ 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,12 +361,7 @@ CalltipHint getCalltipHint(T)(T beforeTokens, out size_t parenIndex)
|
||||||
// evaluate at comma case
|
// evaluate at comma case
|
||||||
if (beforeTokens.isComma)
|
if (beforeTokens.isComma)
|
||||||
{
|
{
|
||||||
size_t tmp = beforeTokens.goBackToOpenParen;
|
parenIndex = 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 = makeSymbolCompletionInfo(symbol, symbol.kind);
|
AutocompleteResponse.Completion c;
|
||||||
c.documentation = symbol.doc;
|
c.documentation = symbol.doc;
|
||||||
response.completions ~= c;
|
response.completions ~= c;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,111 +0,0 @@
|
||||||
/**
|
|
||||||
* 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,14 +57,12 @@ 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_);
|
||||||
|
@ -72,6 +70,7 @@ 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)
|
||||||
|
@ -101,6 +100,7 @@ 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,4 +24,3 @@ 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,8 +147,7 @@ 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 && !beforeTokens.empty &&
|
if (symbols.length == 0 && doUFCSSearch(stringToken(beforeTokens.front), stringToken(beforeTokens.back))) {
|
||||||
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,11 +347,6 @@ 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,9 +35,6 @@ 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 @@
|
||||||
#!/usr/bin/env bash
|
#!/bin/bash
|
||||||
|
|
||||||
if [ -z "${DC:-}" ]; then
|
if [ -z "${DC:-}" ]; then
|
||||||
DC=dmd
|
DC=dmd
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#! /usr/bin/env bash
|
#! /bin/bash
|
||||||
RED="\033[31m"
|
RED="\033[31m"
|
||||||
GREEN="\033[32m"
|
GREEN="\033[32m"
|
||||||
YELLOW="\033[33m"
|
YELLOW="\033[33m"
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
identifiers
|
|
||||||
alignof k
|
|
||||||
init k
|
|
||||||
inside_c v
|
|
||||||
mangleof k
|
|
||||||
sizeof k
|
|
||||||
stringof k
|
|
||||||
tupleof k
|
|
|
@ -1,34 +0,0 @@
|
||||||
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.
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
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
|
|
|
@ -1,3 +0,0 @@
|
||||||
identifiers
|
|
||||||
mangleof k
|
|
||||||
member1 v
|
|
|
@ -1,19 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
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
|
|
|
@ -1,2 +0,0 @@
|
||||||
l ->Point 208
|
|
||||||
l ->Point 247
|
|
|
@ -1,17 +0,0 @@
|
||||||
// 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);
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
set -e
|
|
||||||
set -u
|
|
||||||
|
|
||||||
../../bin/dcd-client $1 --inlayHints file.d > actual.txt
|
|
||||||
diff actual.txt expected.txt --strip-trailing-cr
|
|
|
@ -1,20 +0,0 @@
|
||||||
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
|
|
|
@ -1,2 +0,0 @@
|
||||||
identifiers
|
|
||||||
test v Enum test stdin 121 Enum
|
|
|
@ -1,8 +0,0 @@
|
||||||
identifiers
|
|
||||||
alignof k
|
|
||||||
init k
|
|
||||||
mangleof k
|
|
||||||
ok v bool ok stdin 16 bool
|
|
||||||
sizeof k
|
|
||||||
stringof k
|
|
||||||
tupleof k
|
|
|
@ -1,14 +0,0 @@
|
||||||
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
|
|
|
@ -1,32 +0,0 @@
|
||||||
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.
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
struct MyTemplate(T)
|
|
||||||
{
|
|
||||||
enum Enum { a, b }
|
|
||||||
|
|
||||||
T member1;
|
|
||||||
}
|
|
||||||
|
|
||||||
MyTemplate!long global2;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
typeof(global2).Enum test;
|
|
||||||
test
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
struct S { bool ok; }
|
|
||||||
|
|
||||||
S global3;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
typeof(global3)[] test;
|
|
||||||
test[0].
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue