1 // Copyright 2017 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 
5 #include "BadPatternFinder.h"
6 #include "DiagnosticsReporter.h"
7 
8 #include "clang/AST/ASTContext.h"
9 #include "clang/ASTMatchers/ASTMatchFinder.h"
10 #include "clang/ASTMatchers/ASTMatchers.h"
11 
12 using namespace clang::ast_matchers;
13 
14 namespace {
15 
GarbageCollectedType()16 TypeMatcher GarbageCollectedType() {
17   auto has_gc_base = hasCanonicalType(hasDeclaration(
18       cxxRecordDecl(isDerivedFrom(hasAnyName("::blink::GarbageCollected",
19                                              "::blink::GarbageCollectedMixin")))
20           .bind("gctype")));
21   return anyOf(has_gc_base,
22                hasCanonicalType(arrayType(hasElementType(has_gc_base))));
23 }
24 
25 class UniquePtrGarbageCollectedMatcher : public MatchFinder::MatchCallback {
26  public:
UniquePtrGarbageCollectedMatcher(DiagnosticsReporter & diagnostics)27   explicit UniquePtrGarbageCollectedMatcher(DiagnosticsReporter& diagnostics)
28       : diagnostics_(diagnostics) {}
29 
Register(MatchFinder & match_finder)30   void Register(MatchFinder& match_finder) {
31     // Matches any application of make_unique where the template argument is
32     // known to refer to a garbage-collected type.
33     auto make_unique_matcher =
34         callExpr(
35             callee(functionDecl(
36                        hasAnyName("::std::make_unique", "::base::WrapUnique"),
37                        hasTemplateArgument(
38                            0, refersToType(GarbageCollectedType())))
39                        .bind("badfunc")))
40             .bind("bad");
41     match_finder.addDynamicMatcher(make_unique_matcher, this);
42   }
43 
run(const MatchFinder::MatchResult & result)44   void run(const MatchFinder::MatchResult& result) {
45     auto* bad_use = result.Nodes.getNodeAs<clang::Expr>("bad");
46     auto* bad_function = result.Nodes.getNodeAs<clang::FunctionDecl>("badfunc");
47     auto* gc_type = result.Nodes.getNodeAs<clang::CXXRecordDecl>("gctype");
48     diagnostics_.UniquePtrUsedWithGC(bad_use, bad_function, gc_type);
49   }
50 
51  private:
52   DiagnosticsReporter& diagnostics_;
53 };
54 
55 class OptionalGarbageCollectedMatcher : public MatchFinder::MatchCallback {
56  public:
OptionalGarbageCollectedMatcher(DiagnosticsReporter & diagnostics)57   explicit OptionalGarbageCollectedMatcher(DiagnosticsReporter& diagnostics)
58       : diagnostics_(diagnostics) {}
59 
Register(MatchFinder & match_finder)60   void Register(MatchFinder& match_finder) {
61     // Matches any application of make_unique where the template argument is
62     // known to refer to a garbage-collected type.
63     auto optional_construction =
64         cxxConstructExpr(hasDeclaration(cxxConstructorDecl(ofClass(
65                              classTemplateSpecializationDecl(
66                                  hasName("::base::Optional"),
67                                  hasTemplateArgument(
68                                      0, refersToType(GarbageCollectedType())))
69                                  .bind("optional")))))
70             .bind("bad");
71     match_finder.addDynamicMatcher(optional_construction, this);
72   }
73 
run(const MatchFinder::MatchResult & result)74   void run(const MatchFinder::MatchResult& result) {
75     auto* bad_use = result.Nodes.getNodeAs<clang::Expr>("bad");
76     auto* optional = result.Nodes.getNodeAs<clang::CXXRecordDecl>("optional");
77     auto* gc_type = result.Nodes.getNodeAs<clang::CXXRecordDecl>("gctype");
78     diagnostics_.OptionalUsedWithGC(bad_use, optional, gc_type);
79   }
80 
81  private:
82   DiagnosticsReporter& diagnostics_;
83 };
84 
85 }  // namespace
86 
FindBadPatterns(clang::ASTContext & ast_context,DiagnosticsReporter & diagnostics)87 void FindBadPatterns(clang::ASTContext& ast_context,
88                      DiagnosticsReporter& diagnostics) {
89   MatchFinder match_finder;
90 
91   UniquePtrGarbageCollectedMatcher unique_ptr_gc(diagnostics);
92   unique_ptr_gc.Register(match_finder);
93 
94   OptionalGarbageCollectedMatcher optional_gc(diagnostics);
95   optional_gc.Register(match_finder);
96 
97   match_finder.matchAST(ast_context);
98 }
99