diff --git a/dsymbol/src/dsymbol/conversion/package.d b/dsymbol/src/dsymbol/conversion/package.d index 9de9fd9..e145cdc 100644 --- a/dsymbol/src/dsymbol/conversion/package.d +++ b/dsymbol/src/dsymbol/conversion/package.d @@ -25,6 +25,7 @@ import dparse.rollback_allocator; import dsymbol.cache_entry; import dsymbol.conversion.first; import dsymbol.conversion.second; +import dsymbol.conversion.third; import dsymbol.modulecache; import dsymbol.scope_; import dsymbol.semantic; @@ -49,75 +50,7 @@ ScopeSymbolPair generateAutocompleteTrees(const(Token)[] tokens, 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); + thirdPass(first.moduleScope, cache, cursorPosition); auto r = move(first.rootSymbol.acSymbol); typeid(SemanticSymbol).destroy(first.rootSymbol); diff --git a/dsymbol/src/dsymbol/conversion/third.d b/dsymbol/src/dsymbol/conversion/third.d new file mode 100644 index 0000000..88b7cd3 --- /dev/null +++ b/dsymbol/src/dsymbol/conversion/third.d @@ -0,0 +1,111 @@ +/** + * 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 . + */ + +module dsymbol.conversion.third; + +import dsymbol.modulecache; +import dsymbol.scope_; +import dsymbol.semantic; +import dsymbol.symbol; +import dsymbol.string_interning; +import dsymbol.deferred; + +import containers.hashset; + + +/** + * Used to resolve the type of remaining symbols that were left out due to modules being parsed from other modules that depend on each other (public imports) + * It will start from the scope of interest at the cursorPosition, and it'll traverse the scope from bottom to top and check if the symbol's type is know + * If it is, then it'll set its type + * If the symbol is not found, then it'll do nothing + */ +void thirdPass(Scope* mscope, ref ModuleCache cache, size_t cursorPosition) +{ + auto desired = mscope.getScopeByCursor(cursorPosition); + tryResolve(desired, cache); +} + +/** + * Used to resolve missing symbols within a scope + */ +void tryResolve(Scope* sc, ref ModuleCache cache) +{ + if (sc is null) return; + auto symbols = sc.symbols; + foreach (item; symbols) + { + DSymbol* target = item.type; + + if (target !is null) + { + HashSet!size_t visited; + foreach (part; target.opSlice()) + { + resolvePart(part, sc, cache, visited); + } + } + } + if (sc.parent !is null) tryResolve(sc.parent, cache); +} + +void resolvePart(DSymbol* part, Scope* sc, ref ModuleCache cache, 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, cache, visited); + } +} \ No newline at end of file