Fix "No structure encoding found for ?" exception when calling certain methods with C struct arguments/return value #110
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The Problem
When it comes to working with C struct arguments in Objective-C methods, Mocha (like e.g. PyObjC and other scripting environments) relies on scripting bridge support metadata found in frameworks/bundles those methods come from, like e.g. Foundation or AppKit.
Now, in order to understand which C struct type metadata it needs to look up in these bridge support definitions when calling a certain method, Mocha asks the Objective-C runtime to provide it with a full method type signature. In most cases the result contains a perfectly valid type encoding of this method's struct arguments and/or a struct return value, but in some cases these type encodings might be incorrect or bogus: while the struct fields themselves are encoded correctly, the name of the struct type is replaced with a "?":
This missing name in a struct type encoding prevents routines like
-[MOFunctionArgument getValueAsJSValueInContext:]
and-[MOFunctionArgument setValueAsJSValue:context:]
from converting this struct from/to a JS value, because it fails to look up this struct's definition in bridge support metadata by its bogus name.As a result, it's impossible to call such methods from CocoaScript as doing so leads to the following runtime exception:
Steps to Reproduce
This error is easy to trigger by running the following CocoaScript code:
Merely calling the methods above leads to the "No structure encoding found for ?" exception. I'm not aware of any user-space workarounds.
Proposed Solution
We might expand
_MOFunctionInvoke()
's Objective-C method branch to compare the type declarations we get frommethod_getTypeEncoding()
/-methodSignatureForSelector:
with what's in the bridge support metadata for this method and replace any bogus struct names ("?") with their actual names from the latter if found.Implications
UX
The promise of the proposed solution above is to only fix types for structs with already bogus names, so the worst case scenario is that we replace a bogus struct name with another bogus one (in case there's something wrong with the declaration in the bridge support file) – which won't degrade the user experience a bit.
Performance
The implementation also tries not to perform any additional (to the existing code) work unless necessary, so the performance implications are likely tolerable (although I haven't run any performance stress tests).
References
I've collected a few mentions of this issue from various Sketch plugin developers throughout the years: