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 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: 27 explicit UniquePtrGarbageCollectedMatcher(DiagnosticsReporter& diagnostics) 28 : diagnostics_(diagnostics) {} 29 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 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: 57 explicit OptionalGarbageCollectedMatcher(DiagnosticsReporter& diagnostics) 58 : diagnostics_(diagnostics) {} 59 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 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 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