mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1180993 - Part 1: Add an analysis to help catch unused return values of specific types. r=ehsan
This commit is contained in:
parent
e634b6e971
commit
b12cf73752
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
156
build/clang-plugin/tests/TestMustUse.cpp
Normal file
156
build/clang-plugin/tests/TestMustUse.cpp
Normal 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();
|
||||
}
|
@ -10,6 +10,7 @@ SOURCES += [
|
||||
'TestExplicitOperatorBool.cpp',
|
||||
'TestGlobalClass.cpp',
|
||||
'TestMustOverride.cpp',
|
||||
'TestMustUse.cpp',
|
||||
'TestNANTestingExpr.cpp',
|
||||
'TestNANTestingExprC.c',
|
||||
'TestNoAddRefReleaseOnReturn.cpp',
|
||||
|
Loading…
Reference in New Issue
Block a user