use super::*;
use crate::analysis::DesignRoot;
use crate::ast::search::*;
use crate::ast::WithRef;
use crate::data::SrcPos;
use fnv::FnvHashSet;
#[test]
fn incremental_analysis_of_use_within_package() {
let mut builder = LibraryBuilder::new();
builder.code(
"libname",
"
package pkg is
constant const : natural := 0;
end package;
",
);
builder.code(
"libname",
"
use work.pkg.const;
package pkg2 is
end package;
",
);
check_incremental_analysis(builder, vec![]);
}
#[test]
fn incremental_analysis_of_package_use() {
let mut builder = LibraryBuilder::new();
builder.code(
"libname",
"
package pkg is
constant const : natural := 0;
end package;
",
);
builder.code(
"libname",
"
use work.pkg;
package pkg2 is
end package;
",
);
check_incremental_analysis(builder, vec![]);
}
#[test]
fn incremental_analysis_of_entity_architecture() {
let mut builder = LibraryBuilder::new();
builder.code(
"libname",
"
entity ent is
end entity;
",
);
builder.code(
"libname",
"
architecture a of ent is
begin
end architecture;
",
);
check_incremental_analysis(builder, vec![]);
}
#[test]
fn incremental_analysis_of_package_and_body() {
let mut builder = LibraryBuilder::new();
builder.code(
"libname",
"
package pkg is
end package;
",
);
builder.code(
"libname",
"
package body pkg is
end package body;
",
);
check_incremental_analysis(builder, vec![]);
}
#[test]
fn incremental_analysis_of_entity_instance() {
let mut builder = LibraryBuilder::new();
builder.code(
"libname",
"
entity ent is
end entity;
architecture a of ent is
begin
end architecture;
",
);
builder.code(
"libname",
"
entity ent2 is
end entity;
architecture a of ent2 is
begin
inst: entity work.ent;
end architecture;
",
);
check_incremental_analysis(builder, vec![]);
}
#[test]
fn incremental_analysis_of_configuration_instance() {
let mut builder = LibraryBuilder::new();
builder.code(
"libname",
"
entity ent is
end entity;
architecture a of ent is
begin
end architecture;
",
);
builder.code(
"libname",
"
configuration cfg of ent is
for rtl
end for;
end configuration;
",
);
builder.code(
"libname",
"
entity ent2 is
end entity;
architecture a of ent2 is
begin
inst : configuration work.cfg;
end architecture;
",
);
check_incremental_analysis(builder, vec![]);
}
#[test]
fn incremental_analysis_library_all_collision() {
let mut builder = LibraryBuilder::new();
builder.code(
"libname1",
"
package pkg is
end package;
",
);
builder.code(
"libname2",
"
package pkg is
constant const : natural := 0;
end package;
",
);
let code = builder.code(
"libname3",
"
library libname1;
use libname1.all;
library libname2;
use libname2.all;
use pkg.const;
package pkg is
end package;
",
);
check_incremental_analysis(builder, vec![missing(&code, "pkg", 1)]);
}
#[test]
fn incremental_analysis_of_package_and_body_with_deferred_constant() {
let mut builder = LibraryBuilder::new();
builder.code(
"libname",
"
package pkg is
constant deferred : natural;
end package;
",
);
builder.code(
"libname",
"
package body pkg is
constant deferred : natural := 0;
end package body;
",
);
check_incremental_analysis(builder, vec![]);
}
fn check_incremental_analysis(builder: LibraryBuilder, expected_diagnostics: Vec<Diagnostic>) {
let symbols = builder.symbols();
let codes = builder.take_code();
for i in 0..codes.len() {
let mut fresh_root = DesignRoot::new(symbols.clone());
add_standard_library(symbols.clone(), &mut fresh_root);
let mut root = DesignRoot::new(symbols.clone());
add_standard_library(symbols.clone(), &mut root);
for (j, (library_name, code)) in codes.iter().enumerate() {
root.add_design_file(library_name.clone(), code.design_file());
if i != j {
fresh_root.add_design_file(library_name.clone(), code.design_file());
} else {
fresh_root.ensure_library(library_name.clone());
}
}
let mut diagnostics = Vec::new();
root.analyze(&mut diagnostics);
check_diagnostics(diagnostics, expected_diagnostics.clone());
let (library_name, code) = &codes[i];
root.remove_source(library_name.clone(), code.source());
check_analysis_equal(&mut root, &mut fresh_root);
root.add_design_file(library_name.clone(), code.design_file());
fresh_root.add_design_file(library_name.clone(), code.design_file());
let diagnostics = check_analysis_equal(&mut root, &mut fresh_root);
check_diagnostics(diagnostics, expected_diagnostics.clone());
}
}
fn check_analysis_equal(got: &mut DesignRoot, expected: &mut DesignRoot) -> Vec<Diagnostic> {
let mut got_diagnostics = Vec::new();
got.analyze(&mut got_diagnostics);
let mut expected_diagnostics = Vec::new();
expected.analyze(&mut expected_diagnostics);
check_diagnostics(got_diagnostics.clone(), expected_diagnostics.clone());
use std::iter::FromIterator;
let got_refs = FnvHashSet::from_iter(FindAnyReferences::search(got).into_iter());
let expected_refs = FnvHashSet::from_iter(FindAnyReferences::search(expected).into_iter());
let diff: FnvHashSet<_> = got_refs.symmetric_difference(&expected_refs).collect();
assert_eq!(diff, FnvHashSet::default());
got_diagnostics
}
struct FindAnyReferences {
references: Vec<SrcPos>,
}
impl FindAnyReferences {
fn new() -> FindAnyReferences {
FindAnyReferences {
references: Vec::new(),
}
}
fn search(searchable: &impl Search) -> Vec<SrcPos> {
let mut searcher = Self::new();
let _ = searchable.search(&mut searcher);
searcher.references
}
}
impl Searcher for FindAnyReferences {
fn search_pos_with_ref<U>(&mut self, _: &SrcPos, with_ref: &WithRef<U>) -> SearchState {
if let Some(ref reference) = with_ref.reference {
self.references.push(reference.clone());
};
NotFinished
}
}