build/clang-plugin/MustUseChecker.cpp
author Dustin J. Mitchell <dustin@mozilla.com>
Mon, 02 Oct 2017 18:22:56 +0000
changeset 399728 0f0395687d36597098e4248457ed69f092c39f8f
parent 387474 88c9b8587db69f36601f45e6584ac2d1c5e459b5
child 437021 e3118f787e336e908dd7a8f42d71211cb8738bfe
permissions -rw-r--r--
Bug 1403519 - only build docs when necessary r=gps This marks **/docs/** as exclusively docs, and code that is autodoc'd as inclusively docs. That means that a change that purely modifies documentation files will *only* run `docs` tasks, while a change that modifies autodoc'd source code will *additionaly* run `docs` tasks. The tasks do not run by default. MozReview-Commit-ID: G9tOK0AwtrI

/* 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 "MustUseChecker.h"
#include "CustomMatchers.h"
#include "CustomTypeAnnotation.h"

CustomTypeAnnotation MustUse =
    CustomTypeAnnotation("moz_must_use_type", "must-use");

void MustUseChecker::registerMatchers(MatchFinder *AstMatcher) {
  AstMatcher->addMatcher(switchCase().bind("switchcase"), this);
  AstMatcher->addMatcher(compoundStmt().bind("compound"), this);
  AstMatcher->addMatcher(ifStmt().bind("if"), this);
  AstMatcher->addMatcher(whileStmt().bind("while"), this);
  AstMatcher->addMatcher(doStmt().bind("do"), this);
  AstMatcher->addMatcher(forStmt().bind("for"), this);
  AstMatcher->addMatcher(binaryOperator(binaryCommaOperator()).bind("bin"),
                         this);
}

void MustUseChecker::check(const MatchFinder::MatchResult &Result) {
  if (auto SC = Result.Nodes.getNodeAs<SwitchCase>("switchcase")) {
    handleUnusedExprResult(SC->getSubStmt());
  }
  if (auto C = Result.Nodes.getNodeAs<CompoundStmt>("compound")) {
    for (const auto &S : C->body()) {
      handleUnusedExprResult(S);
    }
  }
  if (auto IF = Result.Nodes.getNodeAs<IfStmt>("if")) {
    handleUnusedExprResult(IF->getThen());
    handleUnusedExprResult(IF->getElse());
  }
  if (auto W = Result.Nodes.getNodeAs<WhileStmt>("while")) {
    handleUnusedExprResult(W->getBody());
  }
  if (auto D = Result.Nodes.getNodeAs<DoStmt>("do")) {
    handleUnusedExprResult(D->getBody());
  }
  if (auto F = Result.Nodes.getNodeAs<ForStmt>("for")) {
    handleUnusedExprResult(F->getBody());
    handleUnusedExprResult(F->getInit());
    handleUnusedExprResult(F->getInc());
  }
  if (auto C = Result.Nodes.getNodeAs<BinaryOperator>("bin")) {
    handleUnusedExprResult(C->getLHS());
  }
}

void MustUseChecker::handleUnusedExprResult(const Stmt *Statement) {
  const Expr *E = dyn_cast_or_null<Expr>(Statement);
  if (E) {
    E = E->IgnoreImplicit(); // Ignore ExprWithCleanup etc. implicit wrappers
    QualType T = E->getType();
    if (MustUse.hasEffectiveAnnotation(T) && !isIgnoredExprForMustUse(E)) {
      diag(E->getLocStart(), "Unused value of must-use type %0",
           DiagnosticIDs::Error)
          << T;
      MustUse.dumpAnnotationReason(*this, T, E->getLocStart());
    }
  }
}