aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/include/clang/Analysis/Analyses/CalledOnceCheck.h
blob: 6a1528a2da248f62475413234247e046648310e8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//===- 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 applies.
/// \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 */