🐛 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)
|
||||
{
|
||||
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_)
|
||||
{
|
||||
// Top-level `uses` is treated as file-global.
|
||||
add_to(file_imports_);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& context = *current_unit_context_;
|
||||
auto* target = current_unit_section_ == symbol::UnitVisibility::kInterface ? &context.interface_imports : &context.implementation_imports;
|
||||
|
||||
for (const auto& unit : node.units)
|
||||
{
|
||||
symbol::UnitImport import;
|
||||
import.unit_name = unit.name;
|
||||
import.location = unit.location;
|
||||
target->push_back(std::move(import));
|
||||
}
|
||||
add_to(*target);
|
||||
}
|
||||
|
||||
void Analyzer::VisitIdentifier(ast::Identifier& node)
|
||||
|
|
@ -1167,64 +1174,78 @@ namespace lsp::language::semantic
|
|||
|
||||
std::optional<symbol::SymbolId> Analyzer::ResolveFromUses(const std::string& name)
|
||||
{
|
||||
if (!current_unit_context_)
|
||||
{
|
||||
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)
|
||||
{
|
||||
const auto& unit_import = *it;
|
||||
|
||||
// 1. 查找导入的 unit 符号
|
||||
auto unit_matches = symbol_table_.FindSymbolsByName(unit_import.unit_name);
|
||||
if (unit_matches.empty())
|
||||
auto resolve_from_imports = [&](const std::vector<symbol::UnitImport>& imports) -> std::optional<symbol::SymbolId> {
|
||||
// 从后往前查找(最后导入的优先级最高)
|
||||
for (auto it = imports.rbegin(); it != imports.rend(); ++it)
|
||||
{
|
||||
// 如果本地找不到,尝试通过 external_symbol_provider_ 查找
|
||||
if (external_symbol_provider_)
|
||||
const auto& unit_import = *it;
|
||||
|
||||
// 1. 查找导入的 unit 符号
|
||||
auto unit_matches = symbol_table_.FindSymbolsByName(unit_import.unit_name);
|
||||
if (unit_matches.empty())
|
||||
{
|
||||
auto external_unit = external_symbol_provider_(unit_import.unit_name);
|
||||
if (external_unit)
|
||||
// 如果本地找不到,尝试通过 external_symbol_provider_ 查找
|
||||
if (external_symbol_provider_)
|
||||
{
|
||||
auto unit_id = symbol_table_.CreateSymbol(std::move(*external_unit));
|
||||
unit_matches.push_back(unit_id);
|
||||
auto external_unit = external_symbol_provider_(unit_import.unit_name);
|
||||
if (external_unit)
|
||||
{
|
||||
auto unit_id = symbol_table_.CreateSymbol(std::move(*external_unit));
|
||||
unit_matches.push_back(unit_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 在每个找到的 unit 中查找目标符号
|
||||
for (auto unit_id : unit_matches)
|
||||
{
|
||||
const auto* unit_symbol = symbol_table_.definition(unit_id);
|
||||
if (!unit_symbol || !unit_symbol->Is<symbol::Unit>())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 3. 查找 unit 的作用域
|
||||
auto unit_scope_id = FindScopeOwnedBy(unit_id);
|
||||
if (!unit_scope_id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 4. 在 unit 的 Interface 作用域中查找符号
|
||||
auto symbol_id = symbol_table_.scopes().FindSymbolInScope(*unit_scope_id, name);
|
||||
if (symbol_id)
|
||||
{
|
||||
// 验证符号是否在 Interface 部分(通过 visibility 检查)
|
||||
const auto* symbol = symbol_table_.definition(*symbol_id);
|
||||
if (symbol)
|
||||
{
|
||||
// 如果符号有 visibility 信息,确保它是 Interface 可见的
|
||||
// TODO: 需要符号表支持 visibility 标记
|
||||
return symbol_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 在每个找到的 unit 中查找目标符号
|
||||
for (auto unit_id : unit_matches)
|
||||
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))
|
||||
{
|
||||
const auto* unit_symbol = symbol_table_.definition(unit_id);
|
||||
if (!unit_symbol || !unit_symbol->Is<symbol::Unit>())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 查找 unit 的作用域
|
||||
auto unit_scope_id = FindScopeOwnedBy(unit_id);
|
||||
if (!unit_scope_id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 4. 在 unit 的 Interface 作用域中查找符号
|
||||
auto symbol_id = symbol_table_.scopes().FindSymbolInScope(*unit_scope_id, name);
|
||||
if (symbol_id)
|
||||
{
|
||||
// 验证符号是否在 Interface 部分(通过 visibility 检查)
|
||||
const auto* symbol = symbol_table_.definition(*symbol_id);
|
||||
if (symbol)
|
||||
{
|
||||
// 如果符号有 visibility 信息,确保它是 Interface 可见的
|
||||
// TODO: 需要符号表支持 visibility 标记
|
||||
return symbol_id;
|
||||
}
|
||||
}
|
||||
if (!file_imports_.empty())
|
||||
{
|
||||
if (auto result = resolve_from_imports(file_imports_))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -681,6 +681,7 @@ export namespace lsp::language::semantic
|
|||
std::optional<symbol::SymbolId> current_class_id_;
|
||||
std::optional<UnitContext> current_unit_context_;
|
||||
std::optional<symbol::UnitVisibility> current_unit_section_;
|
||||
std::vector<symbol::UnitImport> file_imports_;
|
||||
ExternalSymbolProvider external_symbol_provider_;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
return ScopeGuard(*this, current_scope_id_);
|
||||
}
|
||||
|
|
@ -798,6 +822,12 @@ namespace lsp::language::symbol
|
|||
const auto* scope_info = table_.scopes().scope(current_scope_id_);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -608,6 +608,9 @@ export namespace lsp::language::symbol
|
|||
std::optional<SymbolId> current_parent_symbol_id_;
|
||||
std::optional<SymbolId> current_function_id_;
|
||||
|
||||
std::vector<UnitImport> file_imports_;
|
||||
std::unordered_set<SymbolId> file_imports_applied_;
|
||||
|
||||
bool in_interface_section_;
|
||||
ast::AccessModifier current_access_modifier_ = ast::AccessModifier::kPublic;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue