use crate::parsing::resolution::{ImportBinding, ResolutionScope};
use crate::parsing::{ScopeLevel, ScopeType};
use crate::{FileId, SymbolId};
use std::collections::HashMap;
pub struct CSharpResolutionContext {
#[allow(dead_code)]
file_id: FileId,
local_scope: HashMap<String, SymbolId>,
member_scope: HashMap<String, SymbolId>,
namespace_symbols: HashMap<String, SymbolId>,
imported_symbols: HashMap<String, SymbolId>,
global_symbols: HashMap<String, SymbolId>,
scope_stack: Vec<ScopeType>,
using_directives: Vec<(String, Option<String>)>,
import_bindings: HashMap<String, ImportBinding>,
}
impl CSharpResolutionContext {
pub fn new(file_id: FileId) -> Self {
Self {
file_id,
local_scope: HashMap::new(),
member_scope: HashMap::new(),
namespace_symbols: HashMap::new(),
imported_symbols: HashMap::new(),
global_symbols: HashMap::new(),
scope_stack: Vec::new(),
using_directives: Vec::new(),
import_bindings: HashMap::new(),
}
}
pub fn add_using(&mut self, namespace: String, alias: Option<String>) {
self.using_directives.push((namespace, alias));
}
pub fn add_import_symbol(&mut self, name: String, symbol_id: SymbolId, _is_type_only: bool) {
self.imported_symbols.insert(name, symbol_id);
}
pub fn add_symbol_with_context(
&mut self,
name: String,
symbol_id: SymbolId,
scope_context: Option<&crate::symbol::ScopeContext>,
) {
use crate::symbol::ScopeContext;
match scope_context {
Some(ScopeContext::Local { .. }) => {
self.local_scope.insert(name, symbol_id);
}
Some(ScopeContext::ClassMember { .. }) => {
self.member_scope.insert(name, symbol_id);
}
Some(ScopeContext::Parameter) => {
self.local_scope.insert(name, symbol_id);
}
Some(ScopeContext::Module) => {
self.namespace_symbols.insert(name, symbol_id);
}
Some(ScopeContext::Package) => {
self.imported_symbols.insert(name, symbol_id);
}
Some(ScopeContext::Global) => {
self.global_symbols.insert(name, symbol_id);
}
None => {
self.local_scope.insert(name, symbol_id);
}
}
}
}
impl ResolutionScope for CSharpResolutionContext {
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
fn add_symbol(&mut self, name: String, symbol_id: SymbolId, scope_level: ScopeLevel) {
match scope_level {
ScopeLevel::Local => {
self.local_scope.insert(name, symbol_id);
}
ScopeLevel::Module => {
self.namespace_symbols.insert(name, symbol_id);
}
ScopeLevel::Package => {
self.imported_symbols.insert(name, symbol_id);
}
ScopeLevel::Global => {
self.global_symbols.insert(name, symbol_id);
}
}
}
fn resolve(&self, name: &str) -> Option<SymbolId> {
if let Some(&id) = self.local_scope.get(name) {
return Some(id);
}
if let Some(&id) = self.member_scope.get(name) {
return Some(id);
}
if let Some(&id) = self.namespace_symbols.get(name) {
return Some(id);
}
if let Some(&id) = self.imported_symbols.get(name) {
return Some(id);
}
if let Some(&id) = self.global_symbols.get(name) {
return Some(id);
}
if name.contains('.') {
if let Some(&id) = self.imported_symbols.get(name) {
return Some(id);
}
if let Some(&id) = self.namespace_symbols.get(name) {
return Some(id);
}
if let Some(&id) = self.global_symbols.get(name) {
return Some(id);
}
let parts: Vec<&str> = name.split('.').collect();
if parts.len() == 2 {
let type_name = parts[0];
let member_name = parts[1];
if self.resolve(type_name).is_some() {
return self.resolve(member_name);
}
for (namespace, alias) in &self.using_directives {
if let Some(alias_name) = alias {
if alias_name == type_name {
let qualified_name = format!("{namespace}.{member_name}");
return self.resolve(&qualified_name);
}
}
}
}
}
None
}
fn clear_local_scope(&mut self) {
self.local_scope.clear();
}
fn enter_scope(&mut self, scope_type: ScopeType) {
self.scope_stack.push(scope_type);
}
fn exit_scope(&mut self) {
self.scope_stack.pop();
if matches!(
self.scope_stack.last(),
None | Some(ScopeType::Module | ScopeType::Global)
) {
self.clear_local_scope();
}
}
fn symbols_in_scope(&self) -> Vec<(String, SymbolId, ScopeLevel)> {
let mut symbols = Vec::new();
for (name, &id) in &self.local_scope {
symbols.push((name.clone(), id, ScopeLevel::Local));
}
for (name, &id) in &self.imported_symbols {
symbols.push((name.clone(), id, ScopeLevel::Package));
}
for (name, &id) in &self.namespace_symbols {
symbols.push((name.clone(), id, ScopeLevel::Module));
}
for (name, &id) in &self.global_symbols {
symbols.push((name.clone(), id, ScopeLevel::Global));
}
symbols
}
fn resolve_relationship(
&self,
_from_name: &str,
to_name: &str,
kind: crate::RelationKind,
_from_file: FileId,
) -> Option<SymbolId> {
use crate::RelationKind;
match kind {
RelationKind::Implements => {
self.resolve(to_name)
}
RelationKind::Extends => {
self.resolve(to_name)
}
RelationKind::Uses | RelationKind::References => {
self.resolve(to_name)
}
RelationKind::Calls => {
self.resolve(to_name)
}
RelationKind::Defines => {
self.resolve(to_name)
}
RelationKind::CalledBy
| RelationKind::ExtendedBy
| RelationKind::ImplementedBy
| RelationKind::UsedBy
| RelationKind::DefinedIn
| RelationKind::ReferencedBy => {
self.resolve(to_name)
}
}
}
fn register_import_binding(&mut self, binding: ImportBinding) {
self.import_bindings
.insert(binding.exposed_name.clone(), binding);
}
fn import_binding(&self, name: &str) -> Option<ImportBinding> {
self.import_bindings.get(name).cloned()
}
}