brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.7 KiB · 6502fc9 Raw
98 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "UnusedRaiiCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/Lex/Lexer.h"12 13using namespace clang::ast_matchers;14 15namespace clang::tidy::bugprone {16 17namespace {18AST_MATCHER(CXXRecordDecl, hasNonTrivialDestructor) {19  // TODO: If the dtor is there but empty we don't want to warn either.20  return Node.hasDefinition() && Node.hasNonTrivialDestructor();21}22} // namespace23 24void UnusedRaiiCheck::registerMatchers(MatchFinder *Finder) {25  // Look for temporaries that are constructed in-place and immediately26  // destroyed.27  Finder->addMatcher(28      mapAnyOf(cxxConstructExpr, cxxUnresolvedConstructExpr)29          .with(hasParent(compoundStmt().bind("compound")),30                anyOf(hasType(hasCanonicalType(recordType(hasDeclaration(31                          cxxRecordDecl(hasNonTrivialDestructor()))))),32                      hasType(hasCanonicalType(templateSpecializationType(33                          hasDeclaration(classTemplateDecl(has(34                              cxxRecordDecl(hasNonTrivialDestructor())))))))))35          .bind("expr"),36      this);37}38 39template <typename T>40static void reportDiagnostic(const DiagnosticBuilder &D, const T *Node,41                             SourceRange SR, bool DefaultConstruction) {42  const char *Replacement = " give_me_a_name";43 44  // If this is a default ctor we have to remove the parens or we'll introduce a45  // most vexing parse.46  if (DefaultConstruction) {47    D << FixItHint::CreateReplacement(CharSourceRange::getTokenRange(SR),48                                      Replacement);49    return;50  }51 52  // Otherwise just suggest adding a name. To find the place to insert the name53  // find the first TypeLoc in the children of E, which always points to the54  // written type.55  D << FixItHint::CreateInsertion(SR.getBegin(), Replacement);56}57 58void UnusedRaiiCheck::check(const MatchFinder::MatchResult &Result) {59  const auto *E = Result.Nodes.getNodeAs<Expr>("expr");60 61  // We ignore code expanded from macros to reduce the number of false62  // positives.63  if (E->getBeginLoc().isMacroID())64    return;65 66  // Don't emit a warning for the last statement in the surrounding compound67  // statement.68  const auto *CS = Result.Nodes.getNodeAs<CompoundStmt>("compound");69  const auto *LastExpr = dyn_cast<Expr>(CS->body_back());70 71  if (LastExpr && E == LastExpr->IgnoreUnlessSpelledInSource())72    return;73 74  // Emit a warning.75  auto D = diag(E->getBeginLoc(), "object destroyed immediately after "76                                  "creation; did you mean to name the object?");77 78  if (const auto *Node = dyn_cast<CXXConstructExpr>(E))79    reportDiagnostic(D, Node, Node->getParenOrBraceRange(),80                     Node->getNumArgs() == 0 ||81                         isa<CXXDefaultArgExpr>(Node->getArg(0)));82  if (const auto *Node = dyn_cast<CXXUnresolvedConstructExpr>(E)) {83    auto SR = SourceRange(Node->getLParenLoc(), Node->getRParenLoc());84    auto DefaultConstruction = Node->getNumArgs() == 0;85    if (!DefaultConstruction) {86      auto *FirstArg = Node->getArg(0);87      DefaultConstruction = isa<CXXDefaultArgExpr>(FirstArg);88      if (auto *ILE = dyn_cast<InitListExpr>(FirstArg)) {89        DefaultConstruction = ILE->getNumInits() == 0;90        SR = SourceRange(ILE->getLBraceLoc(), ILE->getRBraceLoc());91      }92    }93    reportDiagnostic(D, Node, SR, DefaultConstruction);94  }95}96 97} // namespace clang::tidy::bugprone98