use hir::Semantics; use ide_db::{ base_db::{FilePosition, SourceDatabaseExt}, LineIndexDatabase, RootDatabase, }; use std::{fmt::Write, time::Instant}; use syntax::{algo::ancestors_at_offset, ast, AstNode, TextRange}; // Feature: Interpret Function // // |=== // | Editor | Action Name // // | VS Code | **rust-analyzer: Interpret Function** // |=== pub(crate) fn interpret_function(db: &RootDatabase, position: FilePosition) -> String { let start_time = Instant::now(); let mut result = find_and_interpret(db, position) .unwrap_or_else(|| "Not inside a function body".to_string()); let duration = Instant::now() - start_time; writeln!(result, "").unwrap(); writeln!(result, "----------------------").unwrap(); writeln!(result, " Finished in {}s", duration.as_secs_f32()).unwrap(); result } fn find_and_interpret(db: &RootDatabase, position: FilePosition) -> Option { let sema = Semantics::new(db); let source_file = sema.parse(position.file_id); let item = ancestors_at_offset(source_file.syntax(), position.offset) .filter(|it| !ast::MacroCall::can_cast(it.kind())) .find_map(ast::Item::cast)?; let def = match item { ast::Item::Fn(it) => sema.to_def(&it)?, _ => return None, }; let span_formatter = |file_id, text_range: TextRange| { let path = &db .source_root(db.file_source_root(file_id)) .path_for_file(&file_id) .map(|x| x.to_string()); let path = path.as_deref().unwrap_or(""); match db.line_index(file_id).try_line_col(text_range.start()) { Some(line_col) => format!("file://{path}#{}:{}", line_col.line + 1, line_col.col), None => format!("file://{path} range {:?}", text_range), } }; Some(def.eval(db, span_formatter)) }