DCD/src/dcd/server/autocomplete/inlayhints.d
2023-12-04 11:01:19 +01:00

111 lines
3.2 KiB
D

/**
* 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;
}