//===--- TwineLocalCheck.cpp - clang-tidy ---------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "TwineLocalCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Lex/Lexer.h" using namespace clang::ast_matchers; namespace clang { namespace tidy { namespace llvm_check { void TwineLocalCheck::registerMatchers(MatchFinder *Finder) { auto TwineType = qualType(hasDeclaration(cxxRecordDecl(hasName("::llvm::Twine")))); Finder->addMatcher( varDecl(unless(parmVarDecl()), hasType(TwineType)).bind("variable"), this); } void TwineLocalCheck::check(const MatchFinder::MatchResult &Result) { const auto *VD = Result.Nodes.getNodeAs("variable"); auto Diag = diag(VD->getLocation(), "twine variables are prone to use-after-free bugs"); // If this VarDecl has an initializer try to fix it. if (VD->hasInit()) { // Peel away implicit constructors and casts so we can see the actual type // of the initializer. const Expr *C = VD->getInit()->IgnoreImplicit(); while (isa(C)) { if (cast(C)->getNumArgs() == 0) break; C = cast(C)->getArg(0)->IgnoreParenImpCasts(); } SourceRange TypeRange = VD->getTypeSourceInfo()->getTypeLoc().getSourceRange(); // A real Twine, turn it into a std::string. if (VD->getType()->getCanonicalTypeUnqualified() == C->getType()->getCanonicalTypeUnqualified()) { SourceLocation EndLoc = Lexer::getLocForEndOfToken( VD->getInit()->getEndLoc(), 0, *Result.SourceManager, getLangOpts()); Diag << FixItHint::CreateReplacement(TypeRange, "std::string") << FixItHint::CreateInsertion(VD->getInit()->getBeginLoc(), "(") << FixItHint::CreateInsertion(EndLoc, ").str()"); } else { // Just an implicit conversion. Insert the real type. Diag << FixItHint::CreateReplacement( TypeRange, C->getType().getAsString(Result.Context->getPrintingPolicy())); } } } } // namespace llvm_check } // namespace tidy } // namespace clang