-
Notifications
You must be signed in to change notification settings - Fork 273
Unit tests for invokedynamic with static lambdas [TG-2811] #1946
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
Unit tests for invokedynamic with static lambdas [TG-2811] #1946
Conversation
@thomasspriggs @svorenova any thoughts on the design of the 3 linked commits in the descriptions would be appreciated, particularly the last one. (For some reason can't request your review Tom, don't know why?) |
|
||
Module: Unit tests for converting invokedynamic instructions into codet | ||
|
||
Author: DiffBlue Limited. |
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.
According to the recent update, this should be Diffblue Ltd.
https://github.com/diffblue/doc-diffblue-common/wiki/Process-for-Creating%2C-Reviewing-and-Merging-Pull-Requests
THEN("The local variable should be assigned a non-null pointer") | ||
{ | ||
// TODO(tkiley): we don't want 11 here | ||
// TODO(tkiley): This is the actual lambda which doesn't currently work |
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.
Can you please give an example of what we are expecting to find here, maybe a block of code from an example with anonymous class? This may be deleted or updated later when the actual instruction conversion is implemented but would be good to have a reference point here in the meantime.
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.
Happy to though note comment - this isn't ready for review, just the three linked commits!
@svorenova My initial search found that There is a platform agnostic version in C++17 |
char temp [ PATH_MAX ]; | ||
std::string path = getcwd(temp,PATH_MAX) ? std::string(temp) : ""; | ||
INFO("Working directory: " << path); | ||
#endif |
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.
What about get_current_working_directory
(from util/file_util.h)?
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.
Ah wonderful - someones done the work for me - thanks!
0be81df
to
f14e0d7
Compare
@@ -141,6 +143,47 @@ require_goto_statements::find_struct_component_assignments( | |||
return locations; | |||
} | |||
|
|||
require_goto_statements::pointer_assignment_locationt |
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.
Outstanding: document
@@ -151,31 +194,60 @@ require_goto_statements::pointer_assignment_locationt | |||
require_goto_statements::find_pointer_assignments( | |||
const irep_idt &pointer_name, | |||
const std::vector<codet> &instructions) | |||
{ | |||
INFO("Looking for symbol: " << pointer_name); | |||
std::regex specialChars{R"([-[\]{}()*+?.,\^$|#\s])"}; |
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.
special_chars
const std::vector<codet> &statements, | ||
const irep_idt &function_call_identifier) | ||
{ | ||
// TODO: Would appreciate some review comments on whether it makes the most sense: |
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.
Outstanding: modify behaviour according to suggestions
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'd say the vector is a generalized version of the other two possibilities and therefore it makes the most sense. You could even provide different functions that use the general one to provide the other functionality.
This is now ready for review in totality. I have a few comments I need to address but don't let that hold you back! I've updated the real diff in the description of this PR, along with a summary of its intended purpose. |
f14e0d7
to
a2f9dbe
Compare
Should have resolved the compile errors and my own comments |
@@ -13,6 +13,7 @@ | |||
#include <util/expr_iterator.h> | |||
#include <goto-programs/goto_functions.h> | |||
#include <java_bytecode/java_types.h> | |||
#include <iostream> |
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.
shouldn't be needed
unit/testing-utils/require_expr.cpp
Outdated
REQUIRE(symbol_expr.get_identifier()==symbol_name); | ||
return symbol_expr; | ||
} | ||
|
||
/// Verify a given exprt is an symbol_exprt. |
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.
... is a symbol_exprt.
|
||
Module: Unit tests for converting invokedynamic instructions into codet | ||
|
||
Author: DiffBlue Ltd. |
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.
Diffblue
@@ -410,3 +410,39 @@ require_goto_statements::require_entry_point_argument_assignment( | |||
.get_identifier(); | |||
return argument_tmp_name; | |||
} | |||
|
|||
/// Verify that a collection of statements contains a function call to a | |||
/// function whose symbol idetnfier matches the provided identifier |
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.
... identifier ...
const std::vector<codet> &statements, | ||
const irep_idt &function_call_identifier) | ||
{ | ||
// TODO: Would appreciate some review comments on whether it makes the most sense: |
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'd say the vector is a generalized version of the other two possibilities and therefore it makes the most sense. You could even provide different functions that use the general one to provide the other functionality.
test_data.lambda_function_id = | ||
"java::LocalLambdas.lambda$test$1:(ILjava/lang/" | ||
"Object;LDummyGeneric;)V"; | ||
validate_lamdba_assignement(symbol_table, instructions, test_data); |
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.
there's a typo in that function name
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.
Actually two!
@@ -24,6 +24,7 @@ struct lambda_assignment_test_datat | |||
irep_idt lambda_function_id; | |||
|
|||
std::vector<exprt> expected_params; | |||
bool should_return_value; |
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.
Having been bitten in the past with uninit Booleans, I'd prefer an explicit default value
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.
Set to true
as more likely to produce a failing test, reminding people to set it.
symbol_table, instructions, test_data, "paramLambda"); | ||
} | ||
THEN( | ||
"The local variable should be assigned a non-null pointer to a " |
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.
... to an ...
@@ -470,3 +470,163 @@ SCENARIO( | |||
} | |||
}); | |||
} | |||
|
|||
void validate_static_member_variable_lambda_assignment( |
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.
needs doxygen (I am reviewing commit-by-commit, so may be already fixed in a later commit)
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.
And for the other one that I missed.
Should extend to test:
As the tests pass with prototype code but don't yet work |
The most common error when running unit tests is forgetting to set the working direcotory. This causes problems when loading java classes so to minimize this we print the working directory in the catch output.
a2f9dbe
to
0d1df9d
Compare
Verifies the structure mimics the construction of an anonymous class that implements the interface
Add documentation to find pointer assignments for a component
This will allow sharing code for testing members as well as local variables
0d1df9d
to
397c14e
Compare
All comments addressed, ready for final review @mgudemann @svorenova TG pointer bump (probably not required): diffblue/test-gen#1628 |
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.
LGTM
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 very good in general. I only have some minor comments.
/// {expected_params}) | ||
/// \param symbol_table: The loaded symbol table | ||
/// \param instructions: The instructions of the method that calls invokedynamic | ||
/// \param test_data: The parameters for the test |
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.
Missing doxygen for lambda_assignment
.
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.
Realised it was passing around a confusing structure when it was just the single non-null assignment we care about.
require_type::require_complete_class(lambda_implementor_type_symbol.type); | ||
|
||
REQUIRE(tmp_lambda_class_type.has_base(test_data.lambda_interface)); | ||
REQUIRE(tmp_lambda_class_type.has_base("java::java.lang.Object")); |
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.
Nit: The Object
is here because it is a superclass correct? It should appear first in the list of bases, so consider swapping the require statements for readability.
require_type::require_component(tmp_lambda_class_type, "@java.lang.Object"); | ||
|
||
const symbol_typet &super_class_type = require_type::require_symbol( | ||
super_class_component.type(), "java::java.lang.Object"); |
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.
Why do you need to be checking for the superclass component and its symbol? It is just Object
so nothing specific for the lambda. Also, you use both super_class
and base_class
in the names, can you please unify it?
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.
Good point - just removed the checks on the structure of java.lang.Object
require_type::require_incomplete_class(base_class_symbol.type); | ||
|
||
require_type::require_component(super_class_type_struct, "@class_identifier"); | ||
// TODO verify the components of the class have been set correctly |
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 todo will be aprt of the next tickets for lambdas? Once we know how exactly the code looks right, 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.
Nope TODO no longer relevant as this is handled in a later transformation so not something we can test here. Removed the TODO
assignments, test_data.lambda_function_id); | ||
|
||
INFO("Looking for function call of " << test_data.lambda_function_id); | ||
REQUIRE(function_calls.size() == 1); |
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.
Lambda function can be called more than once in a method, isn't this too restrictive? Or does each lambda call get it's own object?
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.
We're currently looking inside the generated method in the generated class - we have one such class for each lambda. I think this should be documented where the code is generated (which doesn't yet exist). Do you think something should be added to this test to make it clearer?
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 was discussed offline, there indeed should be exactly one call to the lambda from the code we generate.
} | ||
|
||
/// Find the assignment to the lambda and then call validate_lamdba_assignement | ||
/// for full validation. |
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.
Missing doxygen for arguments.
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 was me being lazy as I wasn't sure it would help but have taken the comments from the validate_lambda_assignment
and document the one that's not covered
test_data.lambda_interface_method_descriptor = | ||
".Execute:()Ljava/lang/Object;"; | ||
|
||
//"java::LocalLambdas.lambda$test$0:()V" |
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.
How does this comment relate to the code 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.
Doesn't - removed
@svorenova comments addressed |
Cleaned up some logic Removed some redundant tests relating to java.lang.Object Added missing documentation for helper functions Made the validate_lambda_assignment take a single assignment as the calling functions are already checking that there is precisely one) Addressed linting and formatting problems
45a3e79
to
31fa0fe
Compare
Fixed clang format and linting complaints |
7202003 Merge branch 'develop' of github.com:diffblue/cbmc into CBMC_subtree_2018-04-10 768e8a6 Merge pull request diffblue#2009 from romainbrenguier/solvers/sparse-arrays-in-get 69f6e7b Merge pull request diffblue#2032 from tautschnig/replace-rename-performance ec43b00 Merge pull request diffblue#2026 from tautschnig/sat-clean 64b336a Refactor interval_sparse_array::concretize 5392645 Reserve size of array in concretize 8277e92 Stop using concretize_array_expr in unit tests 1a08772 Tests where model involves long strings a6c4010 Stop using concretize_arrays_in_expression 6d87233 Use concretize instead of fill_in_array 052d503 Use get_array in get_char_array_and_concretize 8ed138b Remove unused header c58ac60 Avoid copy in ranged for loops over expressions beff419 Use sparse arrays in get_array 9b286d9 Use sparse arrays in string_refinement::get 037f631 Refactor string_refinementt::get dfc584a Add concretize function for interval_sparse_array cb10550 Use sparse arrays in substitute_array_access ce4c008 Remove plus_exprt_with_overflow_check 4779b25 Get rid of calls to plus_exprt_with_overflow c40b836 Truncate string concatenations in case of overflow c52c813 Add a sum_overflows function 0d03591 Add an `at` function for access in sparse arrays 848dd95 Add an interval_sparse_array::of_expr function 5f07bf0 Initialization of sparse array from array-list 5b4d618 Reduce number of constraints in format ede2fa1 Clear string_dependencies in calls to dec_solve d483c81 Initialize sparse array from array_exprt a914153 Use map instead of vector for sparse array entries 20d2445 Remove unused rename(expr, old_id, new_id) 430d402 Use exprt::depth_iterator in rename_symbolt 54e5b85 Use a const expr to avoid unnecessary detach 6f71ff6 replace_symbolt: stop early if there is nothing to replace with 1dbb162 Clean locally built SAT solver objects 28c076b Merge pull request diffblue#2013 from LAJW/lajw/java-no-load-class e6a9127 Merge pull request diffblue#2020 from tautschnig/sat-cleanup 70741ff Remove support for Precosat 2aa81eb Remove support for SMVSAT a0fd3f7 Remove support for Limmat as a SAT solver 28cca9c Remove unused DIMACS parser 1d81306 Merge pull request diffblue#2015 from tautschnig/fix-smt2_solver-clean 392144d Makefiles: Place .d suffix used for dependencies in DEPEXT variable 839d32a smt2_solver.{o,d} should be removed by "make clean" 48e427a Merge pull request diffblue#1979 from romainbrenguier/regression/fix-indexOf-test c2f3726 Merge pull request diffblue#1976 from romainbrenguier/regression/activate-dependency-tests 42ecfa2 Add --java-no-load-class option 69fb74a Merge pull request diffblue#1995 from tautschnig/byte-update-soundness aa766ae Set string-max-length in indexOf test 988b818 Merge pull request diffblue#1990 from tautschnig/missing-header 8300147 Abort on byte_update(pointer) 4a8d9b4 Include missing header a695814 Merge pull request diffblue#1986 from thk123/revert/1816/overlay-classes 9933b58 Revert "Merge pull request diffblue#1816 from NathanJPhillips/feature/overlay-methods" cd9b839 Revert "Merge pull request diffblue#1982 from NathanJPhillips/bugfix/load-object-once" 58beeb4 Merge pull request diffblue#1978 from svorenova/lambda_tg2478_cont 1e3a9cd Merge pull request diffblue#1980 from NathanJPhillips/tests/irept 772b603 Merge pull request diffblue#1982 from NathanJPhillips/bugfix/load-object-once 0902ae7 Tests to demonstrate expected sharing behaviour of irept 2239ec1 Unit test of irept's public API 81ac259 Prevent test running on symex-driven lazy loading eae194f Allow incorrect paths for jar files on the classpath without crashing 6749fd0 Tests to ensure invalid values in the classpath are ignored 3c95aa1 Prevent attempting to load any class more than once c520331 Unit test to show java.lang.Object can be loaded from an explicit model 05a7b4a Merge pull request diffblue#1981 from smowton/smowton/cleanup/missing-docstring e4dc2aa Merge pull request diffblue#1946 from thk123/feature/TG-1811/unit-tests-for-invokedynamic-static-lambda 2b53d3b Merge pull request diffblue#1983 from svorenova/lambda_tg2478_fix f428247 Tidying up for lambdas f3b1379 Merge pull request diffblue#1975 from romainbrenguier/bugfix/literal-length-TG2878 7d4441d Regression test for lambda in a package 7366fda Format class name for lambda method handles 7db42c0 Add missing Doxygen parameter description 31fa0fe Addressing review comments 2a0927c Merge pull request diffblue#1643 from NathanJPhillips/bugfix/string-solver-function-type-mistake 229d1ee Merge pull request diffblue#1977 from romainbrenguier/bugfix/string-equals-TG-2179 97a6713 Merge pull request diffblue#1816 from NathanJPhillips/feature/overlay-methods e2d4b09 Updates for merge 674c9f0 Activate tests for StringBuffer concat in loops a997ffb Add verification test for String.equals 1ab596d Merge commit '3b8120f3a8c9ed3a343493a44ac454ae265946c1' into develop f7602af Merge commit 'bb88574aaa4043f0ebf0ad6881ccaaeb1f0413ff' into merge-develop-20180327 55d36b5 Fix code for String.equals baf33f8 Added regression tests 9984fc1 Add ability to overlay classes with new definitions of existing methods 66c529c Tidied up java_class_loader_limitt 397c14e Correcting typos and adding documentation to unit tests 54f1c54 Adding checks for the super class of the generated class df895d3 Temp checkin for checking components 44a5dcb Adding check for inheritance 28bfc37 Amending path to reflect new location e27151b Correcting typo in the scenario name d7356be Modified behaviour to find function calls ac33761 Use raw strings to avoid unnecessary escaping 4201db9 Adding tests for static lambdas f9adaa6 Adding tests for member methods 5f5994b Pull out the logic for getting the inital assignment 7f843a7 Add natural language explanation of the test's checks fa27117 Introduce tests for lambdas that are member variables 8999cf6 Added utiltity for getting this member components 3e0e12e Adding tests for the other two returning lambdas that don't capture f3ddee6 Adding tests to verify the return of the lambda wrapper method db6756e Adding checks for parameters of the called function d2ed92b Adding test for lambda taking array parameters d171f64 Swap finding variable values to use regex 99c21ed Extended find pointer assignment to take a regex 5610aca Added unit test for lambda assigned 7b0cee1 Refactored test method to allow reuse bea730d Adding utility for verifying a set of statements contains a function call ee2179c Introduce checks the the function body for Execute calls the correct lambda 2348d10 Adding unit test for checking local lambda conversion 46fa176 Extending require utilities to be used in test 6df8d6b Extended require_goto_statements to provide meaningful errors 39282a6 Add debug information for working directory 770eb2a Remove methods without a implementation or usage 5cbb758 Merge pull request diffblue#1937 from svorenova/lambda_tg2711 8cfd9bf Merge pull request diffblue#1968 from smowton/smowton/cleanup/remove-exceptions-clarity 6ca3272 Merge pull request diffblue#1973 from karkhaz/kk-c++2a-fixes 212da75 Making members of a test utility class non-const d57fe53 Renaming the folder with lambda unit tests 823f2a7 Adding a unit test for lambda method handles in class symbol 8b172b4 Adding a utility function for lambda method handles in struct 844bb20 Pulling out a utility function to a separate file 3585f73 Updating unit tests for parsing lambda method table 078dc0f Updating a utility function a8ac3d4 Pass lambda method handles to method instruction conversion bf04c93 Add lambda method handles during class conversion a518393 Introduce lambda method handles in java class type 37afd9a Store the full method reference of lambda method handles 0a49697 Store bootstrap method index for invokedynamic instructions 56c9c02 Add test for string literals length af958f0 Correct length field of string literals a190534 Remove-exceptions: make lambda types explicit b052a4d Fix warnings emitted by C++2a compiler 20eaf21 Fix type of call to forName git-subtree-dir: cbmc git-subtree-split: 7202003985a99fb6563cf4d0fb8e7f2c727cc040
Depends on: #1937 ✅
Introduces unit tests for how the
invokedynamic
instruction is translated into codet. They are not turned on, but their behaviour is moddelled on what the codet looks like forWhich is the intended format. I can if it would be helpful split out some of the utility changes from the test introduction, but the changes are all separated by commits and the order provides some motivation for the auxiliary changes.