-
Notifications
You must be signed in to change notification settings - Fork 65
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5d2038d
commit 3d83e55
Showing
8 changed files
with
309 additions
and
151 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,43 +5,26 @@ | |
// Copyright (c) 2018, Olof Kraigher [email protected] | ||
|
||
use clap::Parser; | ||
use itertools::Itertools; | ||
use std::path::Path; | ||
use std::time::SystemTime; | ||
use vhdl_lang::{Config, Diagnostic, MessagePrinter, NullMessages, Project, Severity, SeverityMap}; | ||
use vhdl_lang::{Config, Diagnostic, MessagePrinter, Project, Severity, SeverityMap}; | ||
|
||
/// Run vhdl analysis | ||
#[derive(Parser, Debug)] | ||
#[command(author, version, about, long_about = None)] | ||
struct Args { | ||
/// The number of threads to use. By default the maximum is selected based on process cores | ||
/// The number of threads to use. By default, the maximum is selected based on process cores | ||
#[arg(short = 'p', long)] | ||
num_threads: Option<usize>, | ||
|
||
/// Prints the number of files processed and the execution time | ||
#[arg(long, default_value_t = false)] | ||
perf: bool, | ||
|
||
/// Run repeatedly to get a reliable benchmark result | ||
#[arg(long, default_value_t = false)] | ||
bench: bool, | ||
|
||
/// Hide hint diagnostics | ||
#[arg(long, default_value_t = false)] | ||
no_hint: bool, | ||
/// Path to the config file for the VHDL standard libraries (i.e., IEEE std_logic_1164). | ||
/// If omitted, will search for these libraries in a set of standard paths | ||
#[arg(short = 'l', long)] | ||
libraries: Option<String>, | ||
|
||
/// Config file in TOML format containing libraries and settings | ||
#[arg(short, long)] | ||
config: String, | ||
|
||
/// Dump items that are not resolved into an unique reference | ||
/// This is used for development to test where the language server is blind | ||
#[arg(long)] | ||
dump_unresolved: bool, | ||
|
||
/// Count items that are not resolved into an unique reference | ||
/// This is used for development to test where the language server is blind | ||
#[arg(long)] | ||
count_unresolved: bool, | ||
} | ||
|
||
fn main() { | ||
|
@@ -53,77 +36,36 @@ fn main() { | |
|
||
let mut config = Config::default(); | ||
let mut msg_printer = MessagePrinter::default(); | ||
config.load_external_config(&mut msg_printer); | ||
config.load_external_config(&mut msg_printer, args.libraries.clone()); | ||
config.append( | ||
&Config::read_file_path(Path::new(&args.config)).expect("Failed to read config file"), | ||
&mut msg_printer, | ||
); | ||
|
||
let start = SystemTime::now(); | ||
|
||
let iterations = if args.bench { | ||
let iterations = 10; | ||
println!("Running {iterations} iterations for benchmarking"); | ||
for _ in 0..(iterations - 1) { | ||
let mut project = Project::from_config(config.clone(), &mut NullMessages); | ||
project.analyse(); | ||
} | ||
iterations | ||
} else { | ||
1 | ||
}; | ||
|
||
let severity_map = *config.severities(); | ||
let mut project = Project::from_config(config, &mut msg_printer); | ||
let mut diagnostics = project.analyse(); | ||
let duration = start.elapsed().unwrap() / iterations; | ||
|
||
if args.no_hint { | ||
diagnostics.retain(|diag| severity_map[diag.code] != Some(Severity::Hint)); | ||
} | ||
project.enable_unused_declaration_detection(); | ||
let diagnostics = project.analyse(); | ||
|
||
show_diagnostics(&diagnostics, &severity_map); | ||
|
||
if args.perf || args.bench { | ||
let mut num_files = 0; | ||
let mut num_lines = 0; | ||
for source_file in project.files() { | ||
num_files += 1; | ||
num_lines += source_file.num_lines(); | ||
} | ||
let duration_per_line = duration.checked_div(num_lines as u32).unwrap(); | ||
|
||
println!("Analyzed {num_files} files with {num_lines} lines of code"); | ||
println!( | ||
"Total time to run was {} ms with an average of {} ns per line", | ||
duration.as_millis(), | ||
duration_per_line.as_nanos() | ||
); | ||
} | ||
|
||
if args.dump_unresolved || args.count_unresolved { | ||
let (total, unresolved) = project.find_all_unresolved(); | ||
|
||
if args.dump_unresolved { | ||
for pos in unresolved.iter() { | ||
println!("{}", pos.show("Unresolved")); | ||
} | ||
} | ||
|
||
if args.count_unresolved { | ||
println!("{} out of {} positions unresolved", unresolved.len(), total); | ||
} | ||
if diagnostics | ||
.iter() | ||
.any(|diag| severity_map[diag.code].is_some_and(|severity| severity == Severity::Error)) | ||
{ | ||
std::process::exit(1); | ||
} else { | ||
std::process::exit(0); | ||
} | ||
|
||
// Exit without running Drop on entire allocated AST | ||
std::process::exit(0); | ||
} | ||
|
||
fn show_diagnostics(diagnostics: &[Diagnostic], severity_map: &SeverityMap) { | ||
for diagnostic in diagnostics { | ||
if let Some(str) = diagnostic.show(severity_map) { | ||
println!("{str}"); | ||
} | ||
let diagnostics = diagnostics | ||
.iter() | ||
.filter_map(|diag| diag.show(severity_map)) | ||
.collect_vec(); | ||
for str in &diagnostics { | ||
println!("{str}"); | ||
} | ||
|
||
if !diagnostics.is_empty() { | ||
|
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
use assert_cmd::prelude::*; | ||
use itertools::Itertools; | ||
use predicates::prelude::*; | ||
use std::error::Error; | ||
use std::path::PathBuf; | ||
use std::process::Command; | ||
use vhdl_lang::{Config, MessagePrinter, Project, Severity}; | ||
|
||
#[test] | ||
pub fn parses_example_project_without_errors() { | ||
let mut config = Config::default(); | ||
let mut msg_printer = MessagePrinter::default(); | ||
|
||
let mut vhdl_libraries_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); | ||
// Load the VHDL standard libraries | ||
vhdl_libraries_path.push("../vhdl_libraries/vhdl_ls.toml"); | ||
config.append( | ||
&Config::read_file_path(&vhdl_libraries_path).expect("Failed to read config file"), | ||
&mut msg_printer, | ||
); | ||
|
||
// Load the configuration from the example project | ||
let mut config_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); | ||
config_path.push("../example_project/vhdl_ls.toml"); | ||
config.append( | ||
&Config::read_file_path(&config_path).expect("Failed to read config file"), | ||
&mut msg_printer, | ||
); | ||
|
||
let severity_map = *config.severities(); | ||
let mut project = Project::from_config(config, &mut msg_printer); | ||
project.enable_unused_declaration_detection(); | ||
|
||
let diagnostics = project.analyse(); | ||
let diagnostics_with_errors = diagnostics | ||
.iter() | ||
.filter(|diag| severity_map[diag.code] == Some(Severity::Error)) | ||
.collect_vec(); | ||
if !diagnostics_with_errors.is_empty() { | ||
for diagnostic in diagnostics_with_errors { | ||
println!("{}", diagnostic.show(&severity_map).unwrap()) | ||
} | ||
panic!("Found diagnostics with severity error in the example project"); | ||
} | ||
} | ||
|
||
#[test] | ||
fn unused_function_gets_detected() -> Result<(), Box<dyn Error>> { | ||
let mut cmd = Command::cargo_bin("vhdl_lang")?; | ||
|
||
cmd.arg("--config") | ||
.arg("tests/unused_declarations/vhdl_ls.toml") | ||
.arg("--libraries") | ||
.arg("../vhdl_libraries/vhdl_ls.toml"); | ||
cmd.assert().failure().stdout(predicate::str::contains( | ||
"error: Unused declaration of port 'baz' : inout", | ||
)); | ||
|
||
Ok(()) | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
library ieee; | ||
use ieee.std_logic_1164.all; | ||
|
||
entity my_ent is | ||
port ( | ||
foo : in std_logic; | ||
bar : out std_logic; | ||
baz : inout std_logic | ||
); | ||
end my_ent; | ||
|
||
architecture arch of my_ent is | ||
begin | ||
bar <= foo; | ||
end architecture arch; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[libraries] | ||
|
||
my_library.files = ["my_entity.vhd"] | ||
|
||
[lint] | ||
unused = "error" |
This file contains 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