Skip to content

Commit 7c06e1f

Browse files
committed
Fix generate by class
1 parent 7cd1f06 commit 7c06e1f

32 files changed

+364
-172
lines changed

docker/release_distribution_scripts/utbot_run_system.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ IS_SUSE="$(grep '^NAME=' /etc/os-release | tr '[:upper:]' '[:lower:]' | grep sus
5050
# Setting environment variables for debian packages
5151
export PATH=$UTBOT_ALL/debs-install/usr/bin:$PATH
5252
export LD_LIBRARY_PATH=$UTBOT_ALL/install/lib:$UTBOT_ALL/debs-install/lib/x86_64-linux-gnu:$UTBOT_ALL/debs-install/usr/lib/x86_64-linux-gnu:$UTBOT_ALL/debs-install/usr/local/lib:$UTBOT_ALL/debs-install/lib:$UTBOT_ALL/debs-install/usr/lib:$LD_LIBRARY_PATH
53-
export CPATH=$UTBOT_ALL/debs-install/usr/include/x86_64-linux-gnu/9/include:$UTBOT_ALL/debs-install/usr/include/x86_64-linux-gnu:$UTBOT_ALL/debs-install/usr/include:$CPATH
53+
export CPATH=$UTBOT_ALL/debs-install/usr/lib/gcc/x86_64-linux-gnu/9/include:$UTBOT_ALL/debs-install/usr/local/include:$UTBOT_ALL/debs-install/usr/include/x86_64-linux-gnu:$UTBOT_ALL/debs-install/usr/include:$CPATH
5454
export CPLUS_INCLUDE_PATH=$UTBOT_ALL/debs-install/usr/include/c++/9:$UTBOT_ALL/debs-install/usr/include/x86_64-linux-gnu/c++/9:$UTBOT_ALL/debs-install/usr/include/c++/9/backward:$CPLUS_INCLUDE_PATH
5555
export LDFLAGS="-fuse-ld=gold $LDFLAGS"
5656

server/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ target_link_libraries(
157157
UnitTestBotLib
158158
)
159159

160+
add_test(UTBot_UnitTests UTBot_UnitTests)
161+
160162
install(TARGETS utbot
161163
DESTINATION ${CMAKE_INSTALL_PREFIX}
162164
)
Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright (c) Huawei Technologies Co., Ltd. 2012-2021. All rights reserved.
33
*/
44

5-
#include "StmtBordersFinder.h"
5+
#include "BordersFinder.h"
66

77
#include "Paths.h"
88
#include "clang-utils/ASTPrinter.h"
@@ -17,23 +17,39 @@ using namespace llvm;
1717
using namespace clang::ast_matchers;
1818
using namespace clang::tooling;
1919

20-
StmtBordersFinder::StmtBordersFinder(const fs::path &filePath,
21-
unsigned line,
22-
const shared_ptr<CompilationDatabase> &compilationDatabase,
23-
const fs::path &compileCommandsJsonPath)
24-
: line(line), clangToolRunner(compilationDatabase) {
20+
BordersFinder::BordersFinder(const fs::path &filePath,
21+
unsigned line,
22+
const shared_ptr<CompilationDatabase> &compilationDatabase,
23+
const fs::path &compileCommandsJsonPath)
24+
: line(line), classBorder(std::nullopt), clangToolRunner(compilationDatabase) {
2525
buildRootPath = Paths::subtractPath(compileCommandsJsonPath.string(), CompilationUtils::MOUNTED_CC_JSON_DIR_NAME);
2626
lineInfo.filePath = filePath;
2727
}
2828

29-
void StmtBordersFinder::run(const MatchFinder::MatchResult &Result) {
29+
void BordersFinder::run(const MatchFinder::MatchResult &Result) {
3030
LOG_SCOPE_FUNCTION(MAX);
31-
if (const auto *FS = Result.Nodes.getNodeAs<FunctionDecl>(Matchers::FUNCTION_DEF)) {
31+
if (const auto *ST = Result.Nodes.getNodeAs<clang::CXXRecordDecl>(Matchers::STRUCT_OR_CLASS_JUST_DECL)) {
32+
SourceManager &sourceManager = Result.Context->getSourceManager();
33+
fs::path path = sourceManager.getFileEntryForID(sourceManager.getMainFileID())
34+
->tryGetRealPathName()
35+
.str();
36+
auto borders = getBorders(sourceManager, ST->getSourceRange());
37+
if (!containsLine(borders) || (classBorder.has_value() && !(borders < classBorder.value()))) {
38+
return;
39+
}
40+
classBorder = borders;
41+
lineInfo.begin = borders.start.line;
42+
lineInfo.end = borders.end.line;
43+
lineInfo.scopeName = ST->getNameAsString();
44+
lineInfo.initialized = true;
45+
LOG_S(MAX) << "Class name: " << ST->getNameAsString();
46+
LOG_S(MAX) << "Class's borders: " << lineInfo.begin << ' ' << lineInfo.end;
47+
} else if (const auto *FS = Result.Nodes.getNodeAs<FunctionDecl>(Matchers::FUNCTION_DEF)) {
3248
SourceManager &sourceManager = Result.Context->getSourceManager();
3349

3450
fs::path path = sourceManager.getFileEntryForID(sourceManager.getMainFileID())
35-
->tryGetRealPathName()
36-
.str();
51+
->tryGetRealPathName()
52+
.str();
3753
Stmt *currentStmt = FS->getBody();
3854
if ((currentStmt == nullptr) || !containsLine(getFunctionBordersLines(sourceManager, FS))) {
3955
return;
@@ -51,24 +67,24 @@ void StmtBordersFinder::run(const MatchFinder::MatchResult &Result) {
5167
hasInnerChild = true;
5268
if (isa<IfStmt>(currentStmt) || isa<ForStmt>(currentStmt) ||
5369
isa<WhileStmt>(currentStmt)) {
54-
if (line == borders.first) {
70+
if (line == borders.start.line) {
5571
hasInnerChild = false;
5672
} else {
5773
lineInfo.wrapInBrackets = true;
5874
lineInfo.insertAfter = false;
5975
}
6076
}
61-
if (line == borders.first && isa<ReturnStmt>(currentStmt)) {
77+
if (line == borders.start.line && isa<ReturnStmt>(currentStmt)) {
6278
lineInfo.insertAfter = false;
6379
}
6480
break;
6581
}
6682
}
6783
}
68-
auto *nodeParent = (CXXRecordDecl *)FS->getParent();
84+
auto *nodeParent = (CXXRecordDecl *) FS->getParent();
6985
auto borders = getStmtBordersLines(sourceManager, currentStmt);
70-
lineInfo.begin = borders.first;
71-
lineInfo.end = borders.second;
86+
lineInfo.begin = borders.start.line;
87+
lineInfo.end = borders.end.line;
7288
lineInfo.scopeName = nodeParent != nullptr ? nodeParent->getNameAsString() : path.stem().string();
7389
lineInfo.methodName = FS->getNameAsString();
7490
const clang::QualType realReturnType = FS->getReturnType().getCanonicalType();
@@ -84,8 +100,8 @@ void StmtBordersFinder::run(const MatchFinder::MatchResult &Result) {
84100
break;
85101
}
86102
auto tempBorders = getStmtBordersLinesDynamic(sourceManager, parents[0]);
87-
int from = tempBorders.first;
88-
int to = tempBorders.second;
103+
int from = tempBorders.start.line;
104+
int to = tempBorders.end.line;
89105
if (to - from > 1) {
90106
break;
91107
}
@@ -94,45 +110,52 @@ void StmtBordersFinder::run(const MatchFinder::MatchResult &Result) {
94110
}
95111
lineInfo.stmtString = strRepresentation;
96112
LOG_S(MAX) << "Method name: " << lineInfo.methodName << "\n"
97-
<< "Method's borders: " << borders.first << ' ' << borders.second;
113+
<< "Method's borders: " << borders.start.line << ' ' << borders.end.line;
98114
LOG_S(DEBUG) << "Statement string: " << lineInfo.stmtString;
99115
}
100116
}
101117

102-
LineInfo StmtBordersFinder::getLineInfo() {
118+
LineInfo BordersFinder::getLineInfo() {
103119
return lineInfo;
104120
}
105121

106-
std::pair<unsigned, unsigned> StmtBordersFinder::getFunctionBordersLines(const SourceManager &srcMng, const FunctionDecl *FS) {
122+
BordersFinder::Borders BordersFinder::getFunctionBordersLines(const SourceManager &srcMng, const FunctionDecl *FS) {
107123
auto currentStmt = FS->getBody();
108-
auto bodyBorders = getStmtBordersLines(srcMng, currentStmt);
109-
auto declBorders = getStmtBordersLines(srcMng, FS->getSourceRange());
110-
return {declBorders.first, bodyBorders.second};
124+
return getStmtBordersLines(srcMng, currentStmt);
111125
}
112126

113-
std::pair<unsigned, unsigned> StmtBordersFinder::getStmtBordersLines(const SourceManager &srcMng, const Stmt *st) {
127+
BordersFinder::Borders BordersFinder::getStmtBordersLines(const SourceManager &srcMng, const Stmt *st) {
114128
return getStmtBordersLinesDynamic(srcMng, clang::ast_type_traits::DynTypedNode::create(*st));
115129
}
116130

117-
std::pair<unsigned, unsigned> StmtBordersFinder::getStmtBordersLinesDynamic(const SourceManager &srcMng,
118-
const clang::ast_type_traits::DynTypedNode st) {
131+
BordersFinder::Borders BordersFinder::getStmtBordersLinesDynamic(const SourceManager &srcMng,
132+
const clang::ast_type_traits::DynTypedNode st) {
119133
auto sourceRange = st.getSourceRange();
120-
return getStmtBordersLines(srcMng, sourceRange);
134+
return getBorders(srcMng, sourceRange);
121135
}
122136

123-
std::pair<unsigned int, unsigned int>
124-
StmtBordersFinder::getStmtBordersLines(const SourceManager &srcMng, const SourceRange &sourceRange) {
137+
BordersFinder::Borders BordersFinder::getBorders(const SourceManager &srcMng, const SourceRange &sourceRange) {
125138
auto beginLine = srcMng.getExpansionLineNumber(sourceRange.getBegin());
126139
auto endLine = srcMng.getExpansionLineNumber(sourceRange.getEnd());
127-
return { beginLine, endLine };
140+
auto beginColumn = srcMng.getExpansionColumnNumber(sourceRange.getBegin());
141+
auto endColumn = srcMng.getExpansionColumnNumber(sourceRange.getEnd());
142+
return {{beginLine, beginColumn},
143+
{endLine, endColumn}};
128144
}
129145

130-
bool StmtBordersFinder::containsLine(std::pair<unsigned, unsigned> b) const {
131-
return line >= b.first && line <= b.second;
146+
bool BordersFinder::containsLine(BordersFinder::Borders b) const {
147+
return line >= b.start.line && line <= b.end.line;
132148
}
133149

134-
void StmtBordersFinder::launch() {
150+
void BordersFinder::findFunction() {
135151
MatchFinder finder;
136152
finder.addMatcher(Matchers::functionDefinitionMatcher, this);
137153
clangToolRunner.run(lineInfo.filePath, newFrontendActionFactory(&finder).get());
138154
}
155+
156+
void BordersFinder::findClass() {
157+
MatchFinder finder;
158+
finder.addMatcher(Matchers::classJustDeclMatcher, this);
159+
finder.addMatcher(Matchers::structJustDeclMatcher, this);
160+
clangToolRunner.run(lineInfo.filePath, newFrontendActionFactory(&finder).get(), false, std::nullopt, false);
161+
}

server/src/BordersFinder.h

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) Huawei Technologies Co., Ltd. 2012-2021. All rights reserved.
3+
*/
4+
5+
#ifndef UNITTESTBOT_BORDERSFINDER_H
6+
#define UNITTESTBOT_BORDERSFINDER_H
7+
8+
#include "fetchers/FetcherUtils.h"
9+
#include "LineInfo.h"
10+
11+
#include <clang/ASTMatchers/ASTMatchFinder.h>
12+
#include <clang/ASTMatchers/ASTMatchers.h>
13+
#include <clang/Rewrite/Core/Rewriter.h>
14+
#include <clang/Rewrite/Frontend/Rewriters.h>
15+
#include <clang/Tooling/CommonOptionsParser.h>
16+
#include <clang/Tooling/Tooling.h>
17+
18+
#include "utils/path/FileSystemPath.h"
19+
#include <string>
20+
#include <utility>
21+
22+
using std::string;
23+
using std::unique_ptr;
24+
using std::shared_ptr;
25+
26+
class BordersFinder : public clang::ast_matchers::MatchFinder::MatchCallback {
27+
public:
28+
BordersFinder(const fs::path &filePath,
29+
unsigned line,
30+
const shared_ptr<clang::tooling::CompilationDatabase> &compilationDatabase,
31+
const fs::path &compileCommandsJsonPath);
32+
33+
void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) override;
34+
35+
void findFunction();
36+
37+
void findClass();
38+
39+
LineInfo getLineInfo();
40+
41+
private:
42+
unsigned line;
43+
LineInfo lineInfo{};
44+
fs::path buildRootPath;
45+
struct Borders {
46+
struct Position {
47+
unsigned line;
48+
unsigned column;
49+
};
50+
Position start;
51+
Position end;
52+
53+
friend bool operator<(const Borders& lhs, const Borders& rhs) {
54+
return (rhs.start.line < lhs.start.line ||
55+
(rhs.start.line == lhs.start.line && rhs.start.column <= lhs.start.column)) &&
56+
(rhs.end.line > lhs.start.line ||
57+
(rhs.end.line == lhs.start.line && rhs.end.column >= lhs.start.column));
58+
}
59+
};
60+
std::optional<Borders> classBorder;
61+
ClangToolRunner clangToolRunner;
62+
63+
// TODO: use rewriter for insertion
64+
clang::Rewriter rewrt;
65+
66+
Borders getStmtBordersLines(const clang::SourceManager &srcMng, const clang::Stmt *st);
67+
68+
Borders getStmtBordersLinesDynamic(const clang::SourceManager &srcMng, clang::ast_type_traits::DynTypedNode st);
69+
70+
[[nodiscard]] bool containsLine(Borders b) const;
71+
72+
static Borders getBorders(const clang::SourceManager &srcMng, const clang::SourceRange &sourceRange);
73+
74+
Borders getFunctionBordersLines(const clang::SourceManager &srcMng, const clang::FunctionDecl *FS);
75+
};
76+
77+
78+
#endif //UNITTESTBOT_BORDERSFINDER_H

server/src/KleeGenerator.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include "ProjectContext.h"
1010
#include "Result.h"
1111
#include "SettingsContext.h"
12-
#include "StmtBordersFinder.h"
12+
#include "BordersFinder.h"
1313
#include "Tests.h"
1414
#include "building/BuildDatabase.h"
1515
#include "exceptions/CompilationDatabaseException.h"

server/src/Paths.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,20 @@ namespace Paths {
319319
return makefileDir / makefileName;
320320
}
321321

322+
std::optional<fs::path> headerPathToSourcePath(const fs::path &source) {
323+
std::vector<std::string> sourceExtensions({".cc", ".cp", ".cpp", ".c++", ".cxx"});
324+
if (Paths::isHeaderFile(source)) {
325+
for (const std::string &extension : sourceExtensions) {
326+
fs::path sourceFilePath = replaceExtension(source, extension);
327+
if (fs::exists(sourceFilePath)) {
328+
return {sourceFilePath};
329+
}
330+
}
331+
}
332+
return std::nullopt;
333+
}
334+
335+
322336
fs::path getRelativeDirPath(const utbot::ProjectContext &projectContext,
323337
const fs::path &source) {
324338
return fs::relative(source.parent_path(), projectContext.projectPath);

server/src/Paths.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,13 +221,13 @@ namespace Paths {
221221

222222
static inline bool isCXXFile(const fs::path &path) {
223223
return path.extension() == ".cc" || path.extension() == ".cp" ||
224-
path.extension() == ".cpp" || path.extension() == "c++" ||
224+
path.extension() == ".cpp" || path.extension() == ".c++" ||
225225
path.extension() == ".cxx";
226226
}
227227

228228
static inline bool isHppFile(const fs::path &path) {
229229
return path.extension() == ".hh" || path.extension() == ".hpp" ||
230-
path.extension() == "hxx";
230+
path.extension() == ".hxx";
231231
}
232232

233233
static inline bool isHeaderFile(const fs::path &path) {
@@ -354,6 +354,8 @@ namespace Paths {
354354
fs::path getMakefilePathFromSourceFilePath(const utbot::ProjectContext &projectContext, const fs::path &sourceFilePath);
355355

356356
fs::path getStubsMakefilePath(const utbot::ProjectContext &projectContext, const fs::path &sourceFilePath);
357+
358+
std::optional<fs::path> headerPathToSourcePath(const fs::path &source);
357359
//endregion
358360

359361
//region stubs

server/src/Server.cpp

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -218,28 +218,39 @@ Status Server::TestsGenServiceImpl::ProcessBaseTestRequest(BaseTestGen &testGen,
218218
auto lineTestGen = dynamic_cast<LineTestGen *>(&testGen);
219219

220220
if (lineTestGen != nullptr) {
221-
lineInfo = getLineInfo(*lineTestGen);
222-
CollectionUtils::erase_if(testGen.tests.at(lineInfo->filePath).methods,
223-
[&lineInfo](const auto &methodDescription) {
224-
return methodDescription.name != lineInfo->methodName;
225-
});
221+
if (isSameType<ClassTestGen>(testGen) && Paths::isHeaderFile(lineTestGen->filePath)) {
222+
BordersFinder classFinder(lineTestGen->filePath, lineTestGen->line,
223+
lineTestGen->compilationDatabase,
224+
lineTestGen->compileCommandsJsonPath);
225+
classFinder.findClass();
226+
lineInfo = std::make_shared<LineInfo>(classFinder.getLineInfo());
227+
lineInfo->filePath = lineTestGen->testingMethodsSourcePaths[0];
228+
CollectionUtils::erase_if(testGen.tests.at(lineInfo->filePath).methods,
229+
[&lineInfo](const auto &methodDescription) {
230+
return methodDescription.className != lineInfo->scopeName;
231+
});
232+
} else {
233+
lineInfo = getLineInfo(*lineTestGen);
234+
CollectionUtils::erase_if(testGen.tests.at(lineInfo->filePath).methods,
235+
[&lineInfo](const auto &methodDescription) {
236+
return methodDescription.name != lineInfo->methodName;
237+
});
238+
}
226239
}
227240

228241
FeaturesFilter::filter(testGen.settingsContext, typesHandler, testGen.tests);
229242
StubsCollector(typesHandler).collect(testGen.tests);
230243

231244
PathSubstitution pathSubstitution = {};
232245
if (lineTestGen != nullptr) {
233-
lineInfo = getLineInfo(*lineTestGen);
234246
lineInfo->forMethod = isSameType<FunctionTestGen>(testGen);
235247
lineInfo->forClass = isSameType<ClassTestGen>(testGen);
236248
lineInfo->forAssert = isSameType<AssertionTestGen>(testGen);
237249
if (lineTestGen->needToAddPathFlag()) {
238250
LOG_S(DEBUG) << "Added test line flag for file " << lineInfo->filePath;
239251
fs::path flagFilePath =
240252
printer::KleePrinter(&typesHandler, nullptr, Paths::getSourceLanguage(lineInfo->filePath))
241-
.addTestLineFlag(lineInfo, isSameType<AssertionTestGen>(testGen),
242-
testGen.projectContext);
253+
.addTestLineFlag(lineInfo, lineInfo->forAssert, testGen.projectContext);
243254
pathSubstitution = { testGen.testingMethodsSourcePaths[0], flagFilePath };
244255
}
245256
}
@@ -290,10 +301,10 @@ Status Server::TestsGenServiceImpl::ProcessBaseTestRequest(BaseTestGen &testGen,
290301
}
291302

292303
shared_ptr<LineInfo> Server::TestsGenServiceImpl::getLineInfo(LineTestGen &lineTestGen) {
293-
StmtBordersFinder stmtFinder(lineTestGen.testingMethodsSourcePaths[0], lineTestGen.line,
294-
lineTestGen.compilationDatabase,
295-
lineTestGen.compileCommandsJsonPath);
296-
stmtFinder.launch();
304+
BordersFinder stmtFinder(lineTestGen.testingMethodsSourcePaths[0], lineTestGen.line,
305+
lineTestGen.compilationDatabase,
306+
lineTestGen.compileCommandsJsonPath);
307+
stmtFinder.findFunction();
297308
if (!stmtFinder.getLineInfo().initialized) {
298309
throw NoTestGeneratedException(
299310
"Maybe you tried to generate tests placing cursor on invalid line.");

server/src/Server.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#define UNITTESTBOT_SERVER_H
77

88
#include "KleeGenerator.h"
9-
#include "StmtBordersFinder.h"
9+
#include "BordersFinder.h"
1010
#include "ThreadSafeContainers.h"
1111
#include "TimeExecStatistics.h"
1212
#include "exceptions/CancellationException.h"

0 commit comments

Comments
 (0)