diff --git a/build/clang-plugin/clang-plugin.cpp b/build/clang-plugin/clang-plugin.cpp index f7c7637c7d8..17c74e723b8 100644 --- a/build/clang-plugin/clang-plugin.cpp +++ b/build/clang-plugin/clang-plugin.cpp @@ -235,6 +235,25 @@ public: return attr->getAnnotation() == spelling; } + void HandleUnusedExprResult(const Stmt *stmt) { + const Expr* E = dyn_cast_or_null(stmt); + if (E) { + // XXX It would be nice if we could use getAsTagDecl, + // but our version of clang is too old. + // (getAsTagDecl would also cover enums etc.) + QualType T = E->getType(); + CXXRecordDecl *decl = T->getAsCXXRecordDecl(); + if (decl) { + decl = decl->getDefinition(); + if (decl && hasCustomAnnotation(decl, "moz_must_use")) { + unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Error, "Unused MOZ_MUST_USE value of type %0"); + Diag.Report(E->getLocStart(), errorID) << T; + } + } + } + } + bool VisitCXXRecordDecl(CXXRecordDecl *d) { // We need definitions, not declarations if (!d->isThisDeclarationADefinition()) return true; @@ -317,6 +336,41 @@ public: return true; } + + bool VisitSwitchCase(SwitchCase* stmt) { + HandleUnusedExprResult(stmt->getSubStmt()); + return true; + } + bool VisitCompoundStmt(CompoundStmt* stmt) { + for (CompoundStmt::body_iterator it = stmt->body_begin(), e = stmt->body_end(); + it != e; ++it) { + HandleUnusedExprResult(*it); + } + return true; + } + bool VisitIfStmt(IfStmt* Stmt) { + HandleUnusedExprResult(Stmt->getThen()); + HandleUnusedExprResult(Stmt->getElse()); + return true; + } + bool VisitWhileStmt(WhileStmt* Stmt) { + HandleUnusedExprResult(Stmt->getBody()); + return true; + } + bool VisitDoStmt(DoStmt* Stmt) { + HandleUnusedExprResult(Stmt->getBody()); + return true; + } + bool VisitForStmt(ForStmt* Stmt) { + HandleUnusedExprResult(Stmt->getBody()); + HandleUnusedExprResult(Stmt->getInit()); + HandleUnusedExprResult(Stmt->getInc()); + return true; + } + bool VisitBinComma(BinaryOperator* Op) { + HandleUnusedExprResult(Op->getLHS()); + return true; + } }; /** diff --git a/build/clang-plugin/tests/TestMustUse.cpp b/build/clang-plugin/tests/TestMustUse.cpp new file mode 100644 index 00000000000..edcdb1a508c --- /dev/null +++ b/build/clang-plugin/tests/TestMustUse.cpp @@ -0,0 +1,156 @@ +#define MOZ_MUST_USE __attribute__((annotate("moz_must_use"))) + +class MOZ_MUST_USE MustUse {}; +class MayUse {}; + +MustUse producesMustUse(); +MustUse *producesMustUsePointer(); +MustUse &producesMustUseRef(); + +MayUse producesMayUse(); +MayUse *producesMayUsePointer(); +MayUse &producesMayUseRef(); + +void use(MustUse*); +void use(MustUse&); +void use(MustUse&&); +void use(MayUse*); +void use(MayUse&); +void use(MayUse&&); +void use(bool); + +void foo() { + producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMustUsePointer(); + producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMayUse(); + producesMayUsePointer(); + producesMayUseRef(); + { + producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMustUsePointer(); + producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMayUse(); + producesMayUsePointer(); + producesMayUseRef(); + } + if (true) { + producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMustUsePointer(); + producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMayUse(); + producesMayUsePointer(); + producesMayUseRef(); + } else { + producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMustUsePointer(); + producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMayUse(); + producesMayUsePointer(); + producesMayUseRef(); + } + + if(true) producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + else producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + if(true) producesMustUsePointer(); + else producesMustUsePointer(); + if(true) producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + else producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + if(true) producesMayUse(); + else producesMayUse(); + if(true) producesMayUsePointer(); + else producesMayUsePointer(); + if(true) producesMayUseRef(); + else producesMayUseRef(); + + while (true) producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + while (true) producesMustUsePointer(); + while (true) producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + while (true) producesMayUse(); + while (true) producesMayUsePointer(); + while (true) producesMayUseRef(); + + do producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + while (true); + do producesMustUsePointer(); + while (true); + do producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + while (true); + do producesMayUse(); + while (true); + do producesMayUsePointer(); + while (true); + do producesMayUseRef(); + while (true); + + for (;;) producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + for (;;) producesMustUsePointer(); + for (;;) producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + for (;;) producesMayUse(); + for (;;) producesMayUsePointer(); + for (;;) producesMayUseRef(); + + for (producesMustUse();;); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + for (producesMustUsePointer();;); + for (producesMustUseRef();;); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + for (producesMayUse();;); + for (producesMayUsePointer();;); + for (producesMayUseRef();;); + + for (;;producesMustUse()); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + for (;;producesMustUsePointer()); + for (;;producesMustUseRef()); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + for (;;producesMayUse()); + for (;;producesMayUsePointer()); + for (;;producesMayUseRef()); + + use((producesMustUse(), false)); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + use((producesMustUsePointer(), false)); + use((producesMustUseRef(), false)); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + use((producesMayUse(), false)); + use((producesMayUsePointer(), false)); + use((producesMayUseRef(), false)); + + switch (1) { + case 1: + producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMustUsePointer(); + producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMayUse(); + producesMayUsePointer(); + producesMayUseRef(); + case 2: + producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + case 3: + producesMustUsePointer(); + case 4: + producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + case 5: + producesMayUse(); + case 6: + producesMayUsePointer(); + case 7: + producesMayUseRef(); + default: + producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMustUsePointer(); + producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMayUse(); + producesMayUsePointer(); + producesMayUseRef(); + } + + use(producesMustUse()); + use(producesMustUsePointer()); + use(producesMustUseRef()); + use(producesMayUse()); + use(producesMayUsePointer()); + use(producesMayUseRef()); + + MustUse a = producesMustUse(); + MustUse *b = producesMustUsePointer(); + MustUse &c = producesMustUseRef(); + MayUse d = producesMayUse(); + MayUse *e = producesMayUsePointer(); + MayUse &f = producesMayUseRef(); +} diff --git a/build/clang-plugin/tests/moz.build b/build/clang-plugin/tests/moz.build index 0894046e112..6dc1ec98278 100644 --- a/build/clang-plugin/tests/moz.build +++ b/build/clang-plugin/tests/moz.build @@ -10,6 +10,7 @@ SOURCES += [ 'TestExplicitOperatorBool.cpp', 'TestGlobalClass.cpp', 'TestMustOverride.cpp', + 'TestMustUse.cpp', 'TestNANTestingExpr.cpp', 'TestNANTestingExprC.c', 'TestNoAddRefReleaseOnReturn.cpp',