Skip to content
This repository was archived by the owner on Jun 25, 2025. It is now read-only.

Commit 2040c37

Browse files
committed
[ObjC] Improve naming of arguments to Objective-C methods
Detect and remove common prefixes used on selectors so that their arguments are more naturally named. For instance, a selector of `initWithURL:withStagedURL`: now ends up with arguments named `URL` and `stagedURL`, rather than `initWithURL` and `withStagedURL`.
1 parent 0df5ff8 commit 2040c37

File tree

1 file changed

+33
-1
lines changed

1 file changed

+33
-1
lines changed

Workflow.cpp

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ static std::mutex g_initialAnalysisMutex;
2222
using SectionRef = BinaryNinja::Ref<BinaryNinja::Section>;
2323
using SymbolRef = BinaryNinja::Ref<BinaryNinja::Symbol>;
2424

25+
namespace {
26+
2527
std::vector<std::string> splitSelector(const std::string& selector) {
2628
std::vector<std::string> components;
2729
std::istringstream stream(selector);
@@ -36,18 +38,48 @@ std::vector<std::string> splitSelector(const std::string& selector) {
3638
return components;
3739
}
3840

41+
// Given a selector component such as `initWithPath' and a prefix of `initWith`, returns `path`.
42+
std::optional<std::string> SelectorComponentWithoutPrefix(std::string_view prefix, std::string_view component)
43+
{
44+
if (component.size() <= prefix.size() || component.rfind(prefix.data(), 0) != 0
45+
|| !isupper(component[prefix.size()])) {
46+
return std::nullopt;
47+
}
48+
49+
std::string result(component.substr(prefix.size()));
50+
51+
// Lowercase the first character if the second character is not also uppercase.
52+
// This ensures we leave initialisms such as `URL` alone.
53+
if (result.size() > 1 && islower(result[1]))
54+
result[0] = tolower(result[0]);
55+
56+
return result;
57+
}
58+
59+
std::string ArgumentNameFromSelectorComponent(std::string component)
60+
{
61+
// TODO: Handle other common patterns such as <do some action>With<arg>: and <do some action>For<arg>:
62+
for (const auto& prefix : { "initWith", "with", "and", "using", "set", "read", "to", "for" }) {
63+
if (auto argumentName = SelectorComponentWithoutPrefix(prefix, component); argumentName.has_value())
64+
return std::move(*argumentName);
65+
}
66+
67+
return component;
68+
}
69+
3970
std::vector<std::string> generateArgumentNames(const std::vector<std::string>& components) {
4071
std::vector<std::string> argumentNames;
4172

4273
for (const std::string& component : components) {
4374
size_t startPos = component.find_last_of(" ");
4475
std::string argumentName = (startPos == std::string::npos) ? component : component.substr(startPos + 1);
45-
argumentNames.push_back(argumentName);
76+
argumentNames.push_back(ArgumentNameFromSelectorComponent(std::move(argumentName)));
4677
}
4778

4879
return argumentNames;
4980
}
5081

82+
} // unnamed namespace
5183

5284
bool Workflow::rewriteMethodCall(LLILFunctionRef ssa, size_t insnIndex)
5385
{

0 commit comments

Comments
 (0)