/* * 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 #include #include #include #include #include #include #include #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 &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(); } } } 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