Public import recurse fix (#706)

* Add a 3rd phase to tesolve missing types that were parsed recursively
* store the type name into its own field, so we could resolve templates later

Fixes https://github.com/dlang-community/DCD/issues/678
This commit is contained in:
ryuukk 2023-02-03 11:56:10 +01:00 committed by GitHub
parent c2051b0a62
commit 0f69db00fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 113 additions and 0 deletions

View File

@ -32,6 +32,7 @@ import dsymbol.string_interning;
import dsymbol.symbol;
import std.algorithm;
import std.experimental.allocator;
import containers.hashset;
/**
* Used by autocompletion.
@ -47,6 +48,77 @@ ScopeSymbolPair generateAutocompleteTrees(const(Token)[] tokens,
first.run();
secondPass(first.rootSymbol, first.moduleScope, cache);
void tryResolve(Scope* sc, ref ModuleCache cache)
{
if (sc is null) return;
auto symbols = sc.symbols;
foreach (item; symbols)
{
DSymbol* target = item.type;
void resolvePart(DSymbol* part, Scope* sc, ref HashSet!size_t visited)
{
if (visited.contains(cast(size_t) part))
return;
visited.insert(cast(size_t) part);
// no type but a typeSymbolName, let's resolve its type
if (part.type is null && part.typeSymbolName !is null)
{
import std.string: indexOf;
auto typeName = part.typeSymbolName;
// check if it is available in the scope
// otherwise grab its module symbol to check if it's publickly available
auto result = sc.getSymbolsAtGlobalScope(istring(typeName));
if (result.length > 0)
{
part.type = result[0];
return;
}
else
{
if (part.symbolFile == "stdin") return;
auto moduleSymbol = cache.getModuleSymbol(part.symbolFile);
auto first = moduleSymbol.getFirstPartNamed(istring(typeName));
if (first !is null)
{
part.type = first;
return;
}
else
{
// type couldn't be found, that's stuff like templates
// now we could try to resolve them!
// warning("can't resolve: ", part.name, " callTip: ", typeName);
return;
}
}
}
if (part.type !is null)
{
foreach (typePart; part.type.opSlice())
resolvePart(typePart, sc, visited);
}
}
if (target !is null)
{
HashSet!size_t visited;
foreach (part; target.opSlice())
{
resolvePart(part, sc, visited);
}
}
}
if (sc.parent !is null) tryResolve(sc.parent, cache);
}
auto desired = first.moduleScope.getScopeByCursor(cursorPosition);
tryResolve(desired, cache);
auto r = move(first.rootSymbol.acSymbol);
typeid(SemanticSymbol).destroy(first.rootSymbol);
return ScopeSymbolPair(r, move(first.moduleScope));

View File

@ -245,7 +245,11 @@ do
if (symbols.length > 0)
currentSymbol = symbols[0];
else
{
// store the part, that'll be useful to resolve the type later
symbol.typeSymbolName = istring(part);
return;
}
}
}
else

View File

@ -386,6 +386,11 @@ struct DSymbol
*/
DSymbol*[] functionParameters;
/**
* Used to resolve the type
*/
istring typeSymbolName;
private uint _location;
/**

View File

@ -0,0 +1 @@
import testing; void main() { Hello hello; hello.w }

View File

@ -0,0 +1,8 @@
set -e
set -u
echo "import: $PWD/testing"
../../bin/dcd-client $1 app.d --extended -I $PWD/ -c50 > actual.txt
echo -e "identifiers\nworld\tv\tWorld world\t$PWD/testing/a.d 77\t" > expected.txt
diff actual.txt expected.txt --strip-trailing-cr

View File

@ -0,0 +1,11 @@
module testing.a;
import testing;
struct Fuck {}
struct Hello
{
World world;
Fuck fuck;
}

View File

@ -0,0 +1,8 @@
module testing.b;
import testing;
struct World
{
int field;
}

View File

@ -0,0 +1,4 @@
module testing;
public import testing.a;
public import testing.b;