From 3926e7579203f875e02a3ac5549d05c3d7dabf32 Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Tue, 22 Apr 2025 23:22:38 +0100 Subject: [PATCH] Deny various rustc and clippy lints in ffi-errors crate --- cxx/src/error.rs | 1 + ffi-errors/src/esplugin.rs | 15 ++- ffi-errors/src/lci.rs | 10 +- ffi-errors/src/lib.rs | 166 ++++++++++++++++++++++++++++----- ffi-errors/src/libloadorder.rs | 68 ++++++++------ 5 files changed, 199 insertions(+), 61 deletions(-) diff --git a/cxx/src/error.rs b/cxx/src/error.rs index c735125c..c9ab5196 100644 --- a/cxx/src/error.rs +++ b/cxx/src/error.rs @@ -47,6 +47,7 @@ impl std::fmt::Display for VerboseError { SystemErrorCategory::Esplugin => "EspluginError", SystemErrorCategory::Libloadorder => "LibloadorderError", SystemErrorCategory::LootConditionInterpreter => "LciError", + _ => "UnknownCategoryError", }; write!(f, "{}: {}: {}", prefix, e.code(), e.message()) } diff --git a/ffi-errors/src/esplugin.rs b/ffi-errors/src/esplugin.rs index 71ccba5c..6df1704e 100644 --- a/ffi-errors/src/esplugin.rs +++ b/ffi-errors/src/esplugin.rs @@ -44,6 +44,13 @@ pub static ESP_ERROR_UNRESOLVED_RECORD_IDS: c_int = 13; #[unsafe(no_mangle)] pub static ESP_ERROR_PLUGIN_METADATA_NOT_FOUND: c_int = 14; +#[unsafe(no_mangle)] +pub static ESP_ERROR_UNKNOWN: c_int = c_int::MAX; + +#[expect( + clippy::wildcard_enum_match_arm, + reason = "It doesn't matter if other I/O error kinds are added in the future" +)] fn map_io_error(err: &std::io::Error) -> c_int { match err.kind() { std::io::ErrorKind::NotFound => ESP_ERROR_FILE_NOT_FOUND, @@ -52,12 +59,12 @@ fn map_io_error(err: &std::io::Error) -> c_int { } } +#[must_use] pub fn map_error(err: &Error) -> c_int { - match *err { - Error::IoError(ref x) => map_io_error(x), + match err { + Error::IoError(x) => map_io_error(x), Error::NoFilename(_) => ESP_ERROR_NO_FILENAME, - Error::ParsingIncomplete(_) => ESP_ERROR_PARSE_ERROR, - Error::ParsingError(_, _) => ESP_ERROR_PARSE_ERROR, + Error::ParsingIncomplete(_) | Error::ParsingError(_, _) => ESP_ERROR_PARSE_ERROR, Error::DecodeError(_) => ESP_ERROR_TEXT_DECODE_ERROR, Error::UnresolvedRecordIds(_) => ESP_ERROR_UNRESOLVED_RECORD_IDS, Error::PluginMetadataNotFound(_) => ESP_ERROR_PLUGIN_METADATA_NOT_FOUND, diff --git a/ffi-errors/src/lci.rs b/ffi-errors/src/lci.rs index d2475d50..4ffae62f 100644 --- a/ffi-errors/src/lci.rs +++ b/ffi-errors/src/lci.rs @@ -33,11 +33,15 @@ pub static LCI_ERROR_TEXT_ENCODE_FAIL: c_int = -7; #[unsafe(no_mangle)] pub static LCI_ERROR_INTERNAL_LOGIC_ERROR: c_int = -8; +#[unsafe(no_mangle)] +pub static LCI_ERROR_UNKNOWN: c_int = c_int::MAX; + +#[must_use] pub fn map_error(err: &Error) -> c_int { match err { - Error::ParsingIncomplete(_) => LCI_ERROR_PARSING_ERROR, - Error::UnconsumedInput(_) => LCI_ERROR_PARSING_ERROR, - Error::ParsingError(_, _) => LCI_ERROR_PARSING_ERROR, + Error::ParsingIncomplete(_) | Error::UnconsumedInput(_) | Error::ParsingError(_, _) => { + LCI_ERROR_PARSING_ERROR + } Error::PeParsingError(_, _) => LCI_ERROR_PE_PARSING_ERROR, Error::IoError(_, _) => LCI_ERROR_IO_ERROR, _ => LCI_ERROR_INTERNAL_LOGIC_ERROR, diff --git a/ffi-errors/src/lib.rs b/ffi-errors/src/lib.rs index d2c2d750..b3188028 100644 --- a/ffi-errors/src/lib.rs +++ b/ffi-errors/src/lib.rs @@ -1,8 +1,106 @@ +// Deny some rustc lints that are allow-by-default. +#![deny( + ambiguous_negative_literals, + impl_trait_overcaptures, + let_underscore_drop, + missing_copy_implementations, + missing_debug_implementations, + non_ascii_idents, + redundant_imports, + redundant_lifetimes, + trivial_casts, + trivial_numeric_casts, + unit_bindings, + unreachable_pub +)] +#![deny(clippy::pedantic)] +#![allow(clippy::missing_errors_doc)] +// Selectively deny clippy restriction lints. +#![deny( + clippy::allow_attributes, + clippy::as_conversions, + clippy::as_underscore, + clippy::assertions_on_result_states, + clippy::big_endian_bytes, + clippy::cfg_not_test, + clippy::clone_on_ref_ptr, + clippy::create_dir, + clippy::dbg_macro, + clippy::decimal_literal_representation, + clippy::default_numeric_fallback, + clippy::doc_include_without_cfg, + clippy::empty_drop, + clippy::error_impl_error, + clippy::exit, + clippy::exhaustive_enums, + clippy::expect_used, + clippy::filetype_is_file, + clippy::float_cmp_const, + clippy::fn_to_numeric_cast_any, + clippy::get_unwrap, + clippy::host_endian_bytes, + clippy::if_then_some_else_none, + clippy::indexing_slicing, + clippy::infinite_loop, + clippy::integer_division, + clippy::integer_division_remainder_used, + clippy::iter_over_hash_type, + clippy::let_underscore_must_use, + clippy::lossy_float_literal, + clippy::map_err_ignore, + clippy::map_with_unused_argument_over_ranges, + clippy::mem_forget, + clippy::missing_assert_message, + clippy::missing_asserts_for_indexing, + clippy::missing_asserts_for_indexing, + clippy::mixed_read_write_in_expression, + clippy::multiple_inherent_impl, + clippy::multiple_unsafe_ops_per_block, + clippy::mutex_atomic, + clippy::mutex_integer, + clippy::needless_raw_strings, + clippy::non_ascii_literal, + clippy::non_zero_suggestions, + clippy::panic, + clippy::panic_in_result_fn, + clippy::partial_pub_fields, + clippy::pathbuf_init_then_push, + clippy::precedence_bits, + clippy::print_stderr, + clippy::print_stdout, + clippy::rc_buffer, + clippy::rc_mutex, + clippy::redundant_type_annotations, + clippy::ref_patterns, + clippy::rest_pat_in_fully_bound_structs, + clippy::str_to_string, + clippy::string_lit_chars_any, + clippy::string_slice, + clippy::string_to_string, + clippy::suspicious_xor_used_as_pow, + clippy::tests_outside_test_module, + clippy::todo, + clippy::try_err, + clippy::undocumented_unsafe_blocks, + clippy::unimplemented, + clippy::unnecessary_safety_comment, + clippy::unneeded_field_pattern, + clippy::unreachable, + clippy::unused_result_ok, + clippy::unwrap_in_result, + clippy::unwrap_used, + clippy::use_debug, + clippy::verbose_file_reads, + clippy::wildcard_enum_match_arm +)] use std::{ error::Error, ffi::{c_int, c_uchar}, }; +use esplugin::ESP_ERROR_UNKNOWN; +use lci::LCI_ERROR_UNKNOWN; +use libloadorder::LIBLO_ERROR_UNKNOWN; use libloot::error::{ConditionEvaluationError, LoadOrderError, PluginDataError}; pub mod esplugin; @@ -23,6 +121,7 @@ pub static LIBLOOT_SYSTEM_ERROR_CATEGORY_LCI: c_uchar = 3; #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(u8)] +#[non_exhaustive] pub enum SystemErrorCategory { Esplugin = LIBLOOT_SYSTEM_ERROR_CATEGORY_ESPLUGIN, Libloadorder = LIBLOOT_SYSTEM_ERROR_CATEGORY_LIBLOADORDER, @@ -49,14 +148,17 @@ pub struct SystemError { } impl SystemError { + #[must_use] pub fn code(&self) -> c_int { self.code } + #[must_use] pub fn category(&self) -> SystemErrorCategory { self.category } + #[must_use] pub fn message(&self) -> &str { &self.message } @@ -76,48 +178,66 @@ impl std::error::Error for SystemError {} impl From for SystemError { fn from(value: PluginDataError) -> Self { - let error = value + let (code, message) = if let Some(error) = value .source() - .expect("LoadOrderError has source") - .downcast_ref::<::esplugin::Error>() - .expect("LoadOrderError source is an esplugin::Error"); - let error_code = crate::esplugin::map_error(error); + .and_then(|s| s.downcast_ref::<::esplugin::Error>()) + { + let error_code = crate::esplugin::map_error(error); + (error_code, error.to_string()) + } else { + ( + ESP_ERROR_UNKNOWN, + "Could not retrieve esplugin error message".to_owned(), + ) + }; SystemError { - code: error_code, + code, category: SystemErrorCategory::Esplugin, - message: error.to_string(), + message, } } } impl From for SystemError { fn from(value: LoadOrderError) -> Self { - let error = value + let (code, message) = if let Some(error) = value .source() - .expect("LoadOrderError has source") - .downcast_ref::() - .expect("LoadOrderError source is a loadorder::Error"); - let error_code = crate::libloadorder::map_error(error); + .and_then(|s| s.downcast_ref::<::loadorder::Error>()) + { + let error_code = crate::libloadorder::map_error(error); + (error_code, error.to_string()) + } else { + ( + LIBLO_ERROR_UNKNOWN, + "Could not retrieve libloadorder error message".to_owned(), + ) + }; SystemError { - code: error_code, + code, category: SystemErrorCategory::Libloadorder, - message: error.to_string(), + message, } } } impl From for SystemError { fn from(value: ConditionEvaluationError) -> Self { - let error = value + let (code, message) = if let Some(error) = value .source() - .expect("ConditionEvaluationError has source") - .downcast_ref::() - .expect("ConditionEvaluationError source is a loot_condition_interpreter::Error"); - let error_code = crate::lci::map_error(error); + .and_then(|s| s.downcast_ref::<::loot_condition_interpreter::Error>()) + { + let error_code = crate::lci::map_error(error); + (error_code, error.to_string()) + } else { + ( + LCI_ERROR_UNKNOWN, + "Could not retrieve loot-condition-interpreter error message".to_owned(), + ) + }; SystemError { - code: error_code, + code, category: SystemErrorCategory::LootConditionInterpreter, - message: error.to_string(), + message, } } } @@ -137,9 +257,9 @@ pub fn fmt_error_chain( mut error: &dyn std::error::Error, f: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { - write!(f, "{}", error)?; + write!(f, "{error}")?; while let Some(source) = error.source() { - write!(f, ": {}", source)?; + write!(f, ": {source}")?; error = source; } Ok(()) diff --git a/ffi-errors/src/libloadorder.rs b/ffi-errors/src/libloadorder.rs index dcd23a09..26b84c78 100644 --- a/ffi-errors/src/libloadorder.rs +++ b/ffi-errors/src/libloadorder.rs @@ -1,5 +1,5 @@ use loadorder::Error; -use std::ffi::c_int; +use std::{ffi::c_int, io::ErrorKind}; /// There is a mismatch between the files used to keep track of load order. /// @@ -70,49 +70,55 @@ pub static LIBLO_ERROR_SYSTEM_ERROR: c_int = 22; #[unsafe(no_mangle)] pub static LIBLO_ERROR_NO_PATH: c_int = 23; -/// Matches the value of the highest-numbered return code. +/// Matches the value of the highest-numbered return code, aside from `LIBLO_ERROR_UNKNOWN`. /// /// Provided in case clients wish to incorporate additional return codes in their implementation /// and desire some method of avoiding value conflicts. #[unsafe(no_mangle)] pub static LIBLO_RETURN_MAX: c_int = 23; +#[unsafe(no_mangle)] +pub static LIBLO_ERROR_UNKNOWN: c_int = c_int::MAX; + +#[expect( + clippy::wildcard_enum_match_arm, + reason = "It doesn't matter if other I/O error kinds are added in the future" +)] fn map_io_error(err: &std::io::Error) -> c_int { - use std::io::ErrorKind::*; match err.kind() { - NotFound => LIBLO_ERROR_FILE_NOT_FOUND, - AlreadyExists => LIBLO_ERROR_FILE_RENAME_FAIL, - PermissionDenied => LIBLO_ERROR_IO_PERMISSION_DENIED, + ErrorKind::NotFound => LIBLO_ERROR_FILE_NOT_FOUND, + ErrorKind::AlreadyExists => LIBLO_ERROR_FILE_RENAME_FAIL, + ErrorKind::PermissionDenied => LIBLO_ERROR_IO_PERMISSION_DENIED, _ => LIBLO_ERROR_IO_ERROR, } } +#[must_use] pub fn map_error(err: &Error) -> c_int { - use Error::*; - match *err { - InvalidPath(_) => LIBLO_ERROR_FILE_NOT_FOUND, - IoError(_, ref x) => map_io_error(x), - NoFilename(_) => LIBLO_ERROR_FILE_PARSE_FAIL, - DecodeError(_) => LIBLO_ERROR_TEXT_DECODE_FAIL, - EncodeError(_) => LIBLO_ERROR_TEXT_ENCODE_FAIL, - PluginParsingError(_, _) => LIBLO_ERROR_FILE_PARSE_FAIL, - PluginNotFound(_) => LIBLO_ERROR_INVALID_ARGS, - TooManyActivePlugins { .. } => LIBLO_ERROR_INVALID_ARGS, - DuplicatePlugin(_) => LIBLO_ERROR_INVALID_ARGS, - NonMasterBeforeMaster { .. } => LIBLO_ERROR_INVALID_ARGS, - InvalidEarlyLoadingPluginPosition { .. } => LIBLO_ERROR_INVALID_ARGS, - ImplicitlyActivePlugin(_) => LIBLO_ERROR_INVALID_ARGS, - NoLocalAppData => LIBLO_ERROR_INVALID_ARGS, - NoDocumentsPath => LIBLO_ERROR_INVALID_ARGS, - NoUserConfigPath => LIBLO_ERROR_NO_PATH, - NoUserDataPath => LIBLO_ERROR_NO_PATH, - NoProgramFilesPath => LIBLO_ERROR_NO_PATH, - UnrepresentedHoist { .. } => LIBLO_ERROR_INVALID_ARGS, - InstalledPlugin(_) => LIBLO_ERROR_INVALID_ARGS, - IniParsingError { .. } => LIBLO_ERROR_FILE_PARSE_FAIL, - VdfParsingError(_, _) => LIBLO_ERROR_FILE_PARSE_FAIL, - SystemError(_, _) => LIBLO_ERROR_SYSTEM_ERROR, - InvalidBlueprintPluginPosition { .. } => LIBLO_ERROR_INVALID_ARGS, + match err { + Error::InvalidPath(_) => LIBLO_ERROR_FILE_NOT_FOUND, + Error::IoError(_, x) => map_io_error(x), + Error::NoFilename(_) + | Error::PluginParsingError(_, _) + | Error::IniParsingError { .. } + | Error::VdfParsingError(_, _) => LIBLO_ERROR_FILE_PARSE_FAIL, + Error::DecodeError(_) => LIBLO_ERROR_TEXT_DECODE_FAIL, + Error::EncodeError(_) => LIBLO_ERROR_TEXT_ENCODE_FAIL, + Error::PluginNotFound(_) + | Error::TooManyActivePlugins { .. } + | Error::DuplicatePlugin(_) + | Error::NonMasterBeforeMaster { .. } + | Error::InvalidEarlyLoadingPluginPosition { .. } + | Error::ImplicitlyActivePlugin(_) + | Error::NoLocalAppData + | Error::NoDocumentsPath + | Error::UnrepresentedHoist { .. } + | Error::InstalledPlugin(_) + | Error::InvalidBlueprintPluginPosition { .. } => LIBLO_ERROR_INVALID_ARGS, + Error::NoUserConfigPath | Error::NoUserDataPath | Error::NoProgramFilesPath => { + LIBLO_ERROR_NO_PATH + } + Error::SystemError(_, _) => LIBLO_ERROR_SYSTEM_ERROR, _ => LIBLO_ERROR_INTERNAL_LOGIC_ERROR, } }