void RefCountedCopyConstructorChecker::registerMatchers(MatchFinder* AstMatcher) {
  AstMatcher->addMatcher(
      cxxConstructExpr(
          hasDeclaration(cxxConstructorDecl(isCompilerProvidedCopyConstructor(),
                                            ofClass(hasRefCntMember()))))
          .bind("node"),
      this);
}
void PassByValueCheck::registerMatchers(MatchFinder *Finder) {
  // Only register the matchers for C++; the functionality currently does not
  // provide any benefit to other languages, despite being benign.
  if (!getLangOpts().CPlusPlus)
    return;

  Finder->addMatcher(
      cxxConstructorDecl(
          forEachConstructorInitializer(
              cxxCtorInitializer(
                  // Clang builds a CXXConstructExpr only whin it knows which
                  // constructor will be called. In dependent contexts a
                  // ParenListExpr is generated instead of a CXXConstructExpr,
                  // filtering out templates automatically for us.
                  withInitializer(cxxConstructExpr(
                      has(ignoringParenImpCasts(declRefExpr(to(
                          parmVarDecl(
                              hasType(qualType(
                                  // Match only const-ref or a non-const value
                                  // parameters. Rvalues and const-values
                                  // shouldn't be modified.
                                  anyOf(constRefType(), nonConstValueType()))))
                              .bind("Param"))))),
                      hasDeclaration(cxxConstructorDecl(
                          isCopyConstructor(), unless(isDeleted()),
                          hasDeclContext(
                              cxxRecordDecl(isMoveConstructible())))))))
                  .bind("Initializer")))
          .bind("Ctor"),
      this);
}
예제 #3
0
void SlicingCheck::registerMatchers(MatchFinder *Finder) {
  // When we see:
  //   class B : public A { ... };
  //   A a;
  //   B b;
  //   a = b;
  // The assignment is OK if:
  //   - the assignment operator is defined as taking a B as second parameter,
  //   or
  //   - B does not define any additional members (either variables or
  //   overrides) wrt A.
  //
  // The same holds for copy ctor calls. This also captures stuff like:
  //   void f(A a);
  //   f(b);

  //  Helpers.
  const auto OfBaseClass = ofClass(cxxRecordDecl().bind("BaseDecl"));
  const auto IsDerivedFromBaseDecl =
      cxxRecordDecl(isDerivedFrom(equalsBoundNode("BaseDecl")))
          .bind("DerivedDecl");
  const auto HasTypeDerivedFromBaseDecl =
      anyOf(hasType(IsDerivedFromBaseDecl),
            hasType(references(IsDerivedFromBaseDecl)));
  const auto IsWithinDerivedCtor =
      hasParent(cxxConstructorDecl(ofClass(equalsBoundNode("DerivedDecl"))));

  // Assignement slicing: "a = b;" and "a = std::move(b);" variants.
  const auto SlicesObjectInAssignment =
      callExpr(callee(cxxMethodDecl(anyOf(isCopyAssignmentOperator(),
                                          isMoveAssignmentOperator()),
                                    OfBaseClass)),
               hasArgument(1, HasTypeDerivedFromBaseDecl));

  // Construction slicing: "A a{b};" and "f(b);" variants. Note that in case of
  // slicing the letter will create a temporary and therefore call a ctor.
  const auto SlicesObjectInCtor = cxxConstructExpr(
      hasDeclaration(cxxConstructorDecl(
          anyOf(isCopyConstructor(), isMoveConstructor()), OfBaseClass)),
      hasArgument(0, HasTypeDerivedFromBaseDecl),
      // We need to disable matching on the call to the base copy/move
      // constructor in DerivedDecl's constructors.
      unless(IsWithinDerivedCtor));

  Finder->addMatcher(
      expr(anyOf(SlicesObjectInAssignment, SlicesObjectInCtor)).bind("Call"),
      this);
}
void ForwardingReferenceOverloadCheck::registerMatchers(MatchFinder *Finder) {
  // Forwarding references require C++11 or later.
  if (!getLangOpts().CPlusPlus11)
    return;

  auto ForwardingRefParm =
      parmVarDecl(
          hasType(qualType(rValueReferenceType(),
                           references(templateTypeParmType(hasDeclaration(
                               templateTypeParmDecl().bind("type-parm-decl")))),
                           unless(references(isConstQualified())))))
          .bind("parm-var");

  DeclarationMatcher findOverload =
      cxxConstructorDecl(
          hasParameter(0, ForwardingRefParm),
          unless(hasAnyParameter(
              // No warning: enable_if as constructor parameter.
              parmVarDecl(hasType(isEnableIf())))),
          unless(hasParent(functionTemplateDecl(has(templateTypeParmDecl(
              // No warning: enable_if as type parameter.
              hasDefaultArgument(isEnableIf())))))))
          .bind("ctor");
  Finder->addMatcher(findOverload, this);
}
예제 #5
0
TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorDefault) {
  auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
                                         "struct X { X() = default; };",
                                         Lang_CXX11,
                                         cxxConstructorDecl(hasName("X")));
  EXPECT_FALSE(testStructuralMatch(t));
}
void UseEqualsDeleteCheck::registerMatchers(MatchFinder *Finder) {
  auto PrivateSpecialFn = cxxMethodDecl(
      isPrivate(),
      anyOf(cxxConstructorDecl(anyOf(isDefaultConstructor(),
                                     isCopyConstructor(), isMoveConstructor())),
            cxxMethodDecl(
                anyOf(isCopyAssignmentOperator(), isMoveAssignmentOperator())),
            cxxDestructorDecl()));

  Finder->addMatcher(
      cxxMethodDecl(
          PrivateSpecialFn,
          unless(anyOf(hasBody(stmt()), isDefaulted(), isDeleted(),
                       ast_matchers::isTemplateInstantiation(),
                       // Ensure that all methods except private special member
                       // functions are defined.
                       hasParent(cxxRecordDecl(hasMethod(unless(
                           anyOf(PrivateSpecialFn, hasBody(stmt()), isPure(),
                                 isDefaulted(), isDeleted()))))))))
          .bind(SpecialFunction),
      this);

  Finder->addMatcher(
      cxxMethodDecl(isDeleted(), unless(isPublic())).bind(DeletedNotPublic),
      this);
}
void ExplicitConstructorCheck::registerMatchers(MatchFinder *Finder) {
  // Only register the matchers for C++; the functionality currently does not
  // provide any benefit to other languages, despite being benign.
  if (getLangOpts().CPlusPlus)
    Finder->addMatcher(
        cxxConstructorDecl(unless(isInstantiated())).bind("ctor"), this);
}
예제 #8
0
void ExplicitImplicitChecker::registerMatchers(MatchFinder* AstMatcher) {
  AstMatcher->addMatcher(cxxConstructorDecl(isInterestingImplicitCtor(),
                                            ofClass(allOf(isConcreteClass(),
                                                          decl().bind("class"))),
                                            unless(isMarkedImplicit()))
                            .bind("ctor"),
                        this);
}
void MoveConstructorInitCheck::registerMatchers(MatchFinder *Finder) {
  // Only register the matchers for C++11; the functionality currently does not
  // provide any benefit to other languages, despite being benign.
  if (!getLangOpts().CPlusPlus11)
    return;

  Finder->addMatcher(
      cxxConstructorDecl(
          unless(isImplicit()),
          allOf(isMoveConstructor(),
                hasAnyConstructorInitializer(
                    cxxCtorInitializer(
                        withInitializer(cxxConstructExpr(hasDeclaration(
                            cxxConstructorDecl(isCopyConstructor())
                                .bind("ctor")))))
                        .bind("move-init")))),
      this);

  auto NonConstValueMovableAndExpensiveToCopy =
      qualType(allOf(unless(pointerType()), unless(isConstQualified()),
                     hasDeclaration(cxxRecordDecl(hasMethod(cxxConstructorDecl(
                         isMoveConstructor(), unless(isDeleted()))))),
                     matchers::isExpensiveToCopy()));

  // This checker is also used to implement cert-oop11-cpp, but when using that
  // form of the checker, we do not want to diagnose movable parameters.
  if (!UseCERTSemantics) {
    Finder->addMatcher(
        cxxConstructorDecl(
            allOf(
                unless(isMoveConstructor()),
                hasAnyConstructorInitializer(withInitializer(cxxConstructExpr(
                    hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
                    hasArgument(
                        0,
                        declRefExpr(
                            to(parmVarDecl(
                                   hasType(
                                       NonConstValueMovableAndExpensiveToCopy))
                                   .bind("movable-param")))
                            .bind("init-arg")))))))
            .bind("ctor-decl"),
        this);
  }
}
void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) {
  auto Construct =
      cxxConstructExpr(
          hasDeclaration(cxxConstructorDecl(hasParent(
              cxxRecordDecl(unless(isTriviallyDefaultConstructible()))))))
          .bind("construct");

  Finder->addMatcher(
      cxxConstructorDecl(
          unless(isDelegatingConstructor()),
          ofClass(unless(
              anyOf(isUnion(), ast_matchers::isTemplateInstantiation()))),
          forEachConstructorInitializer(
              cxxCtorInitializer(isWritten(),
                                 withInitializer(ignoringImplicit(Construct)),
                                 unless(forField(hasType(isConstQualified()))))
                  .bind("init"))),
      this);
}
void SpecialMemberFunctionsCheck::registerMatchers(MatchFinder *Finder) {
  if (!getLangOpts().CPlusPlus)
    return;
  Finder->addMatcher(
      cxxRecordDecl(
          eachOf(
              has(cxxDestructorDecl(unless(isImplicit())).bind("dtor")),
              has(cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))
                      .bind("copy-ctor")),
              has(cxxMethodDecl(isCopyAssignmentOperator(),
                                unless(isImplicit()))
                      .bind("copy-assign")),
              has(cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))
                      .bind("move-ctor")),
              has(cxxMethodDecl(isMoveAssignmentOperator(),
                                unless(isImplicit()))
                      .bind("move-assign"))))
          .bind("class-def"),
      this);
}
void ThrownExceptionTypeCheck::registerMatchers(MatchFinder *Finder) {
  if (!getLangOpts().CPlusPlus)
    return;

  Finder->addMatcher(
      cxxThrowExpr(has(ignoringParenImpCasts(
          cxxConstructExpr(hasDeclaration(cxxConstructorDecl(
                               isCopyConstructor(), unless(isNoThrow()))))
              .bind("expr")))),
      this);
}
void VirtualNearMissCheck::registerMatchers(MatchFinder *Finder) {
  if (!getLangOpts().CPlusPlus)
    return;

  Finder->addMatcher(
      cxxMethodDecl(
          unless(anyOf(isOverride(), isImplicit(), cxxConstructorDecl(),
                       cxxDestructorDecl(), cxxConversionDecl(), isStatic(),
                       isOverloadedOperator())))
          .bind("method"),
      this);
}
void NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) {
  // Only register the matchers for C++11; the functionality currently does not
  // provide any benefit to other languages, despite being benign.
  if (!getLangOpts().CPlusPlus11)
    return;

  Finder->addMatcher(
      cxxMethodDecl(anyOf(cxxConstructorDecl(), hasOverloadedOperatorName("=")),
                    unless(isImplicit()), unless(isDeleted()))
          .bind("decl"),
      this);
}
void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) {
  if (!getLangOpts().CPlusPlus11)
    return;

  // FIXME: Bunch of functionality that could be easily added:
  // + add handling of `push_front` for std::forward_list, std::list
  // and std::deque.
  // + add handling of `push` for std::stack, std::queue, std::priority_queue
  // + add handling of `insert` for stl associative container, but be careful
  // because this requires special treatment (it could cause performance
  // regression)
  // + match for emplace calls that should be replaced with insertion
  // + match for make_pair calls.
  auto callPushBack = cxxMemberCallExpr(
      hasDeclaration(functionDecl(hasName("push_back"))),
      on(hasType(cxxRecordDecl(hasAnyName("std::vector", "llvm::SmallVector",
                                          "std::list", "std::deque")))));

  // We can't replace push_backs of smart pointer because
  // if emplacement fails (f.e. bad_alloc in vector) we will have leak of
  // passed pointer because smart pointer won't be constructed
  // (and destructed) as in push_back case.
  auto isCtorOfSmartPtr = hasDeclaration(cxxConstructorDecl(
      ofClass(hasAnyName("std::shared_ptr", "std::unique_ptr", "std::auto_ptr",
                         "std::weak_ptr"))));

  // Bitfields binds only to consts and emplace_back take it by universal ref.
  auto bitFieldAsArgument = hasAnyArgument(ignoringParenImpCasts(
      memberExpr(hasDeclaration(fieldDecl(matchers::isBitfield())))));

  // We could have leak of resource.
  auto newExprAsArgument = hasAnyArgument(ignoringParenImpCasts(cxxNewExpr()));
  auto constructingDerived =
      hasParent(implicitCastExpr(hasCastKind(CastKind::CK_DerivedToBase)));

  auto hasInitList = has(ignoringParenImpCasts(initListExpr()));
  auto soughtConstructExpr =
      cxxConstructExpr(
          unless(anyOf(isCtorOfSmartPtr, hasInitList, bitFieldAsArgument,
                       newExprAsArgument, constructingDerived,
                       has(materializeTemporaryExpr(hasInitList)))))
          .bind("ctor");
  auto hasConstructExpr = has(ignoringParenImpCasts(soughtConstructExpr));

  auto ctorAsArgument = materializeTemporaryExpr(
      anyOf(hasConstructExpr, has(cxxFunctionalCastExpr(hasConstructExpr))));

  Finder->addMatcher(
      cxxMemberCallExpr(callPushBack, has(ctorAsArgument)).bind("call"), this);
}
void UndelegatedConstructorCheck::registerMatchers(MatchFinder *Finder) {
  // We look for calls to constructors of the same type in constructors. To do
  // this we have to look through a variety of nodes that occur in the path,
  // depending on the type's destructor and the number of arguments on the
  // constructor call, this is handled by ignoringTemporaryExpr. Ignore template
  // instantiations to reduce the number of duplicated warnings.
  //
  // Only register the matchers for C++11; the functionality currently does not
  // provide any benefit to other languages, despite being benign.
  if (!getLangOpts().CPlusPlus11)
    return;

  Finder->addMatcher(
      compoundStmt(
          hasParent(
              cxxConstructorDecl(ofClass(cxxRecordDecl().bind("parent")))),
          forEach(ignoringTemporaryExpr(
              cxxConstructExpr(hasDeclaration(cxxConstructorDecl(ofClass(
                                   cxxRecordDecl(baseOfBoundNode("parent"))))))
                  .bind("construct"))),
          unless(isInTemplateInstantiation())),
      this);
}
void ExceptionEscapeCheck::registerMatchers(MatchFinder *Finder) {
  if (!getLangOpts().CPlusPlus || !getLangOpts().CXXExceptions)
    return;

  Finder->addMatcher(
      functionDecl(anyOf(isNoThrow(), cxxDestructorDecl(),
                         cxxConstructorDecl(isMoveConstructor()),
                         cxxMethodDecl(isMoveAssignmentOperator()),
                         hasName("main"), hasName("swap"),
                         isEnabled(FunctionsThatShouldNotThrow)),
                   throws(unless(isIgnored(IgnoredExceptions))))
          .bind("thrower"),
      this);
}
void ExplicitConstructorCheck::registerMatchers(MatchFinder *Finder) {
  // Only register the matchers for C++; the functionality currently does not
  // provide any benefit to other languages, despite being benign.
  if (!getLangOpts().CPlusPlus)
    return;
  Finder->addMatcher(
      cxxConstructorDecl(unless(anyOf(isImplicit(), // Compiler-generated.
                                      isDeleted(), isInstantiated())))
          .bind("ctor"),
      this);
  Finder->addMatcher(
      cxxConversionDecl(unless(anyOf(isExplicit(), // Already marked explicit.
                                     isImplicit(), // Compiler-generated.
                                     isDeleted(), isInstantiated())))

          .bind("conversion"),
      this);
}
void StaticObjectExceptionCheck::registerMatchers(MatchFinder *Finder) {
  if ((!getLangOpts().CPlusPlus) || (!getLangOpts().CXXExceptions))
    return;

  // Match any static or thread_local variable declaration that has an
  // initializer that can throw.
  Finder->addMatcher(
      varDecl(anyOf(hasThreadStorageDuration(), hasStaticStorageDuration()),
              unless(anyOf(isConstexpr(), hasType(cxxRecordDecl(isLambda())),
                           hasAncestor(functionDecl()))),
              anyOf(hasDescendant(cxxConstructExpr(hasDeclaration(
                        cxxConstructorDecl(unless(isNoThrow())).bind("func")))),
                    hasDescendant(cxxNewExpr(hasDeclaration(
                        functionDecl(unless(isNoThrow())).bind("func")))),
                    hasDescendant(callExpr(hasDeclaration(
                        functionDecl(unless(isNoThrow())).bind("func"))))))
          .bind("var"),
      this);
}
void NonConstParameterCheck::registerMatchers(MatchFinder *Finder) {
  // Add parameters to Parameters.
  Finder->addMatcher(parmVarDecl(unless(isInstantiated())).bind("Parm"), this);

  // C++ constructor.
  Finder->addMatcher(cxxConstructorDecl().bind("Ctor"), this);

  // Track unused parameters, there is Wunused-parameter about unused
  // parameters.
  Finder->addMatcher(declRefExpr().bind("Ref"), this);

  // Analyse parameter usage in function.
  Finder->addMatcher(stmt(anyOf(unaryOperator(anyOf(hasOperatorName("++"),
                                                    hasOperatorName("--"))),
                                binaryOperator(), callExpr(), returnStmt(),
                                cxxConstructExpr()))
                         .bind("Mark"),
                     this);
  Finder->addMatcher(varDecl(hasInitializer(anything())).bind("Mark"), this);
}
void StaticallyConstructedObjectsCheck::registerMatchers(MatchFinder *Finder) {
  // Constructing global, non-trivial objects with static storage is
  // disallowed, unless the object is statically initialized with a constexpr 
  // constructor or has no explicit constructor.

  // Constexpr requires C++11 or later.
  if (!getLangOpts().CPlusPlus11)
    return;

  Finder->addMatcher(varDecl(
                         // Match global, statically stored objects...
                         isGlobalStatic(),
                         // ... that have C++ constructors...
                         hasDescendant(cxxConstructExpr(unless(allOf(
                             // ... unless it is constexpr ...
                             hasDeclaration(cxxConstructorDecl(isConstexpr())),
                             // ... and is statically initialized.
                             isConstantInitializer())))))
                         .bind("decl"),
                     this);
}
void ReturnBracedInitListCheck::registerMatchers(MatchFinder *Finder) {
  // Only register the matchers for C++.
  if (!getLangOpts().CPlusPlus11)
    return;

  // Skip list initialization and constructors with an initializer list.
  auto ConstructExpr =
      cxxConstructExpr(
          unless(anyOf(hasDeclaration(cxxConstructorDecl(isExplicit())),
                       isListInitialization(), hasDescendant(initListExpr()),
                       isInTemplateInstantiation())))
          .bind("ctor");

  auto CtorAsArgument = materializeTemporaryExpr(anyOf(
      has(ConstructExpr), has(cxxFunctionalCastExpr(has(ConstructExpr)))));

  Finder->addMatcher(
      functionDecl(isDefinition(), // Declarations don't have return statements.
                   returns(unless(anyOf(builtinType(), autoType()))),
                   hasDescendant(returnStmt(hasReturnValue(
                       has(cxxConstructExpr(has(CtorAsArgument)))))))
          .bind("fn"),
      this);
}
예제 #23
0
void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) {
  if (!getLangOpts().CPlusPlus11)
    return;

  // FIXME: Bunch of functionality that could be easily added:
  // + add handling of `push_front` for std::forward_list, std::list
  // and std::deque.
  // + add handling of `push` for std::stack, std::queue, std::priority_queue
  // + add handling of `insert` for stl associative container, but be careful
  // because this requires special treatment (it could cause performance
  // regression)
  // + match for emplace calls that should be replaced with insertion
  // + match for make_pair calls.
  auto callPushBack = cxxMemberCallExpr(
      hasDeclaration(functionDecl(hasName("push_back"))),
      on(hasType(cxxRecordDecl(hasAnyName(SmallVector<StringRef, 5>(
          ContainersWithPushBack.begin(), ContainersWithPushBack.end()))))));

  // We can't replace push_backs of smart pointer because
  // if emplacement fails (f.e. bad_alloc in vector) we will have leak of
  // passed pointer because smart pointer won't be constructed
  // (and destructed) as in push_back case.
  auto isCtorOfSmartPtr = hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(
      SmallVector<StringRef, 5>(SmartPointers.begin(), SmartPointers.end())))));

  // Bitfields binds only to consts and emplace_back take it by universal ref.
  auto bitFieldAsArgument = hasAnyArgument(
      ignoringImplicit(memberExpr(hasDeclaration(fieldDecl(isBitField())))));

  // Initializer list can't be passed to universal reference.
  auto initializerListAsArgument = hasAnyArgument(
      ignoringImplicit(cxxConstructExpr(isListInitialization())));

  // We could have leak of resource.
  auto newExprAsArgument = hasAnyArgument(ignoringImplicit(cxxNewExpr()));
  // We would call another constructor.
  auto constructingDerived =
      hasParent(implicitCastExpr(hasCastKind(CastKind::CK_DerivedToBase)));

  // emplace_back can't access private constructor.
  auto isPrivateCtor = hasDeclaration(cxxConstructorDecl(isPrivate()));

  auto hasInitList = has(ignoringImplicit(initListExpr()));
  // FIXME: Discard 0/NULL (as nullptr), static inline const data members,
  // overloaded functions and template names.
  auto soughtConstructExpr =
      cxxConstructExpr(
          unless(anyOf(isCtorOfSmartPtr, hasInitList, bitFieldAsArgument,
                       initializerListAsArgument, newExprAsArgument,
                       constructingDerived, isPrivateCtor)))
          .bind("ctor");
  auto hasConstructExpr = has(ignoringImplicit(soughtConstructExpr));

  auto ctorAsArgument = materializeTemporaryExpr(
      anyOf(hasConstructExpr, has(cxxFunctionalCastExpr(hasConstructExpr))));

  Finder->addMatcher(cxxMemberCallExpr(callPushBack, has(ctorAsArgument),
                                       unless(isInTemplateInstantiation()))
                         .bind("call"),
                     this);
}
예제 #24
0
TEST_F(StructuralEquivalenceCXXMethodTest, Constructor) {
  auto t = makeDecls<FunctionDecl>(
      "void foo();", "struct foo { foo(); };", Lang_CXX,
      functionDecl(hasName("foo")), cxxConstructorDecl(hasName("foo")));
  EXPECT_FALSE(testStructuralMatch(t));
}