Skip to content

Commit

Permalink
Add rvalue support (#551)
Browse files Browse the repository at this point in the history
* Add rvalue support

Co-authored-by: Malofeev Mikhail <malofeev.mikhail@huawei.com>
  • Loading branch information
ladisgin and Malofeev Mikhail committed Dec 1, 2022
1 parent 8e3f5df commit 94d79a3
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 17 deletions.
12 changes: 12 additions & 0 deletions server/src/Tests.h
Expand Up @@ -377,6 +377,18 @@ namespace tests {
this->underscoredName() :
this->name;
}

[[nodiscard]] std::string getFunctionParamDecl() const {
if (type.isTwoDimensionalPointer() && types::TypesHandler::isVoid(type.baseTypeObj())) {
std::string qualifier = type.isConstQualified() ? "const " : "";
return StringUtils::stringFormat("(%svoid **) %s", qualifier, name);
} else if (type.isRValueReference()) {
return "std::move(" + name + ")";
} else if (type.maybeJustPointer() && !type.isFilePointer() ) {
return "&" + name;
}
return name;
}
};

struct TestCaseParamValue {
Expand Down
4 changes: 1 addition & 3 deletions server/src/printers/Printer.cpp
Expand Up @@ -281,9 +281,7 @@ namespace printer {
strTabIf(needTabs);
std::vector<std::string> parameters;
for (const auto &param : method.params) {
std::string maybeAmpersand =
param.type.maybeJustPointer() && !param.type.isFilePointer() ? "&" : "";
parameters.push_back(maybeAmpersand + param.name);
parameters.push_back(param.getFunctionParamDecl());
}
auto classObjName = method.getClassName();
return strFunctionCall(method.name, parameters, end, classObjName, needTabs,
Expand Down
2 changes: 1 addition & 1 deletion server/src/printers/Printer.h
Expand Up @@ -223,7 +223,7 @@ namespace printer {
void writeAccessPrivateMacros(types::TypesHandler const *typesHandler, const Tests &tests, bool onlyChangeable);

void genStubForStructFunctionPointer(const std::string &structName,
const types::Field &ieldName,
const types::Field &fieldName,
const std::string &stubName);

void genStubForStructFunctionPointerArray(const std::string &structName,
Expand Down
11 changes: 1 addition & 10 deletions server/src/printers/TestsPrinter.cpp
Expand Up @@ -743,16 +743,7 @@ TestsPrinter::methodParametersListVerbose(const Tests::MethodDescription &method
const Tests::MethodTestCase &testCase) {
std::vector<std::string> args;
for (const auto &param : methodDescription.params) {
if (param.type.isTwoDimensionalPointer() &&
types::TypesHandler::isVoid(param.type.baseTypeObj())) {
std::string qualifier = Printer::getConstQualifier(param.type);
std::string arg = StringUtils::stringFormat("(%svoid **) %s", qualifier, param.name);
args.push_back(arg);
} else {
std::string maybeAmpersand =
param.type.maybeJustPointer() && !param.type.isFilePointer() ? "&" : "";
args.push_back(maybeAmpersand + param.name);
}
args.push_back(param.getFunctionParamDecl());
}
return args;
}
Expand Down
4 changes: 4 additions & 0 deletions server/src/types/Types.cpp
Expand Up @@ -248,6 +248,10 @@ bool types::Type::isLValueReference() const {
return isSimple() && dynamic_cast<SimpleType *>(mKinds.front().get())->isLValue();
}

bool types::Type::isRValueReference() const {
return isSimple() && dynamic_cast<SimpleType *>(mKinds.front().get())->isRValue();
}

bool types::Type::isConstQualified() const {
return isSimple() && dynamic_cast<SimpleType *>(mKinds.front().get())->isConstQualified();
}
Expand Down
6 changes: 6 additions & 0 deletions server/src/types/Types.h
Expand Up @@ -150,6 +150,12 @@ namespace types {
*/
[[nodiscard]] bool isLValueReference() const;

/**
* Checks whether given type is an rvalue reference type.
* @return true if type is rvalue reference, false otherwise.
*/
[[nodiscard]] bool isRValueReference() const;

/**
* Checks whether given type is an const qualified.
* @return true if type is const, false otherwise.
Expand Down
145 changes: 143 additions & 2 deletions server/test/framework/Syntax_Tests.cpp
Expand Up @@ -55,10 +55,11 @@ namespace {
fs::path inner_unnamed_c = getTestFilePath("inner_unnamed.c");
fs::path array_sort_c = getTestFilePath("array_sort.c");
fs::path stubs_c = getTestFilePath("stubs.c");
fs::path namespace_cpp = getTestFilePath("namespace.cpp");
fs::path input_output_c = getTestFilePath("input_output.c");
fs::path file_c = getTestFilePath("file.c");
fs::path bitfields_c = getTestFilePath("bitfields.c");
fs::path namespace_cpp = getTestFilePath("namespace.cpp");
fs::path rvalue_reference_cpp = getTestFilePath("function_with_rvalue_params.cpp");

void SetUp() override {
clearEnv(CompilationUtils::CompilerName::CLANG);
Expand Down Expand Up @@ -2779,7 +2780,7 @@ namespace {
);
}

TEST_F(Syntax_Test, multi_union) {
TEST_F(Syntax_Test, multi_union_cpp) {
auto [testGen, status] = createTestForFunction(namespace_cpp, 38);

ASSERT_TRUE(status.ok()) << status.error_message();
Expand All @@ -2798,6 +2799,146 @@ namespace {
);
}

TEST_F(Syntax_Test, multiple_rvalue_params) {
auto [testGen, status] = createTestForFunction(rvalue_reference_cpp, 9);

ASSERT_TRUE(status.ok()) << status.error_message();

testUtils::checkMinNumberOfTests(testGen.tests.at(rvalue_reference_cpp).methods.begin().value().testCases, 2);

checkTestCasePredicates(
testGen.tests.at(rvalue_reference_cpp).methods.begin().value().testCases,
std::vector<TestCasePredicate>(
{
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.paramValues[0].view->getEntryValue(nullptr)) >
stoi(testCase.paramValues[1].view->getEntryValue(nullptr));
},
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.paramValues[0].view->getEntryValue(nullptr)) <=
stoi(testCase.paramValues[1].view->getEntryValue(nullptr));
}
})
);

checkTestCasePredicates(
testGen.tests.at(rvalue_reference_cpp).methods.begin().value().testCases,
std::vector<TestCasePredicate>(
{
[] (const tests::Tests::MethodTestCase& testCase) {
return 2 * stoi(testCase.paramValues[0].view->getEntryValue(nullptr)) ==
stoi(testCase.returnValue.view->getEntryValue(nullptr));
},
[] (const tests::Tests::MethodTestCase& testCase) {
return 2 * stoi(testCase.paramValues[1].view->getEntryValue(nullptr)) ==
stoi(testCase.returnValue.view->getEntryValue(nullptr));
}
})
);

}

TEST_F(Syntax_Test, const_rvalue_reference) {
auto [testGen, status] = createTestForFunction(rvalue_reference_cpp, 17);

ASSERT_TRUE(status.ok()) << status.error_message();

testUtils::checkMinNumberOfTests(testGen.tests.at(rvalue_reference_cpp).methods.begin().value().testCases, 3);

checkTestCasePredicates(
testGen.tests.at(rvalue_reference_cpp).methods.begin().value().testCases,
std::vector<TestCasePredicate>(
{
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.returnValue.view->getEntryValue(nullptr)) == 0;
},
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.returnValue.view->getEntryValue(nullptr)) == 1;
},
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.returnValue.view->getEntryValue(nullptr)) == 2;
}
})
);

checkTestCasePredicates(
testGen.tests.at(rvalue_reference_cpp).methods.begin().value().testCases,
std::vector<TestCasePredicate>(
{
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.paramValues.front().view->getEntryValue(nullptr)) % 3 == 0;
},
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.paramValues.front().view->getEntryValue(nullptr)) % 3 == 1;
},
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.paramValues.front().view->getEntryValue(nullptr)) % 3 == 2;
}
})
);
}

TEST_F(Syntax_Test, return_and_get_params) {
auto [testGen, status] = createTestForFunction(rvalue_reference_cpp, 28);

ASSERT_TRUE(status.ok()) << status.error_message();

testUtils::checkMinNumberOfTests(testGen.tests.at(rvalue_reference_cpp).methods.begin().value().testCases, 3);

checkTestCasePredicates(
testGen.tests.at(rvalue_reference_cpp).methods.begin().value().testCases,
std::vector<TestCasePredicate>(
{
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.paramValues[0].view->getEntryValue(nullptr)) % 5 == 0;
},
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.paramValues[1].view->getEntryValue(nullptr)) % 5 == 0;
}
})
);

checkTestCasePredicates(
testGen.tests.at(rvalue_reference_cpp).methods.begin().value().testCases,
std::vector<TestCasePredicate>(
{
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.paramValues[0].view->getEntryValue(nullptr)) ==
stoi(testCase.returnValue.view->getEntryValue(nullptr));
},
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.paramValues[1].view->getEntryValue(nullptr)) ==
stoi(testCase.returnValue.view->getEntryValue(nullptr));
},
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.paramValues[0].view->getEntryValue(nullptr)) + stoi(testCase.paramValues[1].view->getEntryValue(nullptr))==
stoi(testCase.returnValue.view->getEntryValue(nullptr));
}
})
);
}

TEST_F(Syntax_Test, rvalue_struct_param) {
auto [testGen, status] = createTestForFunction(rvalue_reference_cpp, 38);

ASSERT_TRUE(status.ok()) << status.error_message();

testUtils::checkMinNumberOfTests(testGen.tests.at(rvalue_reference_cpp).methods.begin().value().testCases, 4);

checkTestCasePredicates(
testGen.tests.at(rvalue_reference_cpp).methods.begin().value().testCases,
std::vector<TestCasePredicate>(
{
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.returnValue.view->getEntryValue(nullptr)) == 1;
},
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.returnValue.view->getEntryValue(nullptr)) == 2;
}
})
);
}

TEST_F(Syntax_Test, simple_getc) {
auto [testGen, status] = createTestForFunction(input_output_c, 4);

Expand Down
3 changes: 2 additions & 1 deletion server/test/suites/syntax/CMakeLists.txt
Expand Up @@ -40,4 +40,5 @@ add_executable(syntax1
namespace.cpp
input_output.c
file.c
bitfields.c)
bitfields.c
function_with_rvalue_params.cpp)
59 changes: 59 additions & 0 deletions server/test/suites/syntax/function_with_rvalue_params.cpp
@@ -0,0 +1,59 @@
#include <utility>
#include "function_with_rvalue_params.h"

int double_max(int && first, int && second) {
if (first > second) {
return 2 * first;
} else {
return 2 * second;
}
}

int remainder(const int && value) {
if (value % 3 == 0) {
return 0;
} else if (value % 3 == 1) {
return 1;
} else {
return 2;
}
}

int && return_and_get_rvalue_reference(int && first, int && second) {
if (first % 5 == 0) {
return std::move(first);
} else if (second % 5 == 0) {
return std::move(second);
} else {
return std::move(first + second);
}
}

int get_rvalue_custom_struct_as_param(Closet && closet) {
if (closet.height > 5 && closet.width > 5 && closet.length > 5) {
closet.height /= 5;
closet.volume /= 5;
closet.width /= 5;
return 1;
} else {
closet.width = 5;
closet.height = 5;
closet.length = 5;
closet.volume = 125;
return 2;
}
}

Closet::Closet() {
length = 1.5;
width = 0.5;
height = 2.5;
volume = height * width * length;
}

Closet::Closet(double length_, double width_, double height_, double volume_) {
length = length_;
width = width_;
height = height_;
volume = volume_;
}
22 changes: 22 additions & 0 deletions server/test/suites/syntax/function_with_rvalue_params.h
@@ -0,0 +1,22 @@
#ifndef UNITTESTBOT_FUNCTION_WITH_RVALUE_PARAMS_H
#define UNITTESTBOT_FUNCTION_WITH_RVALUE_PARAMS_H

struct Closet {
double length;
double width;
double height;
double volume;

Closet();
Closet(double length_, double width_, double height_, double volume_);
};

int double_max(int && first, int && second);

int remainder(const int && value);

int && return_and_get_rvalue_reference(int && first, int && second);

int get_rvalue_custom_struct_as_param(Closet && closet);

#endif // UNITTESTBOT_FUNCTION_WITH_RVALUE_PARAMS_H

0 comments on commit 94d79a3

Please sign in to comment.