Skip to content

Commit 05ed34f

Browse files
committed
Generate declarations for unnamed fields of structs and unions (#604)
* Generate declarations for unnamed fields of structs and unions
1 parent 61b9a3b commit 05ed34f

16 files changed

+268
-27
lines changed

server/src/Server.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,10 @@ Status Server::TestsGenServiceImpl::ProcessBaseTestRequest(BaseTestGen &testGen,
203203
&sizeContext.maximumAlignment,
204204
testGen.compileCommandsJsonPath, false);
205205
fetcher.fetchWithProgress(testGen.progressWriter, logMessage);
206+
types::TypesHandler typesHandler{testGen.types, sizeContext};
206207
SourceToHeaderRewriter(testGen.projectContext, testGen.getTargetBuildDatabase()->compilationDatabase,
207-
fetcher.getStructsToDeclare(), testGen.serverBuildDir)
208+
fetcher.getStructsToDeclare(), testGen.serverBuildDir, typesHandler)
208209
.generateTestHeaders(testGen.tests, testGen.progressWriter);
209-
types::TypesHandler typesHandler{testGen.types, sizeContext};
210210
testGen.progressWriter->writeProgress("Generating stub files", 0.0);
211211
StubGen stubGen(testGen);
212212

server/src/Synchronizer.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ void Synchronizer::synchronize(const types::TypesHandler &typesHandler) {
150150
synchronizeStubs(outdatedStubs, typesHandler);
151151
}
152152
auto outdatedSourcePaths = getOutdatedSourcePaths();
153-
synchronizeWrappers(outdatedSourcePaths);
153+
synchronizeWrappers(outdatedSourcePaths, typesHandler);
154154
}
155155

156156
void Synchronizer::synchronizeStubs(StubSet &outdatedStubs,
@@ -191,7 +191,7 @@ void Synchronizer::synchronizeStubs(StubSet &outdatedStubs,
191191

192192
auto sourceToHeaderRewriter =
193193
SourceToHeaderRewriter(testGen->projectContext, testGen->getProjectBuildDatabase()->compilationDatabase,
194-
stubFetcher.getStructsToDeclare(), testGen->serverBuildDir);
194+
stubFetcher.getStructsToDeclare(), testGen->serverBuildDir, typesHandler);
195195

196196
for (const StubOperator &outdatedStub : outdatedStubs) {
197197
fs::path stubPath = outdatedStub.getStubPath(testGen->projectContext);
@@ -221,7 +221,8 @@ Synchronizer::createStubsCompilationDatabase(StubSet &stubFiles,
221221
return CompilationUtils::getCompilationDatabase(ccJsonStubDirPath);
222222
}
223223

224-
void Synchronizer::synchronizeWrappers(const CollectionUtils::FileSet &outdatedSourcePaths) const {
224+
void Synchronizer::synchronizeWrappers(const CollectionUtils::FileSet &outdatedSourcePaths,
225+
const types::TypesHandler &typesHandler) const {
225226
auto sourceFilesNeedToRegenerateWrappers = outdatedSourcePaths;
226227
for (fs::path const &sourceFilePath : getTargetSourceFiles()) {
227228
if (!CollectionUtils::contains(sourceFilesNeedToRegenerateWrappers, sourceFilePath)) {
@@ -234,10 +235,10 @@ void Synchronizer::synchronizeWrappers(const CollectionUtils::FileSet &outdatedS
234235
}
235236
ExecUtils::doWorkWithProgress(
236237
sourceFilesNeedToRegenerateWrappers, testGen->progressWriter,
237-
"Generating wrappers", [this](fs::path const &sourceFilePath) {
238+
"Generating wrappers", [this, &typesHandler](fs::path const &sourceFilePath) {
238239
SourceToHeaderRewriter sourceToHeaderRewriter(testGen->projectContext,
239240
testGen->getProjectBuildDatabase()->compilationDatabase, nullptr,
240-
testGen->serverBuildDir);
241+
testGen->serverBuildDir, typesHandler);
241242
std::string wrapper = sourceToHeaderRewriter.generateWrapper(sourceFilePath);
242243
printer::SourceWrapperPrinter(Paths::getSourceLanguage(sourceFilePath)).print(testGen->projectContext, sourceFilePath, wrapper);
243244
});

server/src/Synchronizer.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ class Synchronizer {
3737

3838
void synchronizeStubs(std::unordered_set<StubOperator, HashUtils::StubHash> &outdatedStubs,
3939
const types::TypesHandler &typesHandler);
40-
void synchronizeWrappers(const CollectionUtils::FileSet &outdatedSourcePaths) const;
40+
void synchronizeWrappers(const CollectionUtils::FileSet &outdatedSourcePaths,
41+
const types::TypesHandler &typesHandler) const;
4142

4243
std::shared_ptr<CompilationDatabase>
4344
createStubsCompilationDatabase(

server/src/clang-utils/SourceToHeaderMatchCallback.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@ SourceToHeaderMatchCallback::SourceToHeaderMatchCallback(utbot::ProjectContext p
1919
fs::path sourceFilePath,
2020
raw_ostream *externalStream,
2121
raw_ostream *internalStream,
22+
raw_ostream *unnamedTypeDeclsStream,
2223
raw_ostream *wrapperStream,
24+
const types::TypesHandler &typesHandler,
2325
bool forStubHeader)
2426
: projectContext(std::move(projectContext)),
2527
sourceFilePath(std::move(sourceFilePath)), externalStream(externalStream),
26-
internalStream(internalStream), wrapperStream(wrapperStream), forStubHeader(forStubHeader) {
28+
internalStream(internalStream), unnamedTypeDeclsStream(unnamedTypeDeclsStream),
29+
wrapperStream(wrapperStream), typesHandler(typesHandler), forStubHeader(forStubHeader) {
2730
}
2831

2932
void SourceToHeaderMatchCallback::run(const ast_matchers::MatchFinder::MatchResult &Result) {
@@ -128,12 +131,14 @@ void SourceToHeaderMatchCallback::checkVarDecl(const MatchFinder::MatchResult &R
128131

129132
void SourceToHeaderMatchCallback::handleStruct(const RecordDecl *decl) {
130133
print(decl);
134+
generateUnnamedTypeDecls(decl);
131135
}
132136
void SourceToHeaderMatchCallback::handleEnum(const EnumDecl *decl) {
133137
print(decl);
134138
}
135139
void SourceToHeaderMatchCallback::handleUnion(const RecordDecl *decl) {
136140
print(decl);
141+
generateUnnamedTypeDecls(decl);
137142
}
138143

139144
void SourceToHeaderMatchCallback::handleTypedef(const TypedefDecl *decl) {
@@ -301,6 +306,36 @@ void SourceToHeaderMatchCallback::generateWrapper(const VarDecl *decl) const {
301306
*wrapperStream << wrapperPointerDecl << " = &" << name << ";\n";
302307
}
303308

309+
void SourceToHeaderMatchCallback::generateUnnamedTypeDecls(const clang::RecordDecl *decl) const {
310+
if (unnamedTypeDeclsStream == nullptr) {
311+
return;
312+
}
313+
clang::ASTContext const &context = decl->getASTContext();
314+
clang::QualType canonicalType = context.getTypeDeclType(decl).getCanonicalType();
315+
uint64_t id = types::Type::getIdFromCanonicalType(canonicalType);
316+
if (typesHandler.isStructLike(id)) {
317+
types::StructInfo info = typesHandler.getStructInfo(id);
318+
generateUnnamedTypeDeclsForFields(info);
319+
}
320+
}
321+
322+
void SourceToHeaderMatchCallback::generateUnnamedTypeDeclsForFields(const types::StructInfo &info) const {
323+
for (const types::Field &field : info.fields) {
324+
if (!field.unnamedType || field.anonymous) {
325+
continue;
326+
}
327+
if (typesHandler.isStructLike(field.type)) {
328+
types::StructInfo fieldInfo = typesHandler.getStructInfo(field.type);
329+
printUnnamedTypeDecl(info.name, field.name, fieldInfo.name);
330+
generateUnnamedTypeDeclsForFields(fieldInfo);
331+
}
332+
if (typesHandler.isEnum(field.type)) {
333+
types::EnumInfo enumInfo = typesHandler.getEnumInfo(field.type);
334+
printUnnamedTypeDecl(info.name, field.name, enumInfo.name);
335+
}
336+
}
337+
}
338+
304339

305340
void SourceToHeaderMatchCallback::printReturn(const FunctionDecl *decl,
306341
std::string const &name,
@@ -320,6 +355,16 @@ void SourceToHeaderMatchCallback::printReturn(const FunctionDecl *decl,
320355
*stream << printer.ss.str();
321356
}
322357

358+
void SourceToHeaderMatchCallback::printUnnamedTypeDecl(const std::string &structName,
359+
const std::string &fieldName,
360+
const std::string &typeName) const {
361+
std::string typeDecl = StringUtils::stringFormat(
362+
"typedef decltype(%s::%s) %s;\n",
363+
structName, fieldName, typeName
364+
);
365+
*unnamedTypeDeclsStream << typeDecl;
366+
}
367+
323368
std::string SourceToHeaderMatchCallback::decorate(std::string_view name) const {
324369
return forStubHeader ? std::string(name) : NameDecorator::decorate(name);
325370
}

server/src/clang-utils/SourceToHeaderMatchCallback.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,23 @@ class SourceToHeaderMatchCallback : public clang::ast_matchers::MatchFinder::Mat
2121
fs::path sourceFilePath;
2222
llvm::raw_ostream *const externalStream = nullptr;
2323
llvm::raw_ostream *const internalStream = nullptr;
24+
llvm::raw_ostream *const unnamedTypeDeclsStream = nullptr;
2425
llvm::raw_ostream *const wrapperStream = nullptr;
2526

2627
std::unordered_set<std::string> variables{};
2728

29+
const types::TypesHandler &typesHandler;
30+
2831
bool forStubHeader;
2932
public:
3033
SourceToHeaderMatchCallback(
3134
utbot::ProjectContext projectContext,
3235
fs::path sourceFilePath,
3336
llvm::raw_ostream *externalStream,
3437
llvm::raw_ostream *internalStream,
38+
llvm::raw_ostream *unnamedTypeDeclsStream,
3539
llvm::raw_ostream *wrapperStream,
40+
const types::TypesHandler &typesHandler,
3641
bool forStubHeader);
3742

3843
void run(const MatchFinder::MatchResult &Result) override;
@@ -72,6 +77,10 @@ class SourceToHeaderMatchCallback : public clang::ast_matchers::MatchFinder::Mat
7277
std::string const &name,
7378
llvm::raw_ostream *stream) const;
7479

80+
void printUnnamedTypeDecl(const std::string &structName,
81+
const std::string &fieldName,
82+
const std::string &typeName) const;
83+
7584
void generateWrapper(const clang::FunctionDecl *decl) const;
7685

7786
void generateWrapper(const clang::VarDecl *decl) const;
@@ -80,6 +89,10 @@ class SourceToHeaderMatchCallback : public clang::ast_matchers::MatchFinder::Mat
8089

8190
void generateInternal(const clang::VarDecl *decl) const;
8291

92+
void generateUnnamedTypeDeclsForFields(const types::StructInfo &info) const;
93+
94+
void generateUnnamedTypeDecls(const clang::RecordDecl *decl) const;
95+
8396
std::string getRenamedDeclarationAsString(const clang::NamedDecl *decl,
8497
clang::PrintingPolicy const &policy,
8598
std::string const &name) const;

server/src/clang-utils/SourceToHeaderRewriter.cpp

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,26 @@ SourceToHeaderRewriter::SourceToHeaderRewriter(
1515
utbot::ProjectContext projectContext,
1616
const std::shared_ptr<CompilationDatabase> &compilationDatabase,
1717
std::shared_ptr<Fetcher::FileToStringSet> structsToDeclare,
18-
fs::path serverBuildDir)
18+
fs::path serverBuildDir,
19+
const types::TypesHandler &typesHandler)
1920
: projectContext(std::move(projectContext)),
2021
clangToolRunner(compilationDatabase), structsToDeclare(structsToDeclare),
21-
serverBuildDir(std::move(serverBuildDir)) {
22+
serverBuildDir(std::move(serverBuildDir)), typesHandler(typesHandler) {
2223
}
2324

2425
std::unique_ptr<clang::tooling::FrontendActionFactory>
2526
SourceToHeaderRewriter::createFactory(llvm::raw_ostream *externalStream,
2627
llvm::raw_ostream *internalStream,
28+
llvm::raw_ostream *unnamedTypeDeclsStream,
2729
llvm::raw_ostream *wrapperStream,
2830
fs::path sourceFilePath,
2931
bool forStubHeader) {
32+
if (Paths::isCXXFile(sourceFilePath)) {
33+
externalStream = nullptr;
34+
internalStream = nullptr;
35+
}
3036
fetcherInstance = std::make_unique<SourceToHeaderMatchCallback>(
31-
projectContext, sourceFilePath, externalStream, internalStream, wrapperStream, forStubHeader);
37+
projectContext, sourceFilePath, externalStream, internalStream, unnamedTypeDeclsStream, wrapperStream, typesHandler, forStubHeader);
3238
finder = std::make_unique<clang::ast_matchers::MatchFinder>();
3339
finder->addMatcher(Matchers::anyToplevelDeclarationMatcher, fetcherInstance.get());
3440
return clang::tooling::newFrontendActionFactory(finder.get());
@@ -40,8 +46,10 @@ SourceToHeaderRewriter::generateSourceDeclarations(const fs::path &sourceFilePat
4046
llvm::raw_string_ostream externalStream(externalDeclarations);
4147
std::string internalDeclarations;
4248
llvm::raw_string_ostream internalStream(internalDeclarations);
49+
std::string unnamedTypeDeclarations;
50+
llvm::raw_string_ostream unnamedTypeDeclsStream(unnamedTypeDeclarations);
4351

44-
auto factory = createFactory(&externalStream, &internalStream, nullptr, sourceFilePath, forStubHeader);
52+
auto factory = createFactory(&externalStream, &internalStream, &unnamedTypeDeclsStream, nullptr, sourceFilePath, forStubHeader);
4553

4654
if (CollectionUtils::containsKey(*structsToDeclare, sourceFilePath)) {
4755
std::stringstream newContentStream;
@@ -57,14 +65,17 @@ SourceToHeaderRewriter::generateSourceDeclarations(const fs::path &sourceFilePat
5765
}
5866
externalStream.flush();
5967
internalStream.flush();
68+
unnamedTypeDeclsStream.flush();
6069

61-
return { externalDeclarations, internalDeclarations };
70+
return { externalDeclarations, internalDeclarations, unnamedTypeDeclarations };
6271
}
6372

6473

6574
std::string SourceToHeaderRewriter::generateTestHeader(const fs::path &sourceFilePath,
6675
const Tests &test) {
6776
MEASURE_FUNCTION_EXECUTION_TIME
77+
auto sourceDeclarations = generateSourceDeclarations(sourceFilePath, false);
78+
6879
if (Paths::isCXXFile(sourceFilePath)) {
6980
auto sourceFileToInclude = sourceFilePath;
7081
if (test.mainHeader.has_value()) {
@@ -73,12 +84,11 @@ std::string SourceToHeaderRewriter::generateTestHeader(const fs::path &sourceFil
7384
}
7485
sourceFileToInclude = fs::relative(sourceFilePath, test.testHeaderFilePath.parent_path());
7586
return StringUtils::stringFormat("#define main main__\n\n"
76-
"#include \"%s\"\n\n",
77-
sourceFileToInclude);
87+
"#include \"%s\"\n\n"
88+
"%s\n",
89+
sourceFileToInclude, sourceDeclarations.unnamedTypeDeclarations);
7890
}
7991

80-
auto sourceDeclarations = generateSourceDeclarations(sourceFilePath, false);
81-
8292
return StringUtils::stringFormat(
8393
"%s\n"
8494
"namespace %s {\n"
@@ -88,13 +98,14 @@ std::string SourceToHeaderRewriter::generateTestHeader(const fs::path &sourceFil
8898
"%s\n"
8999
"%s\n"
90100
"%s\n"
91-
"}\n"
92-
"%s\n",
101+
"%s\n"
102+
"\n%s"
103+
"}\n",
93104
Copyright::GENERATED_C_CPP_FILE_HEADER, PrinterUtils::TEST_NAMESPACE,
94105
NameDecorator::DEFINES_CODE, PrinterUtils::DEFINES_FOR_C_KEYWORDS,
95106
PrinterUtils::KNOWN_IMPLICIT_RECORD_DECLS_CODE,
96107
sourceDeclarations.externalDeclarations, sourceDeclarations.internalDeclarations,
97-
NameDecorator::UNDEF_WCHAR_T, NameDecorator::UNDEFS_CODE);
108+
NameDecorator::UNDEF_WCHAR_T, NameDecorator::UNDEFS_CODE, sourceDeclarations.unnamedTypeDeclarations);
98109
}
99110

100111
std::string SourceToHeaderRewriter::generateStubHeader(const fs::path &sourceFilePath) {
@@ -122,7 +133,7 @@ std::string SourceToHeaderRewriter::generateWrapper(const fs::path &sourceFilePa
122133
}
123134
std::string result;
124135
llvm::raw_string_ostream wrapperStream(result);
125-
auto factory = createFactory(nullptr, nullptr, &wrapperStream, sourceFilePath, false);
136+
auto factory = createFactory(nullptr, nullptr, nullptr, &wrapperStream, sourceFilePath, false);
126137
clangToolRunner.run(sourceFilePath, factory.get());
127138
wrapperStream.flush();
128139
return result;

server/src/clang-utils/SourceToHeaderRewriter.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ class SourceToHeaderRewriter {
2424
fs::path projectPath;
2525
fs::path serverBuildDir;
2626
std::shared_ptr<Fetcher::FileToStringSet> structsToDeclare;
27+
const types::TypesHandler &typesHandler;
2728

2829
std::unique_ptr<clang::ast_matchers::MatchFinder::MatchCallback> fetcherInstance;
2930
std::unique_ptr<clang::ast_matchers::MatchFinder> finder;
3031

3132
std::unique_ptr<clang::tooling::FrontendActionFactory>
3233
createFactory(llvm::raw_ostream *externalStream,
3334
llvm::raw_ostream *internalStream,
35+
llvm::raw_ostream *unnamedTypeDeclsStream,
3436
llvm::raw_ostream *wrapperStream,
3537
fs::path sourceFilePath,
3638
bool forStubHeader);
@@ -39,6 +41,7 @@ class SourceToHeaderRewriter {
3941
struct SourceDeclarations {
4042
std::string externalDeclarations;
4143
std::string internalDeclarations;
44+
std::string unnamedTypeDeclarations;
4245
};
4346

4447
friend class SourceToHeaderMatchCallback;
@@ -47,7 +50,8 @@ class SourceToHeaderRewriter {
4750
utbot::ProjectContext projectContext,
4851
const std::shared_ptr<CompilationDatabase> &compilationDatabase,
4952
std::shared_ptr<Fetcher::FileToStringSet> structsToDeclare,
50-
fs::path serverBuildDir);
53+
fs::path serverBuildDir,
54+
const types::TypesHandler &typesHandler);
5155

5256
SourceDeclarations generateSourceDeclarations(const fs::path &sourceFilePath, bool forStubHeader);
5357

server/src/types/Types.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ namespace types {
282282

283283
struct Field {
284284
types::Type type;
285+
bool unnamedType;
285286
bool anonymous;
286287
std::string name;
287288
/// size in @b bits
@@ -366,7 +367,7 @@ namespace types {
366367
size_t maximumAlignment = 16; /// maximumAlignment in @b bytes
367368
};
368369

369-
explicit TypesHandler(TypeMaps &types, SizeContext sizeContext)
370+
explicit TypesHandler(const TypeMaps &types, SizeContext sizeContext)
370371
: typeMaps(types), sizeContext(sizeContext){};
371372

372373
/**
@@ -650,7 +651,7 @@ namespace types {
650651
};
651652

652653
private:
653-
TypeMaps &typeMaps;
654+
const TypeMaps &typeMaps;
654655
SizeContext sizeContext;
655656
mutable tsl::ordered_set<TypeName> recursiveCheckStarted{};
656657
mutable std::unordered_map<IsSupportedTypeArguments,

server/src/types/TypesResolver.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,20 @@ std::string TypesResolver::getFullname(const clang::TagDecl *TD, const clang::Qu
6363
uint64_t id, const fs::path &sourceFilePath) {
6464
auto pp = clang::PrintingPolicy(clang::LangOptions());
6565
pp.SuppressTagKeyword = true;
66+
bool typeDeclNeeded = canonicalType->hasUnnamedOrLocalType() && !fullname[id].empty();
6667
std::string currentStructName = canonicalType.getNonReferenceType().getUnqualifiedType().getAsString(pp);
6768
fullname.insert(std::make_pair(id, currentStructName));
6869

69-
if (Paths::getSourceLanguage(sourceFilePath) == utbot::Language::C) {
70+
if (Paths::getSourceLanguage(sourceFilePath) == utbot::Language::C || typeDeclNeeded) {
7071
if (const auto *parentNode = llvm::dyn_cast<const clang::RecordDecl>(TD->getLexicalParent())) {
7172
clang::QualType parentCanonicalType = parentNode->getASTContext().getTypeDeclType(
7273
parentNode).getCanonicalType();
7374
uint64_t parentID = types::Type::getIdFromCanonicalType(parentCanonicalType);
7475
if (!fullname[parentID].empty()) {
7576
fullname[id] = fullname[parentID] + "::" + fullname[id];
77+
if (typeDeclNeeded) {
78+
StringUtils::replaceAll(fullname[id], "::", "_");
79+
}
7680
}
7781
}
7882
}
@@ -132,6 +136,10 @@ void TypesResolver::resolveStructEx(const clang::RecordDecl *D, const std::strin
132136

133137
const clang::QualType paramType = F->getType().getCanonicalType();
134138
field.type = types::Type(paramType, paramType.getAsString(), sourceManager);
139+
field.unnamedType = field.type.isUnnamed();
140+
if (field.unnamedType && !field.anonymous) {
141+
fullname[field.type.getId()] = field.name;
142+
}
135143
if (field.type.isPointerToFunction()) {
136144
structInfo.functionFields[field.name] = ParamsHandler::getFunctionPointerDeclaration(
137145
F->getFunctionType(), field.name, sourceManager,

0 commit comments

Comments
 (0)