🐛 fix(uses): make file-level uses globally visible
- Preserve top-level `uses` imports and apply them to subsequent unit/class/function/method scopes. - Extend semantic ResolveFromUses to consult file-level imports (and fall back from unit imports).
This commit is contained in:
parent
171d5e2064
commit
ab1dcc00bc
|
|
@ -518,21 +518,28 @@ namespace lsp::language::semantic
|
||||||
|
|
||||||
void Analyzer::VisitUsesStatement(ast::UsesStatement& node)
|
void Analyzer::VisitUsesStatement(ast::UsesStatement& node)
|
||||||
{
|
{
|
||||||
|
auto add_to = [&](std::vector<symbol::UnitImport>& target) {
|
||||||
|
target.reserve(target.size() + node.units.size());
|
||||||
|
for (const auto& unit : node.units)
|
||||||
|
{
|
||||||
|
symbol::UnitImport import;
|
||||||
|
import.unit_name = unit.name;
|
||||||
|
import.location = unit.location;
|
||||||
|
target.push_back(std::move(import));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (!current_unit_context_)
|
if (!current_unit_context_)
|
||||||
{
|
{
|
||||||
|
// Top-level `uses` is treated as file-global.
|
||||||
|
add_to(file_imports_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& context = *current_unit_context_;
|
auto& context = *current_unit_context_;
|
||||||
auto* target = current_unit_section_ == symbol::UnitVisibility::kInterface ? &context.interface_imports : &context.implementation_imports;
|
auto* target = current_unit_section_ == symbol::UnitVisibility::kInterface ? &context.interface_imports : &context.implementation_imports;
|
||||||
|
|
||||||
for (const auto& unit : node.units)
|
add_to(*target);
|
||||||
{
|
|
||||||
symbol::UnitImport import;
|
|
||||||
import.unit_name = unit.name;
|
|
||||||
import.location = unit.location;
|
|
||||||
target->push_back(std::move(import));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Analyzer::VisitIdentifier(ast::Identifier& node)
|
void Analyzer::VisitIdentifier(ast::Identifier& node)
|
||||||
|
|
@ -1167,14 +1174,7 @@ namespace lsp::language::semantic
|
||||||
|
|
||||||
std::optional<symbol::SymbolId> Analyzer::ResolveFromUses(const std::string& name)
|
std::optional<symbol::SymbolId> Analyzer::ResolveFromUses(const std::string& name)
|
||||||
{
|
{
|
||||||
if (!current_unit_context_)
|
auto resolve_from_imports = [&](const std::vector<symbol::UnitImport>& imports) -> std::optional<symbol::SymbolId> {
|
||||||
{
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前上下文的导入列表
|
|
||||||
const auto& imports = current_unit_section_ == symbol::UnitVisibility::kInterface ? current_unit_context_->interface_imports : current_unit_context_->implementation_imports;
|
|
||||||
|
|
||||||
// 从后往前查找(最后导入的优先级最高)
|
// 从后往前查找(最后导入的优先级最高)
|
||||||
for (auto it = imports.rbegin(); it != imports.rend(); ++it)
|
for (auto it = imports.rbegin(); it != imports.rend(); ++it)
|
||||||
{
|
{
|
||||||
|
|
@ -1228,6 +1228,27 @@ namespace lsp::language::semantic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (current_unit_context_)
|
||||||
|
{
|
||||||
|
// 获取当前上下文的导入列表
|
||||||
|
const auto& imports = current_unit_section_ == symbol::UnitVisibility::kInterface ? current_unit_context_->interface_imports : current_unit_context_->implementation_imports;
|
||||||
|
if (auto result = resolve_from_imports(imports))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_imports_.empty())
|
||||||
|
{
|
||||||
|
if (auto result = resolve_from_imports(file_imports_))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -681,6 +681,7 @@ export namespace lsp::language::semantic
|
||||||
std::optional<symbol::SymbolId> current_class_id_;
|
std::optional<symbol::SymbolId> current_class_id_;
|
||||||
std::optional<UnitContext> current_unit_context_;
|
std::optional<UnitContext> current_unit_context_;
|
||||||
std::optional<symbol::UnitVisibility> current_unit_section_;
|
std::optional<symbol::UnitVisibility> current_unit_section_;
|
||||||
|
std::vector<symbol::UnitImport> file_imports_;
|
||||||
ExternalSymbolProvider external_symbol_provider_;
|
ExternalSymbolProvider external_symbol_provider_;
|
||||||
std::unordered_map<std::string, symbol::SymbolId> imported_symbols_;
|
std::unordered_map<std::string, symbol::SymbolId> imported_symbols_;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -424,6 +424,30 @@ namespace lsp::language::symbol
|
||||||
|
|
||||||
Builder::ScopeGuard Builder::EnterScopeWithSymbol(ScopeKind kind, SymbolId symbol_id, const ast::Location& range)
|
Builder::ScopeGuard Builder::EnterScopeWithSymbol(ScopeKind kind, SymbolId symbol_id, const ast::Location& range)
|
||||||
{
|
{
|
||||||
|
if (!file_imports_.empty() && file_imports_applied_.insert(symbol_id).second)
|
||||||
|
{
|
||||||
|
Symbol* owner_symbol = const_cast<Symbol*>(table_.definition(symbol_id));
|
||||||
|
if (owner_symbol)
|
||||||
|
{
|
||||||
|
if (auto* fn = owner_symbol->As<Function>())
|
||||||
|
{
|
||||||
|
fn->imports.insert(fn->imports.begin(), file_imports_.begin(), file_imports_.end());
|
||||||
|
}
|
||||||
|
else if (auto* method = owner_symbol->As<Method>())
|
||||||
|
{
|
||||||
|
method->imports.insert(method->imports.begin(), file_imports_.begin(), file_imports_.end());
|
||||||
|
}
|
||||||
|
else if (auto* cls = owner_symbol->As<Class>())
|
||||||
|
{
|
||||||
|
cls->imports.insert(cls->imports.begin(), file_imports_.begin(), file_imports_.end());
|
||||||
|
}
|
||||||
|
else if (auto* unit = owner_symbol->As<Unit>())
|
||||||
|
{
|
||||||
|
unit->interface_imports.insert(unit->interface_imports.begin(), file_imports_.begin(), file_imports_.end());
|
||||||
|
unit->implementation_imports.insert(unit->implementation_imports.begin(), file_imports_.begin(), file_imports_.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
current_scope_id_ = table_.CreateScope(kind, range, current_scope_id_, symbol_id);
|
current_scope_id_ = table_.CreateScope(kind, range, current_scope_id_, symbol_id);
|
||||||
return ScopeGuard(*this, current_scope_id_);
|
return ScopeGuard(*this, current_scope_id_);
|
||||||
}
|
}
|
||||||
|
|
@ -798,6 +822,12 @@ namespace lsp::language::symbol
|
||||||
const auto* scope_info = table_.scopes().scope(current_scope_id_);
|
const auto* scope_info = table_.scopes().scope(current_scope_id_);
|
||||||
if (!scope_info || !scope_info->owner)
|
if (!scope_info || !scope_info->owner)
|
||||||
{
|
{
|
||||||
|
// Top-level `uses` (no owner scope) is treated as file-global.
|
||||||
|
file_imports_.reserve(file_imports_.size() + node.units.size());
|
||||||
|
for (const auto& unit : node.units)
|
||||||
|
{
|
||||||
|
file_imports_.push_back({ unit.name, unit.location });
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -608,6 +608,9 @@ export namespace lsp::language::symbol
|
||||||
std::optional<SymbolId> current_parent_symbol_id_;
|
std::optional<SymbolId> current_parent_symbol_id_;
|
||||||
std::optional<SymbolId> current_function_id_;
|
std::optional<SymbolId> current_function_id_;
|
||||||
|
|
||||||
|
std::vector<UnitImport> file_imports_;
|
||||||
|
std::unordered_set<SymbolId> file_imports_applied_;
|
||||||
|
|
||||||
bool in_interface_section_;
|
bool in_interface_section_;
|
||||||
ast::AccessModifier current_access_modifier_ = ast::AccessModifier::kPublic;
|
ast::AccessModifier current_access_modifier_ = ast::AccessModifier::kPublic;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue