Skip to content

Commit 7ca8a9d

Browse files
committed
Add partial semantic analysis for unmapped files
1 parent a510cdb commit 7ca8a9d

File tree

5 files changed

+61
-13
lines changed

5 files changed

+61
-13
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ This repository includes a medium sized example [project](example_project/README
8888

8989
### Configuration
9090
The language server uses a configuration file in the [TOML](https://github.com/toml-lang/toml) format named `vhdl_ls.toml`.
91-
The file contains the library mapping of all files within the project. Files outside of the project without library mapping are checked for syntax errors only.
91+
The file contains the library mapping of all files within the project.
9292

9393
`vhdl_ls` will load configuration files in the following order of priority (first to last):
9494
1. A file named `.vhdl_ls.toml` in the user home folder.

vhdl_lang/src/analysis/root.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ impl DesignRoot {
327327
FindAllReferences::search(self, decl_pos)
328328
}
329329

330-
pub(super) fn symbol_utf8(&self, name: &str) -> Symbol {
330+
pub fn symbol_utf8(&self, name: &str) -> Symbol {
331331
self.symbols.symtab().insert_utf8(name)
332332
}
333333

vhdl_lang/src/project.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,15 @@ impl Project {
167167
} else {
168168
// File is not part of the project
169169
// @TODO use config wildcards to map to library
170+
171+
// Add unmapped files to an anonymous library work
172+
// To still get some semantic analysis for unmapped files
173+
let mut library_names = FnvHashSet::default();
174+
library_names.insert(self.root.symbol_utf8("work"));
175+
170176
SourceFile {
171177
source: source.clone(),
172-
library_names: FnvHashSet::default(),
178+
library_names,
173179
parser_diagnostics: vec![],
174180
design_file: DesignFile::default(),
175181
}
@@ -311,6 +317,41 @@ lib.files = ['file.vhd']
311317
check_no_diagnostics(&project.analyse());
312318
}
313319

320+
#[test]
321+
fn unmapped_libraries_are_analyzed() {
322+
let mut messages = Vec::new();
323+
let mut project = Project::from_config(&Config::default(), &mut messages);
324+
assert_eq!(messages, vec![]);
325+
let diagnostics = project.analyse();
326+
check_no_diagnostics(&diagnostics);
327+
328+
let root = tempfile::tempdir().unwrap();
329+
let vhdl_file_path = root.path().join("file.vhd");
330+
std::fs::write(
331+
&vhdl_file_path,
332+
"
333+
entity ent is
334+
end ent;
335+
336+
architecture rtl of ent is
337+
begin
338+
end architecture;
339+
340+
architecture rtl of ent is
341+
begin
342+
end architecture;
343+
",
344+
)
345+
.unwrap();
346+
let source = Source::from_latin1_file(&vhdl_file_path).unwrap();
347+
348+
project.update_source(&source);
349+
let diagnostics = project.analyse();
350+
assert_eq!(diagnostics.len(), 1);
351+
let diag = diagnostics.first().unwrap();
352+
assert_eq!(diag.message, "Duplicate architecture 'rtl' of entity 'ent'")
353+
}
354+
314355
/// Test that the same file can be added to several libraries
315356
#[test]
316357
fn test_same_file_in_multiple_libraries() {

vhdl_ls/src/rpc_channel.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ pub trait RpcChannel {
4141
}
4242

4343
fn push_msg(&self, msg: Message) {
44-
if msg.message_type == vhdl_lang::MessageType::Error {
44+
if matches!(
45+
msg.message_type,
46+
vhdl_lang::MessageType::Warning | vhdl_lang::MessageType::Error
47+
) {
4548
self.window_show_message(to_lsp_message_type(&msg.message_type), msg.message.clone());
4649
}
4750
self.window_log_message(to_lsp_message_type(&msg.message_type), msg.message);
@@ -150,6 +153,10 @@ pub mod test_support {
150153
self.expect_notification_contains("window/logMessage", contains);
151154
}
152155

156+
pub fn expect_warning_contains(&self, contains: impl Into<String>) {
157+
self.expect_error_contains(contains)
158+
}
159+
153160
pub fn expect_message_contains(&self, contains: impl Into<String>) {
154161
let contains = contains.into();
155162
self.expect_notification_contains("window/logMessage", contains);

vhdl_ls/src/vhdl_server.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ impl<T: RpcChannel + Clone> VHDLServer<T> {
7171
}
7272
Err(ref err) => {
7373
self.rpc_channel.push_msg(Message::error(format!(
74-
"Found no vhdl_ls.toml config file in the workspace root path: {}",
74+
"Library mapping is unknown due to missing vhdl_ls.toml config file in the workspace root path: {}",
7575
err
7676
)));
7777
self.rpc_channel.push_msg(Message::warning(
78-
"Found no library mapping, semantic analysis disabled, will perform syntax checking only",
78+
"Without library mapping semantic analysis might be incorrect",
7979
));
8080
}
8181
};
@@ -352,7 +352,7 @@ impl<T: RpcChannel + Clone> InitializedVHDLServer<T> {
352352
self.project.update_source(&source);
353353
self.publish_diagnostics();
354354
} else {
355-
self.push_msg(Message::info(format!(
355+
self.push_msg(Message::warning(format!(
356356
"Opening file {} that is not part of the project",
357357
file_name.to_string_lossy()
358358
)));
@@ -598,9 +598,9 @@ mod tests {
598598
}
599599

600600
fn expect_missing_config_messages(mock: &RpcMock) {
601-
mock.expect_error_contains("Found no vhdl_ls.toml config file in the workspace root path");
602-
mock.expect_message_contains(
603-
"Found no library mapping, semantic analysis disabled, will perform syntax checking only",
601+
mock.expect_error_contains("Library mapping is unknown due to missing vhdl_ls.toml config file in the workspace root path");
602+
mock.expect_warning_contains(
603+
"Without library mapping semantic analysis might be incorrect",
604604
);
605605
}
606606

@@ -642,7 +642,7 @@ end entity ent;
642642
},
643643
};
644644

645-
mock.expect_message_contains("is not part of the project");
645+
mock.expect_warning_contains("is not part of the project");
646646

647647
server.text_document_did_open_notification(&did_open);
648648
}
@@ -694,7 +694,7 @@ end entity ent2;
694694
version: None,
695695
};
696696

697-
mock.expect_message_contains("is not part of the project");
697+
mock.expect_warning_contains("is not part of the project");
698698

699699
mock.expect_notification("textDocument/publishDiagnostics", publish_diagnostics);
700700
server.text_document_did_open_notification(&did_open);
@@ -825,7 +825,7 @@ lib.files = [
825825
);
826826

827827
expect_loaded_config_messages(&mock, &config_uri);
828-
mock.expect_message_contains("missing_file.vhd");
828+
mock.expect_warning_contains("missing_file.vhd");
829829
initialize_server(&mut server, root_uri);
830830
}
831831

0 commit comments

Comments
 (0)