pub mod checks;
pub mod operations;
pub mod queries;
use std::path::{Path, PathBuf};
use std::sync::Mutex;
use crate::salsa_full::{Symbol, Type, TypeDatabase};
pub use self::checks::{CheckEngine, CompatibilityResult, InterfaceCheckResult};
pub use self::operations::{OperationEngine, TextEdit, WorkspaceEdit};
pub use self::queries::{QueryEngine, SymbolInfo};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Position {
pub line: usize,
pub character: usize,
}
impl Position {
pub fn new(line: usize, character: usize) -> Self {
Self { line, character }
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Range {
pub start: Position,
pub end: Position,
}
impl Range {
pub fn new(start: Position, end: Position) -> Self {
Self { start, end }
}
pub fn contains(&self, pos: Position) -> bool {
pos.line >= self.start.line
&& pos.line <= self.end.line
&& (pos.line != self.start.line || pos.character >= self.start.character)
&& (pos.line != self.end.line || pos.character <= self.end.character)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct DocumentLocation {
pub path: PathBuf,
pub range: Range,
}
#[derive(Clone, Debug)]
pub struct SemanticInfo {
pub symbol: Symbol,
pub ty: Type,
pub location: DocumentLocation,
pub documentation: Option<String>,
}
#[derive(Clone, Debug)]
pub struct QueryResult<T> {
pub data: T,
pub duration_ms: f64,
pub from_cache: bool,
}
pub struct SemanticOS {
db: TypeDatabase,
query_engine: Mutex<QueryEngine>,
check_engine: Mutex<CheckEngine>,
}
impl SemanticOS {
pub fn new(db: TypeDatabase) -> Self {
Self {
db,
query_engine: Mutex::new(QueryEngine::new()),
check_engine: Mutex::new(CheckEngine::new()),
}
}
pub fn db(&self) -> &TypeDatabase {
&self.db
}
pub fn type_at(&self, file: &Path, position: Position) -> Option<QueryResult<Type>> {
let start = std::time::Instant::now();
let engine = self.query_engine.lock().ok()?;
let result = engine.type_at(file, position);
Some(QueryResult {
data: result?,
duration_ms: start.elapsed().as_secs_f64() * 1000.0,
from_cache: false,
})
}
pub fn goto_definition(
&self,
file: &Path,
position: Position,
) -> Option<QueryResult<DocumentLocation>> {
let start = std::time::Instant::now();
let engine = self.query_engine.lock().ok()?;
let result = engine.goto_definition(file, position)?;
Some(QueryResult {
data: result,
duration_ms: start.elapsed().as_secs_f64() * 1000.0,
from_cache: false,
})
}
pub fn find_references(
&self,
file: &Path,
position: Position,
include_declaration: bool,
) -> Option<QueryResult<Vec<DocumentLocation>>> {
let start = std::time::Instant::now();
let engine = self.query_engine.lock().ok()?;
let result = engine.find_references(file, position, include_declaration);
Some(QueryResult {
data: result,
duration_ms: start.elapsed().as_secs_f64() * 1000.0,
from_cache: false,
})
}
pub fn find_implementations(
&self,
file: &Path,
position: Position,
) -> Option<QueryResult<Vec<DocumentLocation>>> {
let start = std::time::Instant::now();
let engine = self.query_engine.lock().ok()?;
let result = engine.find_implementations(file, position);
Some(QueryResult {
data: result,
duration_ms: start.elapsed().as_secs_f64() * 1000.0,
from_cache: false,
})
}
pub fn check_interface_consistency(
&self,
interface_file: &Path,
interface_name: &str,
) -> Option<QueryResult<checks::InterfaceCheckResult>> {
let start = std::time::Instant::now();
let engine = self.check_engine.lock().ok()?;
let result = engine.check_interface_implementations(interface_file, interface_name);
Some(QueryResult {
data: result,
duration_ms: start.elapsed().as_secs_f64() * 1000.0,
from_cache: false,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_position_contains() {
let range = Range::new(Position::new(1, 5), Position::new(3, 10));
assert!(range.contains(Position::new(2, 0)));
assert!(range.contains(Position::new(1, 5)));
assert!(range.contains(Position::new(3, 10)));
assert!(!range.contains(Position::new(0, 0)));
assert!(!range.contains(Position::new(4, 0)));
}
#[test]
fn test_semantic_os_creation() {
let db = TypeDatabase::new();
let os = SemanticOS::new(db);
let _ = os.db().metrics();
}
}