build/clang-plugin/NaNExprChecker.cpp
author Nathan Froyd <froydnj@mozilla.com>
Wed, 03 Apr 2019 00:06:04 +0000
changeset 467750 1b9e5f4b0589a636233affb84666a469a4cc4ef5
parent 444396 538a16d495142178a73e0bdc30f100b43d2fd62b
permissions -rw-r--r--
Bug 1537643 - update cc crate; r=glandium This update from the official sources brings in the changes that we were using glandium's fork for, as well as changes enabling us to tweak more settings on Windows. Differential Revision: https://phabricator.services.mozilla.com/D25888

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "NaNExprChecker.h"
#include "CustomMatchers.h"

void NaNExprChecker::registerMatchers(MatchFinder *AstMatcher) {
  AstMatcher->addMatcher(
      binaryOperator(
          allOf(binaryEqualityOperator(),
                hasLHS(hasIgnoringParenImpCasts(
                    declRefExpr(hasType(qualType((isFloat())))).bind("lhs"))),
                hasRHS(hasIgnoringParenImpCasts(
                    declRefExpr(hasType(qualType((isFloat())))).bind("rhs"))),
                unless(anyOf(isInSystemHeader(), isInWhitelistForNaNExpr()))))
          .bind("node"),
      this);
}

void NaNExprChecker::check(const MatchFinder::MatchResult &Result) {
  if (!Result.Context->getLangOpts().CPlusPlus) {
    // mozilla::IsNaN is not usable in C, so there is no point in issuing these
    // warnings.
    return;
  }

  const BinaryOperator *Expression =
      Result.Nodes.getNodeAs<BinaryOperator>("node");
  const DeclRefExpr *LHS = Result.Nodes.getNodeAs<DeclRefExpr>("lhs");
  const DeclRefExpr *RHS = Result.Nodes.getNodeAs<DeclRefExpr>("rhs");
  const ImplicitCastExpr *LHSExpr =
      dyn_cast<ImplicitCastExpr>(Expression->getLHS());
  const ImplicitCastExpr *RHSExpr =
      dyn_cast<ImplicitCastExpr>(Expression->getRHS());
  // The AST subtree that we are looking for will look like this:
  // -BinaryOperator ==/!=
  //  |-ImplicitCastExpr LValueToRValue
  //  | |-DeclRefExpr
  //  |-ImplicitCastExpr LValueToRValue
  //    |-DeclRefExpr
  // The check below ensures that we are dealing with the correct AST subtree
  // shape, and
  // also that both of the found DeclRefExpr's point to the same declaration.
  if (LHS->getFoundDecl() == RHS->getFoundDecl() && LHSExpr && RHSExpr &&
      std::distance(LHSExpr->child_begin(), LHSExpr->child_end()) == 1 &&
      std::distance(RHSExpr->child_begin(), RHSExpr->child_end()) == 1 &&
      *LHSExpr->child_begin() == LHS && *RHSExpr->child_begin() == RHS) {
    diag(Expression->getBeginLoc(),
         "comparing a floating point value to itself for "
         "NaN checking can lead to incorrect results",
         DiagnosticIDs::Error);
    diag(Expression->getBeginLoc(), "consider using mozilla::IsNaN instead",
         DiagnosticIDs::Note);
  }
}