| //===- CalledOnceCheck.h - Check 'called once' parameters -------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines a check for function-like parameters that should be |
| // called exactly one time. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_CALLEDONCECHECK_H |
| #define LLVM_CLANG_ANALYSIS_ANALYSES_CALLEDONCECHECK_H |
| |
| namespace clang { |
| |
| class AnalysisDeclContext; |
| class BlockDecl; |
| class CFG; |
| class Decl; |
| class Expr; |
| class ParmVarDecl; |
| class Stmt; |
| |
| /// Classification of situations when parameter is not called on every path. |
| /// \enum IfThen -- then branch of the if statement has no call. |
| /// \enum IfElse -- else branch of the if statement has no call. |
| /// \enum Switch -- one of the switch cases doesn't have a call. |
| /// \enum SwitchSkipped -- there is no call if none of the cases appies. |
| /// \enum LoopEntered -- no call when the loop is entered. |
| /// \enum LoopSkipped -- no call when the loop is not entered. |
| /// \enum FallbackReason -- fallback case when we were not able to figure out |
| /// the reason. |
| enum class NeverCalledReason { |
| IfThen, |
| IfElse, |
| Switch, |
| SwitchSkipped, |
| LoopEntered, |
| LoopSkipped, |
| FallbackReason, |
| LARGEST_VALUE = FallbackReason |
| }; |
| |
| class CalledOnceCheckHandler { |
| public: |
| CalledOnceCheckHandler() = default; |
| virtual ~CalledOnceCheckHandler() = default; |
| |
| /// Called when parameter is called twice. |
| /// \param Parameter -- parameter that should be called once. |
| /// \param Call -- call to report the warning. |
| /// \param PrevCall -- previous call. |
| /// \param IsCompletionHandler -- true, if parameter is a completion handler. |
| /// \param Poised -- true, if the second call is guaranteed to happen after |
| /// the first call. |
| virtual void handleDoubleCall(const ParmVarDecl *Parameter, const Expr *Call, |
| const Expr *PrevCall, bool IsCompletionHandler, |
| bool Poised) {} |
| |
| /// Called when parameter is not called at all. |
| /// \param Parameter -- parameter that should be called once. |
| /// \param IsCompletionHandler -- true, if parameter is a completion handler. |
| virtual void handleNeverCalled(const ParmVarDecl *Parameter, |
| bool IsCompletionHandler) {} |
| |
| /// Called when captured parameter is not called at all. |
| /// \param Parameter -- parameter that should be called once. |
| /// \param Where -- declaration that captures \p Parameter |
| /// \param IsCompletionHandler -- true, if parameter is a completion handler. |
| virtual void handleCapturedNeverCalled(const ParmVarDecl *Parameter, |
| const Decl *Where, |
| bool IsCompletionHandler) {} |
| |
| /// Called when parameter is not called on one of the paths. |
| /// Usually we try to find a statement that is the least common ancestor of |
| /// the path containing the call and not containing the call. This helps us |
| /// to pinpoint a bad path for the user. |
| /// \param Parameter -- parameter that should be called once. |
| /// \param Function -- function declaration where the problem occurred. |
| /// \param Where -- the least common ancestor statement. |
| /// \param Reason -- a reason describing the path without a call. |
| /// \param IsCalledDirectly -- true, if parameter actually gets called on |
| /// the other path. It is opposed to be used in some other way (added to some |
| /// collection, passed as a parameter, etc.). |
| /// \param IsCompletionHandler -- true, if parameter is a completion handler. |
| virtual void handleNeverCalled(const ParmVarDecl *Parameter, |
| const Decl *Function, const Stmt *Where, |
| NeverCalledReason Reason, |
| bool IsCalledDirectly, |
| bool IsCompletionHandler) {} |
| |
| /// Called when the block is guaranteed to be called exactly once. |
| /// It means that we can be stricter with what we report on that block. |
| /// \param Block -- block declaration that is known to be called exactly once. |
| virtual void |
| handleBlockThatIsGuaranteedToBeCalledOnce(const BlockDecl *Block) {} |
| |
| /// Called when the block has no guarantees about how many times it can get |
| /// called. |
| /// It means that we should be more lenient with reporting warnings in it. |
| /// \param Block -- block declaration in question. |
| virtual void handleBlockWithNoGuarantees(const BlockDecl *Block) {} |
| }; |
| |
| /// Check given CFG for 'called once' parameter violations. |
| /// |
| /// It traverses the function and tracks how such parameters are used. |
| /// It detects two main violations: |
| /// * parameter is called twice |
| /// * parameter is not called |
| /// |
| /// \param AC -- context. |
| /// \param Handler -- a handler for found violations. |
| /// \param CheckConventionalParameters -- true, if we want to check parameters |
| /// not explicitly marked as 'called once', but having the same requirements |
| /// according to conventions. |
| void checkCalledOnceParameters(AnalysisDeclContext &AC, |
| CalledOnceCheckHandler &Handler, |
| bool CheckConventionalParameters); |
| |
| } // end namespace clang |
| |
| #endif /* LLVM_CLANG_ANALYSIS_ANALYSES_CALLEDONCECHECK_H */ |