Commit b43bf884 authored by Lukasz Anforowicz's avatar Lukasz Anforowicz Committed by Commit Bot

Support for --exclude-fields=fields-to-ignore.txt cmdline parameter.

Bug: 1069567
Change-Id: I8333f375425024ed83b4ccf23492257c6b773c3b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2158059
Commit-Queue: Łukasz Anforowicz <lukasza@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarBartek Nowierski <bartekn@chromium.org>
Cr-Commit-Position: refs/heads/master@{#771819}
parent aa4ba190
...@@ -48,6 +48,10 @@ namespace { ...@@ -48,6 +48,10 @@ namespace {
// replaces a raw pointer. // replaces a raw pointer.
const char kIncludePath[] = "base/memory/checked_ptr.h"; const char kIncludePath[] = "base/memory/checked_ptr.h";
// Name of a cmdline parameter that can be used to specify a file listing fields
// that should not be rewritten to use CheckedPtr<T>.
const char kExcludeFieldsParamName[] = "exclude-fields";
// Output format is documented in //docs/clang_tool_refactoring.md // Output format is documented in //docs/clang_tool_refactoring.md
class ReplacementsPrinter { class ReplacementsPrinter {
public: public:
...@@ -121,6 +125,67 @@ AST_MATCHER(clang::FieldDecl, isInThirdPartyLocation) { ...@@ -121,6 +125,67 @@ AST_MATCHER(clang::FieldDecl, isInThirdPartyLocation) {
return file_path.contains("third_party"); return file_path.contains("third_party");
} }
class FieldDeclFilterFile {
public:
explicit FieldDeclFilterFile(const std::string& filepath) {
if (!filepath.empty())
ParseInputFile(filepath);
}
bool Contains(const clang::FieldDecl& field_decl) const {
std::string qualified_name = field_decl.getQualifiedNameAsString();
auto it = fields_to_filter_.find(qualified_name);
return it != fields_to_filter_.end();
}
private:
// Expected file format:
// - '#' character starts a comment (which gets ignored).
// - Blank or whitespace-only or comment-only lines are ignored.
// - Other lines are expected to contain a fully-qualified name of a field
// like:
// autofill::AddressField::address1_ # some comment
// - Templates are represented without template arguments, like:
// WTF::HashTable::table_ # some comment
void ParseInputFile(const std::string& filepath) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> file_or_err =
llvm::MemoryBuffer::getFile(filepath);
if (std::error_code err = file_or_err.getError()) {
llvm::errs() << "ERROR: Cannot open the file specified in --"
<< kExcludeFieldsParamName << " argument: " << filepath
<< ": " << err.message() << "\n";
assert(false);
return;
}
llvm::line_iterator it(**file_or_err, true /* SkipBlanks */, '#');
for (; !it.is_at_eof(); ++it) {
llvm::StringRef line = *it;
// Remove trailing comments.
size_t comment_start_pos = line.find('#');
if (comment_start_pos != llvm::StringRef::npos)
line = line.substr(0, comment_start_pos);
line = line.trim();
if (line.empty())
continue;
fields_to_filter_.insert(line);
}
}
// Stores fully-namespace-qualified names of fields matched by the filter.
llvm::StringSet<> fields_to_filter_;
};
AST_MATCHER_P(clang::FieldDecl,
isListedInFilterFile,
FieldDeclFilterFile,
Filter) {
return Filter.Contains(Node);
}
AST_MATCHER(clang::ClassTemplateSpecializationDecl, isImplicitSpecialization) { AST_MATCHER(clang::ClassTemplateSpecializationDecl, isImplicitSpecialization) {
return !Node.isExplicitSpecialization(); return !Node.isExplicitSpecialization();
} }
...@@ -251,6 +316,9 @@ int main(int argc, const char* argv[]) { ...@@ -251,6 +316,9 @@ int main(int argc, const char* argv[]) {
llvm::InitializeNativeTargetAsmParser(); llvm::InitializeNativeTargetAsmParser();
llvm::cl::OptionCategory category( llvm::cl::OptionCategory category(
"rewrite_raw_ptr_fields: changes |T* field_| to |CheckedPtr<T> field_|."); "rewrite_raw_ptr_fields: changes |T* field_| to |CheckedPtr<T> field_|.");
llvm::cl::opt<std::string> exclude_fields_param(
kExcludeFieldsParamName, llvm::cl::value_desc("filepath"),
llvm::cl::desc("file listing fields to be blocked (not rewritten)"));
clang::tooling::CommonOptionsParser options(argc, argv, category); clang::tooling::CommonOptionsParser options(argc, argv, category);
clang::tooling::ClangTool tool(options.getCompilations(), clang::tooling::ClangTool tool(options.getCompilations(),
options.getSourcePathList()); options.getSourcePathList());
...@@ -302,10 +370,15 @@ int main(int argc, const char* argv[]) { ...@@ -302,10 +370,15 @@ int main(int argc, const char* argv[]) {
// matches |int* y|. Doesn't match: // matches |int* y|. Doesn't match:
// - non-pointer types // - non-pointer types
// - fields of lambda-supporting classes // - fields of lambda-supporting classes
// - fields listed in the --exclude-fields cmdline param
// - "implicit" fields (i.e. field decls that are not explicitly present in
// the source code)
FieldDeclFilterFile fields_to_exclude(exclude_fields_param);
auto field_decl_matcher = auto field_decl_matcher =
fieldDecl( fieldDecl(
allOf(hasType(supported_pointer_types_matcher), hasUniqueTypeLoc(), allOf(hasType(supported_pointer_types_matcher), hasUniqueTypeLoc(),
unless(anyOf(isInThirdPartyLocation(), isInMacroLocation(), unless(anyOf(isInThirdPartyLocation(), isInMacroLocation(),
isListedInFilterFile(fields_to_exclude),
implicit_field_decl_matcher)))) implicit_field_decl_matcher))))
.bind("fieldDecl"); .bind("fieldDecl");
FieldDeclRewriter field_decl_rewriter(&replacements_printer); FieldDeclRewriter field_decl_rewriter(&replacements_printer);
......
This diff is collapsed.
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/memory/checked_ptr.h"
class SomeClass;
namespace my_namespace {
struct MyStruct {
// Blocklisted - no rewrite expected.
SomeClass* my_field;
SomeClass* my_field2;
// Non-blocklisted - expected rewrite: CheckedPtr<SomeClass> my_field3;
CheckedPtr<SomeClass> my_field3;
};
template <typename T>
class MyTemplate {
public:
// Blocklisted - no rewrite expected.
SomeClass* my_field;
// Non-blocklisted - expected rewrite: CheckedPtr<SomeClass> my_field2;
CheckedPtr<SomeClass> my_field2;
};
} // namespace my_namespace
namespace other_namespace {
struct MyStruct {
// Blocklisted in another namespace, but not here.
// Expected rewrite: CheckedPtr<SomeClass> my_field;
CheckedPtr<SomeClass> my_field;
};
} // namespace other_namespace
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
class SomeClass;
namespace my_namespace {
struct MyStruct {
// Blocklisted - no rewrite expected.
SomeClass* my_field;
SomeClass* my_field2;
// Non-blocklisted - expected rewrite: CheckedPtr<SomeClass> my_field3;
SomeClass* my_field3;
};
template <typename T>
class MyTemplate {
public:
// Blocklisted - no rewrite expected.
SomeClass* my_field;
// Non-blocklisted - expected rewrite: CheckedPtr<SomeClass> my_field2;
SomeClass* my_field2;
};
} // namespace my_namespace
namespace other_namespace {
struct MyStruct {
// Blocklisted in another namespace, but not here.
// Expected rewrite: CheckedPtr<SomeClass> my_field;
SomeClass* my_field;
};
} // namespace other_namespace
# File that can be used as an argument of the --blocked-fields cmdline
# parameter of rewrite_raw_ptr_fields tool.
#
# Each non-whitespace / non-comment line specified a
# fully-namespace-qualified field that should not be rewritten
# to use CheckedPtr<T>.
# Next line is non-empty, but contains only whitespace.
my_namespace::MyStruct::my_field
my_namespace::MyStruct::my_field2 # Trailing comments also ok.
my_namespace::MyTemplate::my_field
--tool-arg=--exclude-fields=fields-to-ignore.txt
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment