aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Sema/AnalysisBasedWarnings.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/AnalysisBasedWarnings.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Sema/AnalysisBasedWarnings.cpp102
1 files changed, 99 insertions, 3 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm-project/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 3b7356893833..edd9742ed207 100644
--- a/contrib/llvm-project/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/contrib/llvm-project/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
+#include "clang/Analysis/Analyses/CalledOnceCheck.h"
#include "clang/Analysis/Analyses/Consumed.h"
#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/Analyses/ThreadSafety.h"
@@ -36,6 +37,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallString.h"
@@ -1623,6 +1625,82 @@ private:
});
}
};
+
+class CalledOnceCheckReporter : public CalledOnceCheckHandler {
+public:
+ CalledOnceCheckReporter(Sema &S) : S(S) {}
+ void handleDoubleCall(const ParmVarDecl *Parameter, const Expr *Call,
+ const Expr *PrevCall, bool IsCompletionHandler,
+ bool Poised) override {
+ auto DiagToReport = IsCompletionHandler
+ ? diag::warn_completion_handler_called_twice
+ : diag::warn_called_once_gets_called_twice;
+ S.Diag(Call->getBeginLoc(), DiagToReport) << Parameter;
+ S.Diag(PrevCall->getBeginLoc(), diag::note_called_once_gets_called_twice)
+ << Poised;
+ }
+
+ void handleNeverCalled(const ParmVarDecl *Parameter,
+ bool IsCompletionHandler) override {
+ auto DiagToReport = IsCompletionHandler
+ ? diag::warn_completion_handler_never_called
+ : diag::warn_called_once_never_called;
+ S.Diag(Parameter->getBeginLoc(), DiagToReport)
+ << Parameter << /* Captured */ false;
+ }
+
+ void handleNeverCalled(const ParmVarDecl *Parameter, const Stmt *Where,
+ NeverCalledReason Reason, bool IsCalledDirectly,
+ bool IsCompletionHandler) override {
+ auto DiagToReport = IsCompletionHandler
+ ? diag::warn_completion_handler_never_called_when
+ : diag::warn_called_once_never_called_when;
+ S.Diag(Where->getBeginLoc(), DiagToReport)
+ << Parameter << IsCalledDirectly << (unsigned)Reason;
+ }
+
+ void handleCapturedNeverCalled(const ParmVarDecl *Parameter,
+ const Decl *Where,
+ bool IsCompletionHandler) override {
+ auto DiagToReport = IsCompletionHandler
+ ? diag::warn_completion_handler_never_called
+ : diag::warn_called_once_never_called;
+ S.Diag(Where->getBeginLoc(), DiagToReport)
+ << Parameter << /* Captured */ true;
+ }
+
+private:
+ Sema &S;
+};
+
+constexpr unsigned CalledOnceWarnings[] = {
+ diag::warn_called_once_never_called,
+ diag::warn_called_once_never_called_when,
+ diag::warn_called_once_gets_called_twice};
+
+constexpr unsigned CompletionHandlerWarnings[]{
+ diag::warn_completion_handler_never_called,
+ diag::warn_completion_handler_never_called_when,
+ diag::warn_completion_handler_called_twice};
+
+bool shouldAnalyzeCalledOnceImpl(llvm::ArrayRef<unsigned> DiagIDs,
+ const DiagnosticsEngine &Diags,
+ SourceLocation At) {
+ return llvm::any_of(DiagIDs, [&Diags, At](unsigned DiagID) {
+ return !Diags.isIgnored(DiagID, At);
+ });
+}
+
+bool shouldAnalyzeCalledOnceConventions(const DiagnosticsEngine &Diags,
+ SourceLocation At) {
+ return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);
+}
+
+bool shouldAnalyzeCalledOnceParameters(const DiagnosticsEngine &Diags,
+ SourceLocation At) {
+ return shouldAnalyzeCalledOnceImpl(CalledOnceWarnings, Diags, At) ||
+ shouldAnalyzeCalledOnceConventions(Diags, At);
+}
} // anonymous namespace
namespace clang {
@@ -1849,8 +1927,8 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
<< *PossibleMatch);
if (Verbose && POK == POK_VarAccess) {
PartialDiagnosticAt VNote(D->getLocation(),
- S.PDiag(diag::note_guarded_by_declared_here)
- << D->getNameAsString());
+ S.PDiag(diag::note_guarded_by_declared_here)
+ << D->getDeclName());
Warnings.emplace_back(std::move(Warning), getNotes(Note, VNote));
} else
Warnings.emplace_back(std::move(Warning), getNotes(Note));
@@ -1892,6 +1970,13 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
Warnings.emplace_back(std::move(Warning), getNotes());
}
+ void handleNegativeNotHeld(const NamedDecl *D, Name LockName,
+ SourceLocation Loc) override {
+ PartialDiagnosticAt Warning(
+ Loc, S.PDiag(diag::warn_fun_requires_negative_cap) << D << LockName);
+ Warnings.emplace_back(std::move(Warning), getNotes());
+ }
+
void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
SourceLocation Loc) override {
PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_fun_excludes_mutex)
@@ -2089,7 +2174,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
if (cast<DeclContext>(D)->isDependentContext())
return;
- if (Diags.hasUncompilableErrorOccurred()) {
+ if (S.hasUncompilableErrorOccurred()) {
// Flush out any possibly unreachable diagnostics.
flushDiagnostics(S, fscope);
return;
@@ -2257,6 +2342,17 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
}
}
+ // Check for violations of "called once" parameter properties.
+ if (S.getLangOpts().ObjC &&
+ shouldAnalyzeCalledOnceParameters(Diags, D->getBeginLoc())) {
+ if (AC.getCFG()) {
+ CalledOnceCheckReporter Reporter(S);
+ checkCalledOnceParameters(
+ AC, Reporter,
+ shouldAnalyzeCalledOnceConventions(Diags, D->getBeginLoc()));
+ }
+ }
+
bool FallThroughDiagFull =
!Diags.isIgnored(diag::warn_unannotated_fallthrough, D->getBeginLoc());
bool FallThroughDiagPerFunction = !Diags.isIgnored(