File: RewriteTemplatedPtrFields.cpp

package info (click to toggle)
chromium 138.0.7204.157-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 6,071,864 kB
  • sloc: cpp: 34,936,859; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,967; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (1508 lines) | stat: -rw-r--r-- 63,672 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This is the implementation of a clang tool that rewrites containers of
// pointer fields into raw_ptr<T>:
//     std::vector<Pointee*> field_
// becomes:
//     std::vector<raw_ptr<Pointee>> field_
//
// Note that the tool emits two kinds of outputs:
//   1- A pairs of nodes formatted as {lhs};{rhs}\n representing an edge between
//      two nodes.
//   2- A single node formatted as {lhs}\n
// The concatenated outputs from multiple tool runs are then used to construct
// the graph and emit relevant edits using extract_edits.py
//
// A node (lhs, rhs) has the following format:
// '{is_field,is_excluded,has_auto_type,r:::<file
// path>:::<offset>:::<length>:::<replacement text>,include-user-header:::<file
// path>:::-1:::-1:::<include text>}'
//
// where `is_field`,`is_excluded`, and `has_auto_type` are booleans represendted
// as  0 or 1.
//
// For more details, see the doc here:
// https://docs.google.com/document/d/1P8wLVS3xueI4p3EAPO4JJP6d1_zVp5SapQB0EW9iHQI/

#include <assert.h>
#include <algorithm>
#include <cstdio>
#include <fstream>
#include <limits>
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <string>
#include <string_view>
#include <vector>

#include "RawPtrHelpers.h"
#include "RawPtrManualPathsToIgnore.h"
#include "SeparateRepositoryPaths.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchersMacros.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/MacroArgs.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TargetSelect.h"

using namespace clang::ast_matchers;

namespace {

// Include path that needs to be added to all the files where raw_ptr<...>
// replaces a raw pointer.
const char kRawPtrIncludePath[] = "base/memory/raw_ptr.h";

const char kOverrideExcludePathsParamName[] = "override-exclude-paths";

// This iterates over function parameters and matches the ones that match
// parm_var_decl_matcher.
AST_MATCHER_P(clang::FunctionDecl,
              forEachParmVarDecl,
              clang::ast_matchers::internal::Matcher<clang::ParmVarDecl>,
              parm_var_decl_matcher) {
  const clang::FunctionDecl& function_decl = Node;

  auto num_params = function_decl.getNumParams();
  bool is_matching = false;
  clang::ast_matchers::internal::BoundNodesTreeBuilder result;
  for (unsigned i = 0; i < num_params; i++) {
    const clang::ParmVarDecl* param = function_decl.getParamDecl(i);
    clang::ast_matchers::internal::BoundNodesTreeBuilder param_matches;
    if (parm_var_decl_matcher.matches(*param, Finder, &param_matches)) {
      is_matching = true;
      result.addMatch(param_matches);
    }
  }
  *Builder = std::move(result);
  return is_matching;
}

// Returns a StringRef of the elements apprearing after the pattern
// '(anonymous namespace)::' if any, otherwise returns input.
static llvm::StringRef RemoveAnonymous(llvm::StringRef input) {
  constexpr llvm::StringRef kAnonymousNamespace{"(anonymous namespace)::"};
  auto loc = input.find(kAnonymousNamespace);
  if (loc != input.npos) {
    return input.substr(loc + kAnonymousNamespace.size());
  }
  return input;
}

// Statements of the form: for (auto* i : affected_expr)
// need to be changed to: for (type_name* i : affected_expr)
// in order to extract the pointer type from now raw_ptr.
// The text returned by type's `getAsString()` can contain some unuseful
// data. Example: 'const struct n1::(anonymous namespace)::n2::type_name'. As
// is, this wouldn't compile. This needs to be reinterpreted as
// 'const n2::type_name'.
// `RemovePrefix` removes the class/struct keyword if any,
// conserves the constness, and trims '(anonymous namespace)::'
// as well as anything on it's lhs using `RemoveAnonymous`.
static std::string RemovePrefix(llvm::StringRef input) {
  constexpr llvm::StringRef kClassPrefix{"class "};
  constexpr llvm::StringRef kStructPrefix{"struct "};
  constexpr llvm::StringRef kConstPrefix{"const "};

  std::string result;
  result.reserve(input.size());

  if (input.consume_front(kConstPrefix)) {
    result += kConstPrefix;
  }

  input.consume_front(kClassPrefix);
  input.consume_front(kStructPrefix);

  result += RemoveAnonymous(input);
  return result;
}

struct Node {
  bool is_field = false;
  // This is set to true for Fields annotated with RAW_PTR_EXCLUSION
  bool is_excluded = false;
  // auto type variables don't need to be rewritten. They still need to be
  // present in the graph to propagate the rewrite to non auto expressions.
  // Example:
  // auto temp = member_; vector<T*>::iterator it = temp.begin();
  // `it`'s type needs to be rewritten when member's type is.
  bool has_auto_type = false;
  // A replacement follows the following format:
  // `r:::<file path>:::<offset>:::<length>:::<replacement text>`
  std::string replacement;
  // An include directive follows the following format:
  // `include-user-header:::<file path>:::-1:::-1:::<include text>`
  std::string include_directive;
  bool operator==(const Node& other) const {
    return replacement == other.replacement;
  }
  bool operator<(const Node& other) const {
    return replacement < other.replacement;
  }
  // The resulting string follows the following format:
  // {is_field\,is_excluded\,has_auto_type\,r:::<file
  // path>:::<offset>:::<length>:::<replacement
  // text>\,include-user-header:::<file path>:::-1:::-1:::<include text>}
  // where is_field,is_excluded, and has_auto_type are booleans represendted as
  // 0 or 1.
  std::string ToString() const {
    return llvm::formatv("{{{0:d}\\,{1:d}\\,{2:d}\\,{3}\\,{4}}", is_field,
                         is_excluded, has_auto_type, replacement,
                         include_directive);
  }
};

// Helper class to add edges to the set of node_pairs_;
class OutputHelper {
 public:
  OutputHelper() = default;

  void AddEdge(const Node& lhs, const Node& rhs) {
    node_pairs_.insert(
        llvm::formatv("{0};{1}\n", lhs.ToString(), rhs.ToString()));
  }

  void AddSingleNode(const Node& lhs) {
    node_pairs_.insert(llvm::formatv("{0}\n", lhs.ToString()));
  }

  void Emit() {
    for (const auto& p : node_pairs_) {
      llvm::outs() << p;
    }
  }

 private:
  // This represents a line for every 2 adjacent nodes.
  // The format is: {lhs};{rhs}\n where lhs & rhs generated using
  // Node::ToString().
  // There are two cases where the line contains only a lhs node {lhs}\n
  // 1- To make sure that fields that are not connected to any other node are
  // represented in the graph.
  // 2- Fields annotated with RAW_PTR_EXCLUSION are also inserted as a single
  // node to the list.
  std::set<std::string> node_pairs_;
};

// This visitor is used to extract a FunctionDecl* bound with a node id
// "fct_decl" from a given match.
// This is used in the `forEachArg` and `forEachBindArg` matchers below.
class LocalVisitor
    : public clang::ast_matchers::internal::BoundNodesTreeBuilder::Visitor {
 public:
  void visitMatch(
      const clang::ast_matchers::BoundNodes& BoundNodesView) override {
    if (const auto* ptr =
            BoundNodesView.getNodeAs<clang::FunctionDecl>("fct_decl")) {
      fct_decl_ = BoundNodesView.getNodeAs<clang::FunctionDecl>("fct_decl");
      is_lambda_ = false;
    } else {
      const clang::LambdaExpr* lambda_expr =
          BoundNodesView.getNodeAs<clang::LambdaExpr>("lambda_expr");
      fct_decl_ = lambda_expr->getCallOperator();
      is_lambda_ = true;
    }
  }
  const clang::FunctionDecl* fct_decl_;
  bool is_lambda_;
};

// This is used to map arguments passed to std::make_unique to the underlying
// constructor parameters. For each expr that matches, using `LocalVisitor`, we
// extract the ptr to clang::FunctionDecl which represents here the
// constructorDecl and use it to get the parmVarDecl corresponding to the
// argument.
// This iterates over a callExpressions's arguments and matches the ones that
// match expr_matcher. For each argument matched, retrieve the corresponding
// constructor parameter. The constructor parameter is then checked against
// parm_var_decl_matcher.
AST_MATCHER_P2(clang::CallExpr,
               forEachArg,
               clang::ast_matchers::internal::Matcher<clang::Expr>,
               expr_matcher,
               clang::ast_matchers::internal::Matcher<clang::ParmVarDecl>,
               parm_var_decl_matcher) {
  const clang::CallExpr& call_expr = Node;

  auto num_args = call_expr.getNumArgs();
  bool is_matching = false;
  clang::ast_matchers::internal::BoundNodesTreeBuilder result;
  for (unsigned i = 0; i < num_args; i++) {
    const clang::Expr* arg = call_expr.getArg(i);
    clang::ast_matchers::internal::BoundNodesTreeBuilder arg_matches;
    if (expr_matcher.matches(*arg, Finder, &arg_matches)) {
      LocalVisitor l;
      arg_matches.visitMatches(&l);
      const auto* fct_decl = l.fct_decl_;
      if (fct_decl) {
        const auto* param = fct_decl->getParamDecl(i);
        clang::ast_matchers::internal::BoundNodesTreeBuilder parm_var_matches(
            arg_matches);
        if (parm_var_decl_matcher.matches(*param, Finder, &parm_var_matches)) {
          is_matching = true;
          result.addMatch(parm_var_matches);
        }
      }
    }
  }
  *Builder = std::move(result);
  return is_matching;
}

// This is used to handle expressions of the form:
// base::BindOnce(
//                [](std::vector<raw_ptr<Label>>& message_labels,
//                    Label* message_label) {
//                   message_labels.push_back(message_label);
//                 },
//                 std::ref(message_labels_))))
// This creates a link between the parmVarDecl's in the lambda/functionPointer
// passed as 1st argument and the rest of the arguments passed to the bind call.
AST_MATCHER_P2(clang::CallExpr,
               forEachBindArg,
               clang::ast_matchers::internal::Matcher<clang::Expr>,
               expr_matcher,
               clang::ast_matchers::internal::Matcher<clang::ParmVarDecl>,
               parm_var_decl_matcher) {
  const clang::CallExpr& call_expr = Node;

  auto num_args = call_expr.getNumArgs();
  if (num_args == 1) {
    // No arguments to map to the lambda/fct parmVarDecls.
    return false;
  }

  bool is_matching = false;
  clang::ast_matchers::internal::BoundNodesTreeBuilder result;
  for (unsigned i = 1; i < num_args; i++) {
    const clang::Expr* arg = call_expr.getArg(i);
    clang::ast_matchers::internal::BoundNodesTreeBuilder arg_matches;
    if (expr_matcher.matches(*arg, Finder, &arg_matches)) {
      LocalVisitor l;
      arg_matches.visitMatches(&l);
      const auto* fct_decl = l.fct_decl_;

      // start_index=1 when we start with second arg for Bind and first arg for
      // lambda/fct
      unsigned start_index = 1;
      // start_index=2 when the second arg is a pointer to the object on which
      // the function is to be invoked. This is done when the function pointer is
      // not a static class function.
      // isGlobal is true for free functions as well as static member functions,
      // both of which don't need a pointer to the object on which they are
      // invoked.
      if (!l.is_lambda_ && !l.fct_decl_->isGlobal()) {
        start_index = 2;
        // Skip the second argument passed to BindOnce/BindRepeating as it is an
        // object pointer unrelated to target function args.
        if (i == 1) {
          continue;
        }
      }
      const auto* param = fct_decl->getParamDecl(i - start_index);
      clang::ast_matchers::internal::BoundNodesTreeBuilder
          parm_var_decl_matches(arg_matches);
      if (parm_var_decl_matcher.matches(*param, Finder,
                                        &parm_var_decl_matches)) {
        is_matching = true;
        result.addMatch(parm_var_decl_matches);
      }
    }
  }
  *Builder = std::move(result);
  return is_matching;
}

static std::string GenerateNewType(const clang::ASTContext& ast_context,
                                   const clang::QualType& pointer_type) {
  std::string result;

  clang::QualType pointee_type = pointer_type->getPointeeType();

  // Preserve qualifiers.
  assert(!pointer_type.isRestrictQualified() &&
         "|restrict| is a C-only qualifier and raw_ptr<T>/raw_ref<T> need C++");
  if (pointer_type.isConstQualified()) {
    result += "const ";
  }
  if (pointer_type.isVolatileQualified()) {
    result += "volatile ";
  }

  // Convert pointee type to string.
  clang::PrintingPolicy printing_policy(ast_context.getLangOpts());
  printing_policy.SuppressScope = 1;  // s/blink::Pointee/Pointee/
  std::string pointee_type_as_string =
      pointee_type.getAsString(printing_policy);
  result += llvm::formatv("raw_ptr<{0}>", pointee_type_as_string);

  return result;
}

static std::pair<std::string, std::string> GetReplacementAndIncludeDirectives(
    const clang::PointerTypeLoc* type_loc,
    const clang::TemplateSpecializationTypeLoc* tst_loc,
    std::string replacement_text,
    const clang::SourceManager& source_manager) {
  clang::SourceLocation begin_loc = tst_loc->getLAngleLoc().getLocWithOffset(1);
  // This is done to skip the star '*' because type_loc's end loc is just
  // before the star position.
  clang::SourceLocation end_loc = type_loc->getEndLoc().getLocWithOffset(1);

  clang::SourceRange replacement_range(begin_loc, end_loc);

  clang::tooling::Replacement replacement(
      source_manager, clang::CharSourceRange::getCharRange(replacement_range),
      replacement_text);
  llvm::StringRef file_path = replacement.getFilePath();
  if (file_path.empty()) {
    return {"", ""};
  }

  std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0');
  std::string replacement_directive = llvm::formatv(
      "r:::{0}:::{1}:::{2}:::{3}", file_path, replacement.getOffset(),
      replacement.getLength(), replacement_text);

  std::string include_directive =
      llvm::formatv("include-user-header:::{0}:::-1:::-1:::{1}", file_path,
                    kRawPtrIncludePath);

  return {replacement_directive, include_directive};
}

std::string GenerateReplacementForAutoLoc(
    const clang::TypeLoc* auto_loc,
    const std::string& replacement_text,
    const clang::SourceManager& source_manager,
    const clang::ASTContext& ast_context) {
  clang::SourceLocation begin_loc = auto_loc->getBeginLoc();

  clang::SourceRange replacement_range(begin_loc, begin_loc);

  clang::tooling::Replacement replacement(
      source_manager, clang::CharSourceRange::getCharRange(replacement_range),
      replacement_text);
  llvm::StringRef file_path = replacement.getFilePath();

  return llvm::formatv("r:::{0}:::{1}:::{2}:::{3}", file_path,
                       replacement.getOffset(), replacement.getLength(),
                       replacement_text);
}

// Called when the Match registered for it was successfully found in the AST.
// The matches registered represent two categories:
//   1- An adjacency relationship
//      In that case, a node pair is created, using matched node ids, and added
//      to the node_pair list using `OutputHelper::AddEdge`
//   2- A single fieldDecl node match
//      In that case, a single node is created and added to the node_pair list
//      using `OutputHelper::AddSingleNode`
class PotentialNodes : public MatchFinder::MatchCallback {
 public:
  explicit PotentialNodes(OutputHelper& helper) : output_helper_(helper) {}

  PotentialNodes(const PotentialNodes&) = delete;
  PotentialNodes& operator=(const PotentialNodes&) = delete;

  void run(const MatchFinder::MatchResult& result) override {
    const clang::SourceManager& source_manager = *result.SourceManager;
    const clang::ASTContext& ast_context = *result.Context;

    Node lhs;

    if (auto* type_loc = result.Nodes.getNodeAs<clang::PointerTypeLoc>(
            "lhs_argPointerLoc")) {
      std::string replacement_text =
          GenerateNewType(ast_context, type_loc->getType());

      const clang::TemplateSpecializationTypeLoc* tst_loc =
          result.Nodes.getNodeAs<clang::TemplateSpecializationTypeLoc>(
              "lhs_tst_loc");

      auto p = GetReplacementAndIncludeDirectives(
          type_loc, tst_loc, replacement_text, source_manager);
      lhs.replacement = p.first;
      lhs.include_directive = p.second;

      if (const clang::FieldDecl* field_decl =
              result.Nodes.getNodeAs<clang::FieldDecl>("lhs_field")) {
        lhs.is_field = true;
      }

      // To make sure we add all field decls to the graph.(Specifically those
      // not connected to other nodes)
      if (const clang::FieldDecl* field_decl =
              result.Nodes.getNodeAs<clang::FieldDecl>("field_decl")) {
        lhs.is_field = true;
        output_helper_.AddSingleNode(lhs);
        return;
      }

      // RAW_PTR_EXCLUSION is not captured when adding edges between nodes. For
      // that reason, fields annotated with RAW_PTR_EXCLUSION are added as
      // single nodes to the list, this is then used as a starting point to
      // propagate the exclusion to all neighboring nodes.
      if (const clang::FieldDecl* field_decl =
              result.Nodes.getNodeAs<clang::FieldDecl>("excluded_field_decl")) {
        lhs.is_field = true;
        lhs.is_excluded = true;
        output_helper_.AddSingleNode(lhs);
        return;
      }
    } else if (const clang::TypeLoc* auto_loc =
                   result.Nodes.getNodeAs<clang::TypeLoc>("lhs_auto_loc")) {
      lhs.replacement = GenerateReplacementForAutoLoc(
          auto_loc, "replacement_text", source_manager, ast_context);
      lhs.include_directive = lhs.replacement;
      // No need to emit a rewrite for auto type variables. They still need to
      // appear in the graph to propagate the rewrite to non-auto type nodes
      // codes connected to them.
      lhs.has_auto_type = true;
    } else {  // Not supposed to get here
      assert(false);
    }

    Node rhs;
    if (const clang::FieldDecl* field_decl =
            result.Nodes.getNodeAs<clang::FieldDecl>("rhs_field")) {
      rhs.is_field = true;
    }

    if (auto* type_loc = result.Nodes.getNodeAs<clang::PointerTypeLoc>(
            "rhs_argPointerLoc")) {
      std::string replacement_text =
          GenerateNewType(ast_context, type_loc->getType());

      const clang::TemplateSpecializationTypeLoc* tst_loc =
          result.Nodes.getNodeAs<clang::TemplateSpecializationTypeLoc>(
              "rhs_tst_loc");

      auto p = GetReplacementAndIncludeDirectives(
          type_loc, tst_loc, replacement_text, source_manager);

      rhs.replacement = p.first;
      rhs.include_directive = p.second;
    } else if (const clang::TypeLoc* auto_loc =
                   result.Nodes.getNodeAs<clang::TypeLoc>("rhs_auto_loc")) {
      rhs.replacement = GenerateReplacementForAutoLoc(
          auto_loc, "replacement_text", source_manager, ast_context);
      rhs.include_directive = rhs.replacement;
      // No need to emit a rewrite for auto type variables. They still need to
      // appear in the graph to propagate the rewrite to non-auto type nodes
      // codes connected to them.
      rhs.has_auto_type = true;
    } else {  // Not supposed to get here
      assert(false);
    }

    output_helper_.AddEdge(lhs, rhs);
  }

 private:
  OutputHelper& output_helper_;
};

// Called when the Match registered for it was successfully found in the AST.
// The match represents a parmVarDecl Node or an RTNode and the corresponding
// function declaration. Using the function declaration:
//         1- Create a unique key `current_key`
//         2- if the function has a previous declaration or is overridden,
//            retrieve previous decls and create their keys `prev_key`
//         3- for each `prev_key`, add pair `current_key`, `prev_key` to
//         `fct_sig_pairs_`
//
// Using the parmVarDecl or RTNode:
//        1- Create a node
//        2- insert node into `fct_sig_nodes_[current_key]`
//
// At the end of the tool run for a given translation unit, edges between
// corresponding nodes of two adjacent function signatures are created.
class FunctionSignatureNodes : public MatchFinder::MatchCallback {
 public:
  explicit FunctionSignatureNodes(
      std::map<std::string, std::set<Node>>& sig_nodes,
      std::vector<std::pair<std::string, std::string>>& sig_pairs)
      : fct_sig_nodes_(sig_nodes), fct_sig_pairs_(sig_pairs) {}

  FunctionSignatureNodes(const FunctionSignatureNodes&) = delete;
  FunctionSignatureNodes& operator=(const FunctionSignatureNodes&) = delete;

  // Key here means a unique string generated from a function signature
  std::string GetKey(const clang::FunctionDecl* fct_decl,
                     const clang::SourceManager& source_manager) {
    auto name = fct_decl->getNameInfo().getName().getAsString();
    clang::SourceLocation start_loc = fct_decl->getBeginLoc();
    // This is done here to get the spelling loc of a functionDecl. This is
    // needed to handle cases where the function is in a Macro Expansion. In
    // that case, multiple functionDecls will have the same location and this
    // will create problems for argument mapping. Example:
    // MOCK_METHOD0(GetAllStreams, std::vector<DemuxerStream*>());
    clang::SourceRange replacement_range(source_manager.getFileLoc(start_loc),
                                         source_manager.getFileLoc(start_loc));
    clang::tooling::Replacement replacement(
        source_manager, clang::CharSourceRange::getCharRange(replacement_range),
        name.c_str());
    llvm::StringRef file_path = replacement.getFilePath();

    return llvm::formatv("r:::{0}:::{1}:::{2}:::{3}", file_path,
                         replacement.getOffset(), replacement.getLength(),
                         name.c_str());
  }

  void run(const MatchFinder::MatchResult& result) override {
    const clang::SourceManager& source_manager = *result.SourceManager;
    const clang::ASTContext& ast_context = *result.Context;

    const clang::FunctionDecl* fct_decl =
        result.Nodes.getNodeAs<clang::FunctionDecl>("fct_decl");

    std::string key = GetKey(fct_decl, source_manager);
    if (auto* prev_decl = fct_decl->getPreviousDecl()) {
      std::string prev_key = GetKey(prev_decl, source_manager);
      fct_sig_pairs_.push_back({prev_key, key});
    }

    if (const clang::CXXMethodDecl* method_decl =
            result.Nodes.getNodeAs<clang::CXXMethodDecl>("fct_decl")) {
      for (auto* m : method_decl->overridden_methods()) {
        std::string prev_key = GetKey(m, source_manager);
        fct_sig_pairs_.push_back({prev_key, key});
      }
    }

    auto* type_loc =
        result.Nodes.getNodeAs<clang::PointerTypeLoc>("rhs_argPointerLoc");
    Node rhs;
    std::string replacement_text =
        GenerateNewType(ast_context, type_loc->getType());

    const clang::TemplateSpecializationTypeLoc* tst_loc =
        result.Nodes.getNodeAs<clang::TemplateSpecializationTypeLoc>(
            "rhs_tst_loc");

    auto p = GetReplacementAndIncludeDirectives(
        type_loc, tst_loc, replacement_text, source_manager);
    rhs.replacement = p.first;
    rhs.include_directive = p.second;

    fct_sig_nodes_[key].insert(rhs);
  }

 private:
  // Map a function signature, which is modeled as a string representing file
  // location, to it's matched graph nodes (RTNode and ParmVarDecl nodes).
  // Note: `RTNode` represents a function return type node.
  // In order to avoid relying on the order with which nodes are matched in the
  // AST, and to guarantee that nodes are stored in the file declaration order,
  // we use a `std::set<Node>` which sorts Nodes based on the replacement
  // directive which contains the file offset of a given node.
  // Note that a replacement directive has the following format:
  // `r:::<file path>:::<offset>:::<length>:::<replacement text>`
  // The order is important because at the end of a tool run on a
  // translationUnit, for each pair of function signatures, we iterate
  // concurrently through the two sets of Nodes creating edges between nodes
  // that appear at the same index.
  // AddEdge(first function's node1, second function's node1)
  // AddEdge(first function's node2, second function's node2)
  // and so on...
  std::map<std::string, std::set<Node>>& fct_sig_nodes_;
  // Map related function signatures to each other, this is needed for functions
  // with separate definition and declaration, and for overridden functions.
  std::vector<std::pair<std::string, std::string>>& fct_sig_pairs_;
};

// Called when the Match registered for it was successfully found in the AST.
// The matches registered represent three categories:
//   1- Range-based for loops of the form:
//        for (auto* i : ctn_expr) => for (type_name* i : ctn_expr)
//
//   2- Expressions of the form:
//      auto* var = ctn_expr.front(); => auto* var = ctn_expr.front().get();
//
//   3- Expressions of the form:
//      auto* var = ctn_expr[index]; => auto* var = ctn_expr[index].get();
//
// In each of the above cases a node pair is created and added to node_pairs
// using `OutputHelper::AddEdge`
class AffectedPtrExprRewriter : public MatchFinder::MatchCallback {
 public:
  explicit AffectedPtrExprRewriter(OutputHelper& helper)
      : output_helper_(helper) {}

  AffectedPtrExprRewriter(const AffectedPtrExprRewriter&) = delete;
  AffectedPtrExprRewriter& operator=(const AffectedPtrExprRewriter&) = delete;

  void run(const MatchFinder::MatchResult& result) override {
    const clang::SourceManager& source_manager = *result.SourceManager;
    const clang::ASTContext& ast_context = *result.Context;

    Node lhs;
    if (const clang::VarDecl* var_decl =
            result.Nodes.getNodeAs<clang::VarDecl>("autoVarDecl")) {
      auto* type_loc = result.Nodes.getNodeAs<clang::TypeLoc>("autoLoc");

      clang::SourceRange replacement_range(var_decl->getBeginLoc(),
                                           type_loc->getEndLoc());

      std::string replacement_text =
          var_decl->getType()->getPointeeType().getAsString();

      replacement_text = RemovePrefix(replacement_text);
      lhs.replacement = getReplacementDirective(
          replacement_text, replacement_range, source_manager, ast_context);
      lhs.include_directive = lhs.replacement;

    } else if (const clang::CXXMemberCallExpr* member_expr =
                   result.Nodes.getNodeAs<clang::CXXMemberCallExpr>(
                       "affectedMemberExpr")) {
      clang::SourceLocation insertion_loc =
          member_expr->getEndLoc().getLocWithOffset(1);

      clang::SourceRange replacement_range(insertion_loc, insertion_loc);
      std::string replacement_text = ".get()";
      lhs.replacement = getReplacementDirective(
          replacement_text, replacement_range, source_manager, ast_context);
      lhs.include_directive = lhs.replacement;
    } else if (const clang::CXXOperatorCallExpr* op_call_expr =
                   result.Nodes.getNodeAs<clang::CXXOperatorCallExpr>(
                       "affectedOpCall")) {
      clang::SourceLocation insertion_loc =
          op_call_expr->getEndLoc().getLocWithOffset(1);
      clang::SourceRange replacement_range(insertion_loc, insertion_loc);
      std::string replacement_text = ".get()";
      lhs.replacement = getReplacementDirective(
          replacement_text, replacement_range, source_manager, ast_context);
      lhs.include_directive = lhs.replacement;
    } else if (const clang::ParmVarDecl* var_decl =
                   result.Nodes.getNodeAs<clang::ParmVarDecl>(
                       "lambda_parmVarDecl")) {
      auto* type_loc =
          result.Nodes.getNodeAs<clang::TypeLoc>("template_type_param_loc");

      auto* md = result.Nodes.getNodeAs<clang::CXXMethodDecl>("md");

      clang::SourceRange replacement_range(var_decl->getBeginLoc(),
                                           type_loc->getEndLoc());

      std::string replacement_text =
          (md->getParamDecl(var_decl->getFunctionScopeIndex()))
              ->getType()
              ->getPointeeType()
              .getAsString();

      replacement_text = RemovePrefix(replacement_text);
      lhs.replacement = getReplacementDirective(
          replacement_text, replacement_range, source_manager, ast_context);
      lhs.include_directive = lhs.replacement;
    }

    Node rhs;
    if (const clang::FieldDecl* field_decl =
            result.Nodes.getNodeAs<clang::FieldDecl>("rhs_field")) {
      rhs.is_field = true;
    }

    if (auto* type_loc = result.Nodes.getNodeAs<clang::PointerTypeLoc>(
            "rhs_argPointerLoc")) {
      std::string replacement_text =
          GenerateNewType(ast_context, type_loc->getType());

      const clang::TemplateSpecializationTypeLoc* tst_loc =
          result.Nodes.getNodeAs<clang::TemplateSpecializationTypeLoc>(
              "rhs_tst_loc");

      auto p = GetReplacementAndIncludeDirectives(
          type_loc, tst_loc, replacement_text, source_manager);

      rhs.replacement = p.first;
      rhs.include_directive = p.second;
    } else if (const clang::TypeLoc* auto_loc =
                   result.Nodes.getNodeAs<clang::TypeLoc>("rhs_auto_loc")) {
      rhs.replacement = GenerateReplacementForAutoLoc(
          auto_loc, "replacement_text", source_manager, ast_context);
      rhs.include_directive = rhs.replacement;
      rhs.has_auto_type = true;
    } else {
      // Should not get here.
      assert(false);
    }
    output_helper_.AddEdge(lhs, rhs);
  }

 private:
  std::string getReplacementDirective(
      std::string& replacement_text,
      clang::SourceRange replacement_range,
      const clang::SourceManager& source_manager,
      const clang::ASTContext& ast_context) {
    clang::tooling::Replacement replacement(
        source_manager, clang::CharSourceRange::getCharRange(replacement_range),
        replacement_text);
    llvm::StringRef file_path = replacement.getFilePath();

    std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0');
    return llvm::formatv("r:::{0}:::{1}:::{2}:::{3}", file_path,
                         replacement.getOffset(), replacement.getLength(),
                         replacement_text);
  }

  OutputHelper& output_helper_;
};

class ExprVisitor
    : public clang::ast_matchers::internal::BoundNodesTreeBuilder::Visitor {
 public:
  void visitMatch(
      const clang::ast_matchers::BoundNodes& BoundNodesView) override {
    expr_ = BoundNodesView.getNodeAs<clang::Expr>("expr");
  }
  const clang::Expr* expr_;
};

const clang::Expr* getExpr(
    clang::ast_matchers::internal::BoundNodesTreeBuilder& matches) {
  ExprVisitor v;
  matches.visitMatches(&v);
  return v.expr_;
}

// The goal of this matcher is to handle all possible combinations of matching
// expressions. This works by unpacking the expression nodes recursively (in any
// order they appear in) until we reach the matching lhs_expr/rhs_expr. This
// allows to handle cases like the following:
// std::map<int, std::vector<S*>> member;
// std::vector<S*>::iterator it = member.begin()->second;
AST_MATCHER_P(clang::Expr,
              expr_variations,
              clang::ast_matchers::internal::Matcher<clang::Expr>,
              InnerMatcher) {
  auto iterator = cxxMemberCallExpr(
      callee(functionDecl(
          anyOf(hasName("begin"), hasName("cbegin"), hasName("rbegin"),
                hasName("crbegin"), hasName("end"), hasName("cend"),
                hasName("rend"), hasName("crend"), hasName("find"),
                hasName("upper_bound"), hasName("lower_bound"),
                hasName("equal_range"), hasName("emplace"), hasName("Get")))),
      has(memberExpr(has(expr().bind("expr")))));

  auto search_calls = callExpr(callee(functionDecl(matchesName("find"))),
                               hasArgument(0, expr().bind("expr")));

  auto unary_op = unaryOperator(has(expr().bind("expr")));

  auto reversed_expr = callExpr(callee(functionDecl(hasName("base::Reversed"))),
                                hasArgument(0, expr().bind("expr")));

  auto bracket_op_call = cxxOperatorCallExpr(
      has(declRefExpr(to(cxxMethodDecl(hasName("operator[]"))))),
      has(expr(unless(declRefExpr(to(cxxMethodDecl(hasName("operator[]"))))))
              .bind("expr")));

  auto arrow_op_call = cxxOperatorCallExpr(
      has(declRefExpr(to(cxxMethodDecl(hasName("operator->"))))),
      has(expr(unless(declRefExpr(to(cxxMethodDecl(hasName("operator->"))))))
              .bind("expr")));

  auto star_op_call = cxxOperatorCallExpr(
      has(declRefExpr(to(cxxMethodDecl(hasName("operator*"))))),
      has(expr(unless(declRefExpr(to(cxxMethodDecl(hasName("operator*"))))))
              .bind("expr")));

  auto second_member =
      memberExpr(member(hasName("second")), has(expr().bind("expr")));

  auto items = {iterator,        search_calls,  unary_op,     reversed_expr,
                bracket_op_call, arrow_op_call, star_op_call, second_member};
  clang::ast_matchers::internal::BoundNodesTreeBuilder matches;
  const clang::Expr* n = nullptr;
  std::any_of(items.begin(), items.end(), [&](auto& item) {
    if (item.matches(Node, Finder, &matches)) {
      n = getExpr(matches);
      return true;
    }
    return false;
  });

  if (n) {
    auto matcher = expr_variations(InnerMatcher);
    return matcher.matches(*n, Finder, Builder);
  }
  return InnerMatcher.matches(Node, Finder, Builder);
}

class DeclVisitor
    : public clang::ast_matchers::internal::BoundNodesTreeBuilder::Visitor {
 public:
  void visitMatch(
      const clang::ast_matchers::BoundNodes& BoundNodesView) override {
    decl_ = BoundNodesView.getNodeAs<clang::TypedefNameDecl>("decl");
  }
  const clang::TypedefNameDecl* decl_;
};
const clang::TypedefNameDecl* getDecl(
    clang::ast_matchers::internal::BoundNodesTreeBuilder& matches) {
  DeclVisitor v;
  matches.visitMatches(&v);
  return v.decl_;
}
// This allows us to unpack typedefs recursively until we reach the node
// matching InnerMatcher.
// Example:
// using VECTOR = std::vector<S*>;
// using MAP = std::map<int, VECTOR>;
// MAP member; => this will lead to VECTOR being rewritten.
AST_MATCHER_P(clang::TypedefNameDecl,
              type_def_name_decl,
              clang::ast_matchers::internal::Matcher<clang::TypedefNameDecl>,
              InnerMatcher) {
  auto type_def_matcher = typedefNameDecl(
      hasDescendant(loc(qualType(hasDeclaration(
          typedefNameDecl(unless(isExpansionInSystemHeader())).bind("decl"))))),
      unless(isExpansionInSystemHeader()));

  clang::ast_matchers::internal::BoundNodesTreeBuilder matches;
  if (type_def_matcher.matches(Node, Finder, &matches)) {
    const clang::TypedefNameDecl* n = getDecl(matches);
    auto matcher = type_def_name_decl(InnerMatcher);
    return matcher.matches(*n, Finder, Builder);
  }
  return InnerMatcher.matches(Node, Finder, Builder);
}

class ContainerRewriter {
 public:
  explicit ContainerRewriter(
      MatchFinder& finder,
      OutputHelper& output_helper,
      std::map<std::string, std::set<Node>>& sig_nodes,
      std::vector<std::pair<std::string, std::string>>& sig_pairs,
      const raw_ptr_plugin::FilterFile* excluded_paths)
      : match_finder_(finder),
        affected_ptr_expr_rewriter_(output_helper),
        potentail_nodes_(output_helper),
        fct_sig_nodes_(sig_nodes, sig_pairs),
        paths_to_exclude(excluded_paths) {}

  void addMatchers() {
    // Assume every container has the three following methods: begin, end, size
    auto container_methods =
        anyOf(allOf(hasMethod(hasName("push_back")),
                    hasMethod(hasName("pop_back")), hasMethod(hasName("size"))),
              allOf(hasMethod(hasName("insert")), hasMethod(hasName("erase")),
                    hasMethod(hasName("size"))),
              allOf(hasMethod(hasName("push")), hasMethod(hasName("pop")),
                    hasMethod(hasName("size"))));

    // Exclude maps as they need special handling to be rewritten.
    // TODO: handle rewriting maps.
    auto excluded_containers = matchesName("map");

    auto supported_containers = anyOf(
        hasDeclaration(classTemplateSpecializationDecl(
            container_methods, unless(excluded_containers))),
        hasDeclaration(typeAliasTemplateDecl(has(typeAliasDecl(
            hasType(qualType(hasDeclaration(classTemplateDecl(has(cxxRecordDecl(
                container_methods, unless(excluded_containers))))))))))));

    auto tst_type_loc = templateSpecializationTypeLoc(
        loc(qualType(supported_containers)),
        hasTemplateArgumentLoc(
            0, hasTypeLoc(loc(qualType(allOf(
                   raw_ptr_plugin::supported_pointer_type(),
                   unless(raw_ptr_plugin::const_char_pointer_type(false))))))));

    auto lhs_location =
        templateSpecializationTypeLoc(
            tst_type_loc,
            hasTemplateArgumentLoc(
                0, hasTypeLoc(pointerTypeLoc().bind("lhs_argPointerLoc"))))
            .bind("lhs_tst_loc");

    auto rhs_location =
        templateSpecializationTypeLoc(
            tst_type_loc,
            hasTemplateArgumentLoc(
                0, hasTypeLoc(pointerTypeLoc().bind("rhs_argPointerLoc"))))
            .bind("rhs_tst_loc");

    auto exclude_callbacks = anyOf(
        hasType(typedefNameDecl(hasType(qualType(hasDeclaration(
            recordDecl(anyOf(hasName("base::RepeatingCallback"),
                             hasName("base::OnceCallback")))))))),
        hasType(qualType(
            hasDeclaration(recordDecl(anyOf(hasName("base::RepeatingCallback"),
                                            hasName("base::OnceCallback")))))));

    auto field_exclusions =
        anyOf(isExpansionInSystemHeader(), raw_ptr_plugin::isInExternCContext(),
              raw_ptr_plugin::isInThirdPartyLocation(),
              raw_ptr_plugin::isInGeneratedLocation(),
              raw_ptr_plugin::ImplicitFieldDeclaration(), exclude_callbacks,
              // Exclude fieldDecls in macros.
              // `raw_ptr_plugin::isInMacroLocation()` is also true for fields
              // annotated with RAW_PTR_EXCLUSION. The annotated fields are not
              // included in `field_exclusions` as they are handled differently
              // by the `excluded_field_decl` matcher.
              allOf(raw_ptr_plugin::isInMacroLocation(),
                    unless(raw_ptr_plugin::isRawPtrExclusionAnnotated())));

    // Supports typedefs as well.
    auto lhs_type_loc =
        anyOf(hasDescendant(loc(qualType(hasDeclaration(typedefNameDecl(
                  type_def_name_decl(hasDescendant(lhs_location))))))),
              hasDescendant(lhs_location));

    // Supports typedefs as well.
    auto rhs_type_loc =
        anyOf(hasDescendant(loc(qualType(hasDeclaration(typedefNameDecl(
                  type_def_name_decl(hasDescendant(rhs_location))))))),
              hasDescendant(rhs_location));

    auto lhs_field =
        fieldDecl(raw_ptr_plugin::hasExplicitFieldDecl(lhs_type_loc),
                  unless(field_exclusions))
            .bind("lhs_field");
    auto rhs_field =
        fieldDecl(raw_ptr_plugin::hasExplicitFieldDecl(rhs_type_loc),
                  unless(field_exclusions))
            .bind("rhs_field");

    auto lhs_var = anyOf(
        varDecl(hasDescendant(loc(qualType(autoType())).bind("lhs_auto_loc"))),
        varDecl(lhs_type_loc).bind("lhs_var"));

    auto rhs_var = anyOf(
        varDecl(hasDescendant(loc(qualType(autoType())).bind("rhs_auto_loc"))),
        varDecl(rhs_type_loc).bind("rhs_var"));

    auto lhs_param =
        parmVarDecl(raw_ptr_plugin::hasExplicitParmVarDecl(lhs_type_loc))
            .bind("lhs_param");

    auto rhs_param =
        parmVarDecl(raw_ptr_plugin::hasExplicitParmVarDecl(rhs_type_loc))
            .bind("rhs_param");

    auto rhs_call_expr =
        callExpr(callee(functionDecl(hasReturnTypeLoc(rhs_type_loc))));

    auto lhs_call_expr =
        callExpr(callee(functionDecl(hasReturnTypeLoc(lhs_type_loc))));

    auto lhs_expr = expr(
        ignoringImpCasts(anyOf(declRefExpr(to(anyOf(lhs_var, lhs_param))),
                               memberExpr(member(lhs_field)), lhs_call_expr)));

    auto rhs_expr = expr(
        ignoringImpCasts(anyOf(declRefExpr(to(anyOf(rhs_var, rhs_param))),
                               memberExpr(member(rhs_field)), rhs_call_expr)));

    // To make sure we add all field decls to the graph.(Specifically those not
    // connected to other nodes)
    auto field_decl =
        fieldDecl(raw_ptr_plugin::hasExplicitFieldDecl(lhs_type_loc),
                  unless(anyOf(field_exclusions,
                               raw_ptr_plugin::isRawPtrExclusionAnnotated())))
            .bind("field_decl");
    match_finder_.addMatcher(field_decl, &potentail_nodes_);

    // Fields annotated with RAW_PTR_EXCLUSION (as well as fields in excluded
    // paths) cannot be filtered using field exclusions. They need to appear in
    // the graph so that we can properly propagate the exclusion to reachable
    // nodes. For this reason, and in order to capture this information,
    // RAW_PTR_EXCLUSION fields are added as single nodes to the list and then
    // used as a starting point to propagate the exclusion before running dfs on
    // the graph.
    auto excluded_field_decl =
        fieldDecl(raw_ptr_plugin::hasExplicitFieldDecl(lhs_type_loc),
                  anyOf(raw_ptr_plugin::isRawPtrExclusionAnnotated(),
                        isInLocationListedInFilterFile(paths_to_exclude)))
            .bind("excluded_field_decl");
    match_finder_.addMatcher(excluded_field_decl, &potentail_nodes_);

    auto ref_cref_move =
        anyOf(hasName("std::move"), hasName("std::ref"), hasName("std::cref"));
    auto rhs_move_call =
        callExpr(callee(functionDecl(ref_cref_move)), hasArgument(0, rhs_expr));

    // This is needed for ternary cond operator true_expr. (cond) ? true_expr :
    // false_expr;
    auto lhs_move_call =
        callExpr(callee(functionDecl(ref_cref_move)), hasArgument(0, lhs_expr));

    auto rhs_cxx_temp_expr = cxxTemporaryObjectExpr(rhs_type_loc);

    auto lhs_cxx_temp_expr = cxxTemporaryObjectExpr(lhs_type_loc);

    // This represents the forms under which an expr could appear on the right
    // hand side of an assignment operation, var construction, or an expr passed
    // as callExpr argument. Examples: rhs_expr, &rhs_expr, *rhs_expr,
    // fct_call(),*fct_call(), &fct_call(), std::move(), .begin();
    auto rhs_expr_variations =
        expr_variations(anyOf(rhs_expr, rhs_move_call, rhs_cxx_temp_expr));

    auto lhs_expr_variations =
        expr_variations(anyOf(lhs_expr, lhs_move_call, lhs_cxx_temp_expr));

    // rewrite affected expressions
    {
      // This is needed to handle container-like types that implement a begin()
      // method. Range-based for loops over such types also need to be
      // rewritten.
      auto ctn_like_type =
          expr(hasType(cxxRecordDecl(has(functionDecl(
                   hasName("begin"), hasReturnTypeLoc(rhs_type_loc))))),
               unless(isExpansionInSystemHeader()));

      auto reversed_expr =
          callExpr(callee(functionDecl(hasName("base::Reversed"))),
                   hasArgument(0, rhs_expr_variations));

      // handles statements of the form: for (auto* i : member/var/param/fct())
      // that should be modified after rewriting the container.
      auto auto_star_in_range_stmt = traverse(
          clang::TK_IgnoreUnlessSpelledInSource,
          cxxForRangeStmt(
              has(varDecl(hasDescendant(loc(qualType(pointsTo(autoType())))
                                            .bind("autoLoc")))
                      .bind("autoVarDecl")),
              has(expr(
                  anyOf(rhs_expr_variations, reversed_expr, ctn_like_type)))));
      match_finder_.addMatcher(auto_star_in_range_stmt,
                               &affected_ptr_expr_rewriter_);

      // handles expressions of the form: auto* var = member.front();
      // This becomes: auto* var = member.front().get();
      auto affected_expr = traverse(
          clang::TK_IgnoreUnlessSpelledInSource,
          declStmt(has(varDecl(
              hasType(pointsTo(autoType())),
              has(cxxMemberCallExpr(
                      callee(
                          functionDecl(anyOf(hasName("front"), hasName("back"),
                                             hasName("at"), hasName("top")))),
                      has(memberExpr(has(expr(rhs_expr_variations)))))
                      .bind("affectedMemberExpr"))))));
      match_finder_.addMatcher(affected_expr, &affected_ptr_expr_rewriter_);

      // handles expressions of the form: auto* var = member[0];
      // This becomes: auto* var = member[0].get();
      auto affected_op_call =
          traverse(clang::TK_IgnoreUnlessSpelledInSource,
                   declStmt(has(varDecl(
                       hasType(pointsTo(autoType())),
                       has(cxxOperatorCallExpr(has(expr(rhs_expr_variations)))
                               .bind("affectedOpCall"))))));
      match_finder_.addMatcher(affected_op_call, &affected_ptr_expr_rewriter_);

      // handles expressions of the form:
      // std::ranges::any_of(view->children(), [](const auto* v) {
      //     ...
      //   });
      // where auto* needs to be rewritten into type_name*.
      auto range_exprs = callExpr(
          callee(functionDecl(anyOf(
              matchesName("find"), matchesName("any_of"), matchesName("all_of"),
              matchesName("transform"), matchesName("copy"),
              matchesName("accumulate"), matchesName("count")))),
          hasArgument(0, traverse(clang::TK_IgnoreUnlessSpelledInSource,
                                  expr(anyOf(rhs_expr_variations, reversed_expr,
                                             ctn_like_type)))),
          hasAnyArgument(expr(allOf(
              traverse(
                  clang::TK_IgnoreUnlessSpelledInSource,
                  lambdaExpr(
                      has(parmVarDecl(
                              hasTypeLoc(loc(qualType(anything()))
                                             .bind("template_type_param_loc")),
                              hasType(pointsTo(templateTypeParmType())))
                              .bind("lambda_parmVarDecl")))
                      .bind("lambda_expr")),
              lambdaExpr(has(cxxRecordDecl(has(functionTemplateDecl(has(
                  cxxMethodDecl(isTemplateInstantiation()).bind("md")))))))))));
      match_finder_.addMatcher(range_exprs, &affected_ptr_expr_rewriter_);
    }

    // needed for ternary operator expr: (cond) ? true_expr : false_expr;
    // true_expr => lhs; false_expr => rhs;
    // creates a link between false_expr and true_expr of a ternary conditional
    // operator;
    // handles:
    // (cond) ? (a/&a/*a/std::move(a)/fct()/*fct()/&fct()/a.begin()) :
    // (b/&b/*b/std::move(b)/fct()/*fct()/&fct()/b.begin())
    auto ternary_cond_expr =
        traverse(clang::TK_IgnoreUnlessSpelledInSource,
                 conditionalOperator(hasTrueExpression(lhs_expr_variations),
                                     hasFalseExpression(rhs_expr_variations),
                                     unless(isExpansionInSystemHeader())));
    match_finder_.addMatcher(ternary_cond_expr, &potentail_nodes_);

    // Handles assignment:
    // a = b;
    // a = &b;
    // *a = b;
    // *a = *b;
    // a = fct();
    // a = *fct();
    // a = std::move(b);
    // a = &fct();
    // it = member.begin();
    // a = vector<S*>();
    // a = (cond) ? expr1 : expr2;
    auto assignement_relationship = traverse(
        clang::TK_IgnoreUnlessSpelledInSource,
        binaryOperation(hasOperatorName("="),
                        hasOperands(lhs_expr_variations,
                                    anyOf(rhs_expr_variations,
                                          conditionalOperator(hasTrueExpression(
                                              rhs_expr_variations)))),
                        unless(isExpansionInSystemHeader())));
    match_finder_.addMatcher(assignement_relationship, &potentail_nodes_);

    // Supports:
    // std::vector<T*>* temp = &member;
    // std::vector<T*>& temp = member;
    // std::vector<T*> temp = *member;
    // std::vector<T*> temp = member;  and other similar stmts.
    // std::vector<T*> temp = init();
    // std::vector<T*> temp = *fct();
    // std::vector<T*>::iterator it = member.begin();
    // std::vector<T*> temp = (cond) ? expr1 : expr2;
    auto var_construction = traverse(
        clang::TK_IgnoreUnlessSpelledInSource,
        varDecl(
            lhs_var,
            has(expr(anyOf(
                rhs_expr_variations,
                conditionalOperator(hasTrueExpression(rhs_expr_variations)),
                cxxConstructExpr(has(expr(anyOf(
                    rhs_expr_variations, conditionalOperator(hasTrueExpression(
                                             rhs_expr_variations))))))))),
            unless(isExpansionInSystemHeader())));
    match_finder_.addMatcher(var_construction, &potentail_nodes_);

    // Supports:
    // return member;
    // return *member;
    // return &member;
    // return fct();
    // return *fct();
    // return std::move(member);
    // return member.begin();
    // return (cond) ? expr1 : expr2;
    auto returned_var_or_member = traverse(
        clang::TK_IgnoreUnlessSpelledInSource,
        returnStmt(
            hasReturnValue(expr(anyOf(
                rhs_expr_variations,
                conditionalOperator(hasTrueExpression(rhs_expr_variations))))),
            unless(isExpansionInSystemHeader()),
            forFunction(functionDecl(hasReturnTypeLoc(lhs_type_loc))
                            .bind("lhs_fct_return")))
            .bind("lhs_stmt"));
    match_finder_.addMatcher(returned_var_or_member, &potentail_nodes_);

    // Handles expressions of the form member(arg).
    // A(const std::vector<T*>& arg): member(arg){}
    // member(init());
    // member(*fct());
    // member2(&member1);
    auto ctor_initilizer = traverse(
        clang::TK_IgnoreUnlessSpelledInSource,
        cxxCtorInitializer(withInitializer(anyOf(
                               cxxConstructExpr(has(expr(rhs_expr_variations))),
                               rhs_expr_variations)),
                           forField(lhs_field)));

    match_finder_.addMatcher(ctor_initilizer, &potentail_nodes_);

    // link var/field passed as function arguments to function parameter
    // This handles func(var/member/param), func(&var/member/param),
    // func(*var/member/param), func(func2()), func(&func2())
    // cxxOpCallExprs excluded here since operator= can be invoked as a call
    // expr for classes/structs.
    auto call_expr = traverse(
        clang::TK_IgnoreUnlessSpelledInSource,
        callExpr(forEachArgumentWithParam(
                     expr(anyOf(rhs_expr_variations,
                                conditionalOperator(
                                    hasTrueExpression(rhs_expr_variations)))),
                     lhs_param),
                 unless(isExpansionInSystemHeader()),
                 unless(cxxOperatorCallExpr(hasOperatorName("=")))));
    match_finder_.addMatcher(call_expr, &potentail_nodes_);

    // Handles: member.swap(temp); temp.swap(member);
    auto member_swap_call = traverse(
        clang::TK_IgnoreUnlessSpelledInSource,
        cxxMemberCallExpr(callee(functionDecl(hasName("swap"))),
                          hasArgument(0, rhs_expr_variations),
                          has(memberExpr(has(expr(lhs_expr_variations)))),
                          unless(isExpansionInSystemHeader())));
    match_finder_.addMatcher(member_swap_call, &potentail_nodes_);

    // Handles: std::swap(member, temp); std::swap(temp, member);
    auto std_swap_call =
        traverse(clang::TK_IgnoreUnlessSpelledInSource,
                 callExpr(callee(functionDecl(hasName("std::swap"))),
                          hasArgument(0, lhs_expr_variations),
                          hasArgument(1, rhs_expr_variations),
                          unless(isExpansionInSystemHeader())));
    match_finder_.addMatcher(std_swap_call, &potentail_nodes_);

    auto assert_expect_eq =
        traverse(clang::TK_IgnoreUnlessSpelledInSource,
                 callExpr(anyOf(isExpandedFromMacro("EXPECT_EQ"),
                                isExpandedFromMacro("ASSERT_EQ")),
                          hasArgument(2, lhs_expr_variations),
                          hasArgument(3, rhs_expr_variations),
                          unless(isExpansionInSystemHeader())));
    match_finder_.addMatcher(assert_expect_eq, &potentail_nodes_);

    // Supports:
    // std::vector<S*> temp;
    // Obj o(temp); Obj o{temp};
    // This links temp to the parameter in Obj's constructor.
    auto var_passed_in_constructor = traverse(
        clang::TK_IgnoreUnlessSpelledInSource,
        cxxConstructExpr(forEachArgumentWithParam(
            expr(anyOf(
                rhs_expr_variations,
                conditionalOperator(hasTrueExpression(rhs_expr_variations)))),
            lhs_param)));
    match_finder_.addMatcher(var_passed_in_constructor, &potentail_nodes_);

    // handles Obj o{temp} when Obj has no constructor.
    // This creates a link between the expr and the underlying field.
    auto var_passed_in_initlistExpr = traverse(
        clang::TK_IgnoreUnlessSpelledInSource,
        initListExpr(raw_ptr_plugin::forEachInitExprWithFieldDecl(
            expr(anyOf(
                rhs_expr_variations,
                conditionalOperator(hasTrueExpression(rhs_expr_variations)))),
            lhs_field)));
    match_finder_.addMatcher(var_passed_in_initlistExpr, &potentail_nodes_);

    // This creates a link between each argument passed to the make_unique call
    // and the corresponding constructor parameter.
    auto make_unique_call = traverse(
        clang::TK_IgnoreUnlessSpelledInSource,
        callExpr(
            callee(functionDecl(hasName("std::make_unique"))),
            forEachArg(
                expr(rhs_expr_variations,
                     hasParent(callExpr(
                         callee(functionDecl(hasDescendant(cxxConstructExpr(
                             has(cxxNewExpr(has(cxxConstructExpr(hasDeclaration(
                                 functionDecl().bind("fct_decl"))))))))))))),
                lhs_param)));
    match_finder_.addMatcher(make_unique_call, &potentail_nodes_);

    // This creates a link between lhs and an argument passed to emplace.
    // Example:
    // std::map<int, std::vector<S*>> m;
    // m.emplace(index, o.member);
    // where member has type std::vector<S*>;
    auto emplace_call_with_arg =
        traverse(clang::TK_IgnoreUnlessSpelledInSource,
                 cxxMemberCallExpr(callee(functionDecl(hasName("emplace"))),
                                   has(memberExpr(has(rhs_expr_variations))),
                                   hasAnyArgument(lhs_expr_variations)));
    match_finder_.addMatcher(emplace_call_with_arg, &potentail_nodes_);

    // Handle BindOnce/BindRepeating;
    auto first_arg = hasParent(callExpr(hasArgument(
        0, anyOf(lambdaExpr().bind("lambda_expr"),
                 unaryOperator(
                     has(declRefExpr(to(functionDecl().bind("fct_decl")))))))));

    auto bind_args = traverse(
        clang::TK_IgnoreUnlessSpelledInSource,
        callExpr(
            callee(functionDecl(
                anyOf(hasName("BindOnce"), hasName("BindRepeating")))),
            forEachBindArg(expr(rhs_expr_variations, first_arg), lhs_param)));
    match_finder_.addMatcher(bind_args, &potentail_nodes_);

    // This is useful to handle iteration over maps with vector as value.
    // Example:
    // std::vector<int, std::vector<S*>> m;
    // for (auto& p : m){
    // ...
    // }
    // This creates a link between p and m.
    auto for_range_stmts = traverse(
        clang::TK_IgnoreUnlessSpelledInSource,
        cxxForRangeStmt(
            hasLoopVariable(decl(lhs_var, unless(has(pointerTypeLoc())))),
            hasRangeInit(rhs_expr_variations)));
    match_finder_.addMatcher(for_range_stmts, &potentail_nodes_);

    // Map function declaration signature to function definition signature;
    // This is problematic in the case of callbacks defined in function.
    auto fct_decls_params = traverse(
        clang::TK_IgnoreUnlessSpelledInSource,
        functionDecl(forEachParmVarDecl(rhs_param),
                     unless(anyOf(isExpansionInSystemHeader(),
                                  raw_ptr_plugin::isInMacroLocation())))
            .bind("fct_decl"));
    match_finder_.addMatcher(fct_decls_params, &fct_sig_nodes_);

    auto fct_decls_returns = traverse(
        clang::TK_IgnoreUnlessSpelledInSource,
        functionDecl(hasReturnTypeLoc(rhs_type_loc),
                     unless(anyOf(isExpansionInSystemHeader(),
                                  raw_ptr_plugin::isInMacroLocation())))
            .bind("fct_decl"));
    match_finder_.addMatcher(fct_decls_returns, &fct_sig_nodes_);

    auto macro_fct_signatures = traverse(
        clang::TK_IgnoreUnlessSpelledInSource,
        templateSpecializationTypeLoc(
            rhs_location,
            hasAncestor(
                cxxMethodDecl(raw_ptr_plugin::isInMacroLocation(),
                              anyOf(isExpandedFromMacro("MOCK_METHOD"),
                                    isExpandedFromMacro("MOCK_METHOD0"),
                                    isExpandedFromMacro("MOCK_METHOD1"),
                                    isExpandedFromMacro("MOCK_METHOD2"),
                                    isExpandedFromMacro("MOCK_METHOD3"),
                                    isExpandedFromMacro("MOCK_METHOD4"),
                                    isExpandedFromMacro("MOCK_METHOD5"),
                                    isExpandedFromMacro("MOCK_METHOD6"),
                                    isExpandedFromMacro("MOCK_METHOD7"),
                                    isExpandedFromMacro("MOCK_METHOD8"),
                                    isExpandedFromMacro("MOCK_METHOD9"),
                                    isExpandedFromMacro("MOCK_METHOD10"),
                                    isExpandedFromMacro("MOCK_CONST_METHOD0"),
                                    isExpandedFromMacro("MOCK_CONST_METHOD1"),
                                    isExpandedFromMacro("MOCK_CONST_METHOD2"),
                                    isExpandedFromMacro("MOCK_CONST_METHOD3"),
                                    isExpandedFromMacro("MOCK_CONST_METHOD4"),
                                    isExpandedFromMacro("MOCK_CONST_METHOD5"),
                                    isExpandedFromMacro("MOCK_CONST_METHOD6"),
                                    isExpandedFromMacro("MOCK_CONST_METHOD7"),
                                    isExpandedFromMacro("MOCK_CONST_METHOD8"),
                                    isExpandedFromMacro("MOCK_CONST_METHOD9"),
                                    isExpandedFromMacro("MOCK_CONST_METHOD10")),
                              unless(isExpansionInSystemHeader()))
                    .bind("fct_decl"))));
    match_finder_.addMatcher(macro_fct_signatures, &fct_sig_nodes_);

    // TODO: handle calls to templated functions
  }

 private:
  MatchFinder& match_finder_;
  AffectedPtrExprRewriter affected_ptr_expr_rewriter_;
  PotentialNodes potentail_nodes_;
  FunctionSignatureNodes fct_sig_nodes_;
  const raw_ptr_plugin::FilterFile* paths_to_exclude;
};

}  // namespace

int main(int argc, const char* argv[]) {
  llvm::InitializeNativeTarget();
  llvm::InitializeNativeTargetAsmParser();
  llvm::cl::OptionCategory category(
      "rewrite_templated_container_fields: changes |vector<T*> field_| to "
      "|vector<raw_ptr<T>> field_|.");

  llvm::cl::opt<std::string> override_exclude_paths_param(
      kOverrideExcludePathsParamName, llvm::cl::value_desc("filepath"),
      llvm::cl::desc(
          "override file listing paths to be blocked (not rewritten)"));
  llvm::Expected<clang::tooling::CommonOptionsParser> options =
      clang::tooling::CommonOptionsParser::create(argc, argv, category);
  assert(static_cast<bool>(options));  // Should not return an error.
  clang::tooling::ClangTool tool(options->getCompilations(),
                                 options->getSourcePathList());

  std::unique_ptr<raw_ptr_plugin::FilterFile> paths_to_exclude;
  if (override_exclude_paths_param.getValue().empty()) {
    std::vector<std::string> paths_to_exclude_lines;
    for (auto* const line : kRawPtrManualPathsToIgnore) {
      paths_to_exclude_lines.push_back(line);
    }
    for (auto* const line : kSeparateRepositoryPaths) {
      paths_to_exclude_lines.push_back(line);
    }
    paths_to_exclude =
        std::make_unique<raw_ptr_plugin::FilterFile>(paths_to_exclude_lines);
  } else {
    paths_to_exclude = std::make_unique<raw_ptr_plugin::FilterFile>(
        override_exclude_paths_param,
        override_exclude_paths_param.ArgStr.str());
  }

  // Map a function signature, which is modeled as a string representing file
  // location, to it's graph nodes (RTNode and ParmVarDecl nodes).
  // RTNode represents a function return type.
  std::map<std::string, std::set<Node>> fct_sig_nodes;
  // Map related function signatures to each other, this is needed for functions
  // with separate definition and declaration, and for overridden functions.
  std::vector<std::pair<std::string, std::string>> fct_sig_pairs;
  OutputHelper output_helper;
  MatchFinder match_finder;
  ContainerRewriter rewriter(match_finder, output_helper, fct_sig_nodes,
                             fct_sig_pairs, paths_to_exclude.get());
  rewriter.addMatchers();

  // Prepare and run the tool.
  std::unique_ptr<clang::tooling::FrontendActionFactory> factory =
      clang::tooling::newFrontendActionFactory(&match_finder);
  int result = tool.run(factory.get());

  // For each pair of adjacent function signatures, create a link between
  // corresponding parameters.
  // 2 functions are said to be adjacent if one overrides the other, or if one
  // is a function definition and the other is that function's declaration.
  for (auto& [l, r] : fct_sig_pairs) {
    if (fct_sig_nodes.find(l) == fct_sig_nodes.end()) {
      continue;
    }
    if (fct_sig_nodes.find(r) == fct_sig_nodes.end()) {
      continue;
    }
    auto& s1 = fct_sig_nodes[l];
    auto& s2 = fct_sig_nodes[r];
    assert(s1.size() == s2.size());
    auto i1 = s1.begin();
    auto i2 = s2.begin();
    while (i1 != s1.end()) {
      output_helper.AddEdge(*i1, *i2);
      i1++;
      i2++;
    }
  }

  // Emits the list of edges.
  output_helper.Emit();

  return result;
}