Bug 1180993 - Part 1: Add an analysis to help catch unused return values of specific types. r=ehsan

This commit is contained in:
Michael Layzell 2015-07-10 09:46:00 -04:00
parent e634b6e971
commit b12cf73752
3 changed files with 211 additions and 0 deletions

View File

@ -235,6 +235,25 @@ public:
return attr->getAnnotation() == spelling;
}
void HandleUnusedExprResult(const Stmt *stmt) {
const Expr* E = dyn_cast_or_null<Expr>(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;
}
};
/**

View File

@ -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();
}

View File

@ -10,6 +10,7 @@ SOURCES += [
'TestExplicitOperatorBool.cpp',
'TestGlobalClass.cpp',
'TestMustOverride.cpp',
'TestMustUse.cpp',
'TestNANTestingExpr.cpp',
'TestNANTestingExprC.c',
'TestNoAddRefReleaseOnReturn.cpp',