// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "BadPatternFinder.h" #include "DiagnosticsReporter.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" using namespace clang::ast_matchers; namespace { TypeMatcher GarbageCollectedType() { auto has_gc_base = hasCanonicalType(hasDeclaration( cxxRecordDecl(isDerivedFrom(hasAnyName("::blink::GarbageCollected", "::blink::GarbageCollectedMixin"))) .bind("gctype"))); return anyOf(has_gc_base, hasCanonicalType(arrayType(hasElementType(has_gc_base)))); } class UniquePtrGarbageCollectedMatcher : public MatchFinder::MatchCallback { public: explicit UniquePtrGarbageCollectedMatcher(DiagnosticsReporter& diagnostics) : diagnostics_(diagnostics) {} void Register(MatchFinder& match_finder) { // Matches any application of make_unique where the template argument is // known to refer to a garbage-collected type. auto make_unique_matcher = callExpr( callee(functionDecl( hasAnyName("::std::make_unique", "::base::WrapUnique"), hasTemplateArgument( 0, refersToType(GarbageCollectedType()))) .bind("badfunc"))) .bind("bad"); match_finder.addDynamicMatcher(make_unique_matcher, this); } void run(const MatchFinder::MatchResult& result) { auto* bad_use = result.Nodes.getNodeAs<clang::Expr>("bad"); auto* bad_function = result.Nodes.getNodeAs<clang::FunctionDecl>("badfunc"); auto* gc_type = result.Nodes.getNodeAs<clang::CXXRecordDecl>("gctype"); diagnostics_.UniquePtrUsedWithGC(bad_use, bad_function, gc_type); } private: DiagnosticsReporter& diagnostics_; }; class OptionalGarbageCollectedMatcher : public MatchFinder::MatchCallback { public: explicit OptionalGarbageCollectedMatcher(DiagnosticsReporter& diagnostics) : diagnostics_(diagnostics) {} void Register(MatchFinder& match_finder) { // Matches any application of make_unique where the template argument is // known to refer to a garbage-collected type. auto optional_construction = cxxConstructExpr(hasDeclaration(cxxConstructorDecl(ofClass( classTemplateSpecializationDecl( hasName("::base::Optional"), hasTemplateArgument( 0, refersToType(GarbageCollectedType()))) .bind("optional"))))) .bind("bad"); match_finder.addDynamicMatcher(optional_construction, this); } void run(const MatchFinder::MatchResult& result) { auto* bad_use = result.Nodes.getNodeAs<clang::Expr>("bad"); auto* optional = result.Nodes.getNodeAs<clang::CXXRecordDecl>("optional"); auto* gc_type = result.Nodes.getNodeAs<clang::CXXRecordDecl>("gctype"); diagnostics_.OptionalUsedWithGC(bad_use, optional, gc_type); } private: DiagnosticsReporter& diagnostics_; }; } // namespace void FindBadPatterns(clang::ASTContext& ast_context, DiagnosticsReporter& diagnostics) { MatchFinder match_finder; UniquePtrGarbageCollectedMatcher unique_ptr_gc(diagnostics); unique_ptr_gc.Register(match_finder); OptionalGarbageCollectedMatcher optional_gc(diagnostics); optional_gc.Register(match_finder); match_finder.matchAST(ast_context); }