Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate declarations for unnamed fields of structs and unions #604

Merged
merged 7 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions server/src/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,10 @@ Status Server::TestsGenServiceImpl::ProcessBaseTestRequest(BaseTestGen &testGen,
&sizeContext.maximumAlignment,
testGen.compileCommandsJsonPath, false);
fetcher.fetchWithProgress(testGen.progressWriter, logMessage);
types::TypesHandler typesHandler{testGen.types, sizeContext};
SourceToHeaderRewriter(testGen.projectContext, testGen.getTargetBuildDatabase()->compilationDatabase,
fetcher.getStructsToDeclare(), testGen.serverBuildDir)
fetcher.getStructsToDeclare(), testGen.serverBuildDir, typesHandler)
.generateTestHeaders(testGen.tests, testGen.progressWriter);
types::TypesHandler typesHandler{testGen.types, sizeContext};
testGen.progressWriter->writeProgress("Generating stub files", 0.0);
StubGen stubGen(testGen);

Expand Down
11 changes: 6 additions & 5 deletions server/src/Synchronizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ void Synchronizer::synchronize(const types::TypesHandler &typesHandler) {
synchronizeStubs(outdatedStubs, typesHandler);
}
auto outdatedSourcePaths = getOutdatedSourcePaths();
synchronizeWrappers(outdatedSourcePaths);
synchronizeWrappers(outdatedSourcePaths, typesHandler);
}

void Synchronizer::synchronizeStubs(StubSet &outdatedStubs,
Expand Down Expand Up @@ -191,7 +191,7 @@ void Synchronizer::synchronizeStubs(StubSet &outdatedStubs,

auto sourceToHeaderRewriter =
SourceToHeaderRewriter(testGen->projectContext, testGen->getProjectBuildDatabase()->compilationDatabase,
stubFetcher.getStructsToDeclare(), testGen->serverBuildDir);
stubFetcher.getStructsToDeclare(), testGen->serverBuildDir, typesHandler);

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

void Synchronizer::synchronizeWrappers(const CollectionUtils::FileSet &outdatedSourcePaths) const {
void Synchronizer::synchronizeWrappers(const CollectionUtils::FileSet &outdatedSourcePaths,
const types::TypesHandler &typesHandler) const {
auto sourceFilesNeedToRegenerateWrappers = outdatedSourcePaths;
for (fs::path const &sourceFilePath : getTargetSourceFiles()) {
if (!CollectionUtils::contains(sourceFilesNeedToRegenerateWrappers, sourceFilePath)) {
Expand All @@ -234,10 +235,10 @@ void Synchronizer::synchronizeWrappers(const CollectionUtils::FileSet &outdatedS
}
ExecUtils::doWorkWithProgress(
sourceFilesNeedToRegenerateWrappers, testGen->progressWriter,
"Generating wrappers", [this](fs::path const &sourceFilePath) {
"Generating wrappers", [this, &typesHandler](fs::path const &sourceFilePath) {
SourceToHeaderRewriter sourceToHeaderRewriter(testGen->projectContext,
testGen->getProjectBuildDatabase()->compilationDatabase, nullptr,
testGen->serverBuildDir);
testGen->serverBuildDir, typesHandler);
std::string wrapper = sourceToHeaderRewriter.generateWrapper(sourceFilePath);
printer::SourceWrapperPrinter(Paths::getSourceLanguage(sourceFilePath)).print(testGen->projectContext, sourceFilePath, wrapper);
});
Expand Down
3 changes: 2 additions & 1 deletion server/src/Synchronizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ class Synchronizer {

void synchronizeStubs(std::unordered_set<StubOperator, HashUtils::StubHash> &outdatedStubs,
const types::TypesHandler &typesHandler);
void synchronizeWrappers(const CollectionUtils::FileSet &outdatedSourcePaths) const;
void synchronizeWrappers(const CollectionUtils::FileSet &outdatedSourcePaths,
const types::TypesHandler &typesHandler) const;

std::shared_ptr<CompilationDatabase>
createStubsCompilationDatabase(
Expand Down
47 changes: 46 additions & 1 deletion server/src/clang-utils/SourceToHeaderMatchCallback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@ SourceToHeaderMatchCallback::SourceToHeaderMatchCallback(utbot::ProjectContext p
fs::path sourceFilePath,
raw_ostream *externalStream,
raw_ostream *internalStream,
raw_ostream *unnamedTypeDeclsStream,
raw_ostream *wrapperStream,
const types::TypesHandler &typesHandler,
bool forStubHeader)
: projectContext(std::move(projectContext)),
sourceFilePath(std::move(sourceFilePath)), externalStream(externalStream),
internalStream(internalStream), wrapperStream(wrapperStream), forStubHeader(forStubHeader) {
internalStream(internalStream), unnamedTypeDeclsStream(unnamedTypeDeclsStream),
wrapperStream(wrapperStream), typesHandler(typesHandler), forStubHeader(forStubHeader) {
}

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

void SourceToHeaderMatchCallback::handleStruct(const RecordDecl *decl) {
print(decl);
generateUnnamedTypeDecls(decl);
}
void SourceToHeaderMatchCallback::handleEnum(const EnumDecl *decl) {
print(decl);
}
void SourceToHeaderMatchCallback::handleUnion(const RecordDecl *decl) {
print(decl);
generateUnnamedTypeDecls(decl);
}

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

void SourceToHeaderMatchCallback::generateUnnamedTypeDecls(const clang::RecordDecl *decl) const {
if (unnamedTypeDeclsStream == nullptr) {
return;
}
clang::ASTContext const &context = decl->getASTContext();
clang::QualType canonicalType = context.getTypeDeclType(decl).getCanonicalType();
uint64_t id = types::Type::getIdFromCanonicalType(canonicalType);
if (typesHandler.isStructLike(id)) {
types::StructInfo info = typesHandler.getStructInfo(id);
generateUnnamedTypeDeclsForFields(info);
}
}

void SourceToHeaderMatchCallback::generateUnnamedTypeDeclsForFields(const types::StructInfo &info) const {
for (const types::Field &field : info.fields) {
if (!field.unnamedType || field.anonymous) {
continue;
}
if (typesHandler.isStructLike(field.type)) {
types::StructInfo fieldInfo = typesHandler.getStructInfo(field.type);
printUnnamedTypeDecl(info.name, field.name, fieldInfo.name);
generateUnnamedTypeDeclsForFields(fieldInfo);
}
if (typesHandler.isEnum(field.type)) {
types::EnumInfo enumInfo = typesHandler.getEnumInfo(field.type);
printUnnamedTypeDecl(info.name, field.name, enumInfo.name);
}
}
}


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

void SourceToHeaderMatchCallback::printUnnamedTypeDecl(const std::string &structName,
const std::string &fieldName,
const std::string &typeName) const {
std::string typeDecl = StringUtils::stringFormat(
"typedef decltype(%s::%s) %s;\n",
structName, fieldName, typeName
);
*unnamedTypeDeclsStream << typeDecl;
}

std::string SourceToHeaderMatchCallback::decorate(std::string_view name) const {
return forStubHeader ? std::string(name) : NameDecorator::decorate(name);
}
Expand Down
13 changes: 13 additions & 0 deletions server/src/clang-utils/SourceToHeaderMatchCallback.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,23 @@ class SourceToHeaderMatchCallback : public clang::ast_matchers::MatchFinder::Mat
fs::path sourceFilePath;
llvm::raw_ostream *const externalStream = nullptr;
llvm::raw_ostream *const internalStream = nullptr;
llvm::raw_ostream *const unnamedTypeDeclsStream = nullptr;
llvm::raw_ostream *const wrapperStream = nullptr;

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

const types::TypesHandler &typesHandler;

bool forStubHeader;
public:
SourceToHeaderMatchCallback(
utbot::ProjectContext projectContext,
fs::path sourceFilePath,
llvm::raw_ostream *externalStream,
llvm::raw_ostream *internalStream,
llvm::raw_ostream *unnamedTypeDeclsStream,
llvm::raw_ostream *wrapperStream,
const types::TypesHandler &typesHandler,
bool forStubHeader);

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

void printUnnamedTypeDecl(const std::string &structName,
const std::string &fieldName,
const std::string &typeName) const;

void generateWrapper(const clang::FunctionDecl *decl) const;

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

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

void generateUnnamedTypeDeclsForFields(const types::StructInfo &info) const;

void generateUnnamedTypeDecls(const clang::RecordDecl *decl) const;

std::string getRenamedDeclarationAsString(const clang::NamedDecl *decl,
clang::PrintingPolicy const &policy,
std::string const &name) const;
Expand Down
37 changes: 24 additions & 13 deletions server/src/clang-utils/SourceToHeaderRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,26 @@ SourceToHeaderRewriter::SourceToHeaderRewriter(
utbot::ProjectContext projectContext,
const std::shared_ptr<CompilationDatabase> &compilationDatabase,
std::shared_ptr<Fetcher::FileToStringSet> structsToDeclare,
fs::path serverBuildDir)
fs::path serverBuildDir,
const types::TypesHandler &typesHandler)
: projectContext(std::move(projectContext)),
clangToolRunner(compilationDatabase), structsToDeclare(structsToDeclare),
serverBuildDir(std::move(serverBuildDir)) {
serverBuildDir(std::move(serverBuildDir)), typesHandler(typesHandler) {
}

std::unique_ptr<clang::tooling::FrontendActionFactory>
SourceToHeaderRewriter::createFactory(llvm::raw_ostream *externalStream,
llvm::raw_ostream *internalStream,
llvm::raw_ostream *unnamedTypeDeclsStream,
llvm::raw_ostream *wrapperStream,
fs::path sourceFilePath,
bool forStubHeader) {
if (Paths::isCXXFile(sourceFilePath)) {
externalStream = nullptr;
internalStream = nullptr;
}
fetcherInstance = std::make_unique<SourceToHeaderMatchCallback>(
projectContext, sourceFilePath, externalStream, internalStream, wrapperStream, forStubHeader);
projectContext, sourceFilePath, externalStream, internalStream, unnamedTypeDeclsStream, wrapperStream, typesHandler, forStubHeader);
finder = std::make_unique<clang::ast_matchers::MatchFinder>();
finder->addMatcher(Matchers::anyToplevelDeclarationMatcher, fetcherInstance.get());
return clang::tooling::newFrontendActionFactory(finder.get());
Expand All @@ -40,8 +46,10 @@ SourceToHeaderRewriter::generateSourceDeclarations(const fs::path &sourceFilePat
llvm::raw_string_ostream externalStream(externalDeclarations);
std::string internalDeclarations;
llvm::raw_string_ostream internalStream(internalDeclarations);
std::string unnamedTypeDeclarations;
llvm::raw_string_ostream unnamedTypeDeclsStream(unnamedTypeDeclarations);

auto factory = createFactory(&externalStream, &internalStream, nullptr, sourceFilePath, forStubHeader);
auto factory = createFactory(&externalStream, &internalStream, &unnamedTypeDeclsStream, nullptr, sourceFilePath, forStubHeader);

if (CollectionUtils::containsKey(*structsToDeclare, sourceFilePath)) {
std::stringstream newContentStream;
Expand All @@ -57,14 +65,17 @@ SourceToHeaderRewriter::generateSourceDeclarations(const fs::path &sourceFilePat
}
externalStream.flush();
internalStream.flush();
unnamedTypeDeclsStream.flush();

return { externalDeclarations, internalDeclarations };
return { externalDeclarations, internalDeclarations, unnamedTypeDeclarations };
}


std::string SourceToHeaderRewriter::generateTestHeader(const fs::path &sourceFilePath,
const Tests &test) {
MEASURE_FUNCTION_EXECUTION_TIME
auto sourceDeclarations = generateSourceDeclarations(sourceFilePath, false);

if (Paths::isCXXFile(sourceFilePath)) {
auto sourceFileToInclude = sourceFilePath;
if (test.mainHeader.has_value()) {
Expand All @@ -73,12 +84,11 @@ std::string SourceToHeaderRewriter::generateTestHeader(const fs::path &sourceFil
}
sourceFileToInclude = fs::relative(sourceFilePath, test.testHeaderFilePath.parent_path());
return StringUtils::stringFormat("#define main main__\n\n"
"#include \"%s\"\n\n",
sourceFileToInclude);
"#include \"%s\"\n\n"
"%s\n",
sourceFileToInclude, sourceDeclarations.unnamedTypeDeclarations);
}

auto sourceDeclarations = generateSourceDeclarations(sourceFilePath, false);

return StringUtils::stringFormat(
"%s\n"
"namespace %s {\n"
Expand All @@ -88,13 +98,14 @@ std::string SourceToHeaderRewriter::generateTestHeader(const fs::path &sourceFil
"%s\n"
"%s\n"
"%s\n"
"}\n"
"%s\n",
"%s\n"
"\n%s"
"}\n",
Copyright::GENERATED_C_CPP_FILE_HEADER, PrinterUtils::TEST_NAMESPACE,
NameDecorator::DEFINES_CODE, PrinterUtils::DEFINES_FOR_C_KEYWORDS,
PrinterUtils::KNOWN_IMPLICIT_RECORD_DECLS_CODE,
sourceDeclarations.externalDeclarations, sourceDeclarations.internalDeclarations,
NameDecorator::UNDEF_WCHAR_T, NameDecorator::UNDEFS_CODE);
NameDecorator::UNDEF_WCHAR_T, NameDecorator::UNDEFS_CODE, sourceDeclarations.unnamedTypeDeclarations);
}

std::string SourceToHeaderRewriter::generateStubHeader(const fs::path &sourceFilePath) {
Expand Down Expand Up @@ -122,7 +133,7 @@ std::string SourceToHeaderRewriter::generateWrapper(const fs::path &sourceFilePa
}
std::string result;
llvm::raw_string_ostream wrapperStream(result);
auto factory = createFactory(nullptr, nullptr, &wrapperStream, sourceFilePath, false);
auto factory = createFactory(nullptr, nullptr, nullptr, &wrapperStream, sourceFilePath, false);
clangToolRunner.run(sourceFilePath, factory.get());
wrapperStream.flush();
return result;
Expand Down
6 changes: 5 additions & 1 deletion server/src/clang-utils/SourceToHeaderRewriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ class SourceToHeaderRewriter {
fs::path projectPath;
fs::path serverBuildDir;
std::shared_ptr<Fetcher::FileToStringSet> structsToDeclare;
const types::TypesHandler &typesHandler;

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

std::unique_ptr<clang::tooling::FrontendActionFactory>
createFactory(llvm::raw_ostream *externalStream,
llvm::raw_ostream *internalStream,
llvm::raw_ostream *unnamedTypeDeclsStream,
llvm::raw_ostream *wrapperStream,
fs::path sourceFilePath,
bool forStubHeader);
Expand All @@ -39,6 +41,7 @@ class SourceToHeaderRewriter {
struct SourceDeclarations {
std::string externalDeclarations;
std::string internalDeclarations;
std::string unnamedTypeDeclarations;
};

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

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

Expand Down
5 changes: 3 additions & 2 deletions server/src/types/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ namespace types {

struct Field {
types::Type type;
bool unnamedType;
bool anonymous;
std::string name;
/// size in @b bits
Expand Down Expand Up @@ -366,7 +367,7 @@ namespace types {
size_t maximumAlignment = 16; /// maximumAlignment in @b bytes
};

explicit TypesHandler(TypeMaps &types, SizeContext sizeContext)
explicit TypesHandler(const TypeMaps &types, SizeContext sizeContext)
: typeMaps(types), sizeContext(sizeContext){};

/**
Expand Down Expand Up @@ -650,7 +651,7 @@ namespace types {
};

private:
TypeMaps &typeMaps;
const TypeMaps &typeMaps;
SizeContext sizeContext;
mutable tsl::ordered_set<TypeName> recursiveCheckStarted{};
mutable std::unordered_map<IsSupportedTypeArguments,
Expand Down
10 changes: 9 additions & 1 deletion server/src/types/TypesResolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,20 @@ std::string TypesResolver::getFullname(const clang::TagDecl *TD, const clang::Qu
uint64_t id, const fs::path &sourceFilePath) {
auto pp = clang::PrintingPolicy(clang::LangOptions());
pp.SuppressTagKeyword = true;
bool typeDeclNeeded = canonicalType->hasUnnamedOrLocalType() && !fullname[id].empty();
std::string currentStructName = canonicalType.getNonReferenceType().getUnqualifiedType().getAsString(pp);
fullname.insert(std::make_pair(id, currentStructName));

if (Paths::getSourceLanguage(sourceFilePath) == utbot::Language::C) {
if (Paths::getSourceLanguage(sourceFilePath) == utbot::Language::C || typeDeclNeeded) {
if (const auto *parentNode = llvm::dyn_cast<const clang::RecordDecl>(TD->getLexicalParent())) {
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];
if (typeDeclNeeded) {
StringUtils::replaceAll(fullname[id], "::", "_");
}
}
}
}
Expand Down Expand Up @@ -132,6 +136,10 @@ void TypesResolver::resolveStructEx(const clang::RecordDecl *D, const std::strin

const clang::QualType paramType = F->getType().getCanonicalType();
field.type = types::Type(paramType, paramType.getAsString(), sourceManager);
field.unnamedType = field.type.isUnnamed();
if (field.unnamedType && !field.anonymous) {
fullname[field.type.getId()] = field.name;
}
if (field.type.isPointerToFunction()) {
structInfo.functionFields[field.name] = ParamsHandler::getFunctionPointerDeclaration(
F->getFunctionType(), field.name, sourceManager,
Expand Down
Loading