Skip to content

Instantly share code, notes, and snippets.

@bstaletic
Last active March 22, 2018 08:34
Show Gist options
  • Save bstaletic/89b265f3eb9f1dde5988a812cb6669ec to your computer and use it in GitHub Desktop.
Save bstaletic/89b265f3eb9f1dde5988a812cb6669ec to your computer and use it in GitHub Desktop.
Flag sanitisation
#include <regex> // Consider boost::regex - it's much faster
static const std::vector<std::string> INCLUDE_FLAGS {"-isystem",
"-I",
"-iquote",
"-isysroot",
"--sysroot",
"-gcc-toolchain",
"-include-pch",
"-include",
"-iframework",
"-F",
"-imacros",
"-idirafter"}
static const std::vector<std::string> INCLUDE_FLAGS_WIN {"/I"}
static const std::vector<std::string> STATE_FLAGS {"-c",
"-MP",
"-MD",
"-MMD",
"--fcolor-diagnostics"};
static const std::vector<std::string> FILE_FLAGS {"-MF",
"-MT",
"-MQ",
"-o",
"--serialize-diagnostics"};
namespace LibClangSanitiser {
namespace {
void SkipUnusedFlags(std::vector<std::string>& flags, bool clang_cl) {
auto it = flags.begin();
if (!flags[0][0] == '-') ++it;
while (it != flags.end()) {
for (auto state_flag : STATE_FLAGS) {
if (*it == state_flag) it = flags.erase(it);
continue;
}
for (auto file_flag : FILE_FLAGS) {
if (*it == file_flag) it = flags.erase(it, it+1);
continue;
}
//if (*it == TU) it = flags.erase(it);
if SkipStrayFilenameFlag(*it, *(it - 1), clang_cl) {
it = flags.erase(it);
continue;
}
++it;
}
}
bool SkipStrayFilenameFlag(current_flag, previous_flag, clang_cl) {
bool current_starts_with_dash = current_flag[0] == '-';
bool current_starts_with_slash = current_flag[0] == '/';
bool current_may_be_path = current_flag.find('/') != std::string::npos ||
(current_flag.find('\\)' != std::string::npos &&
clang_cl);
bool current_flag_looks_like_flag = current_starts_with_dash ||
(current_starts_with_slash && clang_cl);
bool previous_starts_with_dash = previous_flag[0] == '-';
bool previous_starts_with_slash = previous_flag[0] == '/';
bool previous_is_include = false;
for (auto include_flag : INCLUDE_FLAGS) {
if (previous_flag == include_flag) {
previous_is_include = true;
break;
}
}
if (!previous_is_include) {
for (auto include_flag_win : INCLUDE_FLAGS_WIN) {
if (previous_flag == include_flag_win) {
previous_is_include = true;
break;
}
}
}
bool previous_flag_looks_like_flag = previous_starts_with_dash ||
(previous_starts_with_slash && clang_cl);
return !current_flag_looks_like_flag ||
!previous_flag_looks_like_flag ||
(!previous_is_include && current_may_be_path);
}
void RemoveXclangFlags(std::vector<std::string>& flags) {
for (auto it = flags.begin(); it != flags.end();) {
if (*it == "-Xclang") {
it = flags.erase(it, it + 1);
} else {
++it;
}
}
}
void RemoveFlagsPreceedingCompiler(std::vector<std::string>& flags, clang_cl) {
for (auto it = flags.begin(); it != flags.end(); ++it) {
if (*it[0] == '-') break;
if (*it[0] == '/' && clang_cl) break;
}
flags.erase(flags.begin(), --it);
}
void AddLanguageFlagIfCppFound(std::vector<std::string>& flags, bool clang_cl) {
RemoveFlagsPreceedingCompiler(flags, clang_cl);
const std::regex regex("\\+\\+(-\\d+('.'d+){0,2})?$", std::regex::optimize);
if (std::regex_search(flags[0], regex)) {
flags.insert(flags.begin() + 1, "-xc++");
}
}
bool EnableClangClFlags(const std::vector<std::string>& flags) {
#ifdef _WIN32
for (auto it = flags.rbegin(); it != flags.rend(); ++it) {
if (it->find("--driver-mode=") == 0) {
return *it == "--driver-mode=cl";
}
}
std::string compiler_flag = flags[0];
std::transform(compiler_flag.begin(),
compiler_flag.end(),
compiler_flag.begin(),
::tolower);
return compiler_flag.find("clang-cl") != std::string::npos ||
compiler_flag.find("cl.exe") != std::string::npos;
#endif
return false;
}
void EnableTypoCorrection(std::vector<std::string>& flags) {
if (!flags.find("-fno-spell-checking")) {
flags.emplace_back("-fspell-checking");
}
}
} // unnamed namespace
std::string PrepareFlagsForLibClang(std::vector<std::string> flags) {
bool clang_cl = EnableClangClFlags(flags);
AddLanguageFlagIfCppFound(flags, clang_cl);
RemoveXclangFlags(flags);
SkipUnusedFlags(flags, clang_cl);
//AppendSystemIncludes(flags);
return flags;
}
} // namespace LibClangSanitiser
#ifndef FLAG_SANITISING
#define FLAG_SANITISING
#include <vector>
#include <string>
namepsace LibClangSanitiser {
std::string PrepareFlagsForLibClang(std::vector<std::string> flags);
}
#endif /* ifndef FLAG_SANITISING */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment