diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 7da2074..59ff0ba 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -122,7 +122,7 @@ bool Converter::VisitBuiltinType(clang::BuiltinType *type) { break; default: // FIXME: improve error handling - llvm::errs() << "unsupported builtin type\n"; + log() << "unsupported builtin type\n"; break; } return false; @@ -151,7 +151,7 @@ bool Converter::VisitRecordType(clang::RecordType *type) { } std::string Converter::ConvertPointer(clang::Expr *expr, int line) { - llvm::errs() << "ConvertPointer called from line " << line << "\n"; + log() << "ConvertPointer called from line " << line << "\n"; PushExprKind push(*this, ExprKind::AddrOf); return ToString(expr); } @@ -175,7 +175,7 @@ std::string Converter::ConvertLValue(clang::Expr *expr) { } std::string Converter::ConvertRValue(clang::Expr *expr, int line) { - llvm::errs() << "ConvertRValue called from line " << line << "\n"; + log() << "ConvertRValue called from line " << line << "\n"; PushExprKind push(*this, ExprKind::RValue); return ToString(expr); } @@ -295,7 +295,7 @@ bool Converter::VisitFunctionDecl(clang::FunctionDecl *decl) { if (!IsInMainFile(decl) && !decl_ids_.insert(GetID(decl)).second) { return false; } - decl->dump(); + decl->dump(log()); curr_function_ = decl; std::string function_name; if (decl->isMain()) { @@ -582,7 +582,7 @@ static bool recordDerivesCopy(const clang::RecordDecl *decl) { } bool Converter::VisitRecordDecl(clang::RecordDecl *decl) { - decl->dumpColor(); + decl->dump(log()); // VisitCXXRecordDecl already visited the record if (clang::isa(decl)) { @@ -694,7 +694,7 @@ bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { materializeTemplateSpecialization(decl); } - decl->dump(); + decl->dump(log()); Mapper::AddRuleForUserDefinedType(decl); if (!IsConvertibleCXXRecordDecl(decl)) { @@ -741,7 +741,7 @@ bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { } bool Converter::VisitCXXMethodDecl(clang::CXXMethodDecl *decl) { - decl->dump(); + decl->dump(log()); if (!IsConvertibleCXXMethodDecl(decl)) { return false; } @@ -1085,10 +1085,10 @@ bool Converter::VisitCXXForRangeStmt(clang::CXXForRangeStmt *stmt) { if (!Mapper::Contains(range_init_type.getUnqualifiedType())) { // FIXME: improve error handling - llvm::errs() << "for range stmts only for types in std namespace\n"; + log() << "for range stmts only for types in std namespace\n"; } - llvm::errs() << "GetClassName: " << GetClassName(range_init_type) << "\n"; + log() << "GetClassName: " << GetClassName(range_init_type) << "\n"; if (GetClassName(range_init_type) == "std::map") { return VisitCXXForRangeStmtMap(stmt); @@ -2692,7 +2692,7 @@ bool Converter::VisitUnaryExprOrTypeTraitExpr( break; default: // FIXME: improve error handling - llvm::errs() << "unsupported unary expr or type trait expr\n"; + log() << "unsupported unary expr or type trait expr\n"; } return false; } @@ -3437,7 +3437,7 @@ void Converter::ConvertUnsignedArithBinaryOperator(clang::BinaryOperator *op, default: // FIXME: improve error handling llvm::errs() << "unsupported unsigned binary operator: " << opcode << '\n'; - op->dumpColor(); + op->dump(); assert(0); } PushParen paren(*this); @@ -3747,9 +3747,9 @@ void Converter::SetFreshType(clang::QualType type) { } void Converter::dump_expr_kinds() { - llvm::errs() << "isRValue: " << isRValue() << ", isXValue: " << isXValue() - << ", isAddrOf: " << isAddrOf() << ", isObject: " << isObject() - << ", isVoid: " << isVoid() << "\n"; + log() << "isRValue: " << isRValue() << ", isXValue: " << isXValue() + << ", isAddrOf: " << isAddrOf() << ", isObject: " << isObject() + << ", isVoid: " << isVoid() << "\n"; } void Converter::emplace_back_plugin_construct_arg( diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 27a7804..06a363d 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -17,6 +17,7 @@ #include "converter/lex.h" #include "converter/translation_rule.h" +#include "logging.h" namespace cpp2rust { class Converter : public clang::RecursiveASTVisitor { @@ -329,8 +330,8 @@ class Converter : public clang::RecursiveASTVisitor { template inline void _StrCat(const char *func, int line, const Ts &...vals) { - llvm::errs() << '[' << func << ':' << line << "] "; - ((llvm::errs() << vals << '\n', *rs_code_ += vals, *rs_code_ += ' '), ...); + log() << '[' << func << ':' << line << "] "; + ((log() << vals << '\n', *rs_code_ += vals, *rs_code_ += ' '), ...); } class Buffer { @@ -609,13 +610,13 @@ class Converter : public clang::RecursiveASTVisitor { int line = __builtin_LINE()) : c(c) { c.curr_expr_kind_.push_back(k); - llvm::errs() << "PushExprKind " << file << ':' << line << ' '; + log() << "PushExprKind " << file << ':' << line << ' '; c.dump_expr_kinds(); - llvm::errs() << '['; + log() << '['; for (const auto k : c.curr_expr_kind_) { - llvm::errs() << c.expr_kind_to_string(k) << ", "; + log() << c.expr_kind_to_string(k) << ", "; } - llvm::errs() << "]\n"; + log() << "]\n"; } ~PushExprKind() { c.curr_expr_kind_.pop_back(); } }; diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 027d324..e674a26 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -418,7 +418,7 @@ const char *GetOverloadedOperator(const clang::FunctionDecl *decl) { return "lt"; default: // FIXME: improve error handling - llvm::errs() << "unsupported overloaded operator\n"; + log() << "unsupported overloaded operator\n"; return ""; } } diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index 3a3cf25..3578dca 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -14,6 +14,8 @@ #include #include +#include "logging.h" + namespace cpp2rust { // Order matters: each category is a superset of the previous one. @@ -116,7 +118,7 @@ void ForEachTemplateArgument( break; default: // FIXME: improve logging - llvm::errs() << "unsupported template argument kind\n"; + log() << "unsupported template argument kind\n"; } } } diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index 476eabe..4cf79d3 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -384,11 +384,11 @@ TranslationRule::ExprRule *search(const clang::Expr *expr) { auto qualified_name = ToString(expr); auto [rule, subs] = search(exprs_, qualified_name, GetExprMapKey(qualified_name)); - llvm::errs() << "search expr " << qualified_name << ", result:\n"; + log() << "search expr " << qualified_name << ", result:\n"; if (rule) { rule->dump(); } else { - llvm::errs() << "None\n"; + log() << "None\n"; } return rule; } @@ -396,9 +396,8 @@ TranslationRule::ExprRule *search(const clang::Expr *expr) { TranslationRule::TypeRule *search(clang::QualType qual_type) { auto type = ToString(qual_type); auto [rule, subs] = search(types_, type, GetTypeMapKey(type)); - llvm::errs() << "search type " << type - << ", result: " << (rule ? rule->type_info.type : "None") - << '\n'; + log() << "search type " << type + << ", result: " << (rule ? rule->type_info.type : "None") << '\n'; return rule; } @@ -408,7 +407,7 @@ void addRulesFromDirectory(const std::filesystem::path &dir, Model model) { if (entry.is_regular_file() && path.extension() == ".cpp") { auto [expr_rules, type_rules] = TranslationRule::Load(path, model); if (expr_rules.empty() && type_rules.empty()) { - llvm::errs() << "No rules found in " << path << '\n'; + log() << "No rules found in " << path << '\n'; continue; } for (auto &[_, rule] : expr_rules) { @@ -885,11 +884,11 @@ void LoadTranslationRules(Model model, clang::ASTContext &ctx, #if 0 for (auto &[src, rule] : exprs_) { - llvm::errs() << "Expr key: " << src << '\n'; + log() << "Expr key: " << src << '\n'; rule.dump(); } for (auto &[src, rule] : types_) { - llvm::errs() << "Type key: " << src << '\n'; + log() << "Type key: " << src << '\n'; rule.dump(); } #endif diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 890583e..4389470 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -245,21 +245,21 @@ class ConverterRefCount final : public Converter { if (pushed) { c.conversion_kind_.push_back(k); } - llvm::errs() << "[PushConversionKind:" << line << "] "; + log() << "[PushConversionKind:" << line << "] "; for (auto ck : c.conversion_kind_) { - llvm::errs() << c.ConversionKindToString(ck) << ", "; + log() << c.ConversionKindToString(ck) << ", "; } - llvm::errs() << "\n"; + log() << "\n"; } ~PushConversionKind() { if (pushed) { c.conversion_kind_.pop_back(); } - llvm::errs() << "[PopConversionKind] "; + log() << "[PopConversionKind] "; for (auto ck : c.conversion_kind_) { - llvm::errs() << c.ConversionKindToString(ck) << ", "; + log() << c.ConversionKindToString(ck) << ", "; } - llvm::errs() << "\n"; + log() << "\n"; } }; diff --git a/cpp2rust/converter/plugins/emplace_back.cpp b/cpp2rust/converter/plugins/emplace_back.cpp index 9c156af..306e3c7 100644 --- a/cpp2rust/converter/plugins/emplace_back.cpp +++ b/cpp2rust/converter/plugins/emplace_back.cpp @@ -182,7 +182,7 @@ bool Converter::emplace_back_plugin_convert(clang::CallExpr *call) { StrCat(GetUnsafeTypeAsString(elem_ty)); } } else { - call->dumpColor(); + call->dump(); assert(0 && "no ctor and no pod type"); return false; } diff --git a/cpp2rust/converter/translation_rule.cpp b/cpp2rust/converter/translation_rule.cpp index 34315f7..d20cc48 100644 --- a/cpp2rust/converter/translation_rule.cpp +++ b/cpp2rust/converter/translation_rule.cpp @@ -28,6 +28,7 @@ #include "compat/platform_flags.h" #include "converter/mapper.h" +#include "logging.h" namespace cpp2rust::TranslationRule { @@ -900,21 +901,19 @@ void BodyFragmentDump(const BodyFragment &frag) { } // namespace -void TextFragment::dump() const { - llvm::errs() << " text: \"" << text << "\"\n"; -} +void TextFragment::dump() const { log() << " text: \"" << text << "\"\n"; } void PlaceholderFragment::dump() const { - llvm::errs() << " placeholder: " << n; + log() << " placeholder: " << n; switch (access) { case Access::kRead: - llvm::errs() << " (read)\n"; + log() << " (read)\n"; break; case Access::kWrite: - llvm::errs() << " (write)\n"; + log() << " (write)\n"; break; case Access::kMove: - llvm::errs() << " (move)\n"; + log() << " (move)\n"; break; } } @@ -929,61 +928,59 @@ const PlaceholderFragment *MethodCallFragment::getReceiverPlaceholder() const { } void MethodCallFragment::dump() const { - llvm::errs() << " method_call:\n" - " receiver:\n"; + log() << " method_call:\n" + " receiver:\n"; for (const auto &frag : receiver) { BodyFragmentDump(frag); } - llvm::errs() << " body:\n"; + log() << " body:\n"; for (const auto &frag : body) { BodyFragmentDump(frag); } } void ExprRule::dump() const { - llvm::errs() << "Matching: " << src << '\n'; + log() << "Matching: " << src << '\n'; unsigned i = 0; for (auto &info : params) { - llvm::errs() << " param a" << i++ << ": "; + log() << " param a" << i++ << ": "; info.dump(); - llvm::errs() << '\n'; + log() << '\n'; } if (!return_type.type.empty()) { - llvm::errs() << " return: "; + log() << " return: "; return_type.dump(); - llvm::errs() << '\n'; + log() << '\n'; } i = 0; for (auto &bounds : generics) { - llvm::errs() << " generic T" << ++i << ':'; + log() << " generic T" << ++i << ':'; for (auto &b : bounds) { - llvm::errs() << ' ' << b; + log() << ' ' << b; } - llvm::errs() << '\n'; + log() << '\n'; } for (const auto &frag : body) { BodyFragmentDump(frag); } } -void GenericFragment::dump() const { - llvm::errs() << " generic: " << n << '\n'; -} +void GenericFragment::dump() const { log() << " generic: " << n << '\n'; } void TypeInfo::dump() const { - llvm::errs() << type; + log() << type; if (is_refcount_pointer) - llvm::errs() << " [rc_ptr]"; + log() << " [rc_ptr]"; if (is_unsafe_pointer) - llvm::errs() << " [unsafe_ptr]"; + log() << " [unsafe_ptr]"; } void TypeRule::dump() const { - llvm::errs() << "name: " << src << "\n Rust type: "; + log() << "name: " << src << "\n Rust type: "; type_info.dump(); - llvm::errs() << '\n'; + log() << '\n'; if (!initializer.empty()) { - llvm::errs() << " init: " << initializer << '\n'; + log() << " init: " << initializer << '\n'; } } diff --git a/cpp2rust/cpp2rust.cpp b/cpp2rust/cpp2rust.cpp index 1b929d5..2b197e8 100644 --- a/cpp2rust/cpp2rust.cpp +++ b/cpp2rust/cpp2rust.cpp @@ -19,12 +19,17 @@ #include #include "cpp2rust_lib.h" +#include "logging.h" namespace fs = std::filesystem; namespace { llvm::cl::OptionCategory cpp2rust_cmdargs("Cpp2Rust options"); +llvm::cl::opt Verbose("verbose", llvm::cl::desc("Enable verbose logging"), + llvm::cl::init(false), + llvm::cl::cat(cpp2rust_cmdargs)); + llvm::cl::opt CcFile("file", llvm::cl::desc("Path to the C++ file"), llvm::cl::value_desc("file.cpp"), @@ -89,7 +94,7 @@ static bool ResolveRulesDir() { for (const auto &dir : candidates) { if (fs::exists(dir) && fs::is_directory(dir)) { RulesDir = fs::canonical(dir).string(); - llvm::outs() << "Using rules directory: " << RulesDir << '\n'; + llvm::errs() << "Using rules directory: " << RulesDir << '\n'; return true; } } @@ -100,6 +105,8 @@ int main(int argc, char *argv[]) { llvm::cl::HideUnrelatedOptions(cpp2rust_cmdargs); llvm::cl::ParseCommandLineOptions(argc, argv); + cpp2rust::SetVerbose(Verbose); + if (CcFile.empty() && BuildDir.empty()) { llvm::errs() << "ERROR: please provide either --file or --dir\n"; return EXIT_FAILURE; diff --git a/cpp2rust/logging.cpp b/cpp2rust/logging.cpp new file mode 100644 index 0000000..9755a59 --- /dev/null +++ b/cpp2rust/logging.cpp @@ -0,0 +1,17 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include "logging.h" + +namespace cpp2rust { +namespace { +llvm::raw_ostream *log_ = &llvm::nulls(); +} // namespace + +void SetVerbose(bool verbose) { + log_ = verbose ? &llvm::errs() : &llvm::nulls(); +} + +llvm::raw_ostream &log() { return *log_; } + +} // namespace cpp2rust diff --git a/cpp2rust/logging.h b/cpp2rust/logging.h new file mode 100644 index 0000000..c1cf84f --- /dev/null +++ b/cpp2rust/logging.h @@ -0,0 +1,14 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#pragma once + +#include + +namespace cpp2rust { + +void SetVerbose(bool verbose); + +llvm::raw_ostream &log(); + +} // namespace cpp2rust