def getLibrary(self, path): # type: (Path) -> UnresolvedLibrary """ Gets the library the path is in, inferring and updating it if needed. Any unit that can be used from VHDL code can be bound to a library, even if Verilog and SystemVerilog don't have this concept. """ self._parseSourceIfNeeded(path) if path not in self.paths: # Add the path to the project but put it on a different library self._parseSourceIfNeeded(path) self._updatePathLibrary(path, Identifier("not_in_project", True)) # Report paths that are valid (that is, not temporary) when they # can't be found in the project file if not isinstance(path, TemporaryPath): self._addDiagnostic(PathNotInProjectFile(path)) elif path not in self._library_map: # Library is not defined, try to infer _logger.info("Library for '%s' not set, inferring it", path) library = self._inferLibraryForPath(path) if library is not None: self._updatePathLibrary(path, library) return self._library_map.get(path, None)
def getMessagesWithText(self, path, content): # type: (Path, AnyStr) -> Iterable[CheckerDiagnostic] """ Dumps content to a temprary file and replaces the temporary file name for path on the diagnostics received """ with self._lock: _logger.info("Getting messages for '%s' with content", path) ext = path.name.split(".")[-1] temporary_file = tempfile.NamedTemporaryFile(suffix="." + ext, delete=False) temp_path = TemporaryPath(temporary_file.name) temporary_file.file.write(toBytes(content)) # type: ignore temporary_file.close() # If the reference path was added to the database, add the # temporary file with the same attributes if path in self.database.paths: library = self.database.getLibrary(path) self.database.addSource( temp_path, getattr(library, "display_name", None), self.database.getFlags(path, BuildFlagScope.single), self.database.getFlags(path, BuildFlagScope.dependencies), ) diags = set() # type: Set[CheckerDiagnostic] # Some messages may not include the filename field when checking a # file by content. In this case, we'll assume the empty filenames # refer to the same filename we got in the first place for diag in self.getMessagesByPath(temp_path): if diag.filename in (temp_path, None): diag = diag.copy( text=diag.text.replace(temporary_file.name, path.name), filename=path, ) diags.add(diag) diags |= set(self.database.getDiagnosticsForPath(temporary_file)) self.database.removeSource(temp_path) removeIfExists(temporary_file.name) if self.config_file and path not in self.database.paths: diags.add(PathNotInProjectFile(path)) return diags
def test(): filename = Path(p.join(TEST_TEMP_PATH, "some_file.vhd")) writeListToFile(str(filename), ["library some_lib;"]) diagnostics = it.project.getMessagesByPath(filename) _logger.info("Records found:") for diagnostic in diagnostics: _logger.info(diagnostic) it.assertIn(PathNotInProjectFile(filename), diagnostics) # The builder should find other issues as well... it.assertTrue( len(diagnostics) > 1, "It was expected that the builder added some " "message here indicating an error", )
def test(): filename = Path(p.join(TEST_TEMP_PATH, "some_file.vhd")) writeListToFile(str(filename), ["entity some_entity is end;"]) content = "\n".join([ "library work;", "use work.all;", "entity some_entity is end;" ]) diagnostics = it.project.getMessagesWithText(filename, content) _logger.debug("Records received:") for diagnostic in diagnostics: _logger.debug("- %s", diagnostic) it.assertIn( LibraryShouldBeOmited(library="work", filename=filename, column_number=8, line_number=0), diagnostics, ) it.assertIn(PathNotInProjectFile(filename), diagnostics)
def test(_): with PatchBuilder(): it.project.setConfig(Path(p.join(TEST_PROJECT, "vimhdl.prj"))) it.project._updateConfigIfNeeded() entity_a = _SourceMock( filename=_path("entity_a.vhd"), library="some_lib", design_units=[{ "name": "entity_a", "type": "entity" }], dependencies={("work", "foo")}, ) path_to_foo = Path( p.join(TEST_PROJECT, "another_library", "foo.vhd")) diags = { # entity_a.vhd is the path we're compiling, inject a diagnostic # from the builder str(entity_a.filename): [[ CheckerDiagnostic(filename=entity_a.filename, checker=None, text="some text") ]], # foo.vhd is on the build sequence, check that diagnostics from # the build sequence are only included when their severity is # DiagType.ERROR str(path_to_foo): [[ CheckerDiagnostic( filename=path_to_foo, checker=None, text="should not be included", severity=DiagType.WARNING, ), CheckerDiagnostic( filename=path_to_foo, checker=None, text="style error should be included", severity=DiagType.STYLE_ERROR, ), CheckerDiagnostic( filename=path_to_foo, checker=None, text="should be included", severity=DiagType.ERROR, ), ]], } def build( # pylint: disable=unused-argument path, library, scope, forced=False): _logger.debug("Building library=%s, path=%s", library, path) path_diags = diags.get(str(path), []) if path_diags: return path_diags.pop(), [] return [], [] with patch.object(it.project.builder, "build", build): _logger.info("Project paths: %s", it.project.database._paths) messages = list(it.project.getMessagesByPath( entity_a.filename)) logIterable("Messages", messages, _logger.info) it.assertCountEqual( messages, [ LibraryShouldBeOmited( library="work", filename=entity_a.filename, column_number=8, line_number=0, ), PathNotInProjectFile(entity_a.filename), CheckerDiagnostic(filename=entity_a.filename, checker=None, text="some text"), CheckerDiagnostic( filename=path_to_foo, checker=None, text="style error should be included", severity=DiagType.STYLE_ERROR, ), CheckerDiagnostic( filename=path_to_foo, checker=None, text="should be included", severity=DiagType.ERROR, ), ], )