Skip to content

Commit 608291c

Browse files
committed
Improve verify_message output
1 parent 8dafa1a commit 608291c

File tree

3 files changed

+59
-43
lines changed

3 files changed

+59
-43
lines changed

objc2/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
4545
`ClassBuilder::add_method` before you can use it.
4646
* **BREAKING**: Moved `MessageReceiver::verify_message` to `Class::verify_sel`
4747
and changed return type.
48+
* Improved debug output with `verify_message` feature enabled.
4849

4950
### Removed
5051
* **BREAKING:** Removed the `Sel::from_ptr` and `Sel::as_ptr` methods.

objc2/src/message/mod.rs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ use std::error::Error;
77

88
use crate::rc::{Id, Owned, Ownership};
99
use crate::runtime::{Class, Imp, Object, Sel};
10-
#[cfg(feature = "malloc")]
11-
use crate::verify::VerificationError;
1210
use crate::{Encode, EncodeArguments, RefEncode};
1311

1412
#[cfg(feature = "catch_all")]
@@ -167,7 +165,8 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized {
167165
return Err(MessageError(alloc::format!("Messsaging {:?} to nil", sel)));
168166
};
169167

170-
cls.verify_sel::<A, R>(sel)?;
168+
cls.verify_sel::<A, R>(sel)
169+
.map_err(|err| MessageError::from_verify(cls, sel, err))?;
171170
}
172171
unsafe { send_unverified(this, sel, args) }
173172
}
@@ -208,7 +207,9 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized {
208207
if this.is_null() {
209208
return Err(MessageError(alloc::format!("Messsaging {:?} to nil", sel)));
210209
}
211-
superclass.verify_sel::<A, R>(sel)?;
210+
superclass
211+
.verify_sel::<A, R>(sel)
212+
.map_err(|err| MessageError::from_verify(superclass, sel, err))?;
212213
}
213214
unsafe { send_super_unverified(this, superclass, sel, args) }
214215
}
@@ -386,6 +387,19 @@ message_args_impl!(
386387
#[derive(Debug, PartialEq, Eq, Hash)]
387388
pub struct MessageError(String);
388389

390+
#[cfg(feature = "verify_message")]
391+
impl MessageError {
392+
pub(crate) fn from_verify(cls: &Class, sel: Sel, err: crate::VerificationError) -> Self {
393+
MessageError(alloc::format!(
394+
"invalid message send to {}[{:?} {:?}]: {}",
395+
if cls.is_metaclass() { "+" } else { "-" },
396+
cls,
397+
sel,
398+
err
399+
))
400+
}
401+
}
402+
389403
impl fmt::Display for MessageError {
390404
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391405
fmt::Display::fmt(&self.0, f)
@@ -398,14 +412,6 @@ impl Error for MessageError {
398412
}
399413
}
400414

401-
#[cfg(feature = "malloc")]
402-
impl From<VerificationError> for MessageError {
403-
fn from(err: VerificationError) -> MessageError {
404-
use alloc::string::ToString;
405-
MessageError(err.to_string())
406-
}
407-
}
408-
409415
#[cfg(test)]
410416
mod tests {
411417
use super::*;

objc2/src/verify.rs

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -32,37 +32,37 @@ impl fmt::Display for MallocEncoding {
3232

3333
#[derive(Debug, PartialEq, Eq, Hash)]
3434
enum Inner {
35-
MethodNotFound(Sel),
36-
MismatchedReturn(Sel, MallocEncoding, Encoding<'static>),
37-
MismatchedArgumentsCount(Sel, usize, usize),
38-
MismatchedArgument(Sel, usize, MallocEncoding, Encoding<'static>),
35+
MethodNotFound,
36+
MismatchedReturn(MallocEncoding, Encoding<'static>),
37+
MismatchedArgumentsCount(usize, usize),
38+
MismatchedArgument(usize, MallocEncoding, Encoding<'static>),
3939
}
4040

4141
impl fmt::Display for Inner {
4242
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4343
match self {
44-
Self::MethodNotFound(sel) => {
45-
write!(f, "Method {:?} not found on class", sel)
44+
Self::MethodNotFound => {
45+
write!(f, "method not found")
4646
}
47-
Self::MismatchedReturn(sel, expected, actual) => {
47+
Self::MismatchedReturn(expected, actual) => {
4848
write!(
4949
f,
50-
"Return type code {} does not match expected {} for method {:?}",
51-
actual, expected, sel
50+
"expected return to have type code {}, but found {}",
51+
expected, actual
5252
)
5353
}
54-
Self::MismatchedArgumentsCount(sel, expected, actual) => {
54+
Self::MismatchedArgumentsCount(expected, actual) => {
5555
write!(
5656
f,
57-
"Method {:?} accepts {} arguments, but {} were given",
58-
sel, expected, actual
57+
"expected {} arguments, but {} were given",
58+
expected, actual
5959
)
6060
}
61-
Self::MismatchedArgument(sel, i, expected, actual) => {
61+
Self::MismatchedArgument(i, expected, actual) => {
6262
write!(
6363
f,
64-
"Method {:?} expected argument at index {} with type code {} but was given {}",
65-
sel, i, expected, actual
64+
"expected argument at index {} to have type code {}, but found {}",
65+
i, expected, actual
6666
)
6767
}
6868
}
@@ -101,13 +101,13 @@ where
101101
{
102102
let method = match cls.instance_method(sel) {
103103
Some(method) => method,
104-
None => return Err(Inner::MethodNotFound(sel).into()),
104+
None => return Err(Inner::MethodNotFound.into()),
105105
};
106106

107107
let actual = R::ENCODING;
108108
let expected = method.return_type();
109109
if !actual.equivalent_to_str(&*expected) {
110-
return Err(Inner::MismatchedReturn(sel, MallocEncoding(expected), actual).into());
110+
return Err(Inner::MismatchedReturn(MallocEncoding(expected), actual).into());
111111
}
112112

113113
let self_and_cmd = [<*mut Object>::ENCODING, Sel::ENCODING];
@@ -116,13 +116,13 @@ where
116116
let actual = self_and_cmd.len() + args.len();
117117
let expected = method.arguments_count();
118118
if actual != expected {
119-
return Err(Inner::MismatchedArgumentsCount(sel, expected, actual).into());
119+
return Err(Inner::MismatchedArgumentsCount(expected, actual).into());
120120
}
121121

122122
for (i, actual) in self_and_cmd.iter().chain(args).copied().enumerate() {
123123
let expected = method.argument_type(i).unwrap();
124124
if !actual.equivalent_to_str(&*expected) {
125-
return Err(Inner::MismatchedArgument(sel, i, MallocEncoding(expected), actual).into());
125+
return Err(Inner::MismatchedArgument(i, MallocEncoding(expected), actual).into());
126126
}
127127
}
128128

@@ -154,42 +154,51 @@ mod tests {
154154

155155
// Unimplemented selector (missing colon)
156156
let err = cls.verify_sel::<(), ()>(sel!(setFoo)).unwrap_err();
157-
assert_eq!(err.to_string(), "Method setFoo not found on class");
157+
assert_eq!(err.to_string(), "method not found");
158158

159159
// Incorrect return type
160160
let err = cls.verify_sel::<(u32,), u64>(sel!(setFoo:)).unwrap_err();
161161
assert_eq!(
162162
err.to_string(),
163-
"Return type code Q does not match expected v for method setFoo:"
163+
"expected return to have type code v, but found Q"
164164
);
165165

166166
// Too many arguments
167167
let err = cls.verify_sel::<(u32, i8), ()>(sel!(setFoo:)).unwrap_err();
168-
assert_eq!(
169-
err.to_string(),
170-
"Method setFoo: accepts 3 arguments, but 4 were given"
171-
);
168+
assert_eq!(err.to_string(), "expected 3 arguments, but 4 were given");
172169

173170
// Too few arguments
174171
let err = cls.verify_sel::<(), ()>(sel!(setFoo:)).unwrap_err();
175-
assert_eq!(
176-
err.to_string(),
177-
"Method setFoo: accepts 3 arguments, but 2 were given"
178-
);
172+
assert_eq!(err.to_string(), "expected 3 arguments, but 2 were given");
179173

180174
// Incorrect argument type
181175
let err = cls.verify_sel::<(Sel,), ()>(sel!(setFoo:)).unwrap_err();
182176
assert_eq!(
183177
err.to_string(),
184-
"Method setFoo: expected argument at index 2 with type code I but was given :"
178+
"expected argument at index 2 to have type code I, but found :"
185179
);
180+
181+
// Metaclass
182+
let metaclass = cls.metaclass();
183+
let err = metaclass
184+
.verify_sel::<(i32, i32, i32), i32>(sel!(addNumber:toNumber:))
185+
.unwrap_err();
186+
assert_eq!(err.to_string(), "expected 4 arguments, but 5 were given");
186187
}
187188

188189
#[test]
189190
#[cfg(feature = "verify_message")]
190-
#[should_panic = "Return type code i does not match expected I for method foo"]
191+
#[should_panic = "invalid message send to -[CustomObject foo]: expected return to have type code I, but found i"]
191192
fn test_send_message_verified() {
192193
let obj = test_utils::custom_object();
193194
let _: i32 = unsafe { msg_send![&obj, foo] };
194195
}
196+
197+
#[test]
198+
#[cfg(feature = "verify_message")]
199+
#[should_panic = "invalid message send to +[CustomObject abcDef]: method not found"]
200+
fn test_send_message_verified_to_class() {
201+
let cls = test_utils::custom_class();
202+
let _: i32 = unsafe { msg_send![cls, abcDef] };
203+
}
195204
}

0 commit comments

Comments
 (0)