summaryrefslogtreecommitdiffstats
path: root/lib/Sema/AnalysisBasedWarnings.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/AnalysisBasedWarnings.cpp')
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp191
1 files changed, 136 insertions, 55 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 213d6fb..f666a9b 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -530,44 +530,37 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
return;
- // FIXME: Function try block
- if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
- switch (CheckFallThrough(AC)) {
- case UnknownFallThrough:
- break;
+ SourceLocation LBrace = Body->getLocStart(), RBrace = Body->getLocEnd();
+ // Either in a function body compound statement, or a function-try-block.
+ switch (CheckFallThrough(AC)) {
+ case UnknownFallThrough:
+ break;
- case MaybeFallThrough:
- if (HasNoReturn)
- S.Diag(Compound->getRBracLoc(),
- CD.diag_MaybeFallThrough_HasNoReturn);
- else if (!ReturnsVoid)
- S.Diag(Compound->getRBracLoc(),
- CD.diag_MaybeFallThrough_ReturnsNonVoid);
- break;
- case AlwaysFallThrough:
- if (HasNoReturn)
- S.Diag(Compound->getRBracLoc(),
- CD.diag_AlwaysFallThrough_HasNoReturn);
- else if (!ReturnsVoid)
- S.Diag(Compound->getRBracLoc(),
- CD.diag_AlwaysFallThrough_ReturnsNonVoid);
- break;
- case NeverFallThroughOrReturn:
- if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn)
- << 0 << FD;
- } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn)
- << 1 << MD;
- } else {
- S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn);
- }
+ case MaybeFallThrough:
+ if (HasNoReturn)
+ S.Diag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn);
+ else if (!ReturnsVoid)
+ S.Diag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid);
+ break;
+ case AlwaysFallThrough:
+ if (HasNoReturn)
+ S.Diag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn);
+ else if (!ReturnsVoid)
+ S.Diag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
+ break;
+ case NeverFallThroughOrReturn:
+ if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
+ } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;
+ } else {
+ S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn);
}
- break;
- case NeverFallThrough:
- break;
- }
+ }
+ break;
+ case NeverFallThrough:
+ break;
}
}
@@ -923,7 +916,7 @@ namespace {
// issue a warn_fallthrough_attr_unreachable for them.
for (const auto *B : *Cfg) {
const Stmt *L = B->getLabel();
- if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B))
+ if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B).second)
BlockQueue.push_back(B);
}
@@ -933,7 +926,7 @@ namespace {
for (CFGBlock::const_succ_iterator I = P->succ_begin(),
E = P->succ_end();
I != E; ++I) {
- if (*I && ReachableBlocks.insert(*I))
+ if (*I && ReachableBlocks.insert(*I).second)
BlockQueue.push_back(*I);
}
}
@@ -1444,13 +1437,51 @@ struct SortDiagBySourceLocation {
// -Wthread-safety
//===----------------------------------------------------------------------===//
namespace clang {
-namespace thread_safety {
-namespace {
-class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
+namespace threadSafety {
+
+class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
Sema &S;
DiagList Warnings;
SourceLocation FunLocation, FunEndLocation;
+ const FunctionDecl *CurrentFunction;
+ bool Verbose;
+
+ OptionalNotes getNotes() const {
+ if (Verbose && CurrentFunction) {
+ PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(),
+ S.PDiag(diag::note_thread_warning_in_fun)
+ << CurrentFunction->getNameAsString());
+ return OptionalNotes(1, FNote);
+ }
+ return OptionalNotes();
+ }
+
+ OptionalNotes getNotes(const PartialDiagnosticAt &Note) const {
+ OptionalNotes ONS(1, Note);
+ if (Verbose && CurrentFunction) {
+ PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(),
+ S.PDiag(diag::note_thread_warning_in_fun)
+ << CurrentFunction->getNameAsString());
+ ONS.push_back(FNote);
+ }
+ return ONS;
+ }
+
+ OptionalNotes getNotes(const PartialDiagnosticAt &Note1,
+ const PartialDiagnosticAt &Note2) const {
+ OptionalNotes ONS;
+ ONS.push_back(Note1);
+ ONS.push_back(Note2);
+ if (Verbose && CurrentFunction) {
+ PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(),
+ S.PDiag(diag::note_thread_warning_in_fun)
+ << CurrentFunction->getNameAsString());
+ ONS.push_back(FNote);
+ }
+ return ONS;
+ }
+
// Helper functions
void warnLockMismatch(unsigned DiagID, StringRef Kind, Name LockName,
SourceLocation Loc) {
@@ -1459,12 +1490,15 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
if (!Loc.isValid())
Loc = FunLocation;
PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind << LockName);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
}
public:
ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
- : S(S), FunLocation(FL), FunEndLocation(FEL) {}
+ : S(S), FunLocation(FL), FunEndLocation(FEL),
+ CurrentFunction(nullptr), Verbose(false) {}
+
+ void setVerbose(bool b) { Verbose = b; }
/// \brief Emit all buffered diagnostics in order of sourcelocation.
/// We need to output diagnostics produced while iterating through
@@ -1482,12 +1516,14 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
void handleInvalidLockExp(StringRef Kind, SourceLocation Loc) override {
PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_cannot_resolve_lock)
<< Loc);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
}
+
void handleUnmatchedUnlock(StringRef Kind, Name LockName,
SourceLocation Loc) override {
warnLockMismatch(diag::warn_unlock_but_no_lock, Kind, LockName, Loc);
}
+
void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
LockKind Expected, LockKind Received,
SourceLocation Loc) override {
@@ -1496,8 +1532,9 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_kind_mismatch)
<< Kind << LockName << Received
<< Expected);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
}
+
void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation Loc) override {
warnLockMismatch(diag::warn_double_lock, Kind, LockName, Loc);
}
@@ -1529,10 +1566,10 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
if (LocLocked.isValid()) {
PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here)
<< Kind);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note)));
+ Warnings.push_back(DelayedDiag(Warning, getNotes(Note)));
return;
}
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
}
void handleExclusiveAndShared(StringRef Kind, Name LockName,
@@ -1543,7 +1580,7 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
<< Kind << LockName);
PartialDiagnosticAt Note(Loc2, S.PDiag(diag::note_lock_exclusive_and_shared)
<< Kind << LockName);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note)));
+ Warnings.push_back(DelayedDiag(Warning, getNotes(Note)));
}
void handleNoMutexHeld(StringRef Kind, const NamedDecl *D,
@@ -1556,7 +1593,7 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
diag::warn_var_deref_requires_any_lock;
PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
<< D->getNameAsString() << getLockKindFromAccessKind(AK));
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
}
void handleMutexNotHeld(StringRef Kind, const NamedDecl *D,
@@ -1575,13 +1612,25 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
case POK_FunctionCall:
DiagID = diag::warn_fun_requires_lock_precise;
break;
+ case POK_PassByRef:
+ DiagID = diag::warn_guarded_pass_by_reference;
+ break;
+ case POK_PtPassByRef:
+ DiagID = diag::warn_pt_guarded_pass_by_reference;
+ break;
}
PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind
<< D->getNameAsString()
<< LockName << LK);
PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match)
<< *PossibleMatch);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note)));
+ if (Verbose && POK == POK_VarAccess) {
+ PartialDiagnosticAt VNote(D->getLocation(),
+ S.PDiag(diag::note_guarded_by_declared_here)
+ << D->getNameAsString());
+ Warnings.push_back(DelayedDiag(Warning, getNotes(Note, VNote)));
+ } else
+ Warnings.push_back(DelayedDiag(Warning, getNotes(Note)));
} else {
switch (POK) {
case POK_VarAccess:
@@ -1593,22 +1642,52 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
case POK_FunctionCall:
DiagID = diag::warn_fun_requires_lock;
break;
+ case POK_PassByRef:
+ DiagID = diag::warn_guarded_pass_by_reference;
+ break;
+ case POK_PtPassByRef:
+ DiagID = diag::warn_pt_guarded_pass_by_reference;
+ break;
}
PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind
<< D->getNameAsString()
<< LockName << LK);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ if (Verbose && POK == POK_VarAccess) {
+ PartialDiagnosticAt Note(D->getLocation(),
+ S.PDiag(diag::note_guarded_by_declared_here)
+ << D->getNameAsString());
+ Warnings.push_back(DelayedDiag(Warning, getNotes(Note)));
+ } else
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
}
}
+
+ virtual void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
+ SourceLocation Loc) override {
+ PartialDiagnosticAt Warning(Loc,
+ S.PDiag(diag::warn_acquire_requires_negative_cap)
+ << Kind << LockName << Neg);
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
+ }
+
+
void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
SourceLocation Loc) override {
PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_fun_excludes_mutex)
<< Kind << FunName << LockName);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ Warnings.push_back(DelayedDiag(Warning, getNotes()));
+ }
+
+ void enterFunction(const FunctionDecl* FD) override {
+ CurrentFunction = FD;
+ }
+
+ void leaveFunction(const FunctionDecl* FD) override {
+ CurrentFunction = 0;
}
};
-}
+
}
}
@@ -1896,11 +1975,13 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
if (P.enableThreadSafetyAnalysis) {
SourceLocation FL = AC.getDecl()->getLocation();
SourceLocation FEL = AC.getDecl()->getLocEnd();
- thread_safety::ThreadSafetyReporter Reporter(S, FL, FEL);
+ threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);
if (!Diags.isIgnored(diag::warn_thread_safety_beta, D->getLocStart()))
Reporter.setIssueBetaWarnings(true);
+ if (!Diags.isIgnored(diag::warn_thread_safety_verbose, D->getLocStart()))
+ Reporter.setVerbose(true);
- thread_safety::runThreadSafetyAnalysis(AC, Reporter);
+ threadSafety::runThreadSafetyAnalysis(AC, Reporter);
Reporter.emitDiagnostics();
}
OpenPOWER on IntegriCloud