diff --git a/integration-tests/cpp-example/cxx_lib/multiple_classes.cpp b/integration-tests/cpp-example/cxx_lib/multiple_classes.cpp new file mode 100644 index 000000000..57a6b67ce --- /dev/null +++ b/integration-tests/cpp-example/cxx_lib/multiple_classes.cpp @@ -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() {} + diff --git a/integration-tests/cpp-example/cxx_lib/multiple_classes.h b/integration-tests/cpp-example/cxx_lib/multiple_classes.h new file mode 100644 index 000000000..25b124439 --- /dev/null +++ b/integration-tests/cpp-example/cxx_lib/multiple_classes.h @@ -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 diff --git a/server/src/BordersFinder.cpp b/server/src/BordersFinder.cpp index 2e2750e25..97ec94381 100644 --- a/server/src/BordersFinder.cpp +++ b/server/src/BordersFinder.cpp @@ -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(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; @@ -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; @@ -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; diff --git a/server/src/FeaturesFilter.cpp b/server/src/FeaturesFilter.cpp index a2eac2bdc..808891966 100644 --- a/server/src/FeaturesFilter.cpp +++ b/server/src/FeaturesFilter.cpp @@ -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, @@ -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 ¶m: 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; diff --git a/server/src/KleeGenerator.cpp b/server/src/KleeGenerator.cpp index f67891ab4..efb39e9d9 100644 --- a/server/src/KleeGenerator.cpp +++ b/server/src/KleeGenerator.cpp @@ -38,7 +38,7 @@ KleeGenerator::buildByCDb(const CollectionUtils::MapFileTo &filesToBui auto compileCommands = getCompileCommandsForKlee(filesToBuild, stubSources); printer::DefaultMakefilePrinter makefilePrinter; - std::vector outfilePaths; + std::vector outfilePaths; for (const auto &compileCommand: compileCommands) { fs::path output = compileCommand.getOutput(); outfilePaths.emplace_back(output); @@ -47,6 +47,7 @@ KleeGenerator::buildByCDb(const CollectionUtils::MapFileTo &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()); @@ -200,7 +201,8 @@ Result 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()); @@ -300,13 +302,12 @@ std::vector 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 { diff --git a/server/src/KleeRunner.cpp b/server/src/KleeRunner.cpp index 042e6b2f1..ca09e176a 100644 --- a/server/src/KleeRunner.cpp +++ b/server/src/KleeRunner.cpp @@ -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"); + } if (settingsContext.useDeterministicSearcher) { argvData.emplace_back("--search=dfs"); } diff --git a/server/src/Paths.cpp b/server/src/Paths.cpp index f9d5a1e4b..24b0b8a1e 100644 --- a/server/src/Paths.cpp +++ b/server/src/Paths.cpp @@ -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; } diff --git a/server/src/Paths.h b/server/src/Paths.h index 619e6dbc1..b5fd433ab 100644 --- a/server/src/Paths.h +++ b/server/src/Paths.h @@ -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_"; @@ -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) { @@ -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); diff --git a/server/src/Server.cpp b/server/src/Server.cpp index b17fc4d0c..ef5d606b9 100644 --- a/server/src/Server.cpp +++ b/server/src/Server.cpp @@ -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, @@ -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; diff --git a/server/src/Tests.cpp b/server/src/Tests.cpp index f2cd9b688..0bcdaca05 100644 --- a/server/src/Tests.cpp +++ b/server/src/Tests.cpp @@ -592,9 +592,9 @@ void KTestObjectParser::addToOrder(const std::vector &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; } @@ -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; } diff --git a/server/src/Tests.h b/server/src/Tests.h index b9091b69b..981e65d67 100644 --- a/server/src/Tests.h +++ b/server/src/Tests.h @@ -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')); @@ -491,6 +491,7 @@ namespace tests { struct MethodDescription { std::optional classObj; std::string name; + std::string callName; typedef std::unordered_map SuiteNameToCodeTextMap; std::string stubsText; SuiteNameToCodeTextMap codeText; @@ -513,6 +514,7 @@ namespace tests { std::vector testCases; typedef std::unordered_map> SuiteNameToTestCasesMap; SuiteNameToTestCasesMap suiteTestCases; + types::AccessSpecifier accessSpecifier; ConstructorInfo constructorInfo = ConstructorInfo::NOT_A_CONSTRUCTOR; @@ -546,6 +548,7 @@ 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); @@ -553,15 +556,6 @@ namespace tests { 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(); } diff --git a/server/src/clang-utils/ClangUtils.cpp b/server/src/clang-utils/ClangUtils.cpp index 065447ff6..385a11967 100644 --- a/server/src/clang-utils/ClangUtils.cpp +++ b/server/src/clang-utils/ClangUtils.cpp @@ -29,19 +29,36 @@ namespace ClangUtils { } const clang::FunctionDecl *getFunctionOrConstructor(const clang::ast_matchers::MatchFinder::MatchResult &Result) { - const auto *FS = Result.Nodes.getNodeAs(Matchers::FUNCTION_DEF); + const clang::FunctionDecl *FS = Result.Nodes.getNodeAs(Matchers::FUNCTION_DEF); if (!FS) { FS = getConstructor(Result); } return FS; } - - clang::QualType getReturnType(const clang::FunctionDecl *FS, const clang::ast_matchers::MatchFinder::MatchResult &Result) { + clang::QualType + getReturnType(const clang::FunctionDecl *FS, const clang::ast_matchers::MatchFinder::MatchResult &Result) { clang::QualType realReturnType = FS->getReturnType().getCanonicalType(); if (const auto *CS = getConstructor(Result)) { realReturnType = CS->getThisObjectType(); } return realReturnType; } + + std::string getCallName(const clang::FunctionDecl *FS) { + std::string qualName = ""; + if (auto qualifier = FS->getQualifier()) { + llvm::raw_string_ostream OS(qualName); + if (llvm::dyn_cast(FS)) { + qualifier = qualifier->getPrefix(); + if (qualifier) { + qualifier->print(OS, FS->getASTContext().getPrintingPolicy()); + } + } else if (!llvm::dyn_cast(FS)) { + qualifier->print(OS, FS->getASTContext().getPrintingPolicy()); + } + OS.flush(); + } + return qualName + FS->getNameAsString(); + } } diff --git a/server/src/clang-utils/ClangUtils.h b/server/src/clang-utils/ClangUtils.h index 94602835d..a4ebf4cd7 100644 --- a/server/src/clang-utils/ClangUtils.h +++ b/server/src/clang-utils/ClangUtils.h @@ -6,9 +6,22 @@ namespace ClangUtils { bool isIncomplete(clang::QualType type); + const clang::CXXConstructorDecl *getConstructor(const clang::ast_matchers::MatchFinder::MatchResult &Result); + const clang::FunctionDecl *getFunctionOrConstructor(const clang::ast_matchers::MatchFinder::MatchResult &Result); - clang::QualType getReturnType(const clang::FunctionDecl *FS, const clang::ast_matchers::MatchFinder::MatchResult &Result); + + clang::QualType + getReturnType(const clang::FunctionDecl *FS, const clang::ast_matchers::MatchFinder::MatchResult &Result); + + /* + * @return commands with qualifier if needed for call it in tests + */ + std::string getCallName(const clang::FunctionDecl *FS); + + inline std::string getSourceFilePath(const clang::SourceManager &sourceManager) { + return sourceManager.getFileEntryForID(sourceManager.getMainFileID())->tryGetRealPathName().str(); + } }; diff --git a/server/src/coverage/TestRunner.cpp b/server/src/coverage/TestRunner.cpp index bfab683e8..fe0fed893 100644 --- a/server/src/coverage/TestRunner.cpp +++ b/server/src/coverage/TestRunner.cpp @@ -8,7 +8,6 @@ #include "utils/FileSystemUtils.h" #include "utils/JsonUtils.h" #include "utils/StringUtils.h" -#include "utils/stats/TestsExecutionStats.h" #include "loguru.h" @@ -91,10 +90,11 @@ std::vector TestRunner::getTestsToLaunch() { return; } const auto &testFilePath = directoryEntry.path(); - if (StringUtils::endsWith(testFilePath.c_str(), "_test.cpp")) { + if (testFilePath.extension() == Paths::CXX_EXTENSION && + StringUtils::endsWith(testFilePath.stem().c_str(), Paths::TEST_SUFFIX)) { fs::path sourcePath = Paths::testPathToSourcePath(projectContext, testFilePath); fs::path makefile = - Paths::getMakefilePathFromSourceFilePath(projectContext, sourcePath); + Paths::getMakefilePathFromSourceFilePath(projectContext, sourcePath); if (fs::exists(makefile)) { try { auto tests = getTestsFromMakefile(makefile, testFilePath); @@ -107,10 +107,10 @@ std::vector TestRunner::getTestsToLaunch() { "Makefile for %s not found, candidate: %s", testFilePath, makefile); } } else { - if (!StringUtils::endsWith(testFilePath.c_str(), "_test.h") && - !StringUtils::endsWith(testFilePath.stem().c_str(), "_stub") && - !StringUtils::endsWith(testFilePath.c_str(), "_wrapper.c") && - !StringUtils::endsWith(testFilePath.c_str(), ".mk")) { + if (!StringUtils::endsWith(testFilePath.stem().c_str(), Paths::TEST_SUFFIX) && + !StringUtils::endsWith(testFilePath.stem().c_str(), Paths::STUB_SUFFIX) && + !StringUtils::endsWith(testFilePath.stem().c_str(), Paths::MAKE_WRAPPER_SUFFIX) && + !StringUtils::endsWith(testFilePath.c_str(), Paths::MAKEFILE_EXTENSION)) { LOG_S(WARNING) << "Found extra file in test directory: " << testFilePath; } } diff --git a/server/src/fetchers/ArraySubscriptFetcherMatchCallback.cpp b/server/src/fetchers/ArraySubscriptFetcherMatchCallback.cpp index 075dde892..483816b53 100644 --- a/server/src/fetchers/ArraySubscriptFetcherMatchCallback.cpp +++ b/server/src/fetchers/ArraySubscriptFetcherMatchCallback.cpp @@ -2,6 +2,7 @@ #include "Fetcher.h" #include "clang-utils/Matchers.h" +#include "clang-utils/ClangUtils.h" #include "utils/CollectionUtils.h" #include "loguru.h" @@ -17,10 +18,7 @@ ArraySubscriptFetcherMatchCallback::ArraySubscriptFetcherMatchCallback(Fetcher * void ArraySubscriptFetcherMatchCallback::run(const MatchFinder::MatchResult &Result) { if (const auto *FS = Result.Nodes.getNodeAs(SUBSCRIPT)) { - SourceManager &sourceManager = Result.Context->getSourceManager(); - fs::path sourceFilePath = sourceManager.getFileEntryForID(sourceManager.getMainFileID()) - ->tryGetRealPathName() - .str(); + fs::path sourceFilePath = ClangUtils::getSourceFilePath(Result.Context->getSourceManager()); auto child = FS->children().begin(); while (canBeMissed(*child) && !child->children().empty()) { child = child->children().begin(); @@ -29,8 +27,8 @@ void ArraySubscriptFetcherMatchCallback::run(const MatchFinder::MatchResult &Res if (!isa(variableExpr)) { return; } - auto declrefExpr = cast(variableExpr); - auto variableDecl = declrefExpr->getDecl(); + auto declRefExpr = cast(variableExpr); + auto variableDecl = declRefExpr->getDecl(); auto contextDecl = variableDecl->getParentFunctionOrMethod(); if (contextDecl == nullptr || std::string(contextDecl->getDeclKindName()) != "Function") { return; diff --git a/server/src/fetchers/FetcherUtils.cpp b/server/src/fetchers/FetcherUtils.cpp index a5e844a8c..955caaaa9 100644 --- a/server/src/fetchers/FetcherUtils.cpp +++ b/server/src/fetchers/FetcherUtils.cpp @@ -109,3 +109,16 @@ void ClangToolRunner::setResourceDirOption(clang::tooling::ClangTool *clangTool) clangTool->appendArgumentsAdjuster(resourceDirAdjuster); } } + +types::AccessSpecifier getAcessSpecifier(const clang::Decl *D) { + switch (D->getAccess()) { + case clang::AS_private : + return types::AS_private; + case clang::AS_protected : + return types::AS_protected; + case clang::AS_public : + return types::AS_pubic; + case clang::AS_none : + return types::AS_none; + } +} diff --git a/server/src/fetchers/FetcherUtils.h b/server/src/fetchers/FetcherUtils.h index 7e9ce8098..aa81e4f97 100644 --- a/server/src/fetchers/FetcherUtils.h +++ b/server/src/fetchers/FetcherUtils.h @@ -60,4 +60,6 @@ template bool canBeMissed(StatementType const& statemen llvm::isa(statement) || llvm::isa(statement); } +types::AccessSpecifier getAcessSpecifier(const clang::Decl *D); + #endif //UNITTESTBOT_FETCHERUTILS_H diff --git a/server/src/fetchers/FunctionDeclsMatchCallback.cpp b/server/src/fetchers/FunctionDeclsMatchCallback.cpp index e6a21b38e..e8285a89c 100644 --- a/server/src/fetchers/FunctionDeclsMatchCallback.cpp +++ b/server/src/fetchers/FunctionDeclsMatchCallback.cpp @@ -6,7 +6,6 @@ #include "clang-utils/AlignmentFetcher.h" #include "clang-utils/ClangUtils.h" #include "utils/LogUtils.h" -#include "clang-utils/ClangUtils.h" #include "loguru.h" @@ -16,8 +15,8 @@ FunctionDeclsMatchCallback::FunctionDeclsMatchCallback(const Fetcher *parent, bool onlyNames, bool toResolveReturnTypes, bool onlyReturnTypes) - : parent(parent), typesResolver(parent), onlyNames(onlyNames), - toResolveReturnTypes(toResolveReturnTypes), onlyReturnTypes(onlyReturnTypes) { + : parent(parent), typesResolver(parent), onlyNames(onlyNames), + toResolveReturnTypes(toResolveReturnTypes), onlyReturnTypes(onlyReturnTypes) { } void FunctionDeclsMatchCallback::run(const MatchFinder::MatchResult &Result) { @@ -25,19 +24,17 @@ void FunctionDeclsMatchCallback::run(const MatchFinder::MatchResult &Result) { if (const FunctionDecl *FS = ClangUtils::getFunctionOrConstructor(Result)) { ExecUtils::throwIfCancelled(); SourceManager &sourceManager = Result.Context->getSourceManager(); - fs::path sourceFilePath = sourceManager.getFileEntryForID(sourceManager.getMainFileID()) - ->tryGetRealPathName() - .str(); + fs::path sourceFilePath = ClangUtils::getSourceFilePath(sourceManager); - std::string methodName = FS->getNameAsString(); Tests::MethodDescription methodDescription; - methodDescription.name = methodName; if (const CXXConstructorDecl *CS = ClangUtils::getConstructor(Result)) { - methodDescription.constructorInfo = Tests::ConstructorInfo::CONSTRUCTOR; - if (CS->isMoveConstructor()) { - methodDescription.constructorInfo = Tests::ConstructorInfo::MOVE_CONSTRUCTOR; - } + methodDescription.constructorInfo = CS->isMoveConstructor() ? Tests::ConstructorInfo::MOVE_CONSTRUCTOR + : Tests::ConstructorInfo::CONSTRUCTOR; } + + std::string methodName = FS->getQualifiedNameAsString(); + methodDescription.name = methodName; + methodDescription.callName = ClangUtils::getCallName(FS); methodDescription.sourceFilePath = sourceFilePath; if (onlyNames) { addMethod(sourceFilePath, methodDescription); @@ -45,6 +42,7 @@ void FunctionDeclsMatchCallback::run(const MatchFinder::MatchResult &Result) { } clang::QualType realReturnType = ClangUtils::getReturnType(FS, Result); methodDescription.returnType = ParamsHandler::getType(realReturnType, realReturnType, sourceManager); + methodDescription.accessSpecifier = types::AS_pubic; if (onlyReturnTypes) { addMethod(sourceFilePath, methodDescription); return; @@ -71,6 +69,7 @@ void FunctionDeclsMatchCallback::run(const MatchFinder::MatchResult &Result) { methodDescription.classObj = {classType, classType.typeName() + "_obj", std::nullopt}; + methodDescription.accessSpecifier = getAcessSpecifier(FS); } methodDescription.returnType = ParamsHandler::getType(realReturnType, realReturnType, sourceManager); methodDescription.hasIncompleteReturnType = ClangUtils::isIncomplete(realReturnType); @@ -96,8 +95,11 @@ void FunctionDeclsMatchCallback::run(const MatchFinder::MatchResult &Result) { ASTPrinter::getSourceText(FS->getBody()->getSourceRange(), sourceManager); } + const auto paramsFromDefinition = FS->parameters(); - for (size_t i = 0; i < paramsFromDefinition.size(); ++i) { + const auto paramsFromDeclaration = FSFromHeader->parameters(); + for (size_t i = 0; i < paramsFromDeclaration.size(); ++i) { + const auto &declParam = paramsFromDeclaration[i]; const auto &defParam = paramsFromDefinition[i]; std::string name = NameDecorator::decorate(defParam->getNameAsString()); std::string mangledName = PrinterUtils::getParamMangledName(name, methodName); @@ -107,9 +109,9 @@ void FunctionDeclsMatchCallback::run(const MatchFinder::MatchResult &Result) { if (name == methodDescription.name) { name = mangledName; } - auto paramType = ParamsHandler::getType(defParam->getType(), defParam->getType(), sourceManager); - addFunctionPointer(methodDescription.functionPointers, defParam->getFunctionType(), - defParam->getType(), name, sourceManager, paramType); + auto paramType = ParamsHandler::getType(defParam->getType(), declParam->getType(), sourceManager); + 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); @@ -154,18 +156,22 @@ void FunctionDeclsMatchCallback::logFunction(const Tests::MethodDescription &des } void FunctionDeclsMatchCallback::addFunctionPointer( - tests::Tests::MethodDescription::FPointerMap &functionPointers, - const clang::FunctionType *functionType, - const clang::QualType &qualType, - const std::string &name, - const clang::SourceManager &sourceManager, - const types::Type &type) { + tests::Tests::MethodDescription::FPointerMap &functionPointers, + const clang::FunctionType *functionType, + const clang::QualType &qualType, + const std::string &name, + const clang::SourceManager &sourceManager, + const types::Type &type) { if (type.isPointerToFunction()) { - functionPointers[name] = ParamsHandler::getFunctionPointerDeclaration(functionType, name, sourceManager, - false); + if (functionType) { + functionPointers[name] = ParamsHandler::getFunctionPointerDeclaration(functionType, name, sourceManager, + false); + } else { + LOG_S(WARNING) << "Type '" << name << "' fetch as function pointer but can't get functionType"; + } } else if (type.isArrayOfPointersToFunction()) { functionPointers[name] = ParamsHandler::getFunctionPointerDeclaration( - qualType->getPointeeType()->getPointeeType()->getAs(), name, - sourceManager, true); + qualType->getPointeeType()->getPointeeType()->getAs(), name, + sourceManager, true); } } diff --git a/server/src/fetchers/GlobalVariableUsageMatchCallback.cpp b/server/src/fetchers/GlobalVariableUsageMatchCallback.cpp index 9c6b4230b..faf6bbfb0 100644 --- a/server/src/fetchers/GlobalVariableUsageMatchCallback.cpp +++ b/server/src/fetchers/GlobalVariableUsageMatchCallback.cpp @@ -48,8 +48,7 @@ void GlobalVariableUsageMatchCallback::checkUsage(const MatchFinder::MatchResult void GlobalVariableUsageMatchCallback::handleUsage(const clang::FunctionDecl *functionDecl, const clang::VarDecl *varDecl) { clang::SourceManager &sourceManager = functionDecl->getASTContext().getSourceManager(); - fs::path sourceFilePath = - sourceManager.getFileEntryForID(sourceManager.getMainFileID())->tryGetRealPathName().str(); + fs::path sourceFilePath = ClangUtils::getSourceFilePath(sourceManager); auto const &[iterator, inserted] = usages.emplace(varDecl->getNameAsString(), functionDecl->getNameAsString()); auto const &usage = *iterator; diff --git a/server/src/fetchers/IncludeFetchSourceFileCallback.cpp b/server/src/fetchers/IncludeFetchSourceFileCallback.cpp index 96773b418..cc277aa22 100644 --- a/server/src/fetchers/IncludeFetchSourceFileCallback.cpp +++ b/server/src/fetchers/IncludeFetchSourceFileCallback.cpp @@ -3,6 +3,7 @@ #include "Fetcher.h" #include "utils/ExecUtils.h" #include "utils/LogUtils.h" +#include "clang-utils/ClangUtils.h" #include "loguru.h" @@ -39,9 +40,7 @@ class IncludeFetchPPCallbacks : public clang::PPCallbacks { } return; } - fs::path sourceFilePath = sourceManager.getFileEntryForID(sourceManager.getMainFileID()) - ->tryGetRealPathName() - .str(); + fs::path sourceFilePath = ClangUtils::getSourceFilePath(sourceManager); LOG_S(MAX) << "Fetched inclusion directive. " << "Source file sourceFilePath: " << sourceFilePath << "\nPath:" << sourceFilePath; diff --git a/server/src/fetchers/TypeDeclsMatchCallback.cpp b/server/src/fetchers/TypeDeclsMatchCallback.cpp index 1a1c22512..1e749efaa 100644 --- a/server/src/fetchers/TypeDeclsMatchCallback.cpp +++ b/server/src/fetchers/TypeDeclsMatchCallback.cpp @@ -2,6 +2,7 @@ #include "Fetcher.h" #include "clang-utils/ASTPrinter.h" +#include "clang-utils/ClangUtils.h" #include "utils/LogUtils.h" using namespace clang; @@ -56,10 +57,7 @@ void TypeDeclsMatchCallback::checkStruct(const MatchFinder::MatchResult &Result) void TypeDeclsMatchCallback::checkStructDecl(const MatchFinder::MatchResult &Result) { if (const auto *ST = Result.Nodes.getNodeAs(Matchers::STRUCT_OR_CLASS_JUST_DECL)) { - clang::SourceManager &sourceManager = Result.Context->getSourceManager(); - fs::path sourceFilePath = sourceManager.getFileEntryForID(sourceManager.getMainFileID()) - ->tryGetRealPathName() - .str(); + fs::path sourceFilePath = ClangUtils::getSourceFilePath(Result.Context->getSourceManager()); (*parent->structsDeclared)[sourceFilePath].insert(ST->getNameAsString()); } } diff --git a/server/src/printers/DefaultMakefilePrinter.cpp b/server/src/printers/DefaultMakefilePrinter.cpp index 2981e5dd7..1ca4f00dc 100644 --- a/server/src/printers/DefaultMakefilePrinter.cpp +++ b/server/src/printers/DefaultMakefilePrinter.cpp @@ -7,9 +7,11 @@ namespace printer { const std::string DefaultMakefilePrinter::TARGET_ALL = "all"; const std::string DefaultMakefilePrinter::TARGET_BUILD = "build"; const std::string DefaultMakefilePrinter::TARGET_RUN = "run"; +const std::string DefaultMakefilePrinter::TARGET_FORCE = ".FORCE"; DefaultMakefilePrinter::DefaultMakefilePrinter() { writeCopyrightHeader(); + declareTarget(TARGET_FORCE, {}, {}); } void DefaultMakefilePrinter::comment(std::string const &message) { diff --git a/server/src/printers/DefaultMakefilePrinter.h b/server/src/printers/DefaultMakefilePrinter.h index b355fae15..a787c8a87 100644 --- a/server/src/printers/DefaultMakefilePrinter.h +++ b/server/src/printers/DefaultMakefilePrinter.h @@ -12,6 +12,7 @@ class DefaultMakefilePrinter : public Printer { static const std::string TARGET_ALL; static const std::string TARGET_BUILD; static const std::string TARGET_RUN; + static const std::string TARGET_FORCE; DefaultMakefilePrinter(); diff --git a/server/src/printers/KleePrinter.cpp b/server/src/printers/KleePrinter.cpp index 48bf5950c..700bf7024 100644 --- a/server/src/printers/KleePrinter.cpp +++ b/server/src/printers/KleePrinter.cpp @@ -143,18 +143,27 @@ fs::path KleePrinter::writeTmpKleeFile( strInclude("klee/klee.h") << NL; ss << CALLOC_DECLARATION << NL; writeStubsForStructureFields(tests); - - writeAccessPrivateMacros(typesHandler, tests, false); + writeAccessPrivateMacros(typesHandler, tests, false, + [methodFilter, onlyForOneClass, onlyForOneFunction, testedMethod, testedClass]( + tests::Tests::MethodDescription const &testMethod) { + bool filter = methodFilter(testMethod); + bool forThisFunction = !onlyForOneFunction || testMethod.name == testedMethod; + bool forThisClass = !onlyForOneClass || !testMethod.isClassMethod() || + testMethod.classObj->type.typeName() == testedClass; + return filter && forThisFunction && forThisClass; + }); strDeclareSetOfVars(tests.externVariables); ss << NL; - for (const auto &[methodName, testMethod] : tests.methods) { + for (const auto &[methodName, testMethod]: tests.methods) { if (!methodFilter(testMethod)) { continue; } - if ((onlyForOneFunction && methodName != testedMethod) || - (onlyForOneClass && testMethod.isClassMethod() && testMethod.classObj->type.typeName() != testedClass)) { + if (onlyForOneFunction && methodName != testedMethod) { + continue; + } + if (onlyForOneClass && testMethod.isClassMethod() && testMethod.classObj->type.typeName() != testedClass) { continue; } try { @@ -359,7 +368,7 @@ void KleePrinter::genGlobalParamsDeclarations(const Tests::MethodDescription &te strAssignVar(param.name, kleeParam.name); } } - genConstraints(kleeParam, testMethod.name); + genConstraints(kleeParam); } } @@ -392,11 +401,14 @@ void KleePrinter::genParamsDeclarations( continue; } auto paramType = - kleeParam.type.maybeJustPointer() ? kleeParam.type.baseTypeObj() : kleeParam.type; + kleeParam.type.maybeJustPointer() ? kleeParam.type.baseTypeObj() : kleeParam.type; strKleeMakeSymbolic(paramType, kleeParam.name, param.name, !isArray); - if(testGen->settingsContext.differentVariablesOfTheSameType && typesToNames[param.type.typeName()].size() <= 3){ - genConstraints(kleeParam, testMethod.name, typesToNames[param.type.typeName()]);} - else {genConstraints(kleeParam, testMethod.name);} + if (testGen->settingsContext.differentVariablesOfTheSameType && + typesToNames[param.type.typeName()].size() <= 3) { + genConstraints(kleeParam, typesToNames[param.type.typeName()]); + } else { + genConstraints(kleeParam); + } genTwoDimPointers(param, true); commentBlockSeparator(); } @@ -487,7 +499,7 @@ void KleePrinter::genParamsKleeAssumes( } } -void KleePrinter::genConstraints(const Tests::MethodParam ¶m, const std::string &methodName, const std::vector& names) { +void KleePrinter::genConstraints(const Tests::MethodParam ¶m, const std::vector& names) { KleeConstraintsPrinter constraintsPrinter(typesHandler, srcLanguage); constraintsPrinter.setTabsDepth(tabsDepth); const auto constraintsBlock = constraintsPrinter.genConstraints(param, names).str(); diff --git a/server/src/printers/KleePrinter.h b/server/src/printers/KleePrinter.h index 2b3b25402..1ce867f2f 100644 --- a/server/src/printers/KleePrinter.h +++ b/server/src/printers/KleePrinter.h @@ -30,15 +30,16 @@ namespace printer { utbot::Language getLanguage() const override; fs::path writeTmpKleeFile( - const Tests &tests, - const std::string &buildDir, - const PathSubstitution &pathSubstitution, - const std::optional &predicateInfo = std::nullopt, - const std::string &testedMethod = "", - const std::optional &testedClass = "", - bool onlyForOneFunction = false, - bool onlyForOneClass = false, - const std::function &methodFilter = [](tests::Tests::MethodDescription const &) { return true; }); + const Tests &tests, + const std::string &buildDir, + const PathSubstitution &pathSubstitution, + const std::optional &predicateInfo = std::nullopt, + const std::string &testedMethod = "", + const std::optional &testedClass = "", + bool onlyForOneFunction = false, + bool onlyForOneClass = false, + const std::function &methodFilter = []( + tests::Tests::MethodDescription const &) { return true; }); std::string addTestLineFlag(const std::shared_ptr &lineInfo, bool needAssertion, @@ -87,7 +88,7 @@ namespace printer { /* * Functions for constraints generation. */ - void genConstraints(const Tests::MethodParam ¶m, const std::string& methodName = "", const std::vector& names = {}); + void genConstraints(const Tests::MethodParam ¶m, const std::vector& names = {}); void genTwoDimPointers(const Tests::MethodParam ¶m, bool needDeclare); diff --git a/server/src/printers/NativeMakefilePrinter.cpp b/server/src/printers/NativeMakefilePrinter.cpp index e54c2f287..f38072a32 100644 --- a/server/src/printers/NativeMakefilePrinter.cpp +++ b/server/src/printers/NativeMakefilePrinter.cpp @@ -156,7 +156,6 @@ namespace printer { declareAction(stringFormat("$(shell mkdir -p %s >/dev/null)", getRelativePath(buildDirectory))); declareAction(stringFormat("$(shell mkdir -p %s >/dev/null)", getRelativePath(dependencyDirectory))); - declareTarget(FORCE, {}, {}); comment("{ gtest"); @@ -449,7 +448,7 @@ namespace printer { coverageInfoBinary = testExecutablePath.string(); } - declareTarget("bin", { FORCE }, { stringFormat("echo %s", + declareTarget("bin", { TARGET_FORCE }, { stringFormat("echo %s", getRelativePath(coverageInfoBinary)) }); utbot::RunCommand testRunCommand{ { getRelativePath(testExecutablePath), "$(GTEST_FLAGS)" }, diff --git a/server/src/printers/NativeMakefilePrinter.h b/server/src/printers/NativeMakefilePrinter.h index fa40cc015..6f0a81994 100644 --- a/server/src/printers/NativeMakefilePrinter.h +++ b/server/src/printers/NativeMakefilePrinter.h @@ -10,8 +10,6 @@ #include namespace printer { - static const std::string FORCE = ".FORCE"; - class NativeMakefilePrinter : public RelativeMakefilePrinter { friend class TestMakefilesPrinter; private: diff --git a/server/src/printers/Printer.cpp b/server/src/printers/Printer.cpp index 4d5426ddc..1b1bf6cbc 100644 --- a/server/src/printers/Printer.cpp +++ b/server/src/printers/Printer.cpp @@ -227,25 +227,11 @@ namespace printer { Printer::Stream &Printer::strFunctionDecl(const tests::Tests::MethodDescription &method, const std::string &end, const std::vector &modifiers) { - return strFunctionDecl(method.returnType.usedType(), method.name, method.getParamTypes(), + return strFunctionDecl(method.returnType.usedType(), method.callName, method.getParamTypes(), method.getParamNames(), end, modifiers, method.functionPointers, method.isVariadic); } - - Printer::Stream & - Printer::strFunctionDeclWithParamString(const tests::Tests::MethodDescription &method, - const std::string &end, - const std::vector &modifiers) { - ss << LINE_INDENT(); - for (const auto &modifier : modifiers) { - ss << modifier << " "; - } - ss << method.returnType.usedType() << " " << method.name << "(" << method.paramsString - << ")" << end; - return ss; - } - Printer::Stream &Printer::strFunctionCall(std::string_view functionName, const std::vector &args, const std::string &end, @@ -285,7 +271,7 @@ namespace printer { parameters.push_back(param.getFunctionParamDecl()); } auto classObjName = method.getClassName(); - return strFunctionCall(method.name, parameters, end, classObjName, needTabs, + return strFunctionCall(method.callName, parameters, end, classObjName, needTabs, returnPointers); } @@ -420,6 +406,7 @@ namespace printer { if (!suffix.empty()) { methodCopy.name += "_" + suffix; } + methodCopy.callName = methodCopy.name; std::vector modifiers; if (makeStatic) { modifiers.emplace_back("static"); @@ -583,18 +570,24 @@ namespace printer { stubName, "stub", methodName, fInfo->name, makeStatic); } - void Printer::writeAccessPrivateMacros(types::TypesHandler const *typesHandler, const Tests &tests, bool onlyChangeable) { + void + Printer::writeAccessPrivateMacros(types::TypesHandler const *typesHandler, const Tests &tests, bool onlyChangeable, + const std::function &methodFilter) { if (srcLanguage == utbot::Language::CXX) { ss << NL; strInclude("access_private.hpp"); ss << NL; std::unordered_set checkedOnPrivate; - for (const auto &[methodName, testMethod] : tests.methods) { + for (const auto &[methodName, testMethod]: tests.methods) { + if (!methodFilter(testMethod)) { + continue; + } addAccessor(typesHandler, testMethod.returnType, checkedOnPrivate); if (testMethod.isClassMethod()) { addAccessor(typesHandler, testMethod.classObj->type, checkedOnPrivate); } - for (const auto& param : testMethod.params) { + for (const auto ¶m: testMethod.params) { if (!onlyChangeable || param.isChangeable()) { addAccessor(typesHandler, param.type, checkedOnPrivate); } @@ -604,12 +597,18 @@ namespace printer { } } + void Printer::writeAccessPrivateMacros(types::TypesHandler const *typesHandler, + const Tests &tests, bool onlyChangeable) { + writeAccessPrivateMacros(typesHandler, tests, onlyChangeable, + [](tests::Tests::MethodDescription const &val) { return true; }); + } + void Printer::addAccessor(const types::TypesHandler *typesHandler, const types::Type &type, std::unordered_set &checkedOnPrivate) { if (!checkedOnPrivate.count(type.getId()) && typesHandler->isStructLike(type)) { checkedOnPrivate.insert(type.getId()); for (const auto& field : typesHandler->getStructInfo(type).fields) { - if (field.accessSpecifier != types::Field::AS_pubic) { + if (field.accessSpecifier != types::AccessSpecifier::AS_pubic && !field.type.isArray()) { ss << StringUtils::stringFormat("ACCESS_PRIVATE_FIELD(%s, %s, %s)", type.typeName(), field.type.typeName(), diff --git a/server/src/printers/Printer.h b/server/src/printers/Printer.h index 714ffc4e4..b677bcb8a 100644 --- a/server/src/printers/Printer.h +++ b/server/src/printers/Printer.h @@ -201,10 +201,6 @@ namespace printer { const std::string &end = "", bool needTabs = true); - std::stringstream &strFunctionDeclWithParamString(const Tests::MethodDescription &method, - const std::string &end , - const std::vector &modifiers = {}); - void writeStubsForFunctionParams(const types::TypesHandler* typesHandler, const Tests::MethodDescription& testMethod, bool forKlee); @@ -220,6 +216,9 @@ namespace printer { const std::string &methodName, const std::string &stubName, bool needToTypedef, bool makeStatic); + void writeAccessPrivateMacros(types::TypesHandler const *typesHandler, const Tests &tests, bool onlyChangeable, + const std::function &methodFilter); + void writeAccessPrivateMacros(types::TypesHandler const *typesHandler, const Tests &tests, bool onlyChangeable); void genStubForStructFunctionPointer(const std::string &structName, diff --git a/server/src/printers/TestMakefilesPrinter.cpp b/server/src/printers/TestMakefilesPrinter.cpp index 9788bb8c5..d07b087d9 100644 --- a/server/src/printers/TestMakefilesPrinter.cpp +++ b/server/src/printers/TestMakefilesPrinter.cpp @@ -78,18 +78,16 @@ namespace printer { generalMakefilePrinter.ss << getProjectStructureRelativeTo(generalMakefilePath); generalMakefilePrinter.ss << ss.str(); - generalMakefilePrinter.declareTarget(FORCE, {}, {}); - const std::string sharedMakefilePathRelative = sharedMakefilePrinter.getRelativePath(sharedMakefilePath); const std::string objMakefilePathRelative = objMakefilePrinter.getRelativePath(objMakefilePath); - generalMakefilePrinter.declareTarget("bin", {FORCE}, { + generalMakefilePrinter.declareTarget("bin", {TARGET_FORCE}, { StringUtils::joinWith( MakefileUtils::getMakeCommand(sharedMakefilePathRelative, "bin", true), " ") }); - generalMakefilePrinter.declareTarget(TARGET_BUILD, {FORCE}, { + generalMakefilePrinter.declareTarget(TARGET_BUILD, {TARGET_FORCE}, { StringUtils::stringFormat("%s || %s", StringUtils::joinWith(MakefileUtils::getMakeCommand( sharedMakefilePathRelative, TARGET_BUILD, true), " "), @@ -97,7 +95,7 @@ namespace printer { objMakefilePathRelative, TARGET_BUILD, true), " ")) }); - generalMakefilePrinter.declareTarget(TARGET_RUN, {FORCE}, { + generalMakefilePrinter.declareTarget(TARGET_RUN, {TARGET_FORCE}, { StringUtils::stringFormat("%s && { %s; exit $$?; } || { %s && { %s; exit $$?; } }", StringUtils::joinWith(MakefileUtils::getMakeCommand( sharedMakefilePathRelative, TARGET_BUILD, true), " "), @@ -108,7 +106,7 @@ namespace printer { StringUtils::joinWith(MakefileUtils::getMakeCommand( objMakefilePathRelative, TARGET_RUN, true), " ")) }); - generalMakefilePrinter.declareTarget("clean", {FORCE}, { + generalMakefilePrinter.declareTarget("clean", {TARGET_FORCE}, { StringUtils::joinWith( MakefileUtils::getMakeCommand(sharedMakefilePathRelative, "clean", true), " "), StringUtils::joinWith( diff --git a/server/src/printers/TestsPrinter.cpp b/server/src/printers/TestsPrinter.cpp index 7707d4617..2f6780f62 100644 --- a/server/src/printers/TestsPrinter.cpp +++ b/server/src/printers/TestsPrinter.cpp @@ -194,13 +194,14 @@ void TestsPrinter::genCode(Tests::MethodDescription &methodDescription, static std::string getTestName(const Tests::MethodDescription &methodDescription, int testNum) { std::string renamedMethodDescription = KleeUtils::getRenamedOperator(methodDescription.name); + StringUtils::replaceAll(renamedMethodDescription, ':', '_'); std::string testBaseName = methodDescription.isClassMethod() ? StringUtils::stringFormat("%s_%s", methodDescription.classObj->type.typeName(), renamedMethodDescription) : renamedMethodDescription; - return printer::Printer::concat(testBaseName, "_test_", testNum); + return printer::Printer::concat(testBaseName, Paths::TEST_SUFFIX, testNum); } void TestsPrinter::genCodeBySuiteName(const std::string &targetSuiteName, @@ -446,7 +447,7 @@ void TestsPrinter::verboseParameters(const Tests::MethodDescription &methodDescr const auto ¶m = methodDescription.globalParams[i]; const auto &value = testCase.globalPreValues[i]; if (param.type.isTwoDimensionalPointer()) { - Tests::MethodParam valueParam{ param.type, param.underscoredName(), param.alignment }; + Tests::MethodParam valueParam{param.type, param.underscoredName(), param.alignment }; verboseParameter(methodDescription, valueParam, value, true); gen2DPointer(param, false); } else { @@ -456,7 +457,7 @@ void TestsPrinter::verboseParameters(const Tests::MethodDescription &methodDescr ss << NL; } - std::vector> types = { testCase.stubValuesTypes, testCase.stubParamTypes }; + std::vector> types = {testCase.stubValuesTypes, testCase.stubParamTypes }; std::vector> values = { testCase.stubParamValues, testCase.stubParamValues }; for (int j = 0; j < types.size(); j++) { @@ -468,7 +469,7 @@ void TestsPrinter::verboseParameters(const Tests::MethodDescription &methodDescr const auto ¶m = types[j][i]; const auto &value = values[j][i]; if (param.type.isTwoDimensionalPointer()) { - Tests::MethodParam valueParam{ param.type, param.underscoredName(), param.alignment }; + Tests::MethodParam valueParam{param.type, param.underscoredName(), param.alignment }; verboseParameter(methodDescription, valueParam, value, true); gen2DPointer(param, false); } else { @@ -529,6 +530,9 @@ void printer::TestsPrinter::printClassObject(const Tests::MethodDescription &met if (methodDescription.isClassMethod()) { const auto ¶m = methodDescription.classObj.value(); const auto &value = testCase.classPreValues.value(); + if (!typesHandler->getStructInfo(param.type).isCLike) { + strComment("struct/class maybe can't be construct"); + } verboseParameter(methodDescription, param, value, true); } } @@ -587,11 +591,11 @@ void TestsPrinter::verboseAsserts(const Tests::MethodDescription &methodDescript } else if (types::TypesHandler::isPointerToFunction(methodDescription.returnType) || types::TypesHandler::isArrayOfPointersToFunction(methodDescription.returnType)) { strComment("No check results for function returning pointer to function"); + } else if (methodDescription.isConstructor()) { + strComment("No check results for constructor in current version"); } else { auto visitor = visitor::VerboseAssertsReturnValueVisitor(typesHandler, this, predicateInfo); - if (!methodDescription.isConstructor()) { - visitor.visit(methodDescription, testCase); - } + visitor.visit(methodDescription, testCase); } if (!methodDescription.globalParams.empty()) { @@ -779,7 +783,7 @@ std::string TestsPrinter::constrVisitorFunctionCall(const Tests::MethodDescripti if (testCase.returnValue.view && testCase.returnValue.view->getEntryValue(nullptr) != PrinterUtils::C_NULL) { returnPointersCount = methodDescription.returnType.countReturnPointers(true); } - std::string functionCall = constrFunctionCall(methodDescription.name, methodArgs, "", classObjName, + std::string functionCall = constrFunctionCall(methodDescription.callName, methodArgs, "", classObjName, false, returnPointersCount, castType); if (methodDescription.isMoveConstructor()) { functionCall = "std::move(" + functionCall + ")"; diff --git a/server/src/stubs/StubSourcesFinder.cpp b/server/src/stubs/StubSourcesFinder.cpp index da5a5cbe1..ab7ebd140 100644 --- a/server/src/stubs/StubSourcesFinder.cpp +++ b/server/src/stubs/StubSourcesFinder.cpp @@ -26,7 +26,12 @@ std::vector StubSourcesFinder::excludeFind(const fs::path &testedFileP if (CollectionUtils::contains(libraryBitcodeFiles, bitcodeFile)) continue; fs::path sourcePath = - buildDatabase->getClientCompilationUnitInfo(bitcodeFile)->getSourcePath(); + buildDatabase->getClientCompilationUnitInfo(bitcodeFile)->getSourcePath(); + // TODO Support stubs for c++ code + if (Paths::isCXXFile(sourcePath)) { + LOG_S(DEBUG) << "CXX stubs not supported now, file: " << sourcePath; + continue; + } stubSources.emplace_back(std::move(sourcePath)); } return stubSources; diff --git a/server/src/types/Types.cpp b/server/src/types/Types.cpp index 7242a6fbb..9158c4f4f 100644 --- a/server/src/types/Types.cpp +++ b/server/src/types/Types.cpp @@ -7,6 +7,7 @@ #include "exceptions/UnImplementedException.h" #include "utils/PrinterUtils.h" #include "utils/SizeUtils.h" +#include "clang-utils/ClangUtils.h" #include "loguru.h" @@ -18,7 +19,7 @@ types::Type::Type(clang::QualType qualType, TypeName usedTypeName, const clang::SourceManager &sourceManager): mUsedType(std::move(usedTypeName)) { clang::QualType canonicalType = qualType.getCanonicalType(); auto pp = clang::PrintingPolicy(clang::LangOptions()); - fs::path sourceFilePath = sourceManager.getFileEntryForID(sourceManager.getMainFileID())->tryGetRealPathName().str(); + fs::path sourceFilePath = ClangUtils::getSourceFilePath(sourceManager); if (Paths::getSourceLanguage(sourceFilePath) == utbot::Language::CXX) { pp.adjustForCPlusPlus(); } diff --git a/server/src/types/Types.h b/server/src/types/Types.h index 6e1fda5cf..b2713ab56 100644 --- a/server/src/types/Types.h +++ b/server/src/types/Types.h @@ -26,6 +26,13 @@ namespace types { enum class PointerUsage; enum class ReferenceType; + enum AccessSpecifier { + AS_pubic, + AS_protected, + AS_private, + AS_none + }; + class Type { public: Type() = default; @@ -274,12 +281,6 @@ namespace types { size_t size; /// offset in @b bits, reassigned in structFields size_t offset = 0; - enum AccessSpecifier { - AS_pubic, - AS_protected, - AS_private, - AS_none - }; AccessSpecifier accessSpecifier = AS_pubic; }; @@ -306,6 +307,7 @@ namespace types { bool hasAnonymousStructOrUnion; bool isCLike; SubType subType; + bool hasDefaultPublicConstructor; }; struct EnumInfo: TypeInfo { diff --git a/server/src/types/TypesResolver.cpp b/server/src/types/TypesResolver.cpp index 3effaaa60..8b7e1b64b 100644 --- a/server/src/types/TypesResolver.cpp +++ b/server/src/types/TypesResolver.cpp @@ -2,15 +2,16 @@ #include "Paths.h" #include "clang-utils/ASTPrinter.h" +#include "clang-utils/ClangUtils.h" #include "fetchers/Fetcher.h" #include "fetchers/FetcherUtils.h" #include "utils/LogUtils.h" +#include "utils/path/FileSystemPath.h" #include #include "loguru.h" -#include "utils/path/FileSystemPath.h" #include TypesResolver::TypesResolver(const Fetcher *parent) : parent(parent) { @@ -67,7 +68,8 @@ std::string TypesResolver::getFullname(const clang::TagDecl *TD, const clang::Qu if (Paths::getSourceLanguage(sourceFilePath) == utbot::Language::C) { if (const auto *parentNode = llvm::dyn_cast(TD->getLexicalParent())) { - clang::QualType parentCanonicalType = parentNode->getASTContext().getTypeDeclType(parentNode).getCanonicalType(); + clang::QualType parentCanonicalType = parentNode->getASTContext().getTypeDeclType( + parentNode).getCanonicalType(); uint64_t parentID = types::Type::getIdFromCanonicalType(parentCanonicalType); if (!fullname[parentID].empty()) { fullname[id] = fullname[parentID] + "::" + fullname[id]; @@ -98,16 +100,14 @@ void TypesResolver::resolveStructEx(const clang::RecordDecl *D, const std::strin types::StructInfo structInfo; fs::path filename = sourceManager.getFilename(sourceManager.getSpellingLoc(D->getLocation())).str(); - fs::path sourceFilePath = sourceManager.getFileEntryForID( - sourceManager.getMainFileID())->tryGetRealPathName().str(); + fs::path sourceFilePath = ClangUtils::getSourceFilePath(sourceManager); structInfo.filePath = Paths::getCCJsonFileFullPath(filename, parent->buildRootPath); structInfo.name = getFullname(D, canonicalType, id, sourceFilePath); structInfo.hasAnonymousStructOrUnion = false; if (Paths::getSourceLanguage(sourceFilePath) == utbot::Language::CXX) { - const auto *cppD = llvm::dyn_cast(D); + const auto *cppD = llvm::dyn_cast(D); structInfo.isCLike = cppD != nullptr && cppD->isCLike(); - } - else { + } else { structInfo.isCLike = true; } @@ -121,7 +121,7 @@ void TypesResolver::resolveStructEx(const clang::RecordDecl *D, const std::strin << "\tFile path: " << structInfo.filePath.string() << ""; std::vector fields; - for (const clang::FieldDecl *F : D->fields()) { + for (const clang::FieldDecl *F: D->fields()) { if (F->isUnnamedBitfield()) { continue; } @@ -134,14 +134,14 @@ void TypesResolver::resolveStructEx(const clang::RecordDecl *D, const std::strin field.type = types::Type(paramType, paramType.getAsString(), sourceManager); if (field.type.isPointerToFunction()) { structInfo.functionFields[field.name] = ParamsHandler::getFunctionPointerDeclaration( - F->getFunctionType(), field.name, sourceManager, - field.type.isArrayOfPointersToFunction()); + F->getFunctionType(), field.name, sourceManager, + field.type.isArrayOfPointersToFunction()); auto returnType = F->getFunctionType()->getReturnType(); if (returnType->isPointerType() && returnType->getPointeeType()->isStructureType() && returnType->getPointeeType().getBaseTypeIdentifier()) { std::string structName = - returnType->getPointeeType().getBaseTypeIdentifier()->getName().str(); + returnType->getPointeeType().getBaseTypeIdentifier()->getName().str(); if (!CollectionUtils::containsKey((*parent->structsDeclared).at(sourceFilePath), structName)) { (*parent->structsToDeclare)[sourceFilePath].insert(structName); @@ -149,8 +149,8 @@ void TypesResolver::resolveStructEx(const clang::RecordDecl *D, const std::strin } } else if (field.type.isArrayOfPointersToFunction()) { structInfo.functionFields[field.name] = ParamsHandler::getFunctionPointerDeclaration( - F->getType()->getPointeeType()->getPointeeType()->getAs(), - field.name, sourceManager, field.type.isArrayOfPointersToFunction()); + F->getType()->getPointeeType()->getPointeeType()->getAs(), + field.name, sourceManager, field.type.isArrayOfPointersToFunction()); } field.size = F->isBitField() ? F->getBitWidthValue(context) : context.getTypeSize(F->getType()); field.offset = context.getFieldOffset(F); @@ -158,22 +158,9 @@ void TypesResolver::resolveStructEx(const clang::RecordDecl *D, const std::strin ss << "\n\t" << field.type.typeName() << " " << field.name << ";"; } if (Paths::getSourceLanguage(sourceFilePath) == utbot::Language::CXX) { - switch (F->getAccess()) { - case clang::AccessSpecifier::AS_private : - field.accessSpecifier = types::Field::AS_private; - break; - case clang::AccessSpecifier::AS_protected : - field.accessSpecifier = types::Field::AS_protected; - break; - case clang::AccessSpecifier::AS_public : - field.accessSpecifier = types::Field::AS_pubic; - break; - case clang::AccessSpecifier::AS_none : - field.accessSpecifier = types::Field::AS_none; - break; - } + field.accessSpecifier = getAcessSpecifier(F); } else { - field.accessSpecifier = types::Field::AS_pubic; + field.accessSpecifier = types::AccessSpecifier::AS_pubic; } fields.push_back(field); } @@ -181,6 +168,23 @@ void TypesResolver::resolveStructEx(const clang::RecordDecl *D, const std::strin structInfo.size = getRecordSize(D); structInfo.alignment = getDeclAlignment(D); structInfo.subType = subType; + structInfo.hasDefaultPublicConstructor = false; + if (auto CXXD = dynamic_cast(D)) { + LOG_S(MAX) << "Struct/Class " << structInfo.name << " CXX class"; + if (!CXXD->isCLike()) { + structInfo.isCLike = false; + } + for (const auto &ctor: CXXD->ctors()) { + if (ctor->isDefaultConstructor() && !ctor->isDeleted() && + getAcessSpecifier(ctor) == types::AccessSpecifier::AS_pubic) { + structInfo.hasDefaultPublicConstructor = true; + break; + } + } + LOG_IF_S(MAX, !structInfo.hasDefaultPublicConstructor) << "Struct/Class " + << structInfo.name + << " hasn't default public constructor"; + } addInfo(id, parent->projectTypes->structs, structInfo); ss << "\nName: " << structInfo.name << ", id: " << id << " , size: " << structInfo.size << "\n"; @@ -221,10 +225,10 @@ void TypesResolver::resolveEnum(const clang::EnumDecl *EN, const std::string &na } types::EnumInfo enumInfo; - fs::path sourceFilePath = sourceManager.getFileEntryForID(sourceManager.getMainFileID())->tryGetRealPathName().str(); + fs::path sourceFilePath = ClangUtils::getSourceFilePath(sourceManager); enumInfo.name = getFullname(EN, canonicalType, id, sourceFilePath); enumInfo.filePath = Paths::getCCJsonFileFullPath( - sourceManager.getFilename(EN->getLocation()).str(), parent->buildRootPath.string()); + sourceManager.getFilename(EN->getLocation()).str(), parent->buildRootPath.string()); clang::QualType promotionType = EN->getPromotionType(); enumInfo.size = context.getTypeSize(promotionType); @@ -258,7 +262,6 @@ void TypesResolver::updateMaximumAlignment(size_t alignment) const { } - void TypesResolver::resolve(const clang::QualType &type) { clang::TagDecl *tagDecl = type->getAsTagDecl(); if (tagDecl == nullptr) { diff --git a/server/src/utils/KleeUtils.cpp b/server/src/utils/KleeUtils.cpp index 132872b69..befd88de8 100644 --- a/server/src/utils/KleeUtils.cpp +++ b/server/src/utils/KleeUtils.cpp @@ -57,11 +57,11 @@ namespace KleeUtils { }; const std::string OPERATOR = "operator"; - - if (methodName.size() > OPERATOR.size() && methodName.substr(0, OPERATOR.size()) == OPERATOR) { + size_t operatorStartPos = methodName.find(OPERATOR); + if (operatorStartPos != std::string::npos) { std::stringstream newName; - newName << "operator"; - std::string_view operatorEnd = methodName.substr(8, methodName.size()); + newName << methodName.substr(0, operatorStartPos + OPERATOR.size()); + std::string_view operatorEnd = methodName.substr(operatorStartPos + OPERATOR.size(), std::string::npos); auto operator_name = CPP_OPERATORS.find(operatorEnd); if (isBrackets(operatorEnd, '(')) { newName << "_parentheses"; @@ -83,7 +83,9 @@ namespace KleeUtils { const std::string &methodName, bool needToMangle, bool isWrapped) { - std::string methodNewName = getRenamedOperator(methodName); + std::string methodNewName = methodName; + StringUtils::replaceAll(methodNewName, ':', '_'); + methodNewName = getRenamedOperator(methodNewName); if (isWrapped) { methodNewName += PrinterUtils::WRAPPED_SUFFIX; } diff --git a/server/src/utils/LinkerUtils.cpp b/server/src/utils/LinkerUtils.cpp index 33b494d10..77e3e772b 100644 --- a/server/src/utils/LinkerUtils.cpp +++ b/server/src/utils/LinkerUtils.cpp @@ -5,14 +5,13 @@ #include "exceptions/UnImplementedException.h" namespace LinkerUtils { - static inline const std::string STUB_SUFFIX = "_stub"; fs::path applySuffix(const fs::path &output, BuildResult::Type unitType, const std::string &suffixForParentOfStubs) { switch (unitType) { case BuildResult::Type::ALL_STUBS: - return Paths::addSuffix(output, STUB_SUFFIX); + return Paths::addSuffix(output, Paths::STUB_SUFFIX); case BuildResult::Type::ANY_STUBS: return Paths::addSuffix(output, suffixForParentOfStubs); case BuildResult::Type::NO_STUBS: diff --git a/server/src/utils/PrinterUtils.cpp b/server/src/utils/PrinterUtils.cpp index 7611aa1fb..81fd52137 100644 --- a/server/src/utils/PrinterUtils.cpp +++ b/server/src/utils/PrinterUtils.cpp @@ -27,7 +27,7 @@ namespace PrinterUtils { return objectName; } const std::string &fieldName = field.name; - if (field.accessSpecifier == types::Field::AS_pubic) { + if (field.accessSpecifier == types::AccessSpecifier::AS_pubic) { if (fieldName.empty()) { return objectName; } diff --git a/server/src/utils/StubsUtils.cpp b/server/src/utils/StubsUtils.cpp index 70222fd0d..0765ef99a 100644 --- a/server/src/utils/StubsUtils.cpp +++ b/server/src/utils/StubsUtils.cpp @@ -8,7 +8,7 @@ namespace StubsUtils { bool omitSuffix) { std::string stubName = "*" + scopeName.value_or("") + "_" + methodName; if (!omitSuffix) { - stubName += "_" + paramName + "_stub"; + stubName += "_" + paramName + Paths::STUB_SUFFIX; } else { stubName = stubName.substr(1); } @@ -24,7 +24,7 @@ namespace StubsUtils { bool omitSuffix) { std::string stubName = "*" + structName; if (!omitSuffix) { - stubName += "_" + fieldName + "_stub"; + stubName += "_" + fieldName + Paths::STUB_SUFFIX; } else { stubName = stubName.substr(1); } diff --git a/server/test/framework/KleeGen_Tests.cpp b/server/test/framework/KleeGen_Tests.cpp index 51486f1c6..8a3445dae 100644 --- a/server/test/framework/KleeGen_Tests.cpp +++ b/server/test/framework/KleeGen_Tests.cpp @@ -68,7 +68,7 @@ namespace { KleeGenerator generator(&testGen, typesHandler, {}); fs::path sourceFilePath = *testSuite.sourcesFilePaths.begin(); - auto actualFilePath = generator.defaultBuild(sourceFilePath); - EXPECT_TRUE(fs::exists(actualFilePath.getOpt().value())); + auto actualFilePath = generator.defaultBuild(sourceFilePath).getOpt().value(); + EXPECT_TRUE(fs::exists(actualFilePath)) << testUtils::fileNotExistsMessage(actualFilePath); } } diff --git a/server/test/framework/Server_Tests.cpp b/server/test/framework/Server_Tests.cpp index a7ee01824..736acb9fa 100644 --- a/server/test/framework/Server_Tests.cpp +++ b/server/test/framework/Server_Tests.cpp @@ -1123,7 +1123,7 @@ namespace { "sqr_positive"); } - TEST_P(Parameterized_Server_Test, Class_test1) { + TEST_P(Parameterized_Server_Test, Class_test1_cpp) { auto request = createClassRequest(projectName, suitePath, buildDirRelativePath, srcPaths, multiple_classes_h, 6); auto testGen = ClassTestGen(*request, writer.get(), TESTMODE); @@ -1137,9 +1137,9 @@ namespace { "get1"); } - TEST_P(Parameterized_Server_Test, Class_test2) { + TEST_P(Parameterized_Server_Test, Class_test2_cpp) { auto request = createClassRequest(projectName, suitePath, buildDirRelativePath, srcPaths, - multiple_classes_h, 11); + multiple_classes_h, 14); auto testGen = ClassTestGen(*request, writer.get(), TESTMODE); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -1151,9 +1151,9 @@ namespace { "get2"); } - TEST_P(Parameterized_Server_Test, DISABLED_Class_test3) { + TEST_P(Parameterized_Server_Test, DISABLED_Class_test3_cpp) { auto request = createClassRequest(projectName, suitePath, buildDirRelativePath, srcPaths, - multiple_classes_h, 14); + multiple_classes_h, 18); auto testGen = ClassTestGen(*request, writer.get(), TESTMODE); Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); ASSERT_TRUE(status.ok()) << status.error_message(); diff --git a/server/test/framework/Syntax_Tests.cpp b/server/test/framework/Syntax_Tests.cpp index 3cff24150..3d8347b17 100644 --- a/server/test/framework/Syntax_Tests.cpp +++ b/server/test/framework/Syntax_Tests.cpp @@ -63,6 +63,7 @@ namespace { fs::path namespace_cpp = getTestFilePath("namespace.cpp"); fs::path rvalue_reference_cpp = getTestFilePath("function_with_rvalue_params.cpp"); fs::path hard_linked_list_c = getTestFilePath("hard_linked_list.c"); + fs::path unsupported_class_cpp = getTestFilePath("unsupported_class.cpp"); void SetUp() override { clearEnv(CompilationUtils::CompilerName::CLANG); @@ -2606,7 +2607,7 @@ namespace { })); } - TEST_F(Syntax_Test, Default_constructor) { + TEST_F(Syntax_Test, Default_constructor_cpp) { auto [testGen, status] = createTestForFunction(constructors_cpp, 59); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -2614,7 +2615,7 @@ namespace { testUtils::checkMinNumberOfTests(testGen.tests.at(constructors_cpp).methods.begin().value().testCases, 1); } - TEST_F(Syntax_Test, Constructor_with_parameters) { + TEST_F(Syntax_Test, Constructor_with_parameters_cpp) { auto [testGen, status] = createTestForFunction(constructors_cpp, 86); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -2622,7 +2623,7 @@ namespace { testUtils::checkMinNumberOfTests(testGen.tests.at(constructors_cpp).methods.begin().value().testCases, 1); } - TEST_F(Syntax_Test, Copy_constructor) { + TEST_F(Syntax_Test, Copy_constructor_cpp) { auto [testGen, status] = createTestForFunction(constructors_cpp, 37); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -2630,7 +2631,7 @@ namespace { testUtils::checkMinNumberOfTests(testGen.tests.at(constructors_cpp).methods.begin().value().testCases, 1); } - TEST_F(Syntax_Test, Move_constructor) { + TEST_F(Syntax_Test, Move_constructor_cpp) { auto [testGen, status] = createTestForFunction(constructors_cpp, 67); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -2638,7 +2639,7 @@ namespace { testUtils::checkMinNumberOfTests(testGen.tests.at(constructors_cpp).methods.begin().value().testCases, 1); } - TEST_F(Syntax_Test, Constructor_with_pointers) { + TEST_F(Syntax_Test, Constructor_with_pointers_cpp) { auto [testGen, status] = createTestForFunction(constructors_cpp, 21); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -2646,7 +2647,7 @@ namespace { testUtils::checkMinNumberOfTests(testGen.tests.at(constructors_cpp).methods.begin().value().testCases, 2); } - TEST_F(Syntax_Test, Constructor_with_if_stmt) { + TEST_F(Syntax_Test, Constructor_with_if_stmt_cpp) { auto [testGen, status] = createTestForFunction(constructors_cpp, 9); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -2730,7 +2731,7 @@ namespace { ); } - TEST_F(Syntax_Test, example_namespace) { + TEST_F(Syntax_Test, example_namespace_cpp) { auto [testGen, status] = createTestForFunction(namespace_cpp, 3); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -2793,7 +2794,7 @@ namespace { ); } - TEST_F(Syntax_Test, multiple_rvalue_params) { + TEST_F(Syntax_Test, multiple_rvalue_params_cpp) { auto [testGen, status] = createTestForFunction(rvalue_reference_cpp, 9); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -2832,7 +2833,7 @@ namespace { } - TEST_F(Syntax_Test, const_rvalue_reference) { + TEST_F(Syntax_Test, const_rvalue_reference_cpp) { auto [testGen, status] = createTestForFunction(rvalue_reference_cpp, 17); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -2873,7 +2874,7 @@ namespace { ); } - TEST_F(Syntax_Test, return_and_get_params) { + TEST_F(Syntax_Test, return_and_get_params_cpp) { auto [testGen, status] = createTestForFunction(rvalue_reference_cpp, 28); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -2913,7 +2914,7 @@ namespace { ); } - TEST_F(Syntax_Test, rvalue_struct_param) { + TEST_F(Syntax_Test, rvalue_struct_param_cpp) { auto [testGen, status] = createTestForFunction(rvalue_reference_cpp, 38); ASSERT_TRUE(status.ok()) << status.error_message(); @@ -2934,6 +2935,14 @@ namespace { ); } + TEST_F(Syntax_Test, unsupported_clases_cpp) { + std::vector lines = {4, 8, 12, 16}; + for (const auto &line: lines) { + auto [testGen, status] = createTestForFunction(unsupported_class_cpp, line); + ASSERT_FALSE(status.ok()); + } + } + TEST_F(Syntax_Test, simple_getc) { auto [testGen, status] = createTestForFunction(input_output_c, 4); diff --git a/server/test/suites/server/multiple_classes.cpp b/server/test/suites/server/multiple_classes.cpp index cef9e7a7d..57a6b67ce 100644 --- a/server/test/suites/server/multiple_classes.cpp +++ b/server/test/suites/server/multiple_classes.cpp @@ -11,3 +11,10 @@ int second_class::get2() { int second_class::third_class::get3() { return 3; } + +first_class::first_class() {} + +second_class::second_class() {} + +second_class::third_class::third_class() {} + diff --git a/server/test/suites/server/multiple_classes.h b/server/test/suites/server/multiple_classes.h index a27151ff5..25b124439 100644 --- a/server/test/suites/server/multiple_classes.h +++ b/server/test/suites/server/multiple_classes.h @@ -4,15 +4,22 @@ class first_class { public: + first_class(); + int get1(); }; struct second_class { public: + second_class(); + struct third_class { + third_class(); + public: int get3(); }; + int get2(); }; diff --git a/server/test/suites/syntax/CMakeLists.txt b/server/test/suites/syntax/CMakeLists.txt index dc977c00f..7631c4aaa 100644 --- a/server/test/suites/syntax/CMakeLists.txt +++ b/server/test/suites/syntax/CMakeLists.txt @@ -43,4 +43,5 @@ add_executable(syntax1 file.c bitfields.c function_with_rvalue_params.cpp - hard_linked_list.c) + hard_linked_list.c + unsupported_class.cpp) diff --git a/server/test/suites/syntax/unsupported_class.cpp b/server/test/suites/syntax/unsupported_class.cpp new file mode 100644 index 000000000..ddee6fabe --- /dev/null +++ b/server/test/suites/syntax/unsupported_class.cpp @@ -0,0 +1,17 @@ +#include "unsupported_class.h" + +int private_array::sum() { + return values[0] + values[1]; +} + +private_array return_private_array() { + return private_array(); +} + +bool parameter_private_array(private_array pa) { + return false; +} + +int delete_constructor::sum() { + return values[0] + values[1]; +} diff --git a/server/test/suites/syntax/unsupported_class.h b/server/test/suites/syntax/unsupported_class.h new file mode 100644 index 000000000..8a2c3c21e --- /dev/null +++ b/server/test/suites/syntax/unsupported_class.h @@ -0,0 +1,35 @@ +#ifndef UTBOTCPP_UNSUPPORTED_CLASS_H +#define UTBOTCPP_UNSUPPORTED_CLASS_H + + +class private_array { +private: + int values[2]; +public: + int sum(); +}; + +private_array return_private_array(); + +bool parameter_private_array(private_array pa); + +class delete_constructor { +public: + delete_constructor() = delete; + + int values[5]; + + int sum(); +}; + +class private_constructor { + private_constructor() = default; + +public: + int values[2]; + + int sum(); +}; + + +#endif //UTBOTCPP_UNSUPPORTED_CLASS_H