auto_lsp_core/core_ast/data.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
use std::sync::Arc;
use crate::workspace::Workspace;
use super::core::AstSymbol;
use super::symbol::*;
use lsp_types::Url;
/// Core data of any ast symbol
#[derive(Clone)]
pub struct SymbolData {
/// The workspace url of the symbol
pub url: Arc<Url>,
/// The parent of the symbol
pub parent: Option<WeakSymbol>,
/// The comment's byte range in the source code
pub comment: Option<std::ops::Range<usize>>,
/// The referrers of the symbol (symbols that refer to this symbol)
pub referrers: Option<Referrers>,
/// The target this symbol refers to
pub target: Option<WeakSymbol>,
/// The byte range of the symbol in the source code
pub range: std::ops::Range<usize>,
/// Whether the symbol has been checked for errors
pub unchecked: bool,
}
impl SymbolData {
pub fn new(url: Arc<Url>, range: std::ops::Range<usize>) -> Self {
Self {
url,
parent: None,
comment: None,
referrers: None,
target: None,
range,
unchecked: false,
}
}
}
/// Trait to read or mutate the core data of an ast symbol
pub trait GetSymbolData {
/// Get the workspace url of the symbol
fn get_url(&self) -> Arc<Url>;
/// Get the range of the symbol in the source code
///
/// This is a byte range, not the line and column range
fn get_range(&self) -> std::ops::Range<usize>;
/// Get the parent of the symbol (if any)
fn get_parent(&self) -> Option<WeakSymbol>;
/// Set the parent of the symbol
fn set_parent(&mut self, parent: WeakSymbol);
/// Get the comment of the symbol (if any)
///
/// Requires the source code to be passed since symobls only store byte ranges
fn get_comment<'a>(&self, source_code: &'a [u8]) -> Option<&'a str>;
/// Set the comment of the symbol, where range is the byte range of the comment's text location
fn set_comment(&mut self, range: Option<std::ops::Range<usize>>);
/// The target this symbol refers to
///
/// Note that this only works if the symbol implements [`super::capabilities::Reference`] trait
fn get_target(&self) -> Option<&WeakSymbol>;
/// Set the target of the symbol
///
/// Note that this only works if the symbol implements [`super::capabilities::Reference`] trait
fn set_target_reference(&mut self, target: WeakSymbol);
/// Reset the target of the symbol
fn reset_target_reference_reference(&mut self);
/// Get the referrers of the symbol
///
/// Referrers are symbols that refer to this symbol
fn get_referrers(&self) -> &Option<Referrers>;
/// Get a mutable reference to the referrers of the symbol
///
/// Referrers are symbols that refer to this symbol
fn get_mut_referrers(&mut self) -> &mut Referrers;
/// Get whether the symbol has been checked for errors
fn get_unchecked(&self) -> bool;
/// Set whether the symbol has been checked for errors
fn set_unchecked(&mut self, unchecked: bool);
}
impl GetSymbolData for SymbolData {
fn get_url(&self) -> Arc<Url> {
self.url.clone()
}
fn get_range(&self) -> std::ops::Range<usize> {
self.range.clone()
}
fn get_parent(&self) -> Option<WeakSymbol> {
self.parent.as_ref().map(|p| p.clone())
}
fn set_parent(&mut self, parent: WeakSymbol) {
self.parent = Some(parent);
}
fn get_comment<'a>(&self, source_code: &'a [u8]) -> Option<&'a str> {
match self.comment {
Some(ref range) => {
// Check if the range is within bounds and valid
if range.start <= range.end && range.end <= source_code.len() {
std::str::from_utf8(&source_code[range.start..range.end]).ok()
} else {
None
}
}
None => None,
}
}
fn set_comment(&mut self, range: Option<std::ops::Range<usize>>) {
self.comment = range;
}
fn get_target(&self) -> Option<&WeakSymbol> {
self.target.as_ref()
}
fn set_target_reference(&mut self, target: WeakSymbol) {
self.target = Some(target);
}
fn reset_target_reference_reference(&mut self) {
self.target = None;
}
fn get_referrers(&self) -> &Option<Referrers> {
&self.referrers
}
fn get_mut_referrers(&mut self) -> &mut Referrers {
self.referrers.get_or_insert_default()
}
fn get_unchecked(&self) -> bool {
self.unchecked
}
fn set_unchecked(&mut self, unchecked: bool) {
self.unchecked = unchecked;
}
}
/// List of weak symbols that refer to this symbol
#[derive(Default, Clone)]
pub struct Referrers(Vec<WeakSymbol>);
/// Trait for managing [`Referrers`]
pub trait ReferrersTrait {
/// Add a referrer to the symbol list
fn add_referrer(&mut self, symbol: WeakSymbol);
/// Clean up any null referrers
fn clean_null_referrers(&mut self);
/// Drop any referrers that have an reference
///
/// If the referrer was not dropped, add it to the unsolved checks field of [`Workspace`]
fn drop_referrers(&mut self, workspace: &mut Workspace);
}
impl<'a> IntoIterator for &'a Referrers {
type Item = &'a WeakSymbol;
type IntoIter = std::slice::Iter<'a, WeakSymbol>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<T: AstSymbol + ?Sized> ReferrersTrait for T {
fn add_referrer(&mut self, symbol: WeakSymbol) {
self.get_mut_referrers().0.push(symbol);
}
fn clean_null_referrers(&mut self) {
self.get_mut_referrers()
.0
.retain(|r| r.get_ptr().weak_count() > 0);
}
fn drop_referrers(&mut self, workspace: &mut Workspace) {
self.get_mut_referrers().0.retain(|r| {
if let Some(symbol) = r.to_dyn() {
let read = symbol.read();
if read.get_target().is_some() {
drop(read);
symbol.write().reset_target_reference_reference();
workspace.add_unsolved_reference(&symbol.clone());
}
}
false
});
}
}