Created
May 26, 2025 20:01
-
-
Save kabergstrom/ee8b6884a92e5893a88f5ff3dbefa3e3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use env_logger::Builder; | |
use hydrate_schema::{ | |
Schema, SchemaDefRecordMarkup, SchemaFingerprint, SchemaRecord, SchemaRecordField, | |
}; | |
use ra_ap_base_db::{FileId, SourceDatabase, SourceDatabaseExt, Upcast}; | |
use ra_ap_hir::{db::HirDatabase, Crate, HasSource, HasVisibility, HirDisplay}; | |
use ra_ap_ide_db::{symbol_index::SymbolsDatabase, RootDatabase}; | |
use ra_ap_load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice}; | |
use ra_ap_paths::{AbsPath, AbsPathBuf, Utf8PathBuf}; | |
use ra_ap_project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource}; | |
use ra_ap_syntax::ast::AstNode; | |
use ra_ap_text_edit::TextEdit; | |
use std::{ | |
borrow::Borrow, | |
collections::HashMap, | |
iter::Map, | |
ops::ControlFlow, | |
path::{Path, PathBuf}, | |
}; | |
use uuid::Uuid; | |
pub type Semantics<'db> = ra_ap_hir::Semantics<'db, ra_ap_ide_db::RootDatabase>; | |
use log::{debug, info, trace, LevelFilter}; | |
use std::fs::{read_to_string, write}; | |
mod preloader; | |
struct TestThing { | |
val: bool, | |
f: f32, | |
} | |
fn main() { | |
let mut builder = Builder::from_default_env(); | |
builder.filter_level(LevelFilter::Info).init(); | |
run( | |
"/Users/karl/Perforce/BergstromK_Laptop/rust/card-engine", | |
"", | |
); | |
} | |
pub(crate) fn normalize(name: &str) -> String { | |
name.replace("-", "_") | |
} | |
pub fn run(root: &str, dep: &str) { | |
info!("Workspace root: {}", Path::new(root).display()); | |
// Loading project | |
let root: Utf8PathBuf = root.into(); | |
let manifest = ProjectManifest::discover_single(&AbsPathBuf::assert(root.clone())).unwrap(); | |
let no_progress = &|_| {}; | |
let mut cargo_config = CargoConfig::default(); | |
cargo_config.sysroot = Some(RustLibSource::Discover); | |
let mut workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress).unwrap(); | |
let bs = workspace | |
.run_build_scripts(&cargo_config, no_progress) | |
.unwrap(); | |
workspace.set_build_scripts(bs); | |
let load_cargo_config = LoadCargoConfig { | |
load_out_dirs_from_check: true, | |
prefill_caches: false, | |
with_proc_macro_server: ProcMacroServerChoice::Sysroot, | |
}; | |
let (host, vfs, _) = | |
load_workspace(workspace, &Default::default(), &load_cargo_config).unwrap(); | |
// Preparing running wrapper | |
let db: &RootDatabase = &host; | |
let semantics = Semantics::new(db); | |
let mut changes = HashMap::<FileId, TextEdit>::new(); | |
// Run init hook | |
let mut preloader = preloader::Preloader::default(); | |
debug!("Crate graph: {:#?}", db.crate_graph()); | |
let peers = ["card_engine"]; | |
// Loop to find and eager load the dep we are upgrading | |
for krate in Crate::all(db) { | |
if let Some(name) = krate.display_name(db) { | |
debug!("Checking if we need to preload: {}", name); | |
if let Some(peer) = peers | |
.iter() | |
.find(|x| **x == normalize(&format!("{}", name))) | |
{ | |
// preloader.load(&normalize(&format!("{}", name)), db, &krate); | |
for decl in krate.root_module().declarations(db) { | |
process_decl(decl, db); | |
} | |
for decl in krate.root_module().declarations(db) { | |
info!("crate {} has decl {:?}", name, decl); | |
match decl { | |
ra_ap_hir::ModuleDef::Function(f) => { | |
info!("crate {} has function {:?}", name, f.name(db)) | |
} | |
_ => {} | |
} | |
} | |
} else { | |
println!("skipping {name}"); | |
} | |
} | |
} | |
let root_abs: AbsPathBuf = AbsPathBuf::assert(root.clone()); | |
// Actual loop to walk through the source code | |
for source_root_id in db.local_roots().iter() { | |
let source_root = db.source_root(*source_root_id); | |
let krates = db.source_root_crates(*source_root_id); | |
// Get all crates for this source root and skip if no root files of those crates | |
// are in the root path we are upgrading. | |
if !krates | |
.iter() | |
.filter_map(|crate_id| { | |
let krate: Crate = (*crate_id).into(); | |
source_root.path_for_file(&krate.root_file(db)) | |
}) | |
.filter_map(|path| path.as_path()) | |
.any(|path: &AbsPath| { | |
debug!("Checking if path in workspace: {}", path); | |
path.starts_with(&root_abs) | |
}) | |
{ | |
continue; | |
} | |
for file_id in source_root.iter() { | |
let file = vfs.file_path(file_id); | |
info!("Walking: {}", file.as_path().unwrap()); | |
let source_file = semantics.parse(file_id); | |
trace!("Syntax: {:#?}", source_file.syntax()); | |
// context.walk(source_file.syntax()); | |
// let edit = context.upgrader.finish(); | |
// debug!("Changes to be made: {:#?}", edit); | |
// changes.insert(file_id, edit); | |
} | |
} | |
// Apply changes | |
for (file_id, edit) in changes { | |
let full_path = vfs.file_path(file_id); | |
let full_path = full_path.as_path().unwrap(); | |
let mut file_text = read_to_string(&full_path).unwrap(); | |
edit.apply(&mut file_text); | |
// write(&full_path, file_text)?; | |
} | |
// TODO: Modify Cargo.toml | |
} | |
fn process_decl(decl: ra_ap_hir::ModuleDef, db: &RootDatabase) { | |
match decl { | |
ra_ap_hir::ModuleDef::Module(module) => { | |
for decl in module.declarations(db) { | |
process_decl(decl, db); | |
} | |
} | |
ra_ap_hir::ModuleDef::Adt(adt) => match adt { | |
ra_ap_hir::Adt::Struct(s) => { | |
let has_generics = s.ty(db).generic_parameters(db).next().is_some(); | |
println!( | |
"FOUND {} STRUCT {:?} {:?}", | |
if has_generics { "GENERIC" } else { "" }, | |
s, | |
s.name(db) | |
); | |
// let mut fields = Vec::new(); | |
for field in s.fields(db) { | |
println!( | |
"{:?} {:?} {}", | |
field, | |
field.name(db), | |
field.ty(db).display(db) | |
); | |
if let Some(schema) = get_field_schema(field, db) { | |
} else { | |
continue; | |
} | |
// SchemaRecordField::new(field.name(db), Uuid::nil(), [].into()) | |
} | |
let record = SchemaRecord::new( | |
s.name(db).as_str().unwrap().to_string(), | |
Uuid::nil(), | |
SchemaFingerprint::from_uuid(Uuid::nil()), | |
[].into(), | |
Vec::new(), | |
SchemaDefRecordMarkup::default(), | |
); | |
} | |
ra_ap_hir::Adt::Union(_) => todo!(), | |
ra_ap_hir::Adt::Enum(e) => { | |
println!("FOUND ENUM {:?}", e.name(db)); | |
for variant in e.variants(db) { | |
match variant.kind(db) { | |
ra_ap_hir::StructKind::Tuple => { | |
println!("enum tuple variant {:?} {:?}", e.name(db), variant.name(db)); | |
} | |
ra_ap_hir::StructKind::Record => { | |
println!( | |
"enum record variant {:?} {:?}", | |
e.name(db), | |
variant.name(db) | |
); | |
for field in variant.fields(db) { | |
get_field_schema(field, db); | |
} | |
} | |
ra_ap_hir::StructKind::Unit => { | |
println!("enum unit variant {:?} {:?}", e.name(db), variant.name(db)); | |
} | |
} | |
} | |
} | |
}, | |
_ => {} | |
} | |
} | |
fn get_field_schema(field: ra_ap_hir::Field, db: &RootDatabase) -> Option<Schema> { | |
let ty = field.ty(db); | |
let field_schema = if let Some(builtin) = ty.as_builtin() { | |
if builtin.is_int() { | |
match builtin.ty(db).layout(db).unwrap().size() { | |
4 => Schema::I32, | |
8 => Schema::I64, | |
_ => panic!("unhandled int size"), | |
} | |
} else if builtin.is_f32() { | |
Schema::F32 | |
} else if builtin.is_f64() { | |
Schema::F64 | |
} else if builtin.is_bool() { | |
Schema::Boolean | |
} else if builtin.is_uint() { | |
match builtin.ty(db).layout(db).unwrap().size() { | |
1 => Schema::U8, | |
2 => Schema::U16, | |
4 => Schema::U32, | |
8 => Schema::U64, | |
16 => Schema::U128, | |
_ => panic!("unhandled uint size"), | |
} | |
} else { | |
println!("unhandled builtin{:?}", builtin); | |
return None; | |
} | |
} else if ty.is_tuple() { | |
println!("tuple: {:?}", field.name(db),); | |
return None; | |
} else if ty.is_array() { | |
println!("found array: {:?} {:?}", field.name(db), field.ty(db)); | |
return None; | |
} else if ty.is_scalar() { | |
println!("scalar: {:?}", field.name(db),); | |
return None; | |
} else if ty.is_fn() { | |
println!("found function: {:?} {:?}", field.name(db), field.ty(db)); | |
return None; | |
} else if ty.is_reference() || ty.is_mutable_reference() { | |
println!("found reference: {:?} {:?}", field.name(db), field.ty(db)); | |
return None; | |
} else if ty.is_raw_ptr() { | |
println!("found raw pointer: {:?} {:?}", field.name(db), field.ty(db)); | |
return None; | |
} else if ty.is_tuple() { | |
println!("found tuple: {:?} {:?}", field.name(db), field.ty(db)); | |
return None; | |
} else { | |
if let Some(adt) = ty.as_adt() { | |
println!("found {:?}: {:?}", adt, field.name(db)); | |
} else { | |
println!("unhandled: {:?}", field.name(db),); | |
} | |
return None; | |
// todo!("not a builtin: {:?}", field); | |
}; | |
Some(field_schema) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment