#include "RawPtrPlugin.h"
#include "FindBadRawPtrPatterns.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "llvm/Support/TimeProfiler.h"
#include "tools/clang/plugins/FilteredASTConsumer.h"
using namespace clang;
namespace {
const char kExcludeFieldsArgPrefix[] = "exclude-fields=";
const char kRawPtrExcludePathArgPrefix[] = "raw-ptr-exclude-path=";
const char kBadRawPtrCastExcludePathArgPrefix[] =
"check-bad-raw-ptr-cast-exclude-path=";
const char kCheckBadRawPtrCastExcludeFuncArgPrefix[] =
"check-bad-raw-ptr-cast-exclude-func=";
}
namespace raw_ptr_plugin {
namespace {
class PluginConsumer : public FilteredASTConsumer {
public:
PluginConsumer(CompilerInstance* instance, const Options& options)
: options_(options), instance_(*instance) {}
void HandleTranslationUnit(clang::ASTContext& context) override {
llvm::TimeTraceScope TimeScope("HandleTranslationUnit for raw-ptr plugin");
ApplyFilter(context);
if (options_.check_bad_raw_ptr_cast || options_.check_raw_ptr_fields ||
options_.check_raw_ref_fields ||
(options_.check_raw_ptr_to_stack_allocated &&
!options_.disable_check_raw_ptr_to_stack_allocated_error) ||
options_.check_span_fields) {
FindBadRawPtrPatterns(options_, context, instance_);
}
}
private:
const Options options_;
clang::CompilerInstance& instance_;
};
}
RawPtrPlugin::RawPtrPlugin() {}
std::unique_ptr<ASTConsumer> RawPtrPlugin::CreateASTConsumer(
CompilerInstance& instance,
llvm::StringRef ref) {
return std::make_unique<PluginConsumer>(&instance, options_);
}
bool RawPtrPlugin::ParseArgs(const CompilerInstance& instance,
const std::vector<std::string>& args) {
for (llvm::StringRef arg : args) {
if (arg.starts_with(kExcludeFieldsArgPrefix)) {
options_.exclude_fields_file =
arg.substr(strlen(kExcludeFieldsArgPrefix)).str();
} else if (arg.starts_with(kRawPtrExcludePathArgPrefix)) {
options_.raw_ptr_paths_to_exclude_lines.push_back(
arg.substr(strlen(kRawPtrExcludePathArgPrefix)).str());
} else if (arg.starts_with(kCheckBadRawPtrCastExcludeFuncArgPrefix)) {
options_.check_bad_raw_ptr_cast_exclude_funcs.push_back(
arg.substr(strlen(kCheckBadRawPtrCastExcludeFuncArgPrefix)).str());
} else if (arg.starts_with(kBadRawPtrCastExcludePathArgPrefix)) {
options_.check_bad_raw_ptr_cast_exclude_paths.push_back(
arg.substr(strlen(kBadRawPtrCastExcludePathArgPrefix)).str());
} else if (arg == "check-bad-raw-ptr-cast") {
options_.check_bad_raw_ptr_cast = true;
} else if (arg == "check-raw-ptr-fields") {
options_.check_raw_ptr_fields = true;
} else if (arg == "check-raw-ptr-to-stack-allocated") {
options_.check_raw_ptr_to_stack_allocated = true;
} else if (arg == "disable-check-raw-ptr-to-stack-allocated-error") {
options_.disable_check_raw_ptr_to_stack_allocated_error = true;
} else if (arg == "check-raw-ref-fields") {
options_.check_raw_ref_fields = true;
} else if (arg == "check-ptrs-to-non-string-literals") {
options_.check_ptrs_to_non_string_literals = true;
} else if (arg == "check-span-fields") {
options_.check_span_fields = true;
} else if (arg == "enable-match-profiling") {
options_.enable_match_profiling = true;
} else {
llvm::errs() << "Unknown clang plugin argument: " << arg << "\n";
return false;
}
}
return true;
}
}
static FrontendPluginRegistry::Add<raw_ptr_plugin::RawPtrPlugin> X(
"raw-ptr-plugin",
"Check pointers for safety");