You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

181 lines
5.0 KiB

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <functional>
#include <iostream>
#include <memory>
#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <unordered_map>
#include <llvm/Support/Path.h>
#include "FileUtils.h"
#include "SimplePluginASTAction.h"
namespace ASTPluginLib {
/**
* The actual prefix to prepend to environment variables (but not for the
* command line).
*/
const std::string PluginASTOptionsBase::envPrefix = "CLANG_FRONTEND_PLUGIN__";
PluginASTOptionsBase::argmap_t PluginASTOptionsBase::makeMap(
const std::vector<std::string> &args) {
argmap_t map;
for (auto arg : args) {
size_t pos = arg.find('=');
if (pos != std::string::npos) {
std::string key = arg.substr(0, pos);
std::string value = arg.substr(pos + 1);
map[key] = value;
}
}
return map;
}
bool PluginASTOptionsBase::loadString(const argmap_t &map,
const char *key,
std::string &val) {
auto I = map.find(key);
if (I != map.end()) {
val = I->second;
return true;
}
const char *s = getenv((envPrefix + key).c_str());
if (s != nullptr) {
val = s;
return true;
}
return false;
}
bool PluginASTOptionsBase::loadBool(const argmap_t &map,
const char *key,
bool &val) {
std::string s_val;
if (loadString(map, key, s_val)) {
errno = 0;
val = (bool)strtol(s_val.c_str(), nullptr, 10);
if (errno) {
std::cerr << "[!] Failed to read a bool from " << key << "\n";
}
return true;
}
return false;
}
bool PluginASTOptionsBase::loadInt(const argmap_t &map,
const char *key,
long &val) {
std::string s_val;
if (loadString(map, key, s_val)) {
errno = 0;
val = strtol(s_val.c_str(), nullptr, 10);
if (errno) {
std::cerr << "[!] Failed to read an int from " << key << "\n";
}
return true;
}
return false;
}
bool PluginASTOptionsBase::loadUnsignedInt(const argmap_t &map,
const char *key,
unsigned long &val) {
std::string s_val;
if (loadString(map, key, s_val)) {
errno = 0;
val = strtoul(s_val.c_str(), nullptr, 10);
if (errno) {
std::cerr << "[!] Failed to read an unsigned int from " << key << "\n";
}
return true;
}
return false;
}
void PluginASTOptionsBase::loadValuesFromEnvAndMap(const argmap_t map) {
bool needBasePath = false;
loadBool(map, "ALLOW_SIBLINGS_TO_REPO_ROOT", allowSiblingsToRepoRoot);
loadBool(map, "KEEP_EXTERNAL_PATHS", keepExternalPaths);
loadString(map, "MAKE_RELATIVE_TO", repoRoot);
loadUnsignedInt(map, "MAX_STRING_SIZE", maxStringSize);
// Possibly override the first argument given on the command line.
loadString(map, "OUTPUT_FILE", outputFile);
loadBool(map, "PREPEND_CURRENT_DIR", needBasePath);
loadBool(map, "RESOLVE_SYMLINKS", resolveSymlinks);
loadString(map, "STRIP_ISYSROOT", iSysRoot);
if (needBasePath) {
llvm::SmallString<1024> CurrentDir;
if (llvm::sys::fs::current_path(CurrentDir)) {
llvm::errs() << "Failed to retrieve current working directory\n";
} else {
basePath = CurrentDir.str().str();
}
}
}
void PluginASTOptionsBase::setObjectFile(const std::string &path) {
objectFile = path;
if (path != "" && outputFile.size() > 0 && outputFile[0] == '%') {
outputFile = path + outputFile.substr(1);
}
}
/**
* Expects an immutable string on the heap as an argument
* (e.g. a path extracted from a node in the AST)
* Do not pass pointers to stack variables to this function.
* (e.g. a .str() call on a StringRef)
*/
const std::string &PluginASTOptionsBase::normalizeSourcePath(
const char *path) const {
auto I = normalizationCache->find(path);
if (I != normalizationCache->end()) {
return I->second;
}
std::string &result = (*normalizationCache)[path];
if (basePath == "") {
result = path;
return result;
}
std::string absPath = FileUtils::makeAbsolutePath(basePath, path);
if (resolveSymlinks) {
// if realPath is a symlink, resolve it
char buf[2048];
int len = readlink(absPath.c_str(), buf, sizeof(buf) - 1);
if (len != -1) {
buf[len] = '\0';
absPath = buf;
}
}
// By convention, relative paths are only activated when repoRoot != "".
if (repoRoot != "") {
result = FileUtils::makeRelativePath(repoRoot,
iSysRoot,
keepExternalPaths,
allowSiblingsToRepoRoot,
absPath);
} else {
result = absPath;
}
return result;
}
const std::string &PluginASTOptionsBase::normalizeSourcePath(
llvm::StringRef path) const {
return normalizeSourcePath(path.data());
}
} // namespace ASTPluginLib