1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 #include "MustUseChecker.h"
6 #include "CustomMatchers.h"
7 #include "CustomTypeAnnotation.h"
8 
9 CustomTypeAnnotation MustUse =
10     CustomTypeAnnotation(moz_must_use_type, "must-use");
11 
registerMatchers(MatchFinder * AstMatcher)12 void MustUseChecker::registerMatchers(MatchFinder *AstMatcher) {
13   AstMatcher->addMatcher(switchCase().bind("switchcase"), this);
14   AstMatcher->addMatcher(compoundStmt().bind("compound"), this);
15   AstMatcher->addMatcher(ifStmt().bind("if"), this);
16   AstMatcher->addMatcher(whileStmt().bind("while"), this);
17   AstMatcher->addMatcher(doStmt().bind("do"), this);
18   AstMatcher->addMatcher(forStmt().bind("for"), this);
19   AstMatcher->addMatcher(binaryOperator(binaryCommaOperator()).bind("bin"),
20                          this);
21 }
22 
check(const MatchFinder::MatchResult & Result)23 void MustUseChecker::check(const MatchFinder::MatchResult &Result) {
24   if (auto SC = Result.Nodes.getNodeAs<SwitchCase>("switchcase")) {
25     handleUnusedExprResult(SC->getSubStmt());
26   }
27   if (auto C = Result.Nodes.getNodeAs<CompoundStmt>("compound")) {
28     for (const auto &S : C->body()) {
29       handleUnusedExprResult(S);
30     }
31   }
32   if (auto IF = Result.Nodes.getNodeAs<IfStmt>("if")) {
33     handleUnusedExprResult(IF->getThen());
34     handleUnusedExprResult(IF->getElse());
35   }
36   if (auto W = Result.Nodes.getNodeAs<WhileStmt>("while")) {
37     handleUnusedExprResult(W->getBody());
38   }
39   if (auto D = Result.Nodes.getNodeAs<DoStmt>("do")) {
40     handleUnusedExprResult(D->getBody());
41   }
42   if (auto F = Result.Nodes.getNodeAs<ForStmt>("for")) {
43     handleUnusedExprResult(F->getBody());
44     handleUnusedExprResult(F->getInit());
45     handleUnusedExprResult(F->getInc());
46   }
47   if (auto C = Result.Nodes.getNodeAs<BinaryOperator>("bin")) {
48     handleUnusedExprResult(C->getLHS());
49   }
50 }
51 
handleUnusedExprResult(const Stmt * Statement)52 void MustUseChecker::handleUnusedExprResult(const Stmt *Statement) {
53   const Expr *E = dyn_cast_or_null<Expr>(Statement);
54   if (E) {
55     E = E->IgnoreImplicit(); // Ignore ExprWithCleanup etc. implicit wrappers
56     QualType T = E->getType();
57     if (MustUse.hasEffectiveAnnotation(T) && !isIgnoredExprForMustUse(E)) {
58       diag(E->getBeginLoc(), "Unused value of must-use type %0",
59            DiagnosticIDs::Error)
60           << T;
61       MustUse.dumpAnnotationReason(*this, T, E->getBeginLoc());
62     }
63   }
64 }
65