Skip to content
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

Generate tests for function with incomplete return type #192

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions server/src/FeaturesFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,24 @@ void FeaturesFilter::filter(utbot::SettingsContext const &settingsContext,

size_t erased = CollectionUtils::erase_if(tests.methods,
[&](const tests::Tests::MethodDescription &method) {
auto returnTypeSupport = typesHandler.isSupportedType(method.returnType, types::TypeUsage::RETURN);
updateIfNotCompleteType(returnTypeSupport, method.hasIncompleteReturnType,
"Method has incomplete return type");
if (!returnTypeSupport.isSupported) {
unsupportedStatistics[returnTypeSupport.info]++;
std::stringstream message;
message << "Function '" << method.name << "' was skipped, as return type '"
<< method.returnType.typeName()
<< "' is not fully supported: " << returnTypeSupport.info;
LOG_S(WARNING) << message.str();
tests.commentBlocks.push_back(message.str());
return true;
if (!method.hasPointerToIncompleteReturnType) {
auto returnTypeSupport =
typesHandler.isSupportedType(method.returnType, types::TypeUsage::RETURN);
if (!returnTypeSupport.isSupported) {
unsupportedStatistics[returnTypeSupport.info]++;
std::stringstream message;
message << "Function '" << method.name << "' was skipped, as return type '"
<< method.returnType.typeName()
<< "' is not fully supported: " << returnTypeSupport.info;
LOG_S(WARNING) << message.str();
tests.commentBlocks.push_back(message.str());
return true;
}
}

for (const auto &param: method.params) {
auto paramTypeSupport = typesHandler.isSupportedType(param.type, types::TypeUsage::PARAMETER);
updateIfNotCompleteType(paramTypeSupport, param.hasIncompleteType,
updateIfNotCompleteType(paramTypeSupport, param.isPointerToIncomplete,
"Parameter has incomplete type");
if (!paramTypeSupport.isSupported) {
unsupportedStatistics[paramTypeSupport.info]++;
Expand Down
3 changes: 2 additions & 1 deletion server/src/Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,8 @@ KTestObjectParser::parseTestCaseParams(const UTBotKTest &ktest,
//processSymbolicStdin(testCaseDescription, rawKleeParams);

processStubParamValue(testCaseDescription, methodNameToReturnTypeMap, rawKleeParams);
if (!types::TypesHandler::skipTypeInReturn(methodDescription.returnType)) {
if (!types::TypesHandler::skipTypeInReturn(methodDescription.returnType) &&
!methodDescription.hasPointerToIncompleteReturnType) {
const auto kleeResParam = getKleeParamOrThrow(rawKleeParams, KleeUtils::RESULT_VARIABLE_NAME);
auto paramType = methodDescription.returnType.maybeReturnArray() ? methodDescription.returnType :
methodDescription.returnType.baseTypeObj();
Expand Down
8 changes: 4 additions & 4 deletions server/src/Tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,14 +305,14 @@ namespace tests {
string name;
std::optional<uint64_t> alignment;

bool hasIncompleteType = false;
bool isPointerToIncomplete = false;

MethodParam(types::Type type,
string name,
std::optional<uint64_t> alignment,
bool hasIncompleteType = false)
bool isPointerToIncomplete_ = false)
: type(std::move(type)), name(std::move(name)), alignment(std::move(alignment)),
hasIncompleteType(hasIncompleteType) {
isPointerToIncomplete(isPointerToIncomplete_) {

}

Expand Down Expand Up @@ -412,7 +412,7 @@ namespace tests {
std::string paramsString;

types::Type returnType;
bool hasIncompleteReturnType = false;
bool hasPointerToIncompleteReturnType = false;

std::optional<string> sourceBody;
Modifiers modifiers;
Expand Down
2 changes: 1 addition & 1 deletion server/src/clang-utils/ClangUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace ClangUtils {
return false;
}

bool isIncomplete(clang::QualType type) {
bool isPointerToIncomplete(clang::QualType type) {
clang::QualType canonicalType = type.getCanonicalType();
if (auto const *pType = canonicalType.getTypePtrOrNull()) {
auto pointeeType = pType->getPointeeType();
Expand Down
2 changes: 1 addition & 1 deletion server/src/clang-utils/ClangUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include <clang/AST/Type.h>

namespace ClangUtils {
bool isIncomplete(clang::QualType type);
bool isPointerToIncomplete(clang::QualType type);
};


Expand Down
8 changes: 5 additions & 3 deletions server/src/fetchers/FunctionDeclsMatchCallback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ void FunctionDeclsMatchCallback::run(const MatchFinder::MatchResult &Result) {
std::nullopt };
}
methodDescription.returnType = ParamsHandler::getType(realReturnType, realReturnType, sourceManager);
methodDescription.hasIncompleteReturnType = ClangUtils::isIncomplete(realReturnType);
methodDescription.hasPointerToIncompleteReturnType =
ClangUtils::isPointerToIncomplete(realReturnType);
if (toResolveReturnTypes) {
typesResolver.resolve(realReturnType);
}
Expand Down Expand Up @@ -109,8 +110,9 @@ void FunctionDeclsMatchCallback::run(const MatchFinder::MatchResult &Result) {
addFunctionPointer(methodDescription.functionPointers, declParam->getFunctionType(),
declParam->getType(), name, sourceManager, paramType);
auto alignment = AlignmentFetcher::fetch(defParam);
bool hasIncompleteType = ClangUtils::isIncomplete(defParam->getType());
methodDescription.params.emplace_back(paramType, name, alignment, hasIncompleteType);
bool isPointerToIncomplete = ClangUtils::isPointerToIncomplete(defParam->getType());
methodDescription.params.emplace_back(paramType, name, alignment,
isPointerToIncomplete);
}
if (CollectionUtils::contains(methods[sourceFilePath], methodDescription)) {
LOG_S(ERROR) << "Method " << methodDescription.name << " from " << sourceFilePath
Expand Down
2 changes: 1 addition & 1 deletion server/src/fetchers/GlobalVariableUsageMatchCallback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void GlobalVariableUsageMatchCallback::checkUsage(const MatchFinder::MatchResult
LOG_S(MAX) << "Variable \"" << name << "\" was skipped - it is being blacklisted.";
return;
}
if (ClangUtils::isIncomplete(pVarDecl->getType())) {
if (ClangUtils::isPointerToIncomplete(pVarDecl->getType())) {
LOG_S(MAX) << "Variable \"" << name
<< "\" was skipped - it's type has no definition in current "
"translation unit.";
Expand Down
37 changes: 21 additions & 16 deletions server/src/printers/KleePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,24 +373,29 @@ void KleePrinter::makeBracketsForStrPredicate(const std::optional<PredInfo> &inf
}


void KleePrinter::genReturnDeclaration(const Tests::MethodDescription &testMethod, const std::optional<PredInfo> &predicateInfo) {
void KleePrinter::genReturnDeclaration(const Tests::MethodDescription &testMethod,
const std::optional<PredInfo> &predicateInfo) {
// If return type is a pointer, we compare values that are stored at this pointers,
// not the pointers themselves
Type returnType = types::TypesHandler::isVoid(testMethod.returnType.baseTypeObj())
? Type::minimalScalarType()
: testMethod.returnType;
bool maybeArray = returnType.maybeReturnArray();
bool isPointer = testMethod.returnType.isObjectPointer();
strDeclareVar(returnType.baseType(), KleeUtils::RESULT_VARIABLE_NAME, std::nullopt, std::nullopt, false);
makeBracketsForStrPredicate(predicateInfo);
if (maybeArray) {
size_t size = types::TypesHandler::getElementsNumberInPointerOneDim(PointerUsage::RETURN);
ss << "[" << size << "]";
}
ss << SCNL;
strKleeMakeSymbolic(KleeUtils::RESULT_VARIABLE_NAME,
!maybeArray && !(predicateInfo.has_value() && predicateInfo->type == testsgen::STRING));
if (isPointer) {
if (!testMethod.hasPointerToIncompleteReturnType) {
Type returnType = types::TypesHandler::isVoid(testMethod.returnType.baseTypeObj())
? Type::minimalScalarType()
: testMethod.returnType;
bool maybeArray = returnType.maybeReturnArray();
strDeclareVar(returnType.baseType(), KleeUtils::RESULT_VARIABLE_NAME, std::nullopt,
std::nullopt, false);
makeBracketsForStrPredicate(predicateInfo);
if (maybeArray) {
size_t size =
types::TypesHandler::getElementsNumberInPointerOneDim(PointerUsage::RETURN);
ss << "[" << size << "]";
}
ss << SCNL;
strKleeMakeSymbolic(
KleeUtils::RESULT_VARIABLE_NAME,
!maybeArray && !(predicateInfo.has_value() && predicateInfo->type == testsgen::STRING));
}
if (testMethod.returnType.isObjectPointer()) {
strDeclareVar("int", KleeUtils::NOT_NULL_VARIABLE_NAME);
strKleeMakeSymbolic(KleeUtils::NOT_NULL_VARIABLE_NAME, true);
}
Expand Down
14 changes: 10 additions & 4 deletions server/src/printers/TestsPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,10 @@ void TestsPrinter::verboseOutputVariable(const Tests::MethodDescription &methodD
void TestsPrinter::verboseFunctionCall(const Tests::MethodDescription &methodDescription,
const Tests::MethodTestCase &testCase) {
std::string baseReturnType = types::TypesHandler::cBoolToCpp(methodDescription.returnType.baseType());
types::Type expectedType = typesHandler->getReturnTypeToCheck(methodDescription.returnType);
types::Type expectedType =
methodDescription.hasPointerToIncompleteReturnType
? methodDescription.returnType
: typesHandler->getReturnTypeToCheck(methodDescription.returnType);
if (methodDescription.returnType.maybeReturnArray()) {
expectedType = methodDescription.returnType.arrayClone(types::PointerUsage::RETURN);
}
Expand Down Expand Up @@ -519,7 +522,9 @@ void TestsPrinter::parametrizedAsserts(const Tests::MethodDescription &methodDes
const std::optional<LineInfo::PredicateInfo>& predicateInfo) {
auto visitor = visitor::ParametrizedAssertsVisitor(typesHandler, this, predicateInfo, testCase.isError());
visitor.visit(methodDescription, testCase);
globalParamsAsserts(methodDescription, testCase);
if (!testCase.isError()) {
globalParamsAsserts(methodDescription, testCase);
}
classAsserts(methodDescription, testCase);
changeableParamsAsserts(methodDescription, testCase);
}
Expand Down Expand Up @@ -577,11 +582,12 @@ string TestsPrinter::constrVisitorFunctionCall(const Tests::MethodDescription &m
std::optional<types::Type> castType;
if (types::TypesHandler::skipTypeInReturn(methodDescription.returnType.baseTypeObj()) &&
methodDescription.returnType.isObjectPointer()) {
castType = types::Type::minimalScalarPointerType();
castType = types::Type::minimalScalarPointerType(methodDescription.returnType.getDimension());
}
auto classObjName = methodDescription.getClassName();
size_t returnPointersCount = 0;
if (testCase.returnValueView && testCase.returnValueView->getEntryValue() != PrinterUtils::C_NULL) {
if (!methodDescription.hasPointerToIncompleteReturnType &&
testCase.returnValueView->getEntryValue() != PrinterUtils::C_NULL) {
returnPointersCount = methodDescription.returnType.countReturnPointers(true);
}
return constrFunctionCall(methodDescription.name, methodArgs, "", classObjName, false, returnPointersCount,
Expand Down
2 changes: 1 addition & 1 deletion server/src/visitors/AbstractValueViewVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace visitor {
protected:
types::TypesHandler const * const typesHandler;
types::PointerUsage usage;
size_t additionalPointersCount;
size_t additionalPointersCount = 0;
bool inUnion = false;
public:
explicit AbstractValueViewVisitor(types::TypesHandler const *typesHandler,
Expand Down
6 changes: 4 additions & 2 deletions server/src/visitors/AssertsVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ namespace visitor {

[[nodiscard]] std::string getDecorateActualVarName(const string& access);

FunctionSignature changeSignatureToNullCheck(const FunctionSignature& signature, const types::Type& type,
const tests::AbstractValueView *view, const string &access);
FunctionSignature changeSignatureToNullCheck(const FunctionSignature &signature,
const types::Type &type,
const tests::AbstractValueView *view,
const string &access);

public:
explicit AssertsVisitor(const types::TypesHandler *typesHandler,
Expand Down
23 changes: 4 additions & 19 deletions server/src/visitors/KleeAssumeReturnValueVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ namespace visitor {
const string &access,
int depth) {
if (depth == 0) {
kleeAssumeWithNullCheck("", false);
AbstractValueViewVisitor::visitStruct(type, KleeUtils::TEMP_VARIABLE_NAME, view, PrinterUtils::DEFAULT_ACCESS,
depth);
} else {
Expand All @@ -87,9 +86,6 @@ namespace visitor {
const tests::AbstractValueView *view,
const string &access,
int depth) {
if (depth == 0) {
kleeAssumeWithNullCheck("", false);
}
AbstractValueViewVisitor::visitUnion(type, name, view, access, depth);
}

Expand Down Expand Up @@ -129,21 +125,9 @@ namespace visitor {
printer->closeBrackets(sizes.size());
}

void KleeAssumeReturnValueVisitor::kleeAssumeWithNullCheck(const string& assumption, bool useBasicAssumeIfNotPointer) {
if (!useBasicAssumeIfNotPointer && additionalPointersCount == 0) {
return;
}
if (additionalPointersCount > 0) {
auto notNullAssumptionCheck = KleeUtils::NOT_NULL_VARIABLE_NAME + " == 1";
if (assumption.empty()) {
kleeAssume(notNullAssumptionCheck);
} else {
kleeAssume(notNullAssumptionCheck + " & " + assumption);
}
} else {
kleeAssume(assumption);
}
}
void KleeAssumeReturnValueVisitor::kleeAssumeWithNullCheck(const string& assumption) {
kleeAssume(assumption);
}

types::Type KleeAssumeReturnValueVisitor::getActualTmpVarType(const types::Type &type) {
if (types::TypesHandler::isVoid(type.baseTypeObj())) {
Expand All @@ -160,6 +144,7 @@ namespace visitor {
if (additionalPointersCount > 0) {
printer->ss << printer->TAB_N() << "if (" << KleeUtils::TEMP_VARIABLE_NAME
<< " != " << PrinterUtils::C_NULL << ")" << printer->LB();
kleeAssume(KleeUtils::NOT_NULL_VARIABLE_NAME + " == 1");
}
}

Expand Down
2 changes: 1 addition & 1 deletion server/src/visitors/KleeAssumeReturnValueVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ namespace visitor {

void checkNotNullAfter();

void kleeAssumeWithNullCheck(const string& assumption, bool useBasicAssumeIfNotPointer = true);
void kleeAssumeWithNullCheck(const string& assumption);

static types::Type getActualTmpVarType(const types::Type &type);
};
Expand Down
Loading