コード例 #1
5
void InaccurateEraseCheck::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;

  const auto EndCall =
      callExpr(
          callee(functionDecl(hasAnyName("remove", "remove_if", "unique"))),
          hasArgument(
              1,
              anyOf(cxxConstructExpr(has(ignoringImplicit(
                        cxxMemberCallExpr(callee(cxxMethodDecl(hasName("end"))))
                            .bind("end")))),
                    anything())))
          .bind("alg");

  const auto DeclInStd = type(hasUnqualifiedDesugaredType(
      tagType(hasDeclaration(decl(isInStdNamespace())))));
  Finder->addMatcher(
      cxxMemberCallExpr(
          on(anyOf(hasType(DeclInStd), hasType(pointsTo(DeclInStd)))),
          callee(cxxMethodDecl(hasName("erase"))), argumentCountIs(1),
          hasArgument(0, has(ignoringImplicit(
                             anyOf(EndCall, has(ignoringImplicit(EndCall)))))),
          unless(isInTemplateInstantiation()))
          .bind("erase"),
      this);
}
コード例 #2
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("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);
}
コード例 #3
0
void UseNodiscardCheck::registerMatchers(MatchFinder *Finder) {
  // If we use ``[[nodiscard]]`` attribute, we require at least C++17. Use a
  // macro or ``__attribute__`` with pre c++17 compilers by using
  // ReplacementString option.
  if ((NoDiscardMacro == "[[nodiscard]]" && !getLangOpts().CPlusPlus17) ||
      !getLangOpts().CPlusPlus)
    return;

  auto FunctionObj =
      cxxRecordDecl(hasAnyName("::std::function", "::boost::function"));

  // Find all non-void const methods which have not already been marked to
  // warn on unused result.
  Finder->addMatcher(
      cxxMethodDecl(
          allOf(isConst(), isDefinitionOrInline(),
                unless(anyOf(
                    returns(voidType()), isNoReturn(), isOverloadedOperator(),
                    isVariadic(), hasTemplateReturnType(),
                    hasClassMutableFields(), isConversionOperator(),
                    hasAttr(clang::attr::WarnUnusedResult),
                    hasType(isInstantiationDependentType()),
                    hasAnyParameter(anyOf(
                        parmVarDecl(anyOf(hasType(FunctionObj),
                                          hasType(references(FunctionObj)))),
                        hasType(isNonConstReferenceOrPointer()),
                        hasParameterPack()))))))
          .bind("no_discard"),
      this);
}
コード例 #4
0
void AvoidSpinlockCheck::registerMatchers(MatchFinder *Finder) {
  Finder->addMatcher(
      callExpr(callee((functionDecl(hasAnyName(
                   "OSSpinlockLock", "OSSpinlockUnlock", "OSSpinlockTry")))))
          .bind("spinlock"),
      this);
}
コード例 #5
0
void ProperlySeededRandomGeneratorCheck::registerMatchers(MatchFinder *Finder) {
  auto RandomGeneratorEngineDecl = cxxRecordDecl(hasAnyName(
      "::std::linear_congruential_engine", "::std::mersenne_twister_engine",
      "::std::subtract_with_carry_engine", "::std::discard_block_engine",
      "::std::independent_bits_engine", "::std::shuffle_order_engine"));
  auto RandomGeneratorEngineTypeMatcher = hasType(hasUnqualifiedDesugaredType(
      recordType(hasDeclaration(RandomGeneratorEngineDecl))));

  // std::mt19937 engine;
  // engine.seed();
  //        ^
  // engine.seed(1);
  //        ^
  // const int x = 1;
  // engine.seed(x);
  //        ^
  Finder->addMatcher(
      cxxMemberCallExpr(
          has(memberExpr(has(declRefExpr(RandomGeneratorEngineTypeMatcher)),
                         member(hasName("seed")),
                         unless(hasDescendant(cxxThisExpr())))))
          .bind("seed"),
      this);

  // std::mt19937 engine;
  //              ^
  // std::mt19937 engine(1);
  //              ^
  // const int x = 1;
  // std::mt19937 engine(x);
  //              ^
  Finder->addMatcher(
      cxxConstructExpr(RandomGeneratorEngineTypeMatcher).bind("ctor"), this);

  // srand();
  // ^
  // const int x = 1;
  // srand(x);
  // ^
  Finder->addMatcher(
      callExpr(callee(functionDecl(hasAnyName("::srand", "::std::srand"))))
          .bind("srand"),
      this);
}
コード例 #6
0
void FoldInitTypeCheck::registerMatchers(MatchFinder *Finder) {
  // We match functions of interest and bind the iterator and init value types.
  // Note: Right now we check only builtin types.
  const auto BuiltinTypeWithId = [](const char *ID) {
    return hasCanonicalType(builtinType().bind(ID));
  };
  const auto IteratorWithValueType = [&BuiltinTypeWithId](const char *ID) {
    return anyOf(
        // Pointer types.
        pointsTo(BuiltinTypeWithId(ID)),
        // Iterator types.
        recordType(hasDeclaration(has(typedefNameDecl(
            hasName("value_type"), hasType(BuiltinTypeWithId(ID)))))));
  };

  const auto IteratorParam = parmVarDecl(
      hasType(hasCanonicalType(IteratorWithValueType("IterValueType"))));
  const auto Iterator2Param = parmVarDecl(
      hasType(hasCanonicalType(IteratorWithValueType("Iter2ValueType"))));
  const auto InitParam = parmVarDecl(hasType(BuiltinTypeWithId("InitType")));

  // std::accumulate, std::reduce.
  Finder->addMatcher(
      callExpr(callee(functionDecl(
                   hasAnyName("::std::accumulate", "::std::reduce"),
                   hasParameter(0, IteratorParam), hasParameter(2, InitParam))),
               argumentCountIs(3))
          .bind("Call"),
      this);
  // std::inner_product.
  Finder->addMatcher(
      callExpr(callee(functionDecl(hasName("::std::inner_product"),
                                   hasParameter(0, IteratorParam),
                                   hasParameter(2, Iterator2Param),
                                   hasParameter(3, InitParam))),
               argumentCountIs(4))
          .bind("Call"),
      this);
  // std::reduce with a policy.
  Finder->addMatcher(
      callExpr(callee(functionDecl(hasName("::std::reduce"),
                                   hasParameter(1, IteratorParam),
                                   hasParameter(3, InitParam))),
               argumentCountIs(4))
          .bind("Call"),
      this);
  // std::inner_product with a policy.
  Finder->addMatcher(
      callExpr(callee(functionDecl(hasName("::std::inner_product"),
                                   hasParameter(1, IteratorParam),
                                   hasParameter(3, Iterator2Param),
                                   hasParameter(4, InitParam))),
               argumentCountIs(5))
          .bind("Call"),
      this);
}
コード例 #7
0
void DeprecatedIosBaseAliasesCheck::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;

  auto IoStateDecl = typedefDecl(hasAnyName(DeprecatedTypes)).bind("TypeDecl");
  auto IoStateType =
      qualType(hasDeclaration(IoStateDecl), unless(elaboratedType()));

  Finder->addMatcher(typeLoc(loc(IoStateType)).bind("TypeLoc"), this);
}
コード例 #8
0
void FasterStringFindCheck::registerMatchers(MatchFinder *Finder) {
  if (!getLangOpts().CPlusPlus)
    return;

  const auto SingleChar =
      expr(ignoringParenCasts(stringLiteral(hasSize(1)).bind("literal")));
  const auto StringFindFunctions =
      hasAnyName("find", "rfind", "find_first_of", "find_first_not_of",
                 "find_last_of", "find_last_not_of");

  Finder->addMatcher(
      cxxMemberCallExpr(
          callee(functionDecl(StringFindFunctions).bind("func")),
          anyOf(argumentCountIs(1), argumentCountIs(2)),
          hasArgument(0, SingleChar),
          on(expr(
              hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(
                  recordDecl(hasAnyName(SmallVector<StringRef, 4>(
                      StringLikeClasses.begin(), StringLikeClasses.end()))))))),
              unless(hasSubstitutedType())))),
      this);
}
コード例 #9
0
/// If `Node` is a call to the inverse of `Scale`, return that inverse's
/// argument, otherwise None.
static llvm::Optional<std::string>
rewriteInverseDurationCall(const MatchFinder::MatchResult &Result,
                           DurationScale Scale, const Expr &Node) {
  const std::pair<llvm::StringRef, llvm::StringRef> &InverseFunctions =
      getDurationInverseForScale(Scale);
  if (const auto *MaybeCallArg = selectFirst<const Expr>(
          "e",
          match(callExpr(callee(functionDecl(hasAnyName(
                             InverseFunctions.first, InverseFunctions.second))),
                         hasArgument(0, expr().bind("e"))),
                Node, *Result.Context))) {
    return tooling::fixit::getText(*MaybeCallArg, *Result.Context).str();
  }

  return llvm::None;
}
コード例 #10
0
void ForbiddenSubclassingCheck::registerMatchers(MatchFinder *Finder) {
  // this check should only be applied to ObjC sources.
  if (!getLangOpts().ObjC)
    return;

  Finder->addMatcher(
      objcInterfaceDecl(
          isSubclassOf(
              objcInterfaceDecl(
                  hasAnyName(
                      std::vector<StringRef>(
                          ForbiddenSuperClassNames.begin(),
                          ForbiddenSuperClassNames.end())))
              .bind("superclass")))
      .bind("subclass"),
      this);
}
コード例 #11
0
void SignedBitwiseCheck::registerMatchers(MatchFinder *Finder) {
  const auto SignedIntegerOperand =
      expr(ignoringImpCasts(hasType(isSignedInteger()))).bind("signed-operand");

  // The standard [bitmask.types] allows some integral types to be implemented
  // as signed types. Exclude these types from diagnosing for bitwise or(|) and
  // bitwise and(&). Shifting and complementing such values is still not
  // allowed.
  const auto BitmaskType = namedDecl(
      hasAnyName("::std::locale::category", "::std::ctype_base::mask",
                 "::std::ios_base::fmtflags", "::std::ios_base::iostate",
                 "::std::ios_base::openmode"));
  const auto IsStdBitmask = ignoringImpCasts(declRefExpr(hasType(BitmaskType)));

  // Match binary bitwise operations on signed integer arguments.
  Finder->addMatcher(
      binaryOperator(anyOf(hasOperatorName("^"), hasOperatorName("|"),
                           hasOperatorName("&"), hasOperatorName("^="),
                           hasOperatorName("|="), hasOperatorName("&=")),

                     unless(allOf(hasLHS(IsStdBitmask), hasRHS(IsStdBitmask))),

                     hasEitherOperand(SignedIntegerOperand),
                     hasLHS(hasType(isInteger())), hasRHS(hasType(isInteger())))
          .bind("binary-no-sign-interference"),
      this);

  // Shifting and complement is not allowed for any signed integer type because
  // the sign bit may corrupt the result.
  Finder->addMatcher(
      binaryOperator(anyOf(hasOperatorName("<<"), hasOperatorName(">>"),
                           hasOperatorName("<<="), hasOperatorName(">>=")),
                     hasEitherOperand(SignedIntegerOperand),
                     hasLHS(hasType(isInteger())), hasRHS(hasType(isInteger())))
          .bind("binary-sign-interference"),
      this);

  // Match unary operations on signed integer types.
  Finder->addMatcher(
      unaryOperator(hasOperatorName("~"), hasUnaryOperand(SignedIntegerOperand))
          .bind("unary-signed"),
      this);
}
コード例 #12
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);
}
コード例 #13
0
void UpgradeDurationConversionsCheck::registerMatchers(MatchFinder *Finder) {
  if (!getLangOpts().CPlusPlus)
    return;

  // For the arithmetic calls, we match only the uses of the templated operators
  // where the template parameter is not a built-in type. This means the
  // instantiation makes use of an available user defined conversion to
  // `int64_t`.
  //
  // The implementation of these templates will be updated to fail SFINAE for
  // non-integral types. We match them to suggest an explicit cast.

  // Match expressions like `a *= b` and `a /= b` where `a` has type
  // `absl::Duration` and `b` is not of a built-in type.
  Finder->addMatcher(
      cxxOperatorCallExpr(
          argumentCountIs(2),
          hasArgument(
              0, expr(hasType(cxxRecordDecl(hasName("::absl::Duration"))))),
          hasArgument(1, expr().bind("arg")),
          callee(functionDecl(
              hasParent(functionTemplateDecl()),
              unless(hasTemplateArgument(0, refersToType(builtinType()))),
              hasAnyName("operator*=", "operator/=")))),
      this);

  // Match expressions like `a.operator*=(b)` and `a.operator/=(b)` where `a`
  // has type `absl::Duration` and `b` is not of a built-in type.
  Finder->addMatcher(
      cxxMemberCallExpr(
          callee(cxxMethodDecl(
              ofClass(cxxRecordDecl(hasName("::absl::Duration"))),
              hasParent(functionTemplateDecl()),
              unless(hasTemplateArgument(0, refersToType(builtinType()))),
              hasAnyName("operator*=", "operator/="))),
          argumentCountIs(1), hasArgument(0, expr().bind("arg"))),
      this);

  // Match expressions like `a * b`, `a / b`, `operator*(a, b)`, and
  // `operator/(a, b)` where `a` has type `absl::Duration` and `b` is not of a
  // built-in type.
  Finder->addMatcher(
      callExpr(callee(functionDecl(
                   hasParent(functionTemplateDecl()),
                   unless(hasTemplateArgument(0, refersToType(builtinType()))),
                   hasAnyName("::absl::operator*", "::absl::operator/"))),
               argumentCountIs(2),
               hasArgument(0, expr(hasType(
                                  cxxRecordDecl(hasName("::absl::Duration"))))),
               hasArgument(1, expr().bind("arg"))),
      this);

  // Match expressions like `a * b` and `operator*(a, b)` where `a` is not of a
  // built-in type and `b` has type `absl::Duration`.
  Finder->addMatcher(
      callExpr(callee(functionDecl(
                   hasParent(functionTemplateDecl()),
                   unless(hasTemplateArgument(0, refersToType(builtinType()))),
                   hasName("::absl::operator*"))),
               argumentCountIs(2), hasArgument(0, expr().bind("arg")),
               hasArgument(1, expr(hasType(cxxRecordDecl(
                                  hasName("::absl::Duration")))))),
      this);

  // For the factory functions, we match only the non-templated overloads that
  // take an `int64_t` parameter. Within these calls, we care about implicit
  // casts through a user defined conversion to `int64_t`.
  //
  // The factory functions will be updated to be templated and SFINAE on whether
  // the template parameter is an integral type. This complements the already
  // existing templated overloads that only accept floating point types.

  // Match calls like:
  //   `absl::Nanoseconds(x)`
  //   `absl::Microseconds(x)`
  //   `absl::Milliseconds(x)`
  //   `absl::Seconds(x)`
  //   `absl::Minutes(x)`
  //   `absl::Hours(x)`
  // where `x` is not of a built-in type.
  Finder->addMatcher(
      implicitCastExpr(
          anyOf(hasCastKind(CK_UserDefinedConversion),
                has(implicitCastExpr(hasCastKind(CK_UserDefinedConversion)))),
          hasParent(callExpr(
              callee(functionDecl(DurationFactoryFunction(),
                  unless(hasParent(functionTemplateDecl())))),
              hasArgument(0, expr().bind("arg"))))),
      this);
}
コード例 #14
0
void SuspiciousStringCompareCheck::registerMatchers(MatchFinder *Finder) {
  // Match relational operators.
  const auto ComparisonUnaryOperator = unaryOperator(hasOperatorName("!"));
  const auto ComparisonBinaryOperator =
      binaryOperator(matchers::isComparisonOperator());
  const auto ComparisonOperator =
      expr(anyOf(ComparisonUnaryOperator, ComparisonBinaryOperator));

  // Add the list of known string compare-like functions and add user-defined
  // functions.
  std::vector<std::string> FunctionNames = utils::options::parseStringList(
      (llvm::Twine(KnownStringCompareFunctions) + StringCompareLikeFunctions)
          .str());

  // Match a call to a string compare functions.
  const auto FunctionCompareDecl =
      functionDecl(hasAnyName(std::vector<StringRef>(FunctionNames.begin(),
                                                     FunctionNames.end())))
          .bind("decl");
  const auto DirectStringCompareCallExpr =
      callExpr(hasDeclaration(FunctionCompareDecl)).bind("call");
  const auto MacroStringCompareCallExpr = conditionalOperator(anyOf(
      hasTrueExpression(ignoringParenImpCasts(DirectStringCompareCallExpr)),
      hasFalseExpression(ignoringParenImpCasts(DirectStringCompareCallExpr))));
  // The implicit cast is not present in C.
  const auto StringCompareCallExpr = ignoringParenImpCasts(
      anyOf(DirectStringCompareCallExpr, MacroStringCompareCallExpr));

  if (WarnOnImplicitComparison) {
    // Detect suspicious calls to string compare:
    //     'if (strcmp())'  ->  'if (strcmp() != 0)'
    Finder->addMatcher(
        stmt(anyOf(ifStmt(hasCondition(StringCompareCallExpr)),
                   whileStmt(hasCondition(StringCompareCallExpr)),
                   doStmt(hasCondition(StringCompareCallExpr)),
                   forStmt(hasCondition(StringCompareCallExpr)),
                   binaryOperator(
                       anyOf(hasOperatorName("&&"), hasOperatorName("||")),
                       hasEitherOperand(StringCompareCallExpr))))
            .bind("missing-comparison"),
        this);
  }

  if (WarnOnLogicalNotComparison) {
    // Detect suspicious calls to string compared with '!' operator:
    //     'if (!strcmp())'  ->  'if (strcmp() == 0)'
    Finder->addMatcher(unaryOperator(hasOperatorName("!"),
                                     hasUnaryOperand(ignoringParenImpCasts(
                                         StringCompareCallExpr)))
                           .bind("logical-not-comparison"),
                       this);
  }

  // Detect suspicious cast to an inconsistant type (i.e. not integer type).
  Finder->addMatcher(
      implicitCastExpr(unless(hasType(isInteger())),
                       hasSourceExpression(StringCompareCallExpr))
          .bind("invalid-conversion"),
      this);

  // Detect suspicious operator with string compare function as operand.
  Finder->addMatcher(
      binaryOperator(
          unless(anyOf(matchers::isComparisonOperator(), hasOperatorName("&&"),
                       hasOperatorName("||"), hasOperatorName("="))),
          hasEitherOperand(StringCompareCallExpr))
          .bind("suspicious-operator"),
      this);

  // Detect comparison to invalid constant: 'strcmp() == -1'.
  const auto InvalidLiteral = ignoringParenImpCasts(
      anyOf(integerLiteral(unless(equals(0))),
            unaryOperator(
                hasOperatorName("-"),
                has(ignoringParenImpCasts(integerLiteral(unless(equals(0)))))),
            characterLiteral(), cxxBoolLiteral()));

  Finder->addMatcher(binaryOperator(matchers::isComparisonOperator(),
                                    hasEitherOperand(StringCompareCallExpr),
                                    hasEitherOperand(InvalidLiteral))
                         .bind("invalid-comparison"),
                     this);
}