Bug 1214037 - Don't consider the result of an assignment expression MOZ_MUST_USE, r=ehsan
authorMichael Layzell <michael@thelayzells.com>
Wed, 14 Oct 2015 14:14:28 -0400
changeset 267764 ab276d264008c60bfd20dcc5c13a4e3c48db41dd
parent 267763 35346de03a7388bc2c411c722ed3bff67c13c54e
child 267765 c110cb952c8e43b624520ba903277fab8861833d
push idunknown
push userunknown
push dateunknown
reviewersehsan
bugs1214037
milestone44.0a1
Bug 1214037 - Don't consider the result of an assignment expression MOZ_MUST_USE, r=ehsan
build/clang-plugin/clang-plugin.cpp
build/clang-plugin/tests/TestMustUse.cpp
--- a/build/clang-plugin/clang-plugin.cpp
+++ b/build/clang-plugin/clang-plugin.cpp
@@ -219,16 +219,43 @@ bool isIgnoredPathForImplicitConversion(
   }
   return false;
 }
 
 bool isInterestingDeclForImplicitConversion(const Decl *decl) {
   return !isInIgnoredNamespaceForImplicitConversion(decl) &&
          !isIgnoredPathForImplicitConversion(decl);
 }
+
+bool isIgnoredExprForMustUse(const Expr *E) {
+  if (const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(E)) {
+    switch (OpCall->getOperator()) {
+    case OO_Equal:
+    case OO_PlusEqual:
+    case OO_MinusEqual:
+    case OO_StarEqual:
+    case OO_SlashEqual:
+    case OO_PercentEqual:
+    case OO_CaretEqual:
+    case OO_AmpEqual:
+    case OO_PipeEqual:
+    case OO_LessLessEqual:
+    case OO_GreaterGreaterEqual:
+      return true;
+    default:
+      return false;
+    }
+  }
+
+  if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) {
+    return Op->isAssignmentOp();
+  }
+
+  return false;
+}
 }
 
 class CustomTypeAnnotation {
   enum ReasonKind {
     RK_None,
     RK_Direct,
     RK_ArrayElement,
     RK_BaseClass,
@@ -315,17 +342,17 @@ public:
 
     return false;
   }
 
   void HandleUnusedExprResult(const Stmt *stmt) {
     const Expr *E = dyn_cast_or_null<Expr>(stmt);
     if (E) {
       QualType T = E->getType();
-      if (MustUse.hasEffectiveAnnotation(T)) {
+      if (MustUse.hasEffectiveAnnotation(T) && !isIgnoredExprForMustUse(E)) {
         unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
             DiagnosticIDs::Error, "Unused value of must-use type %0");
 
         Diag.Report(E->getLocStart(), errorID) << T;
         MustUse.dumpAnnotationReason(Diag, T, E->getLocStart());
       }
     }
   }
--- a/build/clang-plugin/tests/TestMustUse.cpp
+++ b/build/clang-plugin/tests/TestMustUse.cpp
@@ -15,142 +15,163 @@ void use(MustUse*);
 void use(MustUse&);
 void use(MustUse&&);
 void use(MayUse*);
 void use(MayUse&);
 void use(MayUse&&);
 void use(bool);
 
 void foo() {
+  MustUse u;
+
   producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
   producesMustUsePointer();
   producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
   producesMayUse();
   producesMayUsePointer();
   producesMayUseRef();
+  u = producesMustUse();
   {
     producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMustUsePointer();
     producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMayUse();
     producesMayUsePointer();
     producesMayUseRef();
+    u = producesMustUse();
   }
   if (true) {
     producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMustUsePointer();
     producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMayUse();
     producesMayUsePointer();
     producesMayUseRef();
+    u = producesMustUse();
   } else {
     producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMustUsePointer();
     producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMayUse();
     producesMayUsePointer();
     producesMayUseRef();
+    u = producesMustUse();
   }
 
   if(true) producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
   else producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
   if(true) producesMustUsePointer();
   else producesMustUsePointer();
   if(true) producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
   else producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
   if(true) producesMayUse();
   else producesMayUse();
   if(true) producesMayUsePointer();
   else producesMayUsePointer();
   if(true) producesMayUseRef();
   else producesMayUseRef();
+  if(true) u = producesMustUse();
+  else u = producesMustUse();
 
   while (true) producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
   while (true) producesMustUsePointer();
   while (true) producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
   while (true) producesMayUse();
   while (true) producesMayUsePointer();
   while (true) producesMayUseRef();
+  while (true) u = producesMustUse();
 
   do producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
   while (true);
   do producesMustUsePointer();
   while (true);
   do producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
   while (true);
   do producesMayUse();
   while (true);
   do producesMayUsePointer();
   while (true);
   do producesMayUseRef();
   while (true);
+  do u = producesMustUse();
+  while (true);
 
   for (;;) producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
   for (;;) producesMustUsePointer();
   for (;;) producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
   for (;;) producesMayUse();
   for (;;) producesMayUsePointer();
   for (;;) producesMayUseRef();
+  for (;;) u = producesMustUse();
 
   for (producesMustUse();;); // expected-error {{Unused value of must-use type 'MustUse'}}
   for (producesMustUsePointer();;);
   for (producesMustUseRef();;); // expected-error {{Unused value of must-use type 'MustUse'}}
   for (producesMayUse();;);
   for (producesMayUsePointer();;);
   for (producesMayUseRef();;);
+  for (u = producesMustUse();;);
 
   for (;;producesMustUse()); // expected-error {{Unused value of must-use type 'MustUse'}}
   for (;;producesMustUsePointer());
   for (;;producesMustUseRef()); // expected-error {{Unused value of must-use type 'MustUse'}}
   for (;;producesMayUse());
   for (;;producesMayUsePointer());
   for (;;producesMayUseRef());
+  for (;;u = producesMustUse());
 
   use((producesMustUse(), false)); // expected-error {{Unused value of must-use type 'MustUse'}}
   use((producesMustUsePointer(), false));
   use((producesMustUseRef(), false)); // expected-error {{Unused value of must-use type 'MustUse'}}
   use((producesMayUse(), false));
   use((producesMayUsePointer(), false));
   use((producesMayUseRef(), false));
+  use((u = producesMustUse(), false));
 
   switch (1) {
   case 1:
     producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMustUsePointer();
     producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMayUse();
     producesMayUsePointer();
     producesMayUseRef();
+    u = producesMustUse();
   case 2:
     producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
   case 3:
     producesMustUsePointer();
   case 4:
     producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
   case 5:
     producesMayUse();
   case 6:
     producesMayUsePointer();
   case 7:
     producesMayUseRef();
+  case 8:
+    u = producesMustUse();
   default:
     producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMustUsePointer();
     producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMayUse();
     producesMayUsePointer();
     producesMayUseRef();
+    u = producesMustUse();
   }
 
   use(producesMustUse());
   use(producesMustUsePointer());
   use(producesMustUseRef());
   use(producesMayUse());
   use(producesMayUsePointer());
   use(producesMayUseRef());
+  use(u = producesMustUse());
 
   MustUse a = producesMustUse();
   MustUse *b = producesMustUsePointer();
   MustUse &c = producesMustUseRef();
   MayUse d = producesMayUse();
   MayUse *e = producesMayUsePointer();
   MayUse &f = producesMayUseRef();
+  MustUse g = u = producesMustUse();
 }