diff --git a/dsymbol/src/dsymbol/conversion/package.d b/dsymbol/src/dsymbol/conversion/package.d index 0cd59190..9de9fd9b 100644 --- a/dsymbol/src/dsymbol/conversion/package.d +++ b/dsymbol/src/dsymbol/conversion/package.d @@ -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)); diff --git a/dsymbol/src/dsymbol/conversion/second.d b/dsymbol/src/dsymbol/conversion/second.d index 933bfef7..433cd667 100644 --- a/dsymbol/src/dsymbol/conversion/second.d +++ b/dsymbol/src/dsymbol/conversion/second.d @@ -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 diff --git a/dsymbol/src/dsymbol/symbol.d b/dsymbol/src/dsymbol/symbol.d index 6f56e0f3..f6d2abb3 100644 --- a/dsymbol/src/dsymbol/symbol.d +++ b/dsymbol/src/dsymbol/symbol.d @@ -386,6 +386,11 @@ struct DSymbol */ DSymbol*[] functionParameters; + /** + * Used to resolve the type + */ + istring typeSymbolName; + private uint _location; /** diff --git a/tests/tc_recursive_public_import/app.d b/tests/tc_recursive_public_import/app.d new file mode 100644 index 00000000..102c7e47 --- /dev/null +++ b/tests/tc_recursive_public_import/app.d @@ -0,0 +1 @@ +import testing; void main() { Hello hello; hello.w } diff --git a/tests/tc_recursive_public_import/run.sh b/tests/tc_recursive_public_import/run.sh new file mode 100755 index 00000000..d1afc35b --- /dev/null +++ b/tests/tc_recursive_public_import/run.sh @@ -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 diff --git a/tests/tc_recursive_public_import/testing/a.d b/tests/tc_recursive_public_import/testing/a.d new file mode 100644 index 00000000..19ecae4e --- /dev/null +++ b/tests/tc_recursive_public_import/testing/a.d @@ -0,0 +1,11 @@ +module testing.a; + +import testing; + +struct Fuck {} + +struct Hello +{ + World world; + Fuck fuck; +} \ No newline at end of file diff --git a/tests/tc_recursive_public_import/testing/b.d b/tests/tc_recursive_public_import/testing/b.d new file mode 100644 index 00000000..9422c907 --- /dev/null +++ b/tests/tc_recursive_public_import/testing/b.d @@ -0,0 +1,8 @@ +module testing.b; + +import testing; + +struct World +{ + int field; +} diff --git a/tests/tc_recursive_public_import/testing/package.d b/tests/tc_recursive_public_import/testing/package.d new file mode 100644 index 00000000..d2465a32 --- /dev/null +++ b/tests/tc_recursive_public_import/testing/package.d @@ -0,0 +1,4 @@ +module testing; + +public import testing.a; +public import testing.b; \ No newline at end of file