-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CommandLineParser #11518
CommandLineParser #11518
Conversation
06297f3
to
fcab7e0
Compare
3f499a6
to
305eed6
Compare
solc/CommandLineParser.cpp
Outdated
bool CommandLineOptions::operator==(CommandLineOptions const& _other) const | ||
{ | ||
return | ||
sourceFilePaths == _other.sourceFilePaths && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need this equality operator? Isn't it very dangerous in case we forget to add some new setting here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The alternative is comparing individual properties one by one, with the same risk.
I thought about adding static_assert
for the size of the struct like I did in operators for the structs containing booleans but the assert was almost as big as the comparison itself so I thought it was too much. It would decrease the risk a lot though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possible using something like here could help?
https://stackoverflow.com/questions/17660095/iterating-over-a-struct-in-c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that solutions boil down to writing a bunch of custom macros or using Boost.Fusion (which is also a bunch of macros and templates :)). I'd be fine with Boost.Fusion - looks like it would solve the problem of operators potentially going out of sync and usage is not complicated. Still, it adds a bunch of weird macro calls and I'd still have to repeat the list of members once (in macro invocation). But that's not a bad trade-off in my opinion. @chriseth What's your opinion on using Boost.Fusion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about that, especially since we already have the code here. I also heard that fusion is a beast. About going out of sync: Would an assert using sizeof not be enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the assert is good enough but this particular function does not have one. I'd have to list all field types from CommandLineOptions
in it and there's a lot of them. I considered adding it but in the end I thought that an assert the size of the whole function might be an overkill :)
Also, C++20 will provide default equality operators which would be a much cleaner solution.
test/solc/CommandLineParser.cpp
Outdated
CommandLineOptions expectedOptions; | ||
expectedOptions.sourceFilePaths = {"contract.sol"}; | ||
expectedOptions.coloredOutput = true; | ||
expectedOptions.expectedExecutionsPerDeployment = 200; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a magic number that should appear exactly once in the whole project source.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does appear once in non-test code and I think that's the part that matters. But I'll make it a constant anyway. Less duplication is always good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean the question is what do we want to test? Do we want to test that it is the number 200 or do we want to test that the parser sets it to OptimiserSettings{}.expectedExecutionsPerDeployment
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm often OK with hard-coding some things in tests because these values get cross-checked so you have to make a mistake in both places to miss the problem. Deduplicating stuff too much sometimes makes it easy for the wrong value to be carried over to the check in the test so I often prefer to see the "raw" values in tests.
That's my general approach but I get your point about this constant. Expecting a particular raw value is not the point of this test so we would indeed be better off with a constant. The problem is - this value is hard-coded all over the code base. I think this PR is not the best place to fix that. I have created a separate one: #11550.
305eed6
to
e070441
Compare
I just pushed an updated version. It only changes the handling of the Once I see that it works, I'll remove the debug commits with stream operators and mark the PR as reviewable. |
e070441
to
2cf6e62
Compare
Still failing. This time because I missed one use of I just pushed a fix. I changed |
2cf6e62
to
924430b
Compare
All tests passed so I'm done here. Marking as reviewable. |
catch (FileNotFound const&) | ||
{ | ||
// Should not happen if `fs::is_regular_file` is correct. | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the filesystem_error
case we could generate a human readable message so the user knows why it failed. If the catch below should not happen, we could make it solAssert(false, "reason here");
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Again, something I did not want to touch yet in this PR.
vector<string> libraries; | ||
boost::split(libraries, data, boost::is_space() || boost::is_any_of(","), boost::token_compress_on); | ||
for (string const& lib: libraries) | ||
if (!lib.empty()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huge nested if. What about:
for (string const& lib: libraries | ranges::views::filter([](auto const& lib) { return lib.empty(); })
// .... (now without the huge if-body)...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Again, something I did not want to touch yet in this PR.
924430b
to
dab3783
Compare
Fixed about half of the small suggestions. The other half is fine but I'd like to leave them out of this PR. This one was meant to be mostly a split and not a complete cleanup of There are two changes I have not done yet: the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall, found a few minor things.
Didn't check the fixup! ones yet.
static_assert( | ||
sizeof(*this) == 15 * sizeof(bool), | ||
"Remember to update code below if you add/remove fields." | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice.
solc/CommandLineParser.cpp
Outdated
bool CommandLineOptions::operator==(CommandLineOptions const& _other) const | ||
{ | ||
return | ||
sourceFilePaths == _other.sourceFilePaths && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possible using something like here could help?
https://stackoverflow.com/questions/17660095/iterating-over-a-struct-in-c
dab3783
to
2aa689f
Compare
82198a0
to
7200fda
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cameel LGTM plus the rest where you said it's for future PRs, which I agree with (to get that one through) :).
@cameel well, a squash would make sense, I guess :) |
7200fda
to
50e1b7a
Compare
Fixups squashed. |
50e1b7a
to
de7881c
Compare
de7881c
to
61e994b
Compare
61e994b
to
ef7abd2
Compare
Just pushed the fix for the |
Related to #11386. Partial solution for #5303.
Depends on #11571.Merged.The PR extracts the logic responsible for interpreting and validating command-line options from
CommandLineInterface
into a new class:CommandLineParser
. The new class has clearly separated input and output and therefore can be easily tested.Putting #11386 on top of this PR will let me actually have the whole path-related behavior covered by some sensible tests rather than just the part that has been extracted into
FileReader
. Hopefully it will also be a good first step for the full CLI refactor in the future.To make this easier to review I tried to keep changes to the absolute minimum. I found some things that could be cleaned up or fixed but I'll be submitting these in separate PRs to keep the diff here understandable. I recommend reviewing individual commits and skipping the first one, which only copies
CommandLineParser.cpp
/.h
without any modifications. This way you'll see in the second one that actual changes are pretty small and most of the churn is the removal of fragments that belong in the other class and switching to getting values from the new options struct.