void DeleteNullPointerCheck::registerMatchers(MatchFinder *Finder) {
  const auto DeleteExpr =
      cxxDeleteExpr(has(castExpr(has(declRefExpr(
                        to(decl(equalsBoundNode("deletedPointer"))))))))
          .bind("deleteExpr");

  const auto DeleteMemberExpr =
      cxxDeleteExpr(has(castExpr(has(memberExpr(hasDeclaration(
                        fieldDecl(equalsBoundNode("deletedMemberPointer"))))))))
          .bind("deleteMemberExpr");

  const auto PointerExpr = ignoringImpCasts(anyOf(
      declRefExpr(to(decl().bind("deletedPointer"))),
      memberExpr(hasDeclaration(fieldDecl().bind("deletedMemberPointer")))));

  const auto PointerCondition = castExpr(hasCastKind(CK_PointerToBoolean),
                                         hasSourceExpression(PointerExpr));
  const auto BinaryPointerCheckCondition =
      binaryOperator(hasEitherOperand(castExpr(hasCastKind(CK_NullToPointer))),
                     hasEitherOperand(PointerExpr));

  Finder->addMatcher(
      ifStmt(hasCondition(anyOf(PointerCondition, BinaryPointerCheckCondition)),
             hasThen(anyOf(
                 DeleteExpr, DeleteMemberExpr,
                 compoundStmt(anyOf(has(DeleteExpr), has(DeleteMemberExpr)),
                              statementCountIs(1))
                     .bind("compound"))))
          .bind("ifWithDelete"),
      this);
}
void RedundantVoidArgCheck::registerMatchers(MatchFinder *Finder) {
  Finder->addMatcher(functionDecl(parameterCountIs(0), unless(isImplicit()),
                                  unless(isExternC()))
                         .bind(FunctionId),
                     this);
  Finder->addMatcher(typedefNameDecl().bind(TypedefId), this);
  auto ParenFunctionType = parenType(innerType(functionType()));
  auto PointerToFunctionType = pointee(ParenFunctionType);
  auto FunctionOrMemberPointer =
      anyOf(hasType(pointerType(PointerToFunctionType)),
            hasType(memberPointerType(PointerToFunctionType)));
  Finder->addMatcher(fieldDecl(FunctionOrMemberPointer).bind(FieldId), this);
  Finder->addMatcher(varDecl(FunctionOrMemberPointer).bind(VarId), this);
  auto CastDestinationIsFunction =
      hasDestinationType(pointsTo(ParenFunctionType));
  Finder->addMatcher(
      cStyleCastExpr(CastDestinationIsFunction).bind(CStyleCastId), this);
  Finder->addMatcher(
      cxxStaticCastExpr(CastDestinationIsFunction).bind(NamedCastId), this);
  Finder->addMatcher(
      cxxReinterpretCastExpr(CastDestinationIsFunction).bind(NamedCastId),
      this);
  Finder->addMatcher(
      cxxConstCastExpr(CastDestinationIsFunction).bind(NamedCastId), this);
  Finder->addMatcher(lambdaExpr().bind(LambdaId), this);
}
void MultiwayPathsCoveredCheck::registerMatchers(MatchFinder *Finder) {
  Finder->addMatcher(
      switchStmt(
          hasCondition(allOf(
              // Match on switch statements that have either a bit-field or
              // an integer condition. The ordering in 'anyOf()' is
              // important because the last condition is the most general.
              anyOf(ignoringImpCasts(memberExpr(hasDeclaration(
                        fieldDecl(isBitField()).bind("bitfield")))),
                    ignoringImpCasts(declRefExpr().bind("non-enum-condition"))),
              // 'unless()' must be the last match here and must be bound,
              // otherwise the matcher does not work correctly, because it
              // will not explicitly ignore enum conditions.
              unless(ignoringImpCasts(
                  declRefExpr(hasType(enumType())).bind("enum-condition"))))))
          .bind("switch"),
      this);

  // This option is noisy, therefore matching is configurable.
  if (WarnOnMissingElse) {
    Finder->addMatcher(
        ifStmt(allOf(hasParent(ifStmt()), unless(hasElse(anything()))))
            .bind("else-if"),
        this);
  }
}
Ejemplo n.º 4
0
TEST_F(StructuralEquivalenceRecordTest,
       UnnamedRecordsShouldBeInequivalentEvenIfTheSecondIsBeingDefined) {
  auto Code =
      R"(
      struct A {
        struct {
          struct A *next;
        } entry0;
        struct {
          struct A *next;
        } entry1;
      };
      )";
  auto t = makeTuDecls(Code, Code, Lang_C);

  auto *FromTU = get<0>(t);
  auto *Entry1 =
      FirstDeclMatcher<FieldDecl>().match(FromTU, fieldDecl(hasName("entry1")));

  auto *ToTU = get<1>(t);
  auto *Entry0 =
      FirstDeclMatcher<FieldDecl>().match(ToTU, fieldDecl(hasName("entry0")));
  auto *A =
      FirstDeclMatcher<RecordDecl>().match(ToTU, recordDecl(hasName("A")));
  A->startDefinition(); // Set isBeingDefined, getDefinition() will return a
                        // nullptr. This may be the case during ASTImport.

  auto *R0 = getRecordDecl(Entry0);
  auto *R1 = getRecordDecl(Entry1);

  ASSERT_NE(R0, R1);
  EXPECT_TRUE(testStructuralMatch(R0, R0));
  EXPECT_TRUE(testStructuralMatch(R1, R1));
  EXPECT_FALSE(testStructuralMatch(R0, R1));
}
void NonPrivateMemberVariablesInClassesCheck::registerMatchers(
    MatchFinder *Finder) {
  if (!getLangOpts().CPlusPlus)
    return;

  // We can ignore structs/classes with all member variables being public.
  auto ShouldIgnoreRecord =
      allOf(boolean(IgnoreClassesWithAllMemberVariablesBeingPublic),
            unless(hasNonPublicMemberVariable()));

  // There are three visibility types: public, protected, private.
  // If we are ok with public fields, then we only want to complain about
  // protected fields, else we want to complain about all non-private fields.
  // We can ignore public member variables in structs/classes, in unions.
  auto InterestingField = fieldDecl(
      IgnorePublicMemberVariables ? isProtected() : unless(isPrivate()));

  // We only want the records that not only contain the mutable data (non-static
  // member variables), but also have some logic (non-static member functions).
  // We may optionally ignore records where all the member variables are public.
  Finder->addMatcher(cxxRecordDecl(anyOf(isStruct(), isClass()), hasMethods(),
                                   hasNonStaticMethod(),
                                   unless(ShouldIgnoreRecord),
                                   forEach(InterestingField.bind("field")))
                         .bind("record"),
                     this);
}
void StringReferenceMemberCheck::registerMatchers(
    ast_matchers::MatchFinder *Finder) {
  // Look for const references to std::string or ::string.
  auto String = anyOf(recordDecl(hasName("::std::basic_string")),
                      recordDecl(hasName("::string")));
  auto ConstString = qualType(isConstQualified(), hasDeclaration(String));

  // Ignore members in template instantiations.
  Finder->addMatcher(fieldDecl(hasType(references(ConstString)),
                               unless(isInstantiated())).bind("member"),
                     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);
}
Ejemplo n.º 8
0
TEST_F(StructuralEquivalenceTest, WrongOrderOfFieldsInClass) {
  auto Code = "class X { int a; int b; };";
  auto Decls = makeNamedDecls(Code, Code, Lang_CXX, "X");

  CXXRecordDecl *RD = FirstDeclMatcher<CXXRecordDecl>().match(
      get<1>(Decls), cxxRecordDecl(hasName("X")));
  FieldDecl *FD =
      FirstDeclMatcher<FieldDecl>().match(get<1>(Decls), fieldDecl(hasName("a")));

  // Reorder the FieldDecls
  RD->removeDecl(FD);
  RD->addDeclInternal(FD);

  EXPECT_FALSE(testStructuralMatch(Decls));
}
Ejemplo n.º 9
0
TEST_F(StructuralEquivalenceRecordTest, Match) {
  auto Code = R"(
      struct A{ };
      struct B{ };
      struct foo: A, virtual B {
        void x();
        int a;
      };
      )";
  auto t = makeNamedDecls(Code, Code, Lang_CXX);
  EXPECT_TRUE(testStructuralMatch(t));
}

TEST_F(StructuralEquivalenceRecordTest, UnnamedRecordsShouldBeInequivalent) {
  auto t = makeTuDecls(
      R"(
      struct A {
        struct {
          struct A *next;
        } entry0;
        struct {
          struct A *next;
        } entry1;
      };
      )",
      "", Lang_C);
  auto *TU = get<0>(t);
  auto *Entry0 =
      FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry0")));
  auto *Entry1 =
      FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry1")));
  auto *R0 = getRecordDecl(Entry0);
  auto *R1 = getRecordDecl(Entry1);

  ASSERT_NE(R0, R1);
  EXPECT_TRUE(testStructuralMatch(R0, R0));
  EXPECT_TRUE(testStructuralMatch(R1, R1));
  EXPECT_FALSE(testStructuralMatch(R0, R1));
}
Ejemplo n.º 10
0
void NonCopyableObjectsCheck::registerMatchers(MatchFinder *Finder) {
  // There are two ways to get into trouble with objects like FILE *:
  // dereferencing the pointer type to be a non-pointer type, and declaring
  // the type as a non-pointer type in the first place. While the declaration
  // itself could technically be well-formed in the case where the type is not
  // an opaque type, it's highly suspicious behavior.
  //
  // POSIX types are a bit different in that it's reasonable to declare a
  // non-pointer variable or data member of the type, but it is not reasonable
  // to dereference a pointer to the type, or declare a parameter of non-pointer
  // type.
  auto BadFILEType = hasType(namedDecl(isFILEType()).bind("type_decl"));
  auto BadPOSIXType = hasType(namedDecl(isPOSIXType()).bind("type_decl"));
  auto BadEitherType = anyOf(BadFILEType, BadPOSIXType);

  Finder->addMatcher(
      namedDecl(anyOf(varDecl(BadFILEType), fieldDecl(BadFILEType)))
          .bind("decl"),
      this);
  Finder->addMatcher(parmVarDecl(BadPOSIXType).bind("decl"), this);
  Finder->addMatcher(
      expr(unaryOperator(hasOperatorName("*"), BadEitherType)).bind("expr"),
      this);
}
Ejemplo n.º 11
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);
}
namespace ProgrammingLanguage {

    //match sturct/union/class 
    DeclarationMatcher recordFieldDeclMatcherPL = recordDecl(has(fieldDecl())).bind("recordDecl");
}