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:
parent
c2051b0a62
commit
0f69db00fb
|
@ -32,6 +32,7 @@ import dsymbol.string_interning;
|
||||||
import dsymbol.symbol;
|
import dsymbol.symbol;
|
||||||
import std.algorithm;
|
import std.algorithm;
|
||||||
import std.experimental.allocator;
|
import std.experimental.allocator;
|
||||||
|
import containers.hashset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by autocompletion.
|
* Used by autocompletion.
|
||||||
|
@ -47,6 +48,77 @@ ScopeSymbolPair generateAutocompleteTrees(const(Token)[] tokens,
|
||||||
first.run();
|
first.run();
|
||||||
|
|
||||||
secondPass(first.rootSymbol, first.moduleScope, cache);
|
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);
|
auto r = move(first.rootSymbol.acSymbol);
|
||||||
typeid(SemanticSymbol).destroy(first.rootSymbol);
|
typeid(SemanticSymbol).destroy(first.rootSymbol);
|
||||||
return ScopeSymbolPair(r, move(first.moduleScope));
|
return ScopeSymbolPair(r, move(first.moduleScope));
|
||||||
|
|
|
@ -245,9 +245,13 @@ do
|
||||||
if (symbols.length > 0)
|
if (symbols.length > 0)
|
||||||
currentSymbol = symbols[0];
|
currentSymbol = symbols[0];
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
// store the part, that'll be useful to resolve the type later
|
||||||
|
symbol.typeSymbolName = istring(part);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (currentSymbol.kind == CompletionKind.aliasName)
|
if (currentSymbol.kind == CompletionKind.aliasName)
|
||||||
|
|
|
@ -386,6 +386,11 @@ struct DSymbol
|
||||||
*/
|
*/
|
||||||
DSymbol*[] functionParameters;
|
DSymbol*[] functionParameters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to resolve the type
|
||||||
|
*/
|
||||||
|
istring typeSymbolName;
|
||||||
|
|
||||||
private uint _location;
|
private uint _location;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
import testing; void main() { Hello hello; hello.w }
|
|
@ -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
|
|
@ -0,0 +1,11 @@
|
||||||
|
module testing.a;
|
||||||
|
|
||||||
|
import testing;
|
||||||
|
|
||||||
|
struct Fuck {}
|
||||||
|
|
||||||
|
struct Hello
|
||||||
|
{
|
||||||
|
World world;
|
||||||
|
Fuck fuck;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
module testing.b;
|
||||||
|
|
||||||
|
import testing;
|
||||||
|
|
||||||
|
struct World
|
||||||
|
{
|
||||||
|
int field;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
module testing;
|
||||||
|
|
||||||
|
public import testing.a;
|
||||||
|
public import testing.b;
|
Loading…
Reference in New Issue