RewriteRawPtrFields.cpp 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. // This is implementation of a clang tool that rewrites raw pointer fields into
  5. // raw_ptr<T>:
  6. // Pointee* field_
  7. // becomes:
  8. // raw_ptr<Pointee> field_
  9. //
  10. // Note that the tool always emits two kinds of output:
  11. // 1. Fields to exclude:
  12. // - FilteredExprWriter
  13. // 2. Edit/replacement directives:
  14. // - FieldDeclRewriter
  15. // - AffectedExprRewriter
  16. // The rewriter is expected to be used twice, in two passes:
  17. // 1. Output from the 1st pass should be used to generate fields-to-ignore.txt
  18. // (or to augment the manually created exclusion list file)
  19. // 2. The 2nd pass should use fields-to-ignore.txt from the first pass as input
  20. // for the --exclude-fields cmdline parameter. The output from the 2nd pass
  21. // can be used to perform the actual rewrite via extract_edits.py and
  22. // apply_edits.py.
  23. //
  24. // For more details, see the doc here:
  25. // https://docs.google.com/document/d/1chTvr3fSofQNV_PDPEHRyUgcJCQBgTDOOBriW9gIm9M
  26. #include <assert.h>
  27. #include <algorithm>
  28. #include <limits>
  29. #include <memory>
  30. #include <string>
  31. #include <vector>
  32. #include "clang/AST/ASTContext.h"
  33. #include "clang/ASTMatchers/ASTMatchFinder.h"
  34. #include "clang/ASTMatchers/ASTMatchers.h"
  35. #include "clang/ASTMatchers/ASTMatchersMacros.h"
  36. #include "clang/Basic/CharInfo.h"
  37. #include "clang/Basic/SourceLocation.h"
  38. #include "clang/Basic/SourceManager.h"
  39. #include "clang/Frontend/CompilerInstance.h"
  40. #include "clang/Frontend/FrontendActions.h"
  41. #include "clang/Lex/Lexer.h"
  42. #include "clang/Lex/MacroArgs.h"
  43. #include "clang/Lex/PPCallbacks.h"
  44. #include "clang/Lex/Preprocessor.h"
  45. #include "clang/Tooling/CommonOptionsParser.h"
  46. #include "clang/Tooling/Refactoring.h"
  47. #include "clang/Tooling/Tooling.h"
  48. #include "llvm/ADT/StringExtras.h"
  49. #include "llvm/Support/CommandLine.h"
  50. #include "llvm/Support/ErrorOr.h"
  51. #include "llvm/Support/FormatVariadic.h"
  52. #include "llvm/Support/LineIterator.h"
  53. #include "llvm/Support/MemoryBuffer.h"
  54. #include "llvm/Support/Path.h"
  55. #include "llvm/Support/TargetSelect.h"
  56. using namespace clang::ast_matchers;
  57. namespace {
  58. // Include path that needs to be added to all the files where raw_ptr<...>
  59. // replaces a raw pointer.
  60. const char kIncludePath[] = "base/memory/raw_ptr.h";
  61. // Name of a cmdline parameter that can be used to specify a file listing fields
  62. // that should not be rewritten to use raw_ptr<T>.
  63. //
  64. // See also:
  65. // - OutputSectionHelper
  66. // - FilterFile
  67. const char kExcludeFieldsParamName[] = "exclude-fields";
  68. // Name of a cmdline parameter that can be used to specify a file listing
  69. // regular expressions describing paths that should be excluded from the
  70. // rewrite.
  71. //
  72. // See also:
  73. // - PathFilterFile
  74. const char kExcludePathsParamName[] = "exclude-paths";
  75. // OutputSectionHelper helps gather and emit a section of output.
  76. //
  77. // The section of output is delimited in a way that makes it easy to extract it
  78. // with sed like so:
  79. // $ DELIM = ...
  80. // $ cat ~/scratch/rewriter.out \
  81. // | sed '/^==== BEGIN $DELIM ====$/,/^==== END $DELIM ====$/{//!b};d' \
  82. // | sort | uniq > ~/scratch/some-out-of-band-output.txt
  83. // (For DELIM="EDITS", there is also tools/clang/scripts/extract_edits.py.)
  84. //
  85. // Each output line is deduped and may be followed by optional comment tags:
  86. // Some filter # tag1, tag2
  87. // Another filter # tag1, tag2, tag3
  88. // An output line with no comment tags
  89. //
  90. // The output lines are sorted. This helps provide deterministic output (even
  91. // if AST matchers start firing in a different order after benign clang
  92. // changes).
  93. //
  94. // See also:
  95. // - FilterFile
  96. // - OutputHelper
  97. class OutputSectionHelper {
  98. public:
  99. explicit OutputSectionHelper(llvm::StringRef output_delimiter)
  100. : output_delimiter_(output_delimiter.str()) {}
  101. OutputSectionHelper(const OutputSectionHelper&) = delete;
  102. OutputSectionHelper& operator=(const OutputSectionHelper&) = delete;
  103. void Add(llvm::StringRef output_line, llvm::StringRef tag = "") {
  104. // Look up |tags| associated with |output_line|. As a side effect of the
  105. // lookup, |output_line| will be inserted if it wasn't already present in
  106. // the map.
  107. llvm::StringSet<>& tags = output_line_to_tags_[output_line];
  108. if (!tag.empty())
  109. tags.insert(tag);
  110. }
  111. void Emit() {
  112. if (output_line_to_tags_.empty())
  113. return;
  114. llvm::outs() << "==== BEGIN " << output_delimiter_ << " ====\n";
  115. for (const llvm::StringRef& output_line :
  116. GetSortedKeys(output_line_to_tags_)) {
  117. llvm::outs() << output_line;
  118. const llvm::StringSet<>& tags = output_line_to_tags_[output_line];
  119. if (!tags.empty()) {
  120. std::vector<llvm::StringRef> sorted_tags = GetSortedKeys(tags);
  121. std::string tags_comment =
  122. llvm::join(sorted_tags.begin(), sorted_tags.end(), ", ");
  123. llvm::outs() << " # " << tags_comment;
  124. }
  125. llvm::outs() << "\n";
  126. }
  127. llvm::outs() << "==== END " << output_delimiter_ << " ====\n";
  128. }
  129. private:
  130. template <typename TValue>
  131. std::vector<llvm::StringRef> GetSortedKeys(
  132. const llvm::StringMap<TValue>& map) {
  133. std::vector<llvm::StringRef> sorted(map.keys().begin(), map.keys().end());
  134. std::sort(sorted.begin(), sorted.end());
  135. return sorted;
  136. }
  137. std::string output_delimiter_;
  138. llvm::StringMap<llvm::StringSet<>> output_line_to_tags_;
  139. };
  140. // Output format is documented in //docs/clang_tool_refactoring.md
  141. class OutputHelper : public clang::tooling::SourceFileCallbacks {
  142. public:
  143. OutputHelper()
  144. : edits_helper_("EDITS"), field_decl_filter_helper_("FIELD FILTERS") {}
  145. ~OutputHelper() = default;
  146. OutputHelper(const OutputHelper&) = delete;
  147. OutputHelper& operator=(const OutputHelper&) = delete;
  148. void AddReplacement(const clang::SourceManager& source_manager,
  149. const clang::SourceRange& replacement_range,
  150. std::string replacement_text,
  151. bool should_add_include = false) {
  152. clang::tooling::Replacement replacement(
  153. source_manager, clang::CharSourceRange::getCharRange(replacement_range),
  154. replacement_text);
  155. llvm::StringRef file_path = replacement.getFilePath();
  156. if (file_path.empty())
  157. return;
  158. std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0');
  159. std::string replacement_directive = llvm::formatv(
  160. "r:::{0}:::{1}:::{2}:::{3}", file_path, replacement.getOffset(),
  161. replacement.getLength(), replacement_text);
  162. edits_helper_.Add(replacement_directive);
  163. if (should_add_include) {
  164. std::string include_directive = llvm::formatv(
  165. "include-user-header:::{0}:::-1:::-1:::{1}", file_path, kIncludePath);
  166. edits_helper_.Add(include_directive);
  167. }
  168. }
  169. void AddFilteredField(const clang::FieldDecl& field_decl,
  170. llvm::StringRef filter_tag) {
  171. std::string qualified_name = field_decl.getQualifiedNameAsString();
  172. field_decl_filter_helper_.Add(qualified_name, filter_tag);
  173. }
  174. private:
  175. // clang::tooling::SourceFileCallbacks override:
  176. bool handleBeginSource(clang::CompilerInstance& compiler) override {
  177. const clang::FrontendOptions& frontend_options = compiler.getFrontendOpts();
  178. assert((frontend_options.Inputs.size() == 1) &&
  179. "run_tool.py should invoke the rewriter one file at a time");
  180. const clang::FrontendInputFile& input_file = frontend_options.Inputs[0];
  181. assert(input_file.isFile() &&
  182. "run_tool.py should invoke the rewriter on actual files");
  183. current_language_ = input_file.getKind().getLanguage();
  184. return true; // Report that |handleBeginSource| succeeded.
  185. }
  186. // clang::tooling::SourceFileCallbacks override:
  187. void handleEndSource() override {
  188. if (ShouldSuppressOutput())
  189. return;
  190. edits_helper_.Emit();
  191. field_decl_filter_helper_.Emit();
  192. }
  193. bool ShouldSuppressOutput() {
  194. switch (current_language_) {
  195. case clang::Language::Unknown:
  196. case clang::Language::Asm:
  197. case clang::Language::LLVM_IR:
  198. case clang::Language::OpenCL:
  199. case clang::Language::CUDA:
  200. case clang::Language::RenderScript:
  201. case clang::Language::HIP:
  202. // Rewriter can't handle rewriting the current input language.
  203. return true;
  204. case clang::Language::C:
  205. case clang::Language::ObjC:
  206. // raw_ptr<T> requires C++. In particular, attempting to #include
  207. // "base/memory/raw_ptr.h" from C-only compilation units will lead
  208. // to compilation errors.
  209. return true;
  210. case clang::Language::CXX:
  211. case clang::Language::OpenCLCXX:
  212. case clang::Language::ObjCXX:
  213. return false;
  214. }
  215. assert(false && "Unrecognized clang::Language");
  216. return true;
  217. }
  218. OutputSectionHelper edits_helper_;
  219. OutputSectionHelper field_decl_filter_helper_;
  220. clang::Language current_language_ = clang::Language::Unknown;
  221. };
  222. llvm::StringRef GetFilePath(const clang::SourceManager& source_manager,
  223. const clang::FieldDecl& field_decl) {
  224. clang::SourceLocation loc = field_decl.getSourceRange().getBegin();
  225. if (loc.isInvalid() || !loc.isFileID())
  226. return llvm::StringRef();
  227. clang::FileID file_id = source_manager.getDecomposedLoc(loc).first;
  228. const clang::FileEntry* file_entry =
  229. source_manager.getFileEntryForID(file_id);
  230. if (!file_entry)
  231. return llvm::StringRef();
  232. return file_entry->getName();
  233. }
  234. AST_MATCHER(clang::FieldDecl, isInThirdPartyLocation) {
  235. llvm::StringRef file_path =
  236. GetFilePath(Finder->getASTContext().getSourceManager(), Node);
  237. // Blink is part of the Chromium git repo, even though it contains
  238. // "third_party" in its path.
  239. if (file_path.contains("third_party/blink/"))
  240. return false;
  241. // Otherwise, just check if the paths contains the "third_party" substring.
  242. // We don't want to rewrite content of such paths even if they are in the main
  243. // Chromium git repository.
  244. return file_path.contains("third_party");
  245. }
  246. AST_MATCHER(clang::FieldDecl, isInGeneratedLocation) {
  247. llvm::StringRef file_path =
  248. GetFilePath(Finder->getASTContext().getSourceManager(), Node);
  249. return file_path.startswith("gen/") || file_path.contains("/gen/");
  250. }
  251. // Represents a filter file specified via cmdline.
  252. class FilterFile {
  253. public:
  254. explicit FilterFile(const llvm::cl::opt<std::string>& cmdline_param) {
  255. ParseInputFile(cmdline_param);
  256. }
  257. FilterFile(const FilterFile&) = delete;
  258. FilterFile& operator=(const FilterFile&) = delete;
  259. // Returns true if any of the filter file lines is exactly equal to |line|.
  260. bool ContainsLine(llvm::StringRef line) const {
  261. auto it = file_lines_.find(line);
  262. return it != file_lines_.end();
  263. }
  264. // Returns true if |string_to_match| matches based on the filter file lines.
  265. // Filter file lines can contain both inclusions and exclusions in the filter.
  266. // Only returns true if |string_to_match| both matches an inclusion filter and
  267. // is *not* matched by an exclusion filter.
  268. bool ContainsSubstringOf(llvm::StringRef string_to_match) const {
  269. if (!inclusion_substring_regex_.hasValue()) {
  270. std::vector<std::string> regex_escaped_inclusion_file_lines;
  271. std::vector<std::string> regex_escaped_exclusion_file_lines;
  272. regex_escaped_inclusion_file_lines.reserve(file_lines_.size());
  273. for (const llvm::StringRef& file_line : file_lines_.keys()) {
  274. if (file_line.startswith("!")) {
  275. regex_escaped_exclusion_file_lines.push_back(
  276. llvm::Regex::escape(file_line.substr(1)));
  277. } else {
  278. regex_escaped_inclusion_file_lines.push_back(
  279. llvm::Regex::escape(file_line));
  280. }
  281. }
  282. std::string inclusion_substring_regex_pattern =
  283. llvm::join(regex_escaped_inclusion_file_lines.begin(),
  284. regex_escaped_inclusion_file_lines.end(), "|");
  285. inclusion_substring_regex_.emplace(inclusion_substring_regex_pattern);
  286. std::string exclusion_substring_regex_pattern =
  287. llvm::join(regex_escaped_exclusion_file_lines.begin(),
  288. regex_escaped_exclusion_file_lines.end(), "|");
  289. exclusion_substring_regex_.emplace(exclusion_substring_regex_pattern);
  290. }
  291. return inclusion_substring_regex_->match(string_to_match) &&
  292. !exclusion_substring_regex_->match(string_to_match);
  293. }
  294. private:
  295. // Expected file format:
  296. // - '#' character starts a comment (which gets ignored).
  297. // - Blank or whitespace-only or comment-only lines are ignored.
  298. // - Other lines are expected to contain a fully-qualified name of a field
  299. // like:
  300. // autofill::AddressField::address1_ # some comment
  301. // - Templates are represented without template arguments, like:
  302. // WTF::HashTable::table_ # some comment
  303. void ParseInputFile(const llvm::cl::opt<std::string>& cmdline_param) {
  304. std::string filepath = cmdline_param;
  305. if (filepath.empty())
  306. return;
  307. llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> file_or_err =
  308. llvm::MemoryBuffer::getFile(filepath);
  309. if (std::error_code err = file_or_err.getError()) {
  310. llvm::errs() << "ERROR: Cannot open the file specified in --"
  311. << cmdline_param.ArgStr << " argument: " << filepath << ": "
  312. << err.message() << "\n";
  313. assert(false);
  314. return;
  315. }
  316. llvm::line_iterator it(**file_or_err, true /* SkipBlanks */, '#');
  317. for (; !it.is_at_eof(); ++it) {
  318. llvm::StringRef line = *it;
  319. // Remove trailing comments.
  320. size_t comment_start_pos = line.find('#');
  321. if (comment_start_pos != llvm::StringRef::npos)
  322. line = line.substr(0, comment_start_pos);
  323. line = line.trim();
  324. if (line.empty())
  325. continue;
  326. file_lines_.insert(line);
  327. }
  328. }
  329. // Stores all file lines (after stripping comments and blank lines).
  330. llvm::StringSet<> file_lines_;
  331. // |file_lines_| is partitioned based on whether the line starts with a !
  332. // (exclusion line) or not (inclusion line). Inclusion lines specify things to
  333. // be matched by the filter. The exclusion lines specify what to force exclude
  334. // from the filter. Lazily-constructed regex that matches strings that contain
  335. // any of the inclusion lines in |file_lines_|.
  336. mutable llvm::Optional<llvm::Regex> inclusion_substring_regex_;
  337. // Lazily-constructed regex that matches strings that contain any of the
  338. // exclusion lines in |file_lines_|.
  339. mutable llvm::Optional<llvm::Regex> exclusion_substring_regex_;
  340. };
  341. AST_MATCHER_P(clang::FieldDecl,
  342. isFieldDeclListedInFilterFile,
  343. const FilterFile*,
  344. Filter) {
  345. return Filter->ContainsLine(Node.getQualifiedNameAsString());
  346. }
  347. AST_MATCHER_P(clang::FieldDecl,
  348. isInLocationListedInFilterFile,
  349. const FilterFile*,
  350. Filter) {
  351. llvm::StringRef file_path =
  352. GetFilePath(Finder->getASTContext().getSourceManager(), Node);
  353. return Filter->ContainsSubstringOf(file_path);
  354. }
  355. AST_MATCHER(clang::Decl, isInExternCContext) {
  356. return Node.getLexicalDeclContext()->isExternCContext();
  357. }
  358. // Given:
  359. // template <typename T, typename T2> class MyTemplate {}; // Node1 and Node4
  360. // template <typename T2> class MyTemplate<int, T2> {}; // Node2
  361. // template <> class MyTemplate<int, char> {}; // Node3
  362. // void foo() {
  363. // // This creates implicit template specialization (Node4) out of the
  364. // // explicit template definition (Node1).
  365. // MyTemplate<bool, double> v;
  366. // }
  367. // with the following AST nodes:
  368. // ClassTemplateDecl MyTemplate - Node1
  369. // | |-CXXRecordDecl class MyTemplate definition
  370. // | `-ClassTemplateSpecializationDecl class MyTemplate definition - Node4
  371. // ClassTemplatePartialSpecializationDecl class MyTemplate definition - Node2
  372. // ClassTemplateSpecializationDecl class MyTemplate definition - Node3
  373. //
  374. // Matches AST node 4, but not AST node2 nor node3.
  375. AST_MATCHER(clang::ClassTemplateSpecializationDecl,
  376. isImplicitClassTemplateSpecialization) {
  377. return !Node.isExplicitSpecialization();
  378. }
  379. // Matches CXXRecordDecls that are classified as trivial:
  380. // https://en.cppreference.com/w/cpp/named_req/TrivialType
  381. AST_MATCHER(clang::CXXRecordDecl, isTrivial) {
  382. return Node.isTrivial();
  383. }
  384. // Given:
  385. // template <typename T, typename T2> void foo(T t, T2 t2) {}; // N1 and N4
  386. // template <typename T2> void foo<int, T2>(int t, T2 t) {}; // N2
  387. // template <> void foo<int, char>(int t, char t2) {}; // N3
  388. // void foo() {
  389. // // This creates implicit template specialization (N4) out of the
  390. // // explicit template definition (N1).
  391. // foo<bool, double>(true, 1.23);
  392. // }
  393. // with the following AST nodes:
  394. // FunctionTemplateDecl foo
  395. // |-FunctionDecl 0x191da68 foo 'void (T, T2)' // N1
  396. // `-FunctionDecl 0x194bf08 foo 'void (bool, double)' // N4
  397. // FunctionTemplateDecl foo
  398. // `-FunctionDecl foo 'void (int, T2)' // N2
  399. // FunctionDecl foo 'void (int, char)' // N3
  400. //
  401. // Matches AST node N4, but not AST nodes N1, N2 nor N3.
  402. AST_MATCHER(clang::FunctionDecl, isImplicitFunctionTemplateSpecialization) {
  403. switch (Node.getTemplateSpecializationKind()) {
  404. case clang::TSK_ImplicitInstantiation:
  405. return true;
  406. case clang::TSK_Undeclared:
  407. case clang::TSK_ExplicitSpecialization:
  408. case clang::TSK_ExplicitInstantiationDeclaration:
  409. case clang::TSK_ExplicitInstantiationDefinition:
  410. return false;
  411. }
  412. }
  413. AST_MATCHER(clang::Type, anyCharType) {
  414. return Node.isAnyCharacterType();
  415. }
  416. AST_POLYMORPHIC_MATCHER(isInMacroLocation,
  417. AST_POLYMORPHIC_SUPPORTED_TYPES(clang::Decl,
  418. clang::Stmt,
  419. clang::TypeLoc)) {
  420. return Node.getBeginLoc().isMacroID();
  421. }
  422. static bool IsAnnotated(const clang::Decl* decl,
  423. const std::string& expected_annotation) {
  424. clang::AnnotateAttr* attr = decl->getAttr<clang::AnnotateAttr>();
  425. return attr && (attr->getAnnotation() == expected_annotation);
  426. }
  427. AST_MATCHER(clang::Decl, IsExclusionAnnotated) {
  428. return IsAnnotated(&Node, "raw_ptr_exclusion");
  429. }
  430. // If |field_decl| declares a field in an implicit template specialization, then
  431. // finds and returns the corresponding FieldDecl from the template definition.
  432. // Otherwise, just returns the original |field_decl| argument.
  433. const clang::FieldDecl* GetExplicitDecl(const clang::FieldDecl* field_decl) {
  434. if (field_decl->isAnonymousStructOrUnion())
  435. return field_decl; // Safe fallback - |field_decl| is not a pointer field.
  436. const clang::CXXRecordDecl* record_decl =
  437. clang::dyn_cast<clang::CXXRecordDecl>(field_decl->getParent());
  438. if (!record_decl)
  439. return field_decl; // Non-C++ records are never template instantiations.
  440. const clang::CXXRecordDecl* pattern_decl =
  441. record_decl->getTemplateInstantiationPattern();
  442. if (!pattern_decl)
  443. return field_decl; // |pattern_decl| is not a template instantiation.
  444. if (record_decl->getTemplateSpecializationKind() !=
  445. clang::TemplateSpecializationKind::TSK_ImplicitInstantiation) {
  446. return field_decl; // |field_decl| was in an *explicit* specialization.
  447. }
  448. // Find the field decl with the same name in |pattern_decl|.
  449. clang::DeclContextLookupResult lookup_result =
  450. pattern_decl->lookup(field_decl->getDeclName());
  451. assert(!lookup_result.empty());
  452. const clang::NamedDecl* found_decl = lookup_result.front();
  453. assert(found_decl);
  454. field_decl = clang::dyn_cast<clang::FieldDecl>(found_decl);
  455. assert(field_decl);
  456. return field_decl;
  457. }
  458. // Given:
  459. // template <typename T>
  460. // class MyTemplate {
  461. // T field; // This is an explicit field declaration.
  462. // };
  463. // void foo() {
  464. // // This creates implicit template specialization for MyTemplate,
  465. // // including an implicit |field| declaration.
  466. // MyTemplate<int> v;
  467. // v.field = 123;
  468. // }
  469. // and
  470. // innerMatcher that will match the explicit |T field| declaration (but not
  471. // necessarily the implicit template declarations),
  472. // hasExplicitFieldDecl(innerMatcher) will match both explicit and implicit
  473. // field declarations.
  474. //
  475. // For example, |member_expr_matcher| below will match |v.field| in the example
  476. // above, even though the type of |v.field| is |int|, rather than |T| (matched
  477. // by substTemplateTypeParmType()):
  478. // auto explicit_field_decl_matcher =
  479. // fieldDecl(hasType(substTemplateTypeParmType()));
  480. // auto member_expr_matcher = memberExpr(member(fieldDecl(
  481. // hasExplicitFieldDecl(explicit_field_decl_matcher))))
  482. AST_MATCHER_P(clang::FieldDecl,
  483. hasExplicitFieldDecl,
  484. clang::ast_matchers::internal::Matcher<clang::FieldDecl>,
  485. InnerMatcher) {
  486. const clang::FieldDecl* explicit_field_decl = GetExplicitDecl(&Node);
  487. return InnerMatcher.matches(*explicit_field_decl, Finder, Builder);
  488. }
  489. // If |original_param| declares a parameter in an implicit template
  490. // specialization of a function or method, then finds and returns the
  491. // corresponding ParmVarDecl from the template definition. Otherwise, just
  492. // returns the |original_param| argument.
  493. //
  494. // Note: nullptr may be returned in rare, unimplemented cases.
  495. const clang::ParmVarDecl* GetExplicitDecl(
  496. const clang::ParmVarDecl* original_param) {
  497. const clang::FunctionDecl* original_func =
  498. clang::dyn_cast<clang::FunctionDecl>(original_param->getDeclContext());
  499. if (!original_func) {
  500. // |!original_func| may happen when the ParmVarDecl is part of a
  501. // FunctionType, but not part of a FunctionDecl:
  502. // base::RepeatingCallback<void(int parm_var_decl_here)>
  503. //
  504. // In theory, |parm_var_decl_here| can also represent an implicit template
  505. // specialization in this scenario. OTOH, it should be rare + shouldn't
  506. // matter for this rewriter, so for now let's just return the
  507. // |original_param|.
  508. //
  509. // TODO: Implement support for this scenario.
  510. return nullptr;
  511. }
  512. const clang::FunctionDecl* pattern_func =
  513. original_func->getTemplateInstantiationPattern();
  514. if (!pattern_func) {
  515. // |original_func| is not a template instantiation - return the
  516. // |original_param|.
  517. return original_param;
  518. }
  519. // See if |pattern_func| has a parameter that is a template parameter pack.
  520. bool has_param_pack = false;
  521. unsigned int index_of_param_pack = std::numeric_limits<unsigned int>::max();
  522. for (unsigned int i = 0; i < pattern_func->getNumParams(); i++) {
  523. const clang::ParmVarDecl* pattern_param = pattern_func->getParamDecl(i);
  524. if (!pattern_param->isParameterPack())
  525. continue;
  526. if (has_param_pack) {
  527. // TODO: Implement support for multiple parameter packs.
  528. return nullptr;
  529. }
  530. has_param_pack = true;
  531. index_of_param_pack = i;
  532. }
  533. // Find and return the corresponding ParmVarDecl from |pattern_func|.
  534. unsigned int original_index = original_param->getFunctionScopeIndex();
  535. unsigned int pattern_index = std::numeric_limits<unsigned int>::max();
  536. if (!has_param_pack) {
  537. pattern_index = original_index;
  538. } else {
  539. // |original_func| has parameters that look like this:
  540. // l1, l2, l3, p1, p2, p3, t1, t2, t3
  541. // where
  542. // lN is a leading, non-pack parameter
  543. // pN is an expansion of a template parameter pack
  544. // tN is a trailing, non-pack parameter
  545. // Using the knowledge above, let's adjust |pattern_index| as needed.
  546. unsigned int leading_param_num = index_of_param_pack; // How many |lN|.
  547. unsigned int pack_expansion_num = // How many |pN| above.
  548. original_func->getNumParams() - pattern_func->getNumParams() + 1;
  549. if (original_index < leading_param_num) {
  550. // |original_param| is a leading, non-pack parameter.
  551. pattern_index = original_index;
  552. } else if (leading_param_num <= original_index &&
  553. original_index < (leading_param_num + pack_expansion_num)) {
  554. // |original_param| is an expansion of a template pack parameter.
  555. pattern_index = index_of_param_pack;
  556. } else if ((leading_param_num + pack_expansion_num) <= original_index) {
  557. // |original_param| is a trailing, non-pack parameter.
  558. pattern_index = original_index - pack_expansion_num + 1;
  559. }
  560. }
  561. assert(pattern_index < pattern_func->getNumParams());
  562. return pattern_func->getParamDecl(pattern_index);
  563. }
  564. AST_MATCHER_P(clang::ParmVarDecl,
  565. hasExplicitParmVarDecl,
  566. clang::ast_matchers::internal::Matcher<clang::ParmVarDecl>,
  567. InnerMatcher) {
  568. const clang::ParmVarDecl* explicit_param = GetExplicitDecl(&Node);
  569. if (!explicit_param) {
  570. // Rare, unimplemented case - fall back to returning "no match".
  571. return false;
  572. }
  573. return InnerMatcher.matches(*explicit_param, Finder, Builder);
  574. }
  575. // Returns |true| if and only if:
  576. // 1. |a| and |b| are in the same file (e.g. |false| is returned if any location
  577. // is within macro scratch space or a similar location; similarly |false| is
  578. // returned if |a| and |b| are in different files).
  579. // 2. |a| and |b| overlap.
  580. bool IsOverlapping(const clang::SourceManager& source_manager,
  581. const clang::SourceRange& a,
  582. const clang::SourceRange& b) {
  583. clang::FullSourceLoc a1(a.getBegin(), source_manager);
  584. clang::FullSourceLoc a2(a.getEnd(), source_manager);
  585. clang::FullSourceLoc b1(b.getBegin(), source_manager);
  586. clang::FullSourceLoc b2(b.getEnd(), source_manager);
  587. // Are all locations in a file?
  588. if (!a1.isFileID() || !a2.isFileID() || !b1.isFileID() || !b2.isFileID())
  589. return false;
  590. // Are all locations in the same file?
  591. if (a1.getFileID() != a2.getFileID() || a2.getFileID() != b1.getFileID() ||
  592. b1.getFileID() != b2.getFileID()) {
  593. return false;
  594. }
  595. // Check the 2 cases below:
  596. // 1. A: |============|
  597. // B: |===============|
  598. // a1 b1 a2 b2
  599. // or
  600. // 2. A: |====================|
  601. // B: |=======|
  602. // a1 b1 b2 a2
  603. bool b1_is_inside_a_range = a1.getFileOffset() <= b1.getFileOffset() &&
  604. b1.getFileOffset() <= a2.getFileOffset();
  605. // Check the 2 cases below:
  606. // 1. B: |============|
  607. // A: |===============|
  608. // b1 a1 b2 a2
  609. // or
  610. // 2. B: |====================|
  611. // A: |=======|
  612. // b1 a1 a2 b2
  613. bool a1_is_inside_b_range = b1.getFileOffset() <= a1.getFileOffset() &&
  614. a1.getFileOffset() <= b2.getFileOffset();
  615. return b1_is_inside_a_range || a1_is_inside_b_range;
  616. }
  617. // Matcher for FieldDecl that has a SourceRange that overlaps other declarations
  618. // within the parent RecordDecl.
  619. //
  620. // Given
  621. // struct MyStruct {
  622. // int f;
  623. // int f2, f3;
  624. // struct S { int x } f4;
  625. // };
  626. // - doesn't match |f|
  627. // - matches |f2| and |f3| (which overlap each other's location)
  628. // - matches |f4| (which overlaps the location of |S|)
  629. AST_MATCHER(clang::FieldDecl, overlapsOtherDeclsWithinRecordDecl) {
  630. const clang::FieldDecl& self = Node;
  631. const clang::SourceManager& source_manager =
  632. Finder->getASTContext().getSourceManager();
  633. const clang::RecordDecl* record_decl = self.getParent();
  634. if (!record_decl)
  635. return false;
  636. clang::SourceRange self_range(self.getBeginLoc(), self.getEndLoc());
  637. auto is_overlapping_sibling = [&](const clang::Decl* other_decl) {
  638. if (other_decl == &self)
  639. return false;
  640. clang::SourceRange other_range(other_decl->getBeginLoc(),
  641. other_decl->getEndLoc());
  642. return IsOverlapping(source_manager, self_range, other_range);
  643. };
  644. bool has_sibling_with_overlapping_location =
  645. std::any_of(record_decl->decls_begin(), record_decl->decls_end(),
  646. is_overlapping_sibling);
  647. return has_sibling_with_overlapping_location;
  648. }
  649. // Matches clang::Type if
  650. // 1) it represents a RecordDecl with a FieldDecl that matches the InnerMatcher
  651. // (*all* such FieldDecls will be matched)
  652. // or
  653. // 2) it represents an array or a RecordDecl that nests the case #1
  654. // (this recurses to any depth).
  655. AST_MATCHER_P(clang::QualType,
  656. typeWithEmbeddedFieldDecl,
  657. clang::ast_matchers::internal::Matcher<clang::FieldDecl>,
  658. InnerMatcher) {
  659. const clang::Type* type =
  660. Node.getDesugaredType(Finder->getASTContext()).getTypePtrOrNull();
  661. if (!type)
  662. return false;
  663. if (const clang::CXXRecordDecl* record_decl = type->getAsCXXRecordDecl()) {
  664. auto matcher = recordDecl(forEach(fieldDecl(hasExplicitFieldDecl(anyOf(
  665. InnerMatcher, hasType(typeWithEmbeddedFieldDecl(InnerMatcher)))))));
  666. return matcher.matches(*record_decl, Finder, Builder);
  667. }
  668. if (type->isArrayType()) {
  669. const clang::ArrayType* array_type =
  670. Finder->getASTContext().getAsArrayType(Node);
  671. auto matcher = typeWithEmbeddedFieldDecl(InnerMatcher);
  672. return matcher.matches(array_type->getElementType(), Finder, Builder);
  673. }
  674. return false;
  675. }
  676. // forEachInitExprWithFieldDecl matches InitListExpr if it
  677. // 1) evaluates to a RecordType
  678. // 2) has a InitListExpr + FieldDecl pair that matches the submatcher args.
  679. //
  680. // forEachInitExprWithFieldDecl is based on and very similar to the builtin
  681. // forEachArgumentWithParam matcher.
  682. AST_MATCHER_P2(clang::InitListExpr,
  683. forEachInitExprWithFieldDecl,
  684. clang::ast_matchers::internal::Matcher<clang::Expr>,
  685. init_expr_matcher,
  686. clang::ast_matchers::internal::Matcher<clang::FieldDecl>,
  687. field_decl_matcher) {
  688. const clang::InitListExpr& init_list_expr = Node;
  689. const clang::Type* type = init_list_expr.getType()
  690. .getDesugaredType(Finder->getASTContext())
  691. .getTypePtrOrNull();
  692. if (!type)
  693. return false;
  694. const clang::CXXRecordDecl* record_decl = type->getAsCXXRecordDecl();
  695. if (!record_decl)
  696. return false;
  697. bool is_matching = false;
  698. clang::ast_matchers::internal::BoundNodesTreeBuilder result;
  699. const llvm::SmallVector<const clang::FieldDecl*> field_decls(
  700. record_decl->fields());
  701. for (unsigned i = 0; i < init_list_expr.getNumInits(); i++) {
  702. const clang::Expr* expr = init_list_expr.getInit(i);
  703. const clang::FieldDecl* field_decl = nullptr;
  704. if (const clang::ImplicitValueInitExpr* implicit_value_init_expr =
  705. clang::dyn_cast<clang::ImplicitValueInitExpr>(expr)) {
  706. continue; // Do not match implicit value initializers.
  707. } else if (const clang::DesignatedInitExpr* designated_init_expr =
  708. clang::dyn_cast<clang::DesignatedInitExpr>(expr)) {
  709. // Nested designators are unsupported by C++.
  710. if (designated_init_expr->size() != 1)
  711. break;
  712. expr = designated_init_expr->getInit();
  713. field_decl = designated_init_expr->getDesignator(0)->getField();
  714. } else {
  715. if (i >= field_decls.size())
  716. break;
  717. field_decl = field_decls[i];
  718. }
  719. clang::ast_matchers::internal::BoundNodesTreeBuilder field_matches(
  720. *Builder);
  721. if (field_decl_matcher.matches(*field_decl, Finder, &field_matches)) {
  722. clang::ast_matchers::internal::BoundNodesTreeBuilder expr_matches(
  723. field_matches);
  724. if (init_expr_matcher.matches(*expr, Finder, &expr_matches)) {
  725. result.addMatch(expr_matches);
  726. is_matching = true;
  727. }
  728. }
  729. }
  730. *Builder = std::move(result);
  731. return is_matching;
  732. }
  733. // Rewrites |SomeClass* field| (matched as "affectedFieldDecl") into
  734. // |raw_ptr<SomeClass> field| and for each file rewritten in such way adds an
  735. // |#include "base/memory/raw_ptr.h"|.
  736. class FieldDeclRewriter : public MatchFinder::MatchCallback {
  737. public:
  738. explicit FieldDeclRewriter(OutputHelper* output_helper)
  739. : output_helper_(output_helper) {}
  740. FieldDeclRewriter(const FieldDeclRewriter&) = delete;
  741. FieldDeclRewriter& operator=(const FieldDeclRewriter&) = delete;
  742. void run(const MatchFinder::MatchResult& result) override {
  743. const clang::ASTContext& ast_context = *result.Context;
  744. const clang::SourceManager& source_manager = *result.SourceManager;
  745. const clang::FieldDecl* field_decl =
  746. result.Nodes.getNodeAs<clang::FieldDecl>("affectedFieldDecl");
  747. assert(field_decl && "matcher should bind 'fieldDecl'");
  748. const clang::TypeSourceInfo* type_source_info =
  749. field_decl->getTypeSourceInfo();
  750. if (auto* ivar_decl = clang::dyn_cast<clang::ObjCIvarDecl>(field_decl)) {
  751. // Objective-C @synthesize statements should not be rewritten. They return
  752. // null for getTypeSourceInfo().
  753. if (ivar_decl->getSynthesize()) {
  754. assert(!type_source_info);
  755. return;
  756. }
  757. }
  758. assert(type_source_info && "assuming |type_source_info| is always present");
  759. clang::QualType pointer_type = type_source_info->getType();
  760. assert(type_source_info->getType()->isPointerType() &&
  761. "matcher should only match pointer types");
  762. // Calculate the |replacement_range|.
  763. //
  764. // Consider the following example:
  765. // const Pointee* const field_name_;
  766. // ^--------------------^ = |replacement_range|
  767. // ^ = |field_decl->getLocation()|
  768. // ^ = |field_decl->getBeginLoc()|
  769. // ^ = PointerTypeLoc::getStarLoc
  770. // ^------^ = TypeLoc::getSourceRange
  771. //
  772. // We get the |replacement_range| in a bit clumsy way, because clang docs
  773. // for QualifiedTypeLoc explicitly say that these objects "intentionally do
  774. // not provide source location for type qualifiers".
  775. clang::SourceRange replacement_range(field_decl->getBeginLoc(),
  776. field_decl->getLocation());
  777. // Calculate |replacement_text|.
  778. std::string replacement_text = GenerateNewText(ast_context, pointer_type);
  779. if (field_decl->isMutable())
  780. replacement_text.insert(0, "mutable ");
  781. // Generate and print a replacement.
  782. output_helper_->AddReplacement(source_manager, replacement_range,
  783. replacement_text,
  784. true /* should_add_include */);
  785. }
  786. private:
  787. std::string GenerateNewText(const clang::ASTContext& ast_context,
  788. const clang::QualType& pointer_type) {
  789. std::string result;
  790. assert(pointer_type->isPointerType() && "caller must pass a pointer type!");
  791. clang::QualType pointee_type = pointer_type->getPointeeType();
  792. // Preserve qualifiers.
  793. assert(!pointer_type.isRestrictQualified() &&
  794. "|restrict| is a C-only qualifier and raw_ptr<T> needs C++");
  795. if (pointer_type.isConstQualified())
  796. result += "const ";
  797. if (pointer_type.isVolatileQualified())
  798. result += "volatile ";
  799. // Convert pointee type to string.
  800. clang::PrintingPolicy printing_policy(ast_context.getLangOpts());
  801. printing_policy.SuppressScope = 1; // s/blink::Pointee/Pointee/
  802. std::string pointee_type_as_string =
  803. pointee_type.getAsString(printing_policy);
  804. result += llvm::formatv("raw_ptr<{0}> ", pointee_type_as_string);
  805. return result;
  806. }
  807. OutputHelper* const output_helper_;
  808. };
  809. // Rewrites |my_struct.ptr_field| (matched as "affectedMemberExpr") into
  810. // |my_struct.ptr_field.get()|.
  811. class AffectedExprRewriter : public MatchFinder::MatchCallback {
  812. public:
  813. explicit AffectedExprRewriter(OutputHelper* output_helper)
  814. : output_helper_(output_helper) {}
  815. AffectedExprRewriter(const AffectedExprRewriter&) = delete;
  816. AffectedExprRewriter& operator=(const AffectedExprRewriter&) = delete;
  817. void run(const MatchFinder::MatchResult& result) override {
  818. const clang::SourceManager& source_manager = *result.SourceManager;
  819. const clang::MemberExpr* member_expr =
  820. result.Nodes.getNodeAs<clang::MemberExpr>("affectedMemberExpr");
  821. assert(member_expr && "matcher should bind 'affectedMemberExpr'");
  822. clang::SourceLocation member_name_start = member_expr->getMemberLoc();
  823. size_t member_name_length = member_expr->getMemberDecl()->getName().size();
  824. clang::SourceLocation insertion_loc =
  825. member_name_start.getLocWithOffset(member_name_length);
  826. clang::SourceRange replacement_range(insertion_loc, insertion_loc);
  827. output_helper_->AddReplacement(source_manager, replacement_range, ".get()");
  828. }
  829. private:
  830. OutputHelper* const output_helper_;
  831. };
  832. // Emits problematic fields (matched as "affectedFieldDecl") as filtered fields.
  833. class FilteredExprWriter : public MatchFinder::MatchCallback {
  834. public:
  835. FilteredExprWriter(OutputHelper* output_helper, llvm::StringRef filter_tag)
  836. : output_helper_(output_helper), filter_tag_(filter_tag) {}
  837. FilteredExprWriter(const FilteredExprWriter&) = delete;
  838. FilteredExprWriter& operator=(const FilteredExprWriter&) = delete;
  839. void run(const MatchFinder::MatchResult& result) override {
  840. const clang::FieldDecl* field_decl =
  841. result.Nodes.getNodeAs<clang::FieldDecl>("affectedFieldDecl");
  842. assert(field_decl && "matcher should bind 'affectedFieldDecl'");
  843. output_helper_->AddFilteredField(*field_decl, filter_tag_);
  844. }
  845. private:
  846. OutputHelper* const output_helper_;
  847. llvm::StringRef filter_tag_;
  848. };
  849. } // namespace
  850. int main(int argc, const char* argv[]) {
  851. // TODO(dcheng): Clang tooling should do this itself.
  852. // http://llvm.org/bugs/show_bug.cgi?id=21627
  853. llvm::InitializeNativeTarget();
  854. llvm::InitializeNativeTargetAsmParser();
  855. llvm::cl::OptionCategory category(
  856. "rewrite_raw_ptr_fields: changes |T* field_| to |raw_ptr<T> field_|.");
  857. llvm::cl::opt<std::string> exclude_fields_param(
  858. kExcludeFieldsParamName, llvm::cl::value_desc("filepath"),
  859. llvm::cl::desc("file listing fields to be blocked (not rewritten)"));
  860. llvm::cl::opt<std::string> exclude_paths_param(
  861. kExcludePathsParamName, llvm::cl::value_desc("filepath"),
  862. llvm::cl::desc("file listing paths to be blocked (not rewritten)"));
  863. llvm::Expected<clang::tooling::CommonOptionsParser> options =
  864. clang::tooling::CommonOptionsParser::create(argc, argv, category);
  865. assert(static_cast<bool>(options)); // Should not return an error.
  866. clang::tooling::ClangTool tool(options->getCompilations(),
  867. options->getSourcePathList());
  868. MatchFinder match_finder;
  869. OutputHelper output_helper;
  870. // Supported pointer types =========
  871. // Given
  872. // struct MyStrict {
  873. // int* int_ptr;
  874. // int i;
  875. // int (*func_ptr)();
  876. // int (MyStruct::* member_func_ptr)(char);
  877. // int (*ptr_to_array_of_ints)[123]
  878. // };
  879. // matches |int*|, but not the other types.
  880. auto supported_pointer_types_matcher =
  881. pointerType(unless(pointee(hasUnqualifiedDesugaredType(
  882. anyOf(functionType(), memberPointerType(), arrayType())))));
  883. // Implicit field declarations =========
  884. // Matches field declarations that do not explicitly appear in the source
  885. // code:
  886. // 1. fields of classes generated by the compiler to back capturing lambdas,
  887. // 2. fields within an implicit class or function template specialization
  888. // (e.g. when a template is instantiated by a bit of code and there's no
  889. // explicit specialization for it).
  890. auto implicit_class_specialization_matcher =
  891. classTemplateSpecializationDecl(isImplicitClassTemplateSpecialization());
  892. auto implicit_function_specialization_matcher =
  893. functionDecl(isImplicitFunctionTemplateSpecialization());
  894. auto implicit_field_decl_matcher = fieldDecl(hasParent(cxxRecordDecl(anyOf(
  895. isLambda(), implicit_class_specialization_matcher,
  896. hasAncestor(decl(anyOf(implicit_class_specialization_matcher,
  897. implicit_function_specialization_matcher)))))));
  898. // Field declarations =========
  899. // Given
  900. // struct S {
  901. // int* y;
  902. // };
  903. // matches |int* y|. Doesn't match:
  904. // - non-pointer types
  905. // - fields of lambda-supporting classes
  906. // - fields listed in the --exclude-fields cmdline param or located in paths
  907. // matched by --exclude-paths cmdline param
  908. // - "implicit" fields (i.e. field decls that are not explicitly present in
  909. // the source code)
  910. FilterFile fields_to_exclude(exclude_fields_param);
  911. FilterFile paths_to_exclude(exclude_paths_param);
  912. auto field_decl_matcher =
  913. fieldDecl(
  914. allOf(hasType(supported_pointer_types_matcher),
  915. unless(anyOf(isExpansionInSystemHeader(), isInExternCContext(),
  916. isInThirdPartyLocation(), isInGeneratedLocation(),
  917. isInLocationListedInFilterFile(&paths_to_exclude),
  918. isFieldDeclListedInFilterFile(&fields_to_exclude),
  919. IsExclusionAnnotated(),
  920. implicit_field_decl_matcher))))
  921. .bind("affectedFieldDecl");
  922. FieldDeclRewriter field_decl_rewriter(&output_helper);
  923. match_finder.addMatcher(field_decl_matcher, &field_decl_rewriter);
  924. // Matches expressions that used to return a value of type |SomeClass*|
  925. // but after the rewrite return an instance of |raw_ptr<SomeClass>|.
  926. // Many such expressions might need additional changes after the rewrite:
  927. // - Some expressions (printf args, const_cast args, etc.) might need |.get()|
  928. // appended.
  929. // - Using such expressions in specific contexts (e.g. as in-out arguments or
  930. // as a return value of a function returning references) may require
  931. // additional work and should cause related fields to be emitted as
  932. // candidates for the --field-filter-file parameter.
  933. auto affected_member_expr_matcher =
  934. memberExpr(member(fieldDecl(hasExplicitFieldDecl(field_decl_matcher))))
  935. .bind("affectedMemberExpr");
  936. auto affected_expr_matcher = ignoringImplicit(affected_member_expr_matcher);
  937. // Places where |.get()| needs to be appended =========
  938. // Given
  939. // void foo(const S& s) {
  940. // printf("%p", s.y);
  941. // const_cast<...>(s.y)
  942. // reinterpret_cast<...>(s.y)
  943. // }
  944. // matches the |s.y| expr if it matches the |affected_expr_matcher| above.
  945. //
  946. // See also testcases in tests/affected-expr-original.cc
  947. auto affected_expr_that_needs_fixing_matcher = expr(allOf(
  948. affected_expr_matcher,
  949. hasParent(expr(anyOf(callExpr(callee(functionDecl(isVariadic()))),
  950. cxxConstCastExpr(), cxxReinterpretCastExpr())))));
  951. AffectedExprRewriter affected_expr_rewriter(&output_helper);
  952. match_finder.addMatcher(affected_expr_that_needs_fixing_matcher,
  953. &affected_expr_rewriter);
  954. // Affected ternary operator args =========
  955. // Given
  956. // void foo(const S& s) {
  957. // cond ? s.y : ...
  958. // }
  959. // binds the |s.y| expr if it matches the |affected_expr_matcher| above.
  960. //
  961. // See also testcases in tests/affected-expr-original.cc
  962. auto affected_ternary_operator_arg_matcher =
  963. conditionalOperator(eachOf(hasTrueExpression(affected_expr_matcher),
  964. hasFalseExpression(affected_expr_matcher)));
  965. match_finder.addMatcher(affected_ternary_operator_arg_matcher,
  966. &affected_expr_rewriter);
  967. // Affected string binary operator =========
  968. // Given
  969. // struct S { const char* y; }
  970. // void foo(const S& s) {
  971. // std::string other;
  972. // bool v1 = s.y == other;
  973. // std::string v2 = s.y + other;
  974. // }
  975. // binds the |s.y| expr if it matches the |affected_expr_matcher| above.
  976. //
  977. // See also testcases in tests/affected-expr-original.cc
  978. auto std_string_expr_matcher =
  979. expr(hasType(cxxRecordDecl(hasName("::std::basic_string"))));
  980. auto affected_string_binary_operator_arg_matcher = cxxOperatorCallExpr(
  981. hasAnyOverloadedOperatorName("+", "==", "!=", "<", "<=", ">", ">="),
  982. hasAnyArgument(std_string_expr_matcher),
  983. forEachArgumentWithParam(affected_expr_matcher, parmVarDecl()));
  984. match_finder.addMatcher(affected_string_binary_operator_arg_matcher,
  985. &affected_expr_rewriter);
  986. // Calls to templated functions =========
  987. // Given
  988. // struct S { int* y; };
  989. // template <typename T>
  990. // void templatedFunc(T* arg) {}
  991. // void foo(const S& s) {
  992. // templatedFunc(s.y);
  993. // }
  994. // binds the |s.y| expr if it matches the |affected_expr_matcher| above.
  995. //
  996. // See also testcases in tests/affected-expr-original.cc
  997. auto templated_function_arg_matcher = forEachArgumentWithParam(
  998. affected_expr_matcher,
  999. parmVarDecl(allOf(
  1000. hasType(qualType(allOf(findAll(qualType(substTemplateTypeParmType())),
  1001. unless(referenceType())))),
  1002. unless(hasAncestor(functionDecl(hasName("Unretained")))))));
  1003. match_finder.addMatcher(callExpr(templated_function_arg_matcher),
  1004. &affected_expr_rewriter);
  1005. // TODO(lukasza): It is unclear why |traverse| below is needed. Maybe it can
  1006. // be removed if https://bugs.llvm.org/show_bug.cgi?id=46287 is fixed.
  1007. match_finder.addMatcher(
  1008. traverse(clang::TraversalKind::TK_AsIs,
  1009. cxxConstructExpr(templated_function_arg_matcher)),
  1010. &affected_expr_rewriter);
  1011. // Calls to constructors via an implicit cast =========
  1012. // Given
  1013. // struct I { I(int*) {} };
  1014. // void bar(I i) {}
  1015. // struct S { int* y; };
  1016. // void foo(const S& s) {
  1017. // bar(s.y); // implicit cast from |s.y| to I.
  1018. // }
  1019. // binds the |s.y| expr if it matches the |affected_expr_matcher| above.
  1020. //
  1021. // See also testcases in tests/affected-expr-original.cc
  1022. auto implicit_ctor_expr_matcher = cxxConstructExpr(allOf(
  1023. anyOf(hasParent(materializeTemporaryExpr()),
  1024. hasParent(implicitCastExpr())),
  1025. hasDeclaration(
  1026. cxxConstructorDecl(allOf(parameterCountIs(1), unless(isExplicit())))),
  1027. forEachArgumentWithParam(affected_expr_matcher, parmVarDecl())));
  1028. match_finder.addMatcher(implicit_ctor_expr_matcher, &affected_expr_rewriter);
  1029. // |auto| type declarations =========
  1030. // Given
  1031. // struct S { int* y; };
  1032. // void foo(const S& s) {
  1033. // auto* p = s.y;
  1034. // }
  1035. // binds the |s.y| expr if it matches the |affected_expr_matcher| above.
  1036. //
  1037. // See also testcases in tests/affected-expr-original.cc
  1038. auto auto_var_decl_matcher = declStmt(forEach(
  1039. varDecl(allOf(hasType(pointerType(pointee(autoType()))),
  1040. hasInitializer(anyOf(
  1041. affected_expr_matcher,
  1042. initListExpr(hasInit(0, affected_expr_matcher))))))));
  1043. match_finder.addMatcher(auto_var_decl_matcher, &affected_expr_rewriter);
  1044. // address-of(affected-expr) =========
  1045. // Given
  1046. // ... &s.y ...
  1047. // matches the |s.y| expr if it matches the |affected_member_expr_matcher|
  1048. // above.
  1049. //
  1050. // See also the testcases in tests/gen-in-out-arg-test.cc.
  1051. auto affected_addr_of_expr_matcher = expr(allOf(
  1052. affected_expr_matcher, hasParent(unaryOperator(hasOperatorName("&")))));
  1053. FilteredExprWriter filtered_addr_of_expr_writer(&output_helper, "addr-of");
  1054. match_finder.addMatcher(affected_addr_of_expr_matcher,
  1055. &filtered_addr_of_expr_writer);
  1056. // in-out reference arg =========
  1057. // Given
  1058. // struct S { SomeClass* ptr_field; };
  1059. // void f(SomeClass*& in_out_arg) { ... }
  1060. // template <typename T> void f2(T&& rvalue_ref_arg) { ... }
  1061. // template <typename... Ts> void f3(Ts&&... rvalue_ref_args) { ... }
  1062. // void bar() {
  1063. // S s;
  1064. // foo(s.ptr_field)
  1065. // }
  1066. // matches the |s.ptr_field| expr if it matches the
  1067. // |affected_member_expr_matcher| and is passed as a function argument that
  1068. // has |FooBar*&| type (like |f|, but unlike |f2| and |f3|).
  1069. //
  1070. // See also the testcases in tests/gen-in-out-arg-test.cc.
  1071. auto affected_in_out_ref_arg_matcher = callExpr(forEachArgumentWithParam(
  1072. affected_expr_matcher, hasExplicitParmVarDecl(hasType(qualType(
  1073. allOf(referenceType(pointee(pointerType())),
  1074. unless(rValueReferenceType())))))));
  1075. FilteredExprWriter filtered_in_out_ref_arg_writer(&output_helper,
  1076. "in-out-param-ref");
  1077. match_finder.addMatcher(affected_in_out_ref_arg_matcher,
  1078. &filtered_in_out_ref_arg_writer);
  1079. // See the doc comment for the overlapsOtherDeclsWithinRecordDecl matcher
  1080. // and the testcases in tests/gen-overlaps-test.cc.
  1081. auto overlapping_field_decl_matcher = fieldDecl(
  1082. allOf(field_decl_matcher, overlapsOtherDeclsWithinRecordDecl()));
  1083. FilteredExprWriter overlapping_field_decl_writer(&output_helper,
  1084. "overlapping");
  1085. match_finder.addMatcher(overlapping_field_decl_matcher,
  1086. &overlapping_field_decl_writer);
  1087. // Matches fields initialized with a non-nullptr value in a constexpr
  1088. // constructor. See also the testcase in tests/gen-constexpr-test.cc.
  1089. auto non_nullptr_expr_matcher =
  1090. expr(unless(ignoringImplicit(cxxNullPtrLiteralExpr())));
  1091. auto constexpr_ctor_field_initializer_matcher = cxxConstructorDecl(
  1092. allOf(isConstexpr(), forEachConstructorInitializer(allOf(
  1093. forField(field_decl_matcher),
  1094. withInitializer(non_nullptr_expr_matcher)))));
  1095. FilteredExprWriter constexpr_ctor_field_initializer_writer(
  1096. &output_helper, "constexpr-ctor-field-initializer");
  1097. match_finder.addMatcher(constexpr_ctor_field_initializer_matcher,
  1098. &constexpr_ctor_field_initializer_writer);
  1099. // Matches constexpr initializer list expressions that initialize a rewritable
  1100. // field with a non-nullptr value. For more details and rationale see the
  1101. // testcases in tests/gen-constexpr-test.cc.
  1102. auto constexpr_var_initializer_matcher = varDecl(
  1103. allOf(isConstexpr(),
  1104. hasInitializer(findAll(initListExpr(forEachInitExprWithFieldDecl(
  1105. non_nullptr_expr_matcher,
  1106. hasExplicitFieldDecl(field_decl_matcher)))))));
  1107. FilteredExprWriter constexpr_var_initializer_writer(
  1108. &output_helper, "constexpr-var-initializer");
  1109. match_finder.addMatcher(constexpr_var_initializer_matcher,
  1110. &constexpr_var_initializer_writer);
  1111. // See the doc comment for the isInMacroLocation matcher
  1112. // and the testcases in tests/gen-macro-test.cc.
  1113. auto macro_field_decl_matcher =
  1114. fieldDecl(allOf(field_decl_matcher, isInMacroLocation()));
  1115. FilteredExprWriter macro_field_decl_writer(&output_helper, "macro");
  1116. match_finder.addMatcher(macro_field_decl_matcher, &macro_field_decl_writer);
  1117. // See the doc comment for the anyCharType matcher
  1118. // and the testcases in tests/gen-char-test.cc.
  1119. auto char_ptr_field_decl_matcher = fieldDecl(allOf(
  1120. field_decl_matcher,
  1121. hasType(pointerType(pointee(qualType(allOf(
  1122. isConstQualified(), hasUnqualifiedDesugaredType(anyCharType()))))))));
  1123. FilteredExprWriter char_ptr_field_decl_writer(&output_helper, "const-char");
  1124. match_finder.addMatcher(char_ptr_field_decl_matcher,
  1125. &char_ptr_field_decl_writer);
  1126. // See the testcases in tests/gen-global-destructor-test.cc.
  1127. auto global_destructor_matcher =
  1128. varDecl(allOf(hasGlobalStorage(),
  1129. hasType(typeWithEmbeddedFieldDecl(field_decl_matcher))));
  1130. FilteredExprWriter global_destructor_writer(&output_helper, "global-scope");
  1131. match_finder.addMatcher(global_destructor_matcher, &global_destructor_writer);
  1132. // Matches fields in unions (both directly rewritable fields as well as union
  1133. // fields that embed a struct that contains a rewritable field). See also the
  1134. // testcases in tests/gen-unions-test.cc.
  1135. auto union_field_decl_matcher = recordDecl(allOf(
  1136. isUnion(), forEach(fieldDecl(anyOf(field_decl_matcher,
  1137. hasType(typeWithEmbeddedFieldDecl(
  1138. field_decl_matcher)))))));
  1139. FilteredExprWriter union_field_decl_writer(&output_helper, "union");
  1140. match_finder.addMatcher(union_field_decl_matcher, &union_field_decl_writer);
  1141. // Matches rewritable fields of struct `SomeStruct` if that struct happens to
  1142. // be a destination type of a `reinterpret_cast<SomeStruct*>` cast and is a
  1143. // trivial type (otherwise `reinterpret_cast<SomeStruct*>` wouldn't be valid
  1144. // before the rewrite if it skipped non-trivial constructors).
  1145. auto reinterpret_cast_struct_matcher =
  1146. cxxReinterpretCastExpr(hasDestinationType(pointerType(pointee(
  1147. hasUnqualifiedDesugaredType(recordType(hasDeclaration(cxxRecordDecl(
  1148. allOf(forEach(field_decl_matcher), isTrivial())))))))));
  1149. FilteredExprWriter reinterpret_cast_struct_writer(
  1150. &output_helper, "reinterpret-cast-trivial-type");
  1151. match_finder.addMatcher(reinterpret_cast_struct_matcher,
  1152. &reinterpret_cast_struct_writer);
  1153. // Prepare and run the tool.
  1154. std::unique_ptr<clang::tooling::FrontendActionFactory> factory =
  1155. clang::tooling::newFrontendActionFactory(&match_finder, &output_helper);
  1156. int result = tool.run(factory.get());
  1157. if (result != 0)
  1158. return result;
  1159. return 0;
  1160. }