Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

arch: migrate lsp document_symbol to new sema model #918

Merged
merged 1 commit into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion kclvm/sema/src/core/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub trait Symbol {
fn full_dump(&self, data: &Self::SymbolData) -> Option<String>;
}

type KCLSymbol = dyn Symbol<SymbolData = KCLSymbolData, SemanticInfo = KCLSymbolSemanticInfo>;
pub type KCLSymbol = dyn Symbol<SymbolData = KCLSymbolData, SemanticInfo = KCLSymbolSemanticInfo>;
#[derive(Debug, Clone, Default)]
pub struct KCLSymbolSemanticInfo {
pub ty: Option<Arc<Type>>,
Expand Down
226 changes: 129 additions & 97 deletions kclvm/tools/src/LSP/src/document_symbol.rs
Original file line number Diff line number Diff line change
@@ -1,107 +1,134 @@
use std::path::Path;

use kclvm_ast::ast::Program;
use kclvm_ast::MAIN_PKG;
use kclvm_sema::resolver::scope::ProgramScope;
use kclvm_sema::resolver::scope::Scope;
use kclvm_sema::resolver::scope::ScopeKind;
use kclvm_sema::resolver::scope::ScopeObject;
use kclvm_sema::resolver::scope::ScopeObjectKind;
use kclvm_error::Position;
use kclvm_sema::core::global_state::GlobalState;
use kclvm_sema::core::symbol::KCLSymbol;
use kclvm_sema::core::symbol::SymbolKind as KCLSymbolKind;
use lsp_types::Range;
use lsp_types::{DocumentSymbol, DocumentSymbolResponse, SymbolKind};

use crate::to_lsp::lsp_pos;

pub(crate) fn document_symbol(
file: &str,
_program: &Program,
prog_scope: &ProgramScope,
gs: &GlobalState,
) -> Option<lsp_types::DocumentSymbolResponse> {
let mut documentsymbols: Vec<DocumentSymbol> = vec![];
let scope = prog_scope.scope_map.get(MAIN_PKG).unwrap().borrow();
// Get variable in scope
for obj in scope.elems.values().filter(|obj| {
if let Ok(canonicalized_path) = Path::new(&obj.borrow().start.filename).canonicalize() {
// skip schema definition
canonicalized_path.eq(Path::new(file))
&& obj.borrow().kind != ScopeObjectKind::Definition
} else {
false
}
}) {
documentsymbols.push(scope_obj_to_document_symbol(obj.borrow().clone()));
}
// Get schema definition in scope
for child in scope.children.iter().filter(|child| {
if let Ok(canonicalized_path) = Path::new(&child.borrow().start.filename).canonicalize() {
canonicalized_path.eq(Path::new(file))
} else {
false
}
}) {
if let Some(symbol) = schema_scope_to_document_symbol(child.borrow().clone()) {
documentsymbols.push(symbol)

let dummy_pos = Position {
filename: file.to_string(),
line: 1,
column: Some(0),
};

if let Some(scope) = gs.look_up_scope(&dummy_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(symbol) => {
let def = symbol.get_definition();
match def {
Some(def) => {
let symbol_range = symbol.get_range();
// filter current file symbols
if let Ok(canonicalized_path) =
Path::new(&symbol_range.0.filename).canonicalize()
{
if canonicalized_path.eq(Path::new(file)) {
match def.get_kind() {
KCLSymbolKind::Schema => {
match &mut symbol_to_document_symbol(symbol) {
Some(schema_symbol) => {
let module_info = gs
.get_packages()
.get_module_info(&dummy_pos.filename);
let attrs = symbol.get_all_attributes(
gs.get_symbols(),
module_info,
);
let mut children = vec![];

for attr in attrs {
match gs.get_symbols().get_symbol(attr)
{
Some(attr_symbol) => {
match symbol_to_document_symbol(
attr_symbol,
) {
Some(symbol) => {
children.push(symbol)
}
None => {}
}
}
None => {}
}
}

schema_symbol.children = Some(children);
documentsymbols.push(schema_symbol.clone());
}
None => {}
}
}
_ => match symbol_to_document_symbol(symbol) {
Some(symbol) => documentsymbols.push(symbol),
None => {}
},
}
}
}
}
None => {}
}
}
None => {}
}
}
}
}
Some(DocumentSymbolResponse::Nested(documentsymbols))
}

#[allow(deprecated)]
fn schema_scope_to_document_symbol(scope: Scope) -> Option<DocumentSymbol> {
if let ScopeKind::Schema(schema_name) = &scope.kind {
let range = Range {
start: lsp_pos(&scope.start),
end: lsp_pos(&scope.end),
};
Some(DocumentSymbol {
name: schema_name.clone(),
kind: SymbolKind::STRUCT,
range,
selection_range: range,
children: Some(
scope
.elems
.iter()
.map(|(_, obj)| scope_obj_to_document_symbol(obj.borrow().clone()))
.collect(),
),
detail: Some("schema".to_string()),
tags: None,
deprecated: None,
})
} else {
None
}
}
fn symbol_to_document_symbol(symbol: &KCLSymbol) -> Option<DocumentSymbol> {
let sema_info = symbol.get_sema_info();
let def = symbol.get_definition();
match def {
Some(def) => {
let name = symbol.get_name();
let symbol_range = symbol.get_range();
let range = Range {
start: lsp_pos(&symbol_range.0),
end: lsp_pos(&symbol_range.1),
};
let kind = def.get_kind();
let kind = symbol_kind_to_document_symbol_kind(kind);
let detail = sema_info.ty.clone().map(|ty| ty.ty_str());

#[allow(deprecated)]
fn scope_obj_to_document_symbol(obj: ScopeObject) -> DocumentSymbol {
let kind = scope_obj_kind_to_document_symbol_kind(obj.kind);
let range = Range {
start: lsp_pos(&obj.start),
end: lsp_pos(&obj.end),
};
DocumentSymbol {
name: obj.name.clone(),
kind,
range,
selection_range: range,
detail: Some(obj.ty.ty_str()),
tags: None,
children: None,
deprecated: None,
Some(DocumentSymbol {
name,
kind,
range,
selection_range: range,
detail,
tags: None,
children: None,
deprecated: None,
})
}
None => None,
}
}

fn scope_obj_kind_to_document_symbol_kind(kind: ScopeObjectKind) -> SymbolKind {
fn symbol_kind_to_document_symbol_kind(kind: KCLSymbolKind) -> SymbolKind {
match kind {
ScopeObjectKind::Variable => SymbolKind::VARIABLE,
ScopeObjectKind::Attribute => SymbolKind::PROPERTY,
ScopeObjectKind::Definition => SymbolKind::STRUCT,
ScopeObjectKind::Parameter => SymbolKind::VARIABLE,
ScopeObjectKind::TypeAlias => SymbolKind::TYPE_PARAMETER,
ScopeObjectKind::Module(_) => SymbolKind::MODULE,
ScopeObjectKind::FunctionCall => SymbolKind::FUNCTION,
KCLSymbolKind::Schema => SymbolKind::STRUCT,
KCLSymbolKind::Attribute => SymbolKind::PROPERTY,
KCLSymbolKind::Value => SymbolKind::VARIABLE,
KCLSymbolKind::Package => SymbolKind::PACKAGE,
KCLSymbolKind::TypeAlias => SymbolKind::TYPE_PARAMETER,
KCLSymbolKind::Unresolved => SymbolKind::NULL,
KCLSymbolKind::Rule => SymbolKind::FUNCTION,
}
}

Expand Down Expand Up @@ -145,32 +172,37 @@ mod tests {
#[test]
#[bench_test]
fn document_symbol_test() {
let (file, program, prog_scope, _, _gs) =
compile_test_file("src/test_data/document_symbol.k");
let (file, _, _, _, gs) = compile_test_file("src/test_data/document_symbol.k");

let res = document_symbol(file.as_str(), &program, &prog_scope).unwrap();
let mut res = document_symbol(file.as_str(), &gs).unwrap();
let mut expect = vec![];
expect.push(build_document_symbol(
"p",
SymbolKind::VARIABLE,
((3, 0), (3, 1)),
None,
Some("Person4".to_string()),
));
expect.push(build_document_symbol(
"Person4",
SymbolKind::STRUCT,
((0, 7), (1, 13)),
((0, 7), (0, 14)),
Some(vec![build_document_symbol(
"name",
SymbolKind::PROPERTY,
((1, 4), (1, 8)),
None,
Some("str".to_string()),
)]),
Some("schema".to_string()),
Some("Person4".to_string()),
));
let expect = DocumentSymbolResponse::Nested(expect);
assert_eq!(res, expect)
expect.push(build_document_symbol(
"p",
SymbolKind::VARIABLE,
((3, 0), (3, 1)),
None,
Some("Person4".to_string()),
));

match &mut res {
DocumentSymbolResponse::Flat(_) => panic!("test failed"),
DocumentSymbolResponse::Nested(got) => {
got.sort_by(|a, b| a.name.cmp(&b.name));
assert_eq!(got, &expect)
}
}
}
}
2 changes: 1 addition & 1 deletion kclvm/tools/src/LSP/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ pub(crate) fn handle_document_symbol(
return Ok(None);
}
let db = snapshot.get_db(&path.clone().into())?;
let res = document_symbol(&file, &db.prog, &db.scope);
let res = document_symbol(&file, &db.gs);
if res.is_none() {
log_message(format!("File {file} Document symbol not found"), &sender)?;
}
Expand Down
Loading