Skip to content

Commit

Permalink
arch: migrate lsp variable and schema attr completion to new sema mod…
Browse files Browse the repository at this point in the history
…el (#886)

* arch: migrate lsp schema attr completion to new sema model

Signed-off-by: he1pa <18012015693@163.com>

* feat: remove completion attr and variable, replace with `get_all_defs_in_scope`

Signed-off-by: he1pa <18012015693@163.com>

* fix: fix unit test

Signed-off-by: he1pa <18012015693@163.com>

* chore: remove unused code

Signed-off-by: he1pa <18012015693@163.com>

---------

Signed-off-by: he1pa <18012015693@163.com>
  • Loading branch information
He1pa committed Nov 16, 2023
1 parent 45235ec commit e7164d8
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 136 deletions.
4 changes: 2 additions & 2 deletions kclvm/sema/src/advanced_resolver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1255,7 +1255,7 @@ mod tests {
.replace("/", &std::path::MAIN_SEPARATOR.to_string()),
17_u64,
26_u64,
11_usize,
9_usize,
),
// __main__.Main schema expr scope
(
Expand All @@ -1264,7 +1264,7 @@ mod tests {
.replace("/", &std::path::MAIN_SEPARATOR.to_string()),
30,
41,
11,
9,
),
// pkg.Person schema expr scope
(
Expand Down
17 changes: 10 additions & 7 deletions kclvm/sema/src/core/global_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,16 @@ impl GlobalState {
pub fn get_all_defs_in_scope(&self, scope: ScopeRef) -> Option<Vec<SymbolRef>> {
let scopes = &self.scopes;
let scope = scopes.get_scope(scope)?;
let mut all_defs = scope.get_all_defs(
scopes,
&self.symbols,
self.packages.get_module_info(scope.get_filename()),
);
all_defs.sort();
all_defs.dedup();
let all_defs: Vec<SymbolRef> = scope
.get_all_defs(
scopes,
&self.symbols,
self.packages.get_module_info(scope.get_filename()),
)
.values()
.into_iter()
.cloned()
.collect();
Some(all_defs)
}

Expand Down
4 changes: 4 additions & 0 deletions kclvm/sema/src/core/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,8 @@ impl ModuleInfo {
pub fn get_import_info(&self, name: &str) -> Option<&ImportInfo> {
self.imports.get(name)
}

pub fn get_imports(&self) -> IndexMap<String, ImportInfo> {
self.imports.clone()
}
}
46 changes: 32 additions & 14 deletions kclvm/sema/src/core/scope.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::path::Path;
use std::{collections::HashMap, path::Path};

use indexmap::IndexMap;
use kclvm_error::Position;
Expand Down Expand Up @@ -29,7 +29,7 @@ pub trait Scope {
scope_data: &ScopeData,
symbol_data: &Self::SymbolData,
module_info: Option<&ModuleInfo>,
) -> Vec<SymbolRef>;
) -> HashMap<String, SymbolRef>;

fn dump(&self, scope_data: &ScopeData, symbol_data: &Self::SymbolData) -> Option<String>;
}
Expand Down Expand Up @@ -214,12 +214,18 @@ impl Scope for RootSymbolScope {
_scope_data: &ScopeData,
symbol_data: &Self::SymbolData,
module_info: Option<&ModuleInfo>,
) -> Vec<SymbolRef> {
) -> HashMap<String, SymbolRef> {
let mut all_defs_map = HashMap::new();
if let Some(owner) = symbol_data.get_symbol(self.owner) {
owner.get_all_attributes(symbol_data, module_info)
} else {
vec![]
let all_defs = owner.get_all_attributes(symbol_data, module_info);

for def_ref in all_defs {
if let Some(def) = symbol_data.get_symbol(def_ref) {
all_defs_map.insert(def.get_name(), def_ref);
}
}
}
all_defs_map
}

fn dump(&self, scope_data: &ScopeData, symbol_data: &Self::SymbolData) -> Option<String> {
Expand Down Expand Up @@ -349,21 +355,33 @@ impl Scope for LocalSymbolScope {
scope_data: &ScopeData,
symbol_data: &Self::SymbolData,
module_info: Option<&ModuleInfo>,
) -> Vec<SymbolRef> {
let mut result = vec![];
for def in self.defs.values() {
result.push(*def);
) -> HashMap<String, SymbolRef> {
let mut all_defs_map = HashMap::new();
for def_ref in self.defs.values() {
if let Some(def) = symbol_data.get_symbol(*def_ref) {
all_defs_map.insert(def.get_name(), *def_ref);
}
}
if let Some(owner) = self.owner {
if let Some(owner) = symbol_data.get_symbol(owner) {
result.append(&mut owner.get_all_attributes(symbol_data, module_info));
for def_ref in owner.get_all_attributes(symbol_data, module_info) {
if let Some(def) = symbol_data.get_symbol(def_ref) {
let name = def.get_name();
if !all_defs_map.contains_key(&name) {
all_defs_map.insert(name, def_ref);
}
}
}
}
}
if let Some(parent) = scope_data.get_scope(self.parent) {
result.append(&mut parent.get_all_defs(scope_data, symbol_data, module_info));
for (name, def_ref) in parent.get_all_defs(scope_data, symbol_data, module_info) {
if !all_defs_map.contains_key(&name) {
all_defs_map.insert(name, def_ref);
}
}
}
result.sort();
result
all_defs_map
}

fn dump(&self, scope_data: &ScopeData, symbol_data: &Self::SymbolData) -> Option<String> {
Expand Down
171 changes: 74 additions & 97 deletions kclvm/tools/src/LSP/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use std::{fs, path::Path};

use crate::goto_def::find_def_with_gs;
use indexmap::IndexSet;
use kclvm_ast::ast::{Expr, ImportStmt, Node, Program, Stmt};
use kclvm_ast::ast::{Expr, ImportStmt, Program, Stmt};
use kclvm_ast::pos::GetPos;
use kclvm_ast::MAIN_PKG;
use kclvm_config::modfile::KCL_FILE_EXTENSION;
Expand All @@ -29,7 +29,7 @@ use kclvm_sema::core::global_state::GlobalState;
use kclvm_error::Position as KCLPos;
use kclvm_sema::builtin::{STANDARD_SYSTEM_MODULES, STRING_MEMBER_FUNCTIONS};
use kclvm_sema::resolver::doc::{parse_doc_string, Doc};
use kclvm_sema::resolver::scope::{ProgramScope, ScopeObjectKind};
use kclvm_sema::resolver::scope::ProgramScope;
use kclvm_sema::ty::{FunctionType, SchemaType, Type};
use lsp_types::{CompletionItem, CompletionItemKind};

Expand Down Expand Up @@ -90,12 +90,60 @@ pub(crate) fn completion(
},
None => {
let mut completions: IndexSet<KCLCompletionItem> = IndexSet::new();
// Complete builtin pkgs if in import stmt
completions.extend(completion_import_builtin_pkg(program, pos, prog_scope));
if !completions.is_empty() {
return Some(into_completion_items(&completions).into());
}

completions.extend(completion_variable(pos, prog_scope));

completions.extend(completion_attr(program, pos, prog_scope));
// Complete import pkgs name
if let Some(pkg_info) = gs.get_packages().get_module_info(&pos.filename) {
completions.extend(pkg_info.get_imports().keys().map(|key| KCLCompletionItem {
label: key.clone(),
detail: None,
documentation: None,
kind: Some(KCLCompletionItemKind::Module),
}));
}

completions.extend(completion_import_builtin_pkg(program, pos, prog_scope));
// Complete all usable symbol obj in inner most scope
if let Some(scope) = gs.look_up_scope(pos) {
if let Some(defs) = gs.get_all_defs_in_scope(scope) {
for symbol_ref in defs {
match gs.get_symbols().get_symbol(symbol_ref) {
Some(def) => {
let sema_info = def.get_sema_info();
let name = def.get_name();
let ty = sema_info.ty.clone().unwrap();

match symbol_ref.get_kind() {
kclvm_sema::core::symbol::SymbolKind::Schema => {
let schema_ty = ty.into_schema_type();
completions.insert(schema_ty_completion_item(&schema_ty));
}
kclvm_sema::core::symbol::SymbolKind::Package => {
completions.insert(KCLCompletionItem {
label: name,
detail: None,
documentation: None,
kind: Some(KCLCompletionItemKind::Module),
});
}
_ => {
completions.insert(KCLCompletionItem {
label: name,
detail: None,
documentation: None,
kind: None,
});
}
}
}
None => {}
}
}
}
}

Some(into_completion_items(&completions).into())
}
Expand Down Expand Up @@ -333,95 +381,15 @@ fn completion_import_builtin_pkg(
completions
}

/// Complete schema attr
///
/// ```no_run
/// p = Person {
/// n<cursor>
/// }
/// ```
/// complete to
/// ```no_run
/// p = Person {
/// name<cursor>
/// }
/// ```
fn completion_attr(
program: &Program,
pos: &KCLPos,
prog_scope: &ProgramScope,
) -> IndexSet<KCLCompletionItem> {
let mut completions: IndexSet<KCLCompletionItem> = IndexSet::new();

if let Some((node, schema_expr)) = is_in_schema_expr(program, pos) {
let schema_def = find_def(node, &schema_expr.name.get_end_pos(), prog_scope);
if let Some(schema) = schema_def {
if let Definition::Object(obj, _) = schema {
let schema_type = obj.ty.into_schema_type();
completions.extend(schema_type.attrs.iter().map(|(name, attr)| {
KCLCompletionItem {
label: name.clone(),
detail: Some(format!("{}: {}", name, attr.ty.ty_str())),
documentation: attr.doc.clone(),
kind: Some(KCLCompletionItemKind::SchemaAttr),
}
}));
}
}
}
completions
}

/// Complete all usable scope obj in inner_most_scope
fn completion_variable(pos: &KCLPos, prog_scope: &ProgramScope) -> IndexSet<KCLCompletionItem> {
let mut completions: IndexSet<KCLCompletionItem> = IndexSet::new();
if let Some(inner_most_scope) = prog_scope.inner_most_scope(pos) {
for (name, obj) in inner_most_scope.all_usable_objects() {
match &obj.borrow().kind {
kclvm_sema::resolver::scope::ScopeObjectKind::Module(module) => {
for stmt in &module.import_stmts {
match &stmt.0.node {
Stmt::Import(import_stmt) => {
completions.insert(KCLCompletionItem {
label: import_stmt.name.clone(),
detail: None,
documentation: None,
kind: Some(KCLCompletionItemKind::Module),
});
}
_ => {}
}
}
}
kclvm_sema::resolver::scope::ScopeObjectKind::Definition => {
let schema_ty = obj.borrow().ty.clone().into_schema_type();
completions.insert(schema_ty_completion_item(&schema_ty));
}
_ => {
completions.insert(KCLCompletionItem {
label: name,
detail: Some(format!(
"{}: {}",
obj.borrow().name,
obj.borrow().ty.ty_str()
)),
documentation: obj.borrow().doc.clone(),
kind: Some(KCLCompletionItemKind::Schema),
});
}
}
}
}
completions
}

/// Complete schema name
///
/// ```no_run
/// #[cfg(not(test))]
/// p = P<cursor>
/// ```
/// complete to
/// ```no_run
/// #[cfg(not(test))]
/// p = Person(param1, param2){}<cursor>
/// ```
fn schema_ty_completion_item(schema_ty: &SchemaType) -> KCLCompletionItem {
Expand Down Expand Up @@ -609,11 +577,11 @@ mod tests {
let pos = KCLPos {
filename: file.to_owned(),
line: 26,
column: Some(5),
column: Some(1),
};

let got = completion(None, &program, &pos, &prog_scope, &gs).unwrap();
let got_labels: Vec<String> = match got {
let mut got_labels: Vec<String> = match got {
CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
CompletionResponse::List(_) => panic!("test failed"),
};
Expand All @@ -622,6 +590,8 @@ mod tests {
"", // generate from error recovery of "pkg."
"subpkg", "math", "Person{}", "P{}", "p", "p1", "p2", "p3", "p4", "aaaa",
];
got_labels.sort();
expected_labels.sort();

assert_eq!(got_labels, expected_labels);

Expand All @@ -633,12 +603,14 @@ mod tests {
};

let got = completion(None, &program, &pos, &prog_scope, &gs).unwrap();
let got_labels: Vec<String> = match got {
let mut got_labels: Vec<String> = match got {
CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
CompletionResponse::List(_) => panic!("test failed"),
};

expected_labels.extend(["name", "age"]);
got_labels.sort();
expected_labels.sort();
assert_eq!(got_labels, expected_labels);
}

Expand Down Expand Up @@ -903,10 +875,12 @@ mod tests {
};

let got = completion(None, &program, &pos, &prog_scope, &gs).unwrap();

let got_labels: Vec<String> = match &got {
CompletionResponse::Array(arr) => arr.iter().map(|item| item.label.clone()).collect(),
CompletionResponse::List(_) => panic!("test failed"),
};
items.extend(
[
"", // generate from error recovery
"collection",
"net",
"manifests",
Expand Down Expand Up @@ -1044,12 +1018,15 @@ mod tests {
column: Some(5),
};

let got = completion(None, &program, &pos, &prog_scope, &gs).unwrap();
match got {
let mut got = completion(None, &program, &pos, &prog_scope, &gs).unwrap();
match &mut got {
CompletionResponse::Array(arr) => {
assert_eq!(
arr[1],
CompletionItem {
arr.iter()
.filter(|item| item.label == "Person(b){}")
.next()
.unwrap(),
&CompletionItem {
label: "Person(b){}".to_string(),
kind: Some(CompletionItemKind::CLASS),
detail: Some(
Expand Down
Loading

0 comments on commit e7164d8

Please sign in to comment.