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