diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/AnalysisBasedWarnings.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Sema/AnalysisBasedWarnings.cpp | 102 |
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( |