Merge branch 'foonathan:main' into main
This commit is contained in:
commit
c125883083
6 changed files with 161 additions and 11 deletions
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
namespace cppast
|
namespace cppast
|
||||||
{
|
{
|
||||||
/// The C++ standard that should be used.
|
/// The C/C++ standard that should be used.
|
||||||
enum class cpp_standard
|
enum class cpp_standard
|
||||||
{
|
{
|
||||||
cpp_98,
|
cpp_98,
|
||||||
|
|
@ -26,8 +26,16 @@ enum class cpp_standard
|
||||||
cpp_17,
|
cpp_17,
|
||||||
cpp_2a,
|
cpp_2a,
|
||||||
cpp_20,
|
cpp_20,
|
||||||
|
cpp_2b,
|
||||||
|
|
||||||
|
c_89,
|
||||||
|
c_99,
|
||||||
|
c_11,
|
||||||
|
c_17,
|
||||||
|
c_2x,
|
||||||
|
|
||||||
cpp_latest = cpp_standard::cpp_14, //< The latest supported C++ standard.
|
cpp_latest = cpp_standard::cpp_14, //< The latest supported C++ standard.
|
||||||
|
c_latest = cpp_standard::c_17, //< The latest supported C standard.
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \returns A human readable string representing the option,
|
/// \returns A human readable string representing the option,
|
||||||
|
|
@ -52,12 +60,52 @@ inline const char* to_string(cpp_standard standard) noexcept
|
||||||
return "c++2a";
|
return "c++2a";
|
||||||
case cpp_standard::cpp_20:
|
case cpp_standard::cpp_20:
|
||||||
return "c++20";
|
return "c++20";
|
||||||
|
case cpp_standard::cpp_2b:
|
||||||
|
return "c++2b";
|
||||||
|
|
||||||
|
case cpp_standard::c_89:
|
||||||
|
return "c89";
|
||||||
|
case cpp_standard::c_99:
|
||||||
|
return "c99";
|
||||||
|
case cpp_standard::c_11:
|
||||||
|
return "c11";
|
||||||
|
case cpp_standard::c_17:
|
||||||
|
return "c17";
|
||||||
|
case cpp_standard::c_2x:
|
||||||
|
return "c2x";
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||||
return "ups";
|
return "ups";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \returns whether the language standard is a C standard
|
||||||
|
inline bool is_c_standard(cpp_standard standard) noexcept
|
||||||
|
{
|
||||||
|
switch (standard)
|
||||||
|
{
|
||||||
|
case cpp_standard::cpp_98:
|
||||||
|
case cpp_standard::cpp_03:
|
||||||
|
case cpp_standard::cpp_11:
|
||||||
|
case cpp_standard::cpp_14:
|
||||||
|
case cpp_standard::cpp_1z:
|
||||||
|
case cpp_standard::cpp_17:
|
||||||
|
case cpp_standard::cpp_2a:
|
||||||
|
case cpp_standard::cpp_20:
|
||||||
|
case cpp_standard::cpp_2b:
|
||||||
|
return false;
|
||||||
|
case cpp_standard::c_89:
|
||||||
|
case cpp_standard::c_99:
|
||||||
|
case cpp_standard::c_11:
|
||||||
|
case cpp_standard::c_17:
|
||||||
|
case cpp_standard::c_2x:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Other special compilation flags.
|
/// Other special compilation flags.
|
||||||
enum class compile_flag
|
enum class compile_flag
|
||||||
{
|
{
|
||||||
|
|
@ -114,6 +162,12 @@ public:
|
||||||
return do_get_name();
|
return do_get_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \returns Whether to parse files as C rather than C++.
|
||||||
|
bool use_c() const noexcept
|
||||||
|
{
|
||||||
|
return do_use_c();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
compile_config(std::vector<std::string> def_flags) : flags_(std::move(def_flags)) {}
|
compile_config(std::vector<std::string> def_flags) : flags_(std::move(def_flags)) {}
|
||||||
|
|
||||||
|
|
@ -157,6 +211,9 @@ private:
|
||||||
/// \notes This allows detecting mismatches of configurations and parsers.
|
/// \notes This allows detecting mismatches of configurations and parsers.
|
||||||
virtual const char* do_get_name() const noexcept = 0;
|
virtual const char* do_get_name() const noexcept = 0;
|
||||||
|
|
||||||
|
/// \returns Whether to parse files as C rather than C++.
|
||||||
|
virtual bool do_use_c() const noexcept = 0;
|
||||||
|
|
||||||
std::vector<std::string> flags_;
|
std::vector<std::string> flags_;
|
||||||
};
|
};
|
||||||
} // namespace cppast
|
} // namespace cppast
|
||||||
|
|
|
||||||
|
|
@ -187,10 +187,13 @@ private:
|
||||||
return "libclang";
|
return "libclang";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool do_use_c() const noexcept override;
|
||||||
|
|
||||||
std::string clang_binary_;
|
std::string clang_binary_;
|
||||||
bool write_preprocessed_ : 1;
|
bool write_preprocessed_ : 1;
|
||||||
bool fast_preprocessing_ : 1;
|
bool fast_preprocessing_ : 1;
|
||||||
bool remove_comments_in_macro_ : 1;
|
bool remove_comments_in_macro_ : 1;
|
||||||
|
bool use_c_ : 1;
|
||||||
|
|
||||||
friend detail::libclang_compile_config_access;
|
friend detail::libclang_compile_config_access;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ libclang_compile_config::libclang_compile_config() : libclang_compile_config(CPP
|
||||||
|
|
||||||
libclang_compile_config::libclang_compile_config(std::string clang_binary)
|
libclang_compile_config::libclang_compile_config(std::string clang_binary)
|
||||||
: compile_config({}), write_preprocessed_(false), fast_preprocessing_(false),
|
: compile_config({}), write_preprocessed_(false), fast_preprocessing_(false),
|
||||||
remove_comments_in_macro_(false)
|
remove_comments_in_macro_(false), use_c_(false)
|
||||||
{
|
{
|
||||||
// set given clang binary
|
// set given clang binary
|
||||||
set_clang_binary(clang_binary);
|
set_clang_binary(clang_binary);
|
||||||
|
|
@ -226,6 +226,11 @@ cppast::libclang_compile_config::libclang_compile_config(
|
||||||
for (auto i = 0u; i != size; ++i)
|
for (auto i = 0u; i != size; ++i)
|
||||||
{
|
{
|
||||||
auto cmd = clang_CompileCommands_getCommand(commands.get(), i);
|
auto cmd = clang_CompileCommands_getCommand(commands.get(), i);
|
||||||
|
|
||||||
|
// If ++ exists within the compiler name (e.g. clang++, g++, etc), use C++
|
||||||
|
std::string exe(clang_getCString(clang_CompileCommand_getArg(cmd, 0)));
|
||||||
|
use_c_ = (exe.find("++", 0) == std::string::npos);
|
||||||
|
|
||||||
auto dir = detail::cxstring(clang_CompileCommand_getDirectory(cmd));
|
auto dir = detail::cxstring(clang_CompileCommand_getDirectory(cmd));
|
||||||
parse_flags(cmd, [&](std::string flag, std::string args) {
|
parse_flags(cmd, [&](std::string flag, std::string args) {
|
||||||
if (flag == "-I")
|
if (flag == "-I")
|
||||||
|
|
@ -243,11 +248,21 @@ cppast::libclang_compile_config::libclang_compile_config(
|
||||||
add_flag(std::move(flag));
|
add_flag(std::move(flag));
|
||||||
}
|
}
|
||||||
else if (flag == "-std")
|
else if (flag == "-std")
|
||||||
// standard
|
{
|
||||||
|
use_c_ = (args.find("++") == std::string::npos);
|
||||||
add_flag(std::move(flag) + "=" + std::move(args));
|
add_flag(std::move(flag) + "=" + std::move(args));
|
||||||
|
}
|
||||||
else if (flag == "-f")
|
else if (flag == "-f")
|
||||||
// other options
|
// other options
|
||||||
add_flag(std::move(flag) + std::move(args));
|
add_flag(std::move(flag) + std::move(args));
|
||||||
|
else if (flag == "-x")
|
||||||
|
{
|
||||||
|
// language
|
||||||
|
if (args == "c")
|
||||||
|
use_c_ = true;
|
||||||
|
else
|
||||||
|
use_c_ = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -270,8 +285,9 @@ bool is_valid_binary(const std::string& binary)
|
||||||
void add_default_include_dirs(libclang_compile_config& config)
|
void add_default_include_dirs(libclang_compile_config& config)
|
||||||
{
|
{
|
||||||
std::string verbose_output;
|
std::string verbose_output;
|
||||||
|
std::string language = config.use_c() ? "-xc" : "-xc++";
|
||||||
tpl::Process process(
|
tpl::Process process(
|
||||||
detail::libclang_compile_config_access::clang_binary(config) + " -x c++ -v -", "",
|
detail::libclang_compile_config_access::clang_binary(config) + " " + language + " -v -", "",
|
||||||
[](const char*, std::size_t) {},
|
[](const char*, std::size_t) {},
|
||||||
[&](const char* str, std::size_t n) { verbose_output.append(str, n); }, true);
|
[&](const char* str, std::size_t n) { verbose_output.append(str, n); }, true);
|
||||||
process.write("", 1);
|
process.write("", 1);
|
||||||
|
|
@ -415,6 +431,66 @@ void libclang_compile_config::do_set_flags(cpp_standard standard, compile_flags
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw std::invalid_argument("c++20 is not yet supported for current version of clang");
|
throw std::invalid_argument("c++20 is not yet supported for current version of clang");
|
||||||
|
case cpp_standard::cpp_2b:
|
||||||
|
if (libclang_parser::libclang_minor_version() >= 61)
|
||||||
|
{ // Corresponds to Clang version 12
|
||||||
|
if (flags & compile_flag::gnu_extensions)
|
||||||
|
add_flag("-std=gnu++2a");
|
||||||
|
else
|
||||||
|
add_flag("-std=c++2a");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw std::invalid_argument("c++2b is not yet supported for current version of clang");
|
||||||
|
case cpp_standard::c_89:
|
||||||
|
if (flags & compile_flag::gnu_extensions)
|
||||||
|
add_flag("-std=gnu89");
|
||||||
|
else
|
||||||
|
add_flag("-std=c89");
|
||||||
|
break;
|
||||||
|
case cpp_standard::c_99:
|
||||||
|
if (flags & compile_flag::gnu_extensions)
|
||||||
|
add_flag("-std=gnu99");
|
||||||
|
else
|
||||||
|
add_flag("-std=c99");
|
||||||
|
break;
|
||||||
|
case cpp_standard::c_11:
|
||||||
|
if (flags & compile_flag::gnu_extensions)
|
||||||
|
add_flag("-std=gnu11");
|
||||||
|
else
|
||||||
|
add_flag("-std=c11");
|
||||||
|
break;
|
||||||
|
case cpp_standard::c_17:
|
||||||
|
if (libclang_parser::libclang_minor_version() >= 45)
|
||||||
|
{ // Corresponds to Clang version 6
|
||||||
|
if (flags & compile_flag::gnu_extensions)
|
||||||
|
add_flag("-std=gnu17");
|
||||||
|
else
|
||||||
|
add_flag("-std=c17");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw std::invalid_argument("c17 is not yet supported for current version of clang");
|
||||||
|
case cpp_standard::c_2x:
|
||||||
|
if (libclang_parser::libclang_minor_version() >= 59)
|
||||||
|
{ // Corresponds to Clang version 9
|
||||||
|
if (flags & compile_flag::gnu_extensions)
|
||||||
|
add_flag("-std=gnu2x");
|
||||||
|
else
|
||||||
|
add_flag("-std=c2x");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw std::invalid_argument("c2x is not yet supported for current version of clang");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add language flag for C or C++
|
||||||
|
if (is_c_standard(standard)) {
|
||||||
|
add_flag("-xc");
|
||||||
|
use_c_ = true;
|
||||||
|
} else {
|
||||||
|
add_flag("-xc++");
|
||||||
|
use_c_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & compile_flag::ms_compatibility)
|
if (flags & compile_flag::ms_compatibility)
|
||||||
|
|
@ -452,6 +528,11 @@ void libclang_compile_config::do_remove_macro_definition(std::string name)
|
||||||
add_flag("-U" + std::move(name));
|
add_flag("-U" + std::move(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool libclang_compile_config::do_use_c() const noexcept
|
||||||
|
{
|
||||||
|
return use_c_;
|
||||||
|
}
|
||||||
|
|
||||||
type_safe::optional<libclang_compile_config> cppast::find_config_for(
|
type_safe::optional<libclang_compile_config> cppast::find_config_for(
|
||||||
const libclang_compilation_database& database, std::string file_name)
|
const libclang_compilation_database& database, std::string file_name)
|
||||||
{
|
{
|
||||||
|
|
@ -465,7 +546,7 @@ type_safe::optional<libclang_compile_config> cppast::find_config_for(
|
||||||
if (database.has_config(file_name))
|
if (database.has_config(file_name))
|
||||||
return libclang_compile_config(database, std::move(file_name));
|
return libclang_compile_config(database, std::move(file_name));
|
||||||
static const char* extensions[]
|
static const char* extensions[]
|
||||||
= {".h", ".hpp", ".cpp", ".h++", ".c++", ".hxx", ".cxx", ".hh", ".cc", ".H", ".C"};
|
= {".h", ".hpp", ".cpp", ".h++", ".c++", ".hxx", ".cxx", ".hh", ".cc", ".H", ".C", ".c"};
|
||||||
for (auto ext : extensions)
|
for (auto ext : extensions)
|
||||||
{
|
{
|
||||||
auto name = file_name + ext;
|
auto name = file_name + ext;
|
||||||
|
|
@ -502,8 +583,8 @@ namespace
|
||||||
std::vector<const char*> get_arguments(const libclang_compile_config& config)
|
std::vector<const char*> get_arguments(const libclang_compile_config& config)
|
||||||
{
|
{
|
||||||
std::vector<const char*> args
|
std::vector<const char*> args
|
||||||
// TODO: Why? and Why?
|
// TODO: Why?
|
||||||
= {"-x", "c++", "-I."}; // force C++ and enable current directory for include search
|
= {"-I."}; // enable current directory for include search
|
||||||
for (auto& flag : detail::libclang_compile_config_access::flags(config))
|
for (auto& flag : detail::libclang_compile_config_access::flags(config))
|
||||||
args.push_back(flag.c_str());
|
args.push_back(flag.c_str());
|
||||||
return args;
|
return args;
|
||||||
|
|
|
||||||
|
|
@ -174,11 +174,12 @@ std::string diagnostics_flags()
|
||||||
// get the command that returns all macros defined in the TU
|
// get the command that returns all macros defined in the TU
|
||||||
std::string get_macro_command(const libclang_compile_config& c, const char* full_path)
|
std::string get_macro_command(const libclang_compile_config& c, const char* full_path)
|
||||||
{
|
{
|
||||||
// -x c++: force C++ as input language
|
// -xc/-xc++: force C or C++ as input language
|
||||||
// -I.: add current working directory to include search path
|
// -I.: add current working directory to include search path
|
||||||
// -E: print preprocessor output
|
// -E: print preprocessor output
|
||||||
// -dM: print macro definitions instead of preprocessed file
|
// -dM: print macro definitions instead of preprocessed file
|
||||||
auto flags = std::string("-x c++ -I. -E -dM");
|
std::string language = c.use_c() ? "-xc" : "-xc++";
|
||||||
|
auto flags = language + " -I. -E -dM";
|
||||||
flags += diagnostics_flags();
|
flags += diagnostics_flags();
|
||||||
|
|
||||||
std::string cmd(detail::libclang_compile_config_access::clang_binary(c) + " " + std::move(flags)
|
std::string cmd(detail::libclang_compile_config_access::clang_binary(c) + " " + std::move(flags)
|
||||||
|
|
@ -198,10 +199,11 @@ std::string get_macro_command(const libclang_compile_config& c, const char* full
|
||||||
std::string get_preprocess_command(const libclang_compile_config& c, const char* full_path,
|
std::string get_preprocess_command(const libclang_compile_config& c, const char* full_path,
|
||||||
const char* macro_file_path)
|
const char* macro_file_path)
|
||||||
{
|
{
|
||||||
// -x c++: force C++ as input language
|
// -xc/-xc++: force C or C++ as input language
|
||||||
// -E: print preprocessor output
|
// -E: print preprocessor output
|
||||||
// -dD: keep macros
|
// -dD: keep macros
|
||||||
auto flags = std::string("-x c++ -E -dD");
|
std::string language = c.use_c() ? "-xc" : "-xc++";
|
||||||
|
auto flags = language + " -E -dD";
|
||||||
|
|
||||||
// -CC: keep comments, even in macro
|
// -CC: keep comments, even in macro
|
||||||
// -C: keep comments, but not in macro
|
// -C: keep comments, but not in macro
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,11 @@ TEST_CASE("parse_files")
|
||||||
{
|
{
|
||||||
return "null";
|
return "null";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool do_use_c() const noexcept override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} config;
|
} config;
|
||||||
|
|
||||||
class null_parser : public parser
|
class null_parser : public parser
|
||||||
|
|
|
||||||
|
|
@ -310,6 +310,8 @@ try
|
||||||
config.set_flags(cppast::cpp_standard::cpp_2a, flags);
|
config.set_flags(cppast::cpp_standard::cpp_2a, flags);
|
||||||
else if (options["std"].as<std::string>() == "c++20")
|
else if (options["std"].as<std::string>() == "c++20")
|
||||||
config.set_flags(cppast::cpp_standard::cpp_20, flags);
|
config.set_flags(cppast::cpp_standard::cpp_20, flags);
|
||||||
|
else if (options["std"].as<std::string>() == "c++2b")
|
||||||
|
config.set_flags(cppast::cpp_standard::cpp_2b, flags);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
print_error("invalid value '" + options["std"].as<std::string>() + "' for std flag");
|
print_error("invalid value '" + options["std"].as<std::string>() + "' for std flag");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue