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

CPP ignore unsupported functions #112

Merged
merged 2 commits into from
Jun 21, 2023
Merged
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
20 changes: 20 additions & 0 deletions integration-tests/cpp-example/cxx_lib/multiple_classes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include "multiple_classes.h"

int first_class::get1() {
return 1;
}

int second_class::get2() {
return 2;
}

int second_class::third_class::get3() {
return 3;
}

first_class::first_class() {}

second_class::second_class() {}

second_class::third_class::third_class() {}

27 changes: 27 additions & 0 deletions integration-tests/cpp-example/cxx_lib/multiple_classes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef UNITTESTBOT_MULTIPLE_CLASSES_H
#define UNITTESTBOT_MULTIPLE_CLASSES_H


class first_class {
public:
first_class();

int get1();
};

struct second_class {
public:
second_class();

struct third_class {
third_class();

public:
int get3();
};

int get2();
};


#endif //UNITTESTBOT_MULTIPLE_CLASSES_H
13 changes: 4 additions & 9 deletions server/src/BordersFinder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@ BordersFinder::BordersFinder(const fs::path &filePath,

void BordersFinder::run(const MatchFinder::MatchResult &Result) {
LOG_SCOPE_FUNCTION(MAX);
SourceManager &sourceManager = Result.Context->getSourceManager();
if (const auto *ST = Result.Nodes.getNodeAs<clang::CXXRecordDecl>(Matchers::STRUCT_OR_CLASS_JUST_DECL)) {
SourceManager &sourceManager = Result.Context->getSourceManager();
fs::path path = sourceManager.getFileEntryForID(sourceManager.getMainFileID())
->tryGetRealPathName()
.str();
fs::path path = ClangUtils::getSourceFilePath(sourceManager);
auto borders = getBorders(sourceManager, ST->getSourceRange());
if (!containsLine(borders) || (classBorder.has_value() && !(borders < classBorder.value()))) {
return;
Expand All @@ -40,10 +38,7 @@ void BordersFinder::run(const MatchFinder::MatchResult &Result) {
LOG_S(MAX) << "Class name: " << ST->getNameAsString();
LOG_S(MAX) << "Class's borders: " << lineInfo.begin << ' ' << lineInfo.end;
} else if (const FunctionDecl *FS = ClangUtils::getFunctionOrConstructor(Result)) {
SourceManager &sourceManager = Result.Context->getSourceManager();
fs::path path = sourceManager.getFileEntryForID(sourceManager.getMainFileID())
->tryGetRealPathName()
.str();
fs::path path = ClangUtils::getSourceFilePath(sourceManager);
Stmt *currentStmt = FS->getBody();
if ((currentStmt == nullptr) || !containsLine(getFunctionBordersLines(sourceManager, FS))) {
return;
Expand Down Expand Up @@ -83,7 +78,7 @@ void BordersFinder::run(const MatchFinder::MatchResult &Result) {
} else {
lineInfo.scopeName = path.stem().string();
}
lineInfo.methodName = FS->getNameAsString();
lineInfo.methodName = FS->getQualifiedNameAsString();
clang::QualType realReturnType = ClangUtils::getReturnType(FS, Result);
lineInfo.functionReturnType = ParamsHandler::getType(realReturnType, realReturnType, sourceManager);
lineInfo.initialized = true;
Expand Down
81 changes: 81 additions & 0 deletions server/src/FeaturesFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,27 @@ static void updateIfNotCompleteType(types::TypeSupport &typeSupport,
}
}

bool hasPrivateArray(const types::Type &type, const types::TypesHandler &typesHandler) {
switch (typesHandler.getTypeKind(type)) {
case types::TypeKind::STRUCT_LIKE:
for (const auto &field: typesHandler.getStructInfo(type).fields) {
if (field.type.isArray() && field.accessSpecifier != types::AccessSpecifier::AS_pubic) {
return true;
}
return hasPrivateArray(field.type, typesHandler);
}
break;
case types::TypeKind::OBJECT_POINTER:
case types::TypeKind::ARRAY:
case types::TypeKind::PRIMITIVE:
case types::TypeKind::ENUM:
case types::TypeKind::UNKNOWN:
default:
return false;
}
return false;
}

void FeaturesFilter::filter(utbot::SettingsContext const &settingsContext,
const types::TypesHandler &typesHandler,
tests::TestsMap &testsMap,
Expand Down Expand Up @@ -80,6 +101,66 @@ void FeaturesFilter::filter(utbot::SettingsContext const &settingsContext,
tests.commentBlocks.push_back(message.str());
return true;
}

if (method.isClassMethod() &&
!typesHandler.getStructInfo(method.classObj->type).hasDefaultPublicConstructor) {
std::stringstream message;
message
<< "Method '" << method.name
<< "' was skipped, as class '" << method.getClassTypeName().value()
<< "' can't be construct in current version";
LOG_S(DEBUG) << message.str();
tests.commentBlocks.push_back(message.str());
return true;
}

if (method.isClassMethod() &&
hasPrivateArray(method.classObj->type, typesHandler)) {
std::stringstream message;
message
<< "Method '" << method.name
<< "' was skipped, as class '" << method.classObj->type.typeName()
<< "' has private field";
LOG_S(DEBUG) << message.str();
tests.commentBlocks.push_back(message.str());
return true;
}

for (const auto &param: method.params) {
if (typesHandler.isStructLike(param.type) && hasPrivateArray(param.type, typesHandler)) {
std::stringstream message;
message
<< "Method '" << method.name
<< "' was skipped, as parameter '" << param.type.typeName()
<< "' has private field";
LOG_S(DEBUG) << message.str();
tests.commentBlocks.push_back(message.str());
return true;
}
}

if (typesHandler.isStructLike(method.returnType) && hasPrivateArray(method.returnType, typesHandler)) {
std::stringstream message;
message
<< "Method '" << method.name
<< "' was skipped, as return type '" << method.returnType.typeName()
<< "' has private field";
LOG_S(DEBUG) << message.str();
tests.commentBlocks.push_back(message.str());
return true;
}

if (method.accessSpecifier != types::AS_pubic) {
std::stringstream message;
message
<< "Method '" << method.name
<< "' from class '" << method.getClassTypeName().value_or("")
<< "' was skipped, as private";
LOG_S(DEBUG) << message.str();
tests.commentBlocks.push_back(message.str());
return true;
}

unsupportedStatistics["passed features filter"]++;

return false;
Expand Down
19 changes: 10 additions & 9 deletions server/src/KleeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ KleeGenerator::buildByCDb(const CollectionUtils::MapFileTo<fs::path> &filesToBui
auto compileCommands = getCompileCommandsForKlee(filesToBuild, stubSources);
printer::DefaultMakefilePrinter makefilePrinter;

std::vector<fs::path> outfilePaths;
std::vector<std::string> outfilePaths;
for (const auto &compileCommand: compileCommands) {
fs::path output = compileCommand.getOutput();
outfilePaths.emplace_back(output);
Expand All @@ -47,6 +47,7 @@ KleeGenerator::buildByCDb(const CollectionUtils::MapFileTo<fs::path> &filesToBui
{compileCommandWithChangingDirectory.toStringWithChangingDirectory()});
}

outfilePaths.push_back(printer::DefaultMakefilePrinter::TARGET_FORCE);
makefilePrinter.declareTarget(printer::DefaultMakefilePrinter::TARGET_ALL, outfilePaths, {});
const fs::path makefile = testGen->serverBuildDir / GENERATION_COMPILE_MAKEFILE;
FileSystemUtils::writeToFile(makefile, makefilePrinter.ss.str());
Expand Down Expand Up @@ -200,7 +201,8 @@ Result<fs::path> KleeGenerator::defaultBuild(const fs::path &hintPath,
printer::DefaultMakefilePrinter makefilePrinter;
auto commandWithChangingDirectory = utbot::CompileCommand(command, true);
makefilePrinter.declareTarget(printer::DefaultMakefilePrinter::TARGET_BUILD,
{commandWithChangingDirectory.getSourcePath()},
{commandWithChangingDirectory.getSourcePath(),
printer::DefaultMakefilePrinter::TARGET_FORCE},
{commandWithChangingDirectory.toStringWithChangingDirectory()});
fs::path makefile = testGen->serverBuildDir / GENERATION_KLEE_MAKEFILE;
FileSystemUtils::writeToFile(makefile, makefilePrinter.ss.str());
Expand Down Expand Up @@ -300,13 +302,12 @@ std::vector<fs::path> KleeGenerator::buildKleeFiles(const tests::TestsMap &tests
}
kleeFilesInfo->setCorrectMethods(std::move(correctMethods));

auto kleeFilePath = writeKleeFile(
kleePrinter, tests, lineInfo,
[&kleeFilesInfo](tests::Tests::MethodDescription const &method) -> bool {
return kleeFilesInfo->isCorrectMethod(method.name);
});
auto kleeBitcodeFile =
defaultBuild(filename, kleeFilePath, buildDirPath, includeFlags);
kleeFilePath = writeKleeFile(kleePrinter, tests, lineInfo,
[&kleeFilesInfo](
tests::Tests::MethodDescription const &method) -> bool {
return kleeFilesInfo->isCorrectMethod(method.name);
});
kleeBitcodeFile = defaultBuild(filename, kleeFilePath, buildDirPath, includeFlags);
if (kleeBitcodeFile.isSuccess()) {
outFiles.emplace_back(kleeBitcodeFile.getOpt().value());
} else {
Expand Down
3 changes: 3 additions & 0 deletions server/src/KleeRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ KleeRunner::createKleeParams(const tests::TestMethod &testMethod,
"--use-tbaa",
"--output-dir=" + kleeOut.string()
};
if (Paths::isCXXFile(testMethod.sourceFilePath)) {
argvData.emplace_back("--libcxx=true");
}
ladisgin marked this conversation as resolved.
Show resolved Hide resolved
if (settingsContext.useDeterministicSearcher) {
argvData.emplace_back("--search=dfs");
}
Expand Down
2 changes: 1 addition & 1 deletion server/src/Paths.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ namespace Paths {
fs::path getWrapperFilePath(const utbot::ProjectContext &projectContext,
const fs::path &sourceFilePath) {
fs::path relative = getRelativeDirPath(projectContext, sourceFilePath);
fs::path filename = addSuffix(sourceFilePath.filename(), "_wrapper");
fs::path filename = addSuffix(sourceFilePath.filename(), MAKE_WRAPPER_SUFFIX);
return getWrapperDirPath(projectContext) / relative / filename;
}

Expand Down
9 changes: 2 additions & 7 deletions server/src/Paths.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
namespace Paths {
extern fs::path logPath;
const std::string MAKEFILE_EXTENSION = ".mk";
const std::string CXX_EXTENSION = ".cpp";
const std::string TEST_SUFFIX = "_test";
const std::string STUB_SUFFIX = "_stub";
const std::string DOT_SEP = "_dot_";
Expand Down Expand Up @@ -77,7 +78,7 @@ namespace Paths {
}

static inline fs::path addTestSuffix(const fs::path &path) {
return addSuffix(path, "_test");
return addSuffix(path, Paths::TEST_SUFFIX);
}

static inline fs::path removeSuffix(const fs::path &path, std::string const &suffix) {
Expand Down Expand Up @@ -381,12 +382,6 @@ namespace Paths {
//endregion

//region transformations
extern const std::string MAKEFILE_EXTENSION;
extern const std::string TEST_SUFFIX;
extern const std::string STUB_SUFFIX;
extern const std::string DOT_SEP;
extern const std::string MAKE_WRAPPER_SUFFIX;
extern const char dot;

fs::path sourcePathToTestPath(const utbot::ProjectContext &projectContext, const fs::path &sourceFilePath);

Expand Down
5 changes: 3 additions & 2 deletions server/src/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -562,8 +562,8 @@ Status Server::TestsGenServiceImpl::ProcessProjectStubsRequest(BaseTestGen *test
}

Status Server::TestsGenServiceImpl::failedToLoadCDbStatus(const CompilationDatabaseException &e) {
return Status(StatusCode::INVALID_ARGUMENT,
"Failed to find compile_commands.json:\n" + std::string(e.what()));
return {StatusCode::INVALID_ARGUMENT,
"Failed to find compile_commands.json:\n" + std::string(e.what())};
}

Status Server::TestsGenServiceImpl::PrintModulesContent(ServerContext *context,
Expand Down Expand Up @@ -658,6 +658,7 @@ Status Server::TestsGenServiceImpl::GetProjectTargets(ServerContext *context,
ProjectTargetsWriter targetsWriter(response);
targetsWriter.writeResponse(projectContext, targets);
} catch (CompilationDatabaseException const &e) {
LOG_S(ERROR) << "Compilation database error: " << e.what();
return failedToLoadCDbStatus(e);
}
return Status::OK;
Expand Down
8 changes: 4 additions & 4 deletions server/src/Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,9 +592,9 @@ void KTestObjectParser::addToOrder(const std::vector<UTBotKTestObject> &objects,
if (it != objects.end()) {
size_t jsonInd = it - objects.begin();
visited[jsonInd] = true;
Tests::MethodParam param = { paramType.isObjectPointer() ? paramType.baseTypeObj()
: paramType,
paramName, std::nullopt };
Tests::MethodParam param = {paramType.isObjectPointer() ? paramType.baseTypeObj()
: paramType,
paramName, std::nullopt };
order.emplace(jsonInd, param, paramValue);
return;
}
Expand Down Expand Up @@ -658,7 +658,7 @@ void KTestObjectParser::assignTypeUnnamedVar(
continue;
}
if (!visited[indObj]) {
Tests::MethodParam param = { fieldType.baseTypeObj(1), "", std::nullopt };
Tests::MethodParam param = {fieldType.baseTypeObj(1), "", std::nullopt};
order.emplace(indObj, param, curType.paramValue);
visited[indObj] = true;
}
Expand Down
14 changes: 4 additions & 10 deletions server/src/Tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ namespace tests {
FileInfo getFileByName(char fileName) const {
return filesValues.value()[fileName - 'A'];
}

std::string getError() const {
if (!errorDescriptors.empty()) {
return errorDescriptors[0].substr(0, errorDescriptors[0].find('\n'));
Expand All @@ -491,6 +491,7 @@ namespace tests {
struct MethodDescription {
std::optional<MethodParam> classObj;
std::string name;
std::string callName;
typedef std::unordered_map<std::string, std::string> SuiteNameToCodeTextMap;
std::string stubsText;
SuiteNameToCodeTextMap codeText;
Expand All @@ -513,6 +514,7 @@ namespace tests {
std::vector<MethodTestCase> testCases;
typedef std::unordered_map<std::string, std::vector<int>> SuiteNameToTestCasesMap;
SuiteNameToTestCasesMap suiteTestCases;
types::AccessSpecifier accessSpecifier;

ConstructorInfo constructorInfo = ConstructorInfo::NOT_A_CONSTRUCTOR;

Expand Down Expand Up @@ -546,22 +548,14 @@ namespace tests {
[[nodiscard]] static MethodDescription fromFunctionInfo(const types::FunctionInfo& fInfo) {
MethodDescription method;
method.name = fInfo.name;
method.callName = fInfo.name;
method.returnType = fInfo.returnType;
for (const auto& param: fInfo.params) {
method.params.emplace_back(param.type, param.name, std::nullopt);
}
return method;
}

[[nodiscard]] bool hasChangeable() const {
for (const auto& i : params) {
if (i.isChangeable()) {
return true;
}
}
return false;
}

[[nodiscard]] bool isClassMethod() const {
return classObj.has_value();
}
Expand Down
Loading