106f32e7eSjoerg //== CheckerContext.h - Context info for path-sensitive checkers--*- C++ -*--=//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg //  This file defines CheckerContext that provides contextual info for
1006f32e7eSjoerg // path-sensitive checkers.
1106f32e7eSjoerg //
1206f32e7eSjoerg //===----------------------------------------------------------------------===//
1306f32e7eSjoerg 
1406f32e7eSjoerg #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H
1506f32e7eSjoerg #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H
1606f32e7eSjoerg 
1706f32e7eSjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
1806f32e7eSjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
1906f32e7eSjoerg 
2006f32e7eSjoerg namespace clang {
2106f32e7eSjoerg namespace ento {
2206f32e7eSjoerg 
2306f32e7eSjoerg class CheckerContext {
2406f32e7eSjoerg   ExprEngine &Eng;
2506f32e7eSjoerg   /// The current exploded(symbolic execution) graph node.
2606f32e7eSjoerg   ExplodedNode *Pred;
2706f32e7eSjoerg   /// The flag is true if the (state of the execution) has been modified
2806f32e7eSjoerg   /// by the checker using this context. For example, a new transition has been
2906f32e7eSjoerg   /// added or a bug report issued.
3006f32e7eSjoerg   bool Changed;
3106f32e7eSjoerg   /// The tagged location, which is used to generate all new nodes.
3206f32e7eSjoerg   const ProgramPoint Location;
3306f32e7eSjoerg   NodeBuilder &NB;
3406f32e7eSjoerg 
3506f32e7eSjoerg public:
3606f32e7eSjoerg   /// If we are post visiting a call, this flag will be set if the
3706f32e7eSjoerg   /// call was inlined.  In all other cases it will be false.
3806f32e7eSjoerg   const bool wasInlined;
3906f32e7eSjoerg 
4006f32e7eSjoerg   CheckerContext(NodeBuilder &builder,
4106f32e7eSjoerg                  ExprEngine &eng,
4206f32e7eSjoerg                  ExplodedNode *pred,
4306f32e7eSjoerg                  const ProgramPoint &loc,
4406f32e7eSjoerg                  bool wasInlined = false)
Eng(eng)4506f32e7eSjoerg     : Eng(eng),
4606f32e7eSjoerg       Pred(pred),
4706f32e7eSjoerg       Changed(false),
4806f32e7eSjoerg       Location(loc),
4906f32e7eSjoerg       NB(builder),
5006f32e7eSjoerg       wasInlined(wasInlined) {
5106f32e7eSjoerg     assert(Pred->getState() &&
5206f32e7eSjoerg            "We should not call the checkers on an empty state.");
5306f32e7eSjoerg   }
5406f32e7eSjoerg 
getAnalysisManager()5506f32e7eSjoerg   AnalysisManager &getAnalysisManager() {
5606f32e7eSjoerg     return Eng.getAnalysisManager();
5706f32e7eSjoerg   }
5806f32e7eSjoerg 
getConstraintManager()5906f32e7eSjoerg   ConstraintManager &getConstraintManager() {
6006f32e7eSjoerg     return Eng.getConstraintManager();
6106f32e7eSjoerg   }
6206f32e7eSjoerg 
getStoreManager()6306f32e7eSjoerg   StoreManager &getStoreManager() {
6406f32e7eSjoerg     return Eng.getStoreManager();
6506f32e7eSjoerg   }
6606f32e7eSjoerg 
6706f32e7eSjoerg   /// Returns the previous node in the exploded graph, which includes
6806f32e7eSjoerg   /// the state of the program before the checker ran. Note, checkers should
6906f32e7eSjoerg   /// not retain the node in their state since the nodes might get invalidated.
getPredecessor()7006f32e7eSjoerg   ExplodedNode *getPredecessor() { return Pred; }
getState()7106f32e7eSjoerg   const ProgramStateRef &getState() const { return Pred->getState(); }
7206f32e7eSjoerg 
7306f32e7eSjoerg   /// Check if the checker changed the state of the execution; ex: added
7406f32e7eSjoerg   /// a new transition or a bug report.
isDifferent()7506f32e7eSjoerg   bool isDifferent() { return Changed; }
7606f32e7eSjoerg 
7706f32e7eSjoerg   /// Returns the number of times the current block has been visited
7806f32e7eSjoerg   /// along the analyzed path.
blockCount()7906f32e7eSjoerg   unsigned blockCount() const {
8006f32e7eSjoerg     return NB.getContext().blockCount();
8106f32e7eSjoerg   }
8206f32e7eSjoerg 
getASTContext()8306f32e7eSjoerg   ASTContext &getASTContext() {
8406f32e7eSjoerg     return Eng.getContext();
8506f32e7eSjoerg   }
8606f32e7eSjoerg 
getLangOpts()8706f32e7eSjoerg   const LangOptions &getLangOpts() const {
8806f32e7eSjoerg     return Eng.getContext().getLangOpts();
8906f32e7eSjoerg   }
9006f32e7eSjoerg 
getLocationContext()9106f32e7eSjoerg   const LocationContext *getLocationContext() const {
9206f32e7eSjoerg     return Pred->getLocationContext();
9306f32e7eSjoerg   }
9406f32e7eSjoerg 
getStackFrame()9506f32e7eSjoerg   const StackFrameContext *getStackFrame() const {
9606f32e7eSjoerg     return Pred->getStackFrame();
9706f32e7eSjoerg   }
9806f32e7eSjoerg 
9906f32e7eSjoerg   /// Return true if the current LocationContext has no caller context.
inTopFrame()10006f32e7eSjoerg   bool inTopFrame() const { return getLocationContext()->inTopFrame();  }
10106f32e7eSjoerg 
getBugReporter()10206f32e7eSjoerg   BugReporter &getBugReporter() {
10306f32e7eSjoerg     return Eng.getBugReporter();
10406f32e7eSjoerg   }
10506f32e7eSjoerg 
getSourceManager()10606f32e7eSjoerg   const SourceManager &getSourceManager() {
10706f32e7eSjoerg     return getBugReporter().getSourceManager();
10806f32e7eSjoerg   }
10906f32e7eSjoerg 
getPreprocessor()110*13fbcb42Sjoerg   Preprocessor &getPreprocessor() { return getBugReporter().getPreprocessor(); }
111*13fbcb42Sjoerg 
getSValBuilder()11206f32e7eSjoerg   SValBuilder &getSValBuilder() {
11306f32e7eSjoerg     return Eng.getSValBuilder();
11406f32e7eSjoerg   }
11506f32e7eSjoerg 
getSymbolManager()11606f32e7eSjoerg   SymbolManager &getSymbolManager() {
11706f32e7eSjoerg     return getSValBuilder().getSymbolManager();
11806f32e7eSjoerg   }
11906f32e7eSjoerg 
getStateManager()12006f32e7eSjoerg   ProgramStateManager &getStateManager() {
12106f32e7eSjoerg     return Eng.getStateManager();
12206f32e7eSjoerg   }
12306f32e7eSjoerg 
getCurrentAnalysisDeclContext()12406f32e7eSjoerg   AnalysisDeclContext *getCurrentAnalysisDeclContext() const {
12506f32e7eSjoerg     return Pred->getLocationContext()->getAnalysisDeclContext();
12606f32e7eSjoerg   }
12706f32e7eSjoerg 
12806f32e7eSjoerg   /// Get the blockID.
getBlockID()12906f32e7eSjoerg   unsigned getBlockID() const {
13006f32e7eSjoerg     return NB.getContext().getBlock()->getBlockID();
13106f32e7eSjoerg   }
13206f32e7eSjoerg 
13306f32e7eSjoerg   /// If the given node corresponds to a PostStore program point,
13406f32e7eSjoerg   /// retrieve the location region as it was uttered in the code.
13506f32e7eSjoerg   ///
13606f32e7eSjoerg   /// This utility can be useful for generating extensive diagnostics, for
13706f32e7eSjoerg   /// example, for finding variables that the given symbol was assigned to.
getLocationRegionIfPostStore(const ExplodedNode * N)13806f32e7eSjoerg   static const MemRegion *getLocationRegionIfPostStore(const ExplodedNode *N) {
13906f32e7eSjoerg     ProgramPoint L = N->getLocation();
14006f32e7eSjoerg     if (Optional<PostStore> PSL = L.getAs<PostStore>())
14106f32e7eSjoerg       return reinterpret_cast<const MemRegion*>(PSL->getLocationValue());
14206f32e7eSjoerg     return nullptr;
14306f32e7eSjoerg   }
14406f32e7eSjoerg 
14506f32e7eSjoerg   /// Get the value of arbitrary expressions at this point in the path.
getSVal(const Stmt * S)14606f32e7eSjoerg   SVal getSVal(const Stmt *S) const {
14706f32e7eSjoerg     return Pred->getSVal(S);
14806f32e7eSjoerg   }
14906f32e7eSjoerg 
15006f32e7eSjoerg   /// Returns true if the value of \p E is greater than or equal to \p
15106f32e7eSjoerg   /// Val under unsigned comparison
15206f32e7eSjoerg   bool isGreaterOrEqual(const Expr *E, unsigned long long Val);
15306f32e7eSjoerg 
15406f32e7eSjoerg   /// Returns true if the value of \p E is negative.
15506f32e7eSjoerg   bool isNegative(const Expr *E);
15606f32e7eSjoerg 
15706f32e7eSjoerg   /// Generates a new transition in the program state graph
15806f32e7eSjoerg   /// (ExplodedGraph). Uses the default CheckerContext predecessor node.
15906f32e7eSjoerg   ///
16006f32e7eSjoerg   /// @param State The state of the generated node. If not specified, the state
16106f32e7eSjoerg   ///        will not be changed, but the new node will have the checker's tag.
16206f32e7eSjoerg   /// @param Tag The tag is used to uniquely identify the creation site. If no
16306f32e7eSjoerg   ///        tag is specified, a default tag, unique to the given checker,
16406f32e7eSjoerg   ///        will be used. Tags are used to prevent states generated at
16506f32e7eSjoerg   ///        different sites from caching out.
16606f32e7eSjoerg   ExplodedNode *addTransition(ProgramStateRef State = nullptr,
16706f32e7eSjoerg                               const ProgramPointTag *Tag = nullptr) {
16806f32e7eSjoerg     return addTransitionImpl(State ? State : getState(), false, nullptr, Tag);
16906f32e7eSjoerg   }
17006f32e7eSjoerg 
17106f32e7eSjoerg   /// Generates a new transition with the given predecessor.
17206f32e7eSjoerg   /// Allows checkers to generate a chain of nodes.
17306f32e7eSjoerg   ///
17406f32e7eSjoerg   /// @param State The state of the generated node.
17506f32e7eSjoerg   /// @param Pred The transition will be generated from the specified Pred node
17606f32e7eSjoerg   ///             to the newly generated node.
17706f32e7eSjoerg   /// @param Tag The tag to uniquely identify the creation site.
178*13fbcb42Sjoerg   ExplodedNode *addTransition(ProgramStateRef State, ExplodedNode *Pred,
17906f32e7eSjoerg                               const ProgramPointTag *Tag = nullptr) {
18006f32e7eSjoerg     return addTransitionImpl(State, false, Pred, Tag);
18106f32e7eSjoerg   }
18206f32e7eSjoerg 
18306f32e7eSjoerg   /// Generate a sink node. Generating a sink stops exploration of the
18406f32e7eSjoerg   /// given path. To create a sink node for the purpose of reporting an error,
18506f32e7eSjoerg   /// checkers should use generateErrorNode() instead.
18606f32e7eSjoerg   ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred,
18706f32e7eSjoerg                              const ProgramPointTag *Tag = nullptr) {
18806f32e7eSjoerg     return addTransitionImpl(State ? State : getState(), true, Pred, Tag);
18906f32e7eSjoerg   }
19006f32e7eSjoerg 
191*13fbcb42Sjoerg   /// Add a sink node to the current path of execution, halting analysis.
192*13fbcb42Sjoerg   void addSink(ProgramStateRef State = nullptr,
193*13fbcb42Sjoerg                const ProgramPointTag *Tag = nullptr) {
194*13fbcb42Sjoerg     if (!State)
195*13fbcb42Sjoerg       State = getState();
196*13fbcb42Sjoerg     addTransition(State, generateSink(State, getPredecessor()));
197*13fbcb42Sjoerg   }
198*13fbcb42Sjoerg 
19906f32e7eSjoerg   /// Generate a transition to a node that will be used to report
20006f32e7eSjoerg   /// an error. This node will be a sink. That is, it will stop exploration of
20106f32e7eSjoerg   /// the given path.
20206f32e7eSjoerg   ///
20306f32e7eSjoerg   /// @param State The state of the generated node.
20406f32e7eSjoerg   /// @param Tag The tag to uniquely identify the creation site. If null,
20506f32e7eSjoerg   ///        the default tag for the checker will be used.
20606f32e7eSjoerg   ExplodedNode *generateErrorNode(ProgramStateRef State = nullptr,
20706f32e7eSjoerg                                   const ProgramPointTag *Tag = nullptr) {
20806f32e7eSjoerg     return generateSink(State, Pred,
20906f32e7eSjoerg                        (Tag ? Tag : Location.getTag()));
21006f32e7eSjoerg   }
21106f32e7eSjoerg 
21206f32e7eSjoerg   /// Generate a transition to a node that will be used to report
21306f32e7eSjoerg   /// an error. This node will not be a sink. That is, exploration will
21406f32e7eSjoerg   /// continue along this path.
21506f32e7eSjoerg   ///
21606f32e7eSjoerg   /// @param State The state of the generated node.
21706f32e7eSjoerg   /// @param Tag The tag to uniquely identify the creation site. If null,
21806f32e7eSjoerg   ///        the default tag for the checker will be used.
21906f32e7eSjoerg   ExplodedNode *
22006f32e7eSjoerg   generateNonFatalErrorNode(ProgramStateRef State = nullptr,
22106f32e7eSjoerg                             const ProgramPointTag *Tag = nullptr) {
22206f32e7eSjoerg     return addTransition(State, (Tag ? Tag : Location.getTag()));
22306f32e7eSjoerg   }
22406f32e7eSjoerg 
225*13fbcb42Sjoerg   /// Generate a transition to a node that will be used to report
226*13fbcb42Sjoerg   /// an error. This node will not be a sink. That is, exploration will
227*13fbcb42Sjoerg   /// continue along this path.
228*13fbcb42Sjoerg   ///
229*13fbcb42Sjoerg   /// @param State The state of the generated node.
230*13fbcb42Sjoerg   /// @param Pred The transition will be generated from the specified Pred node
231*13fbcb42Sjoerg   ///             to the newly generated node.
232*13fbcb42Sjoerg   /// @param Tag The tag to uniquely identify the creation site. If null,
233*13fbcb42Sjoerg   ///        the default tag for the checker will be used.
234*13fbcb42Sjoerg   ExplodedNode *
235*13fbcb42Sjoerg   generateNonFatalErrorNode(ProgramStateRef State,
236*13fbcb42Sjoerg                             ExplodedNode *Pred,
237*13fbcb42Sjoerg                             const ProgramPointTag *Tag = nullptr) {
238*13fbcb42Sjoerg     return addTransition(State, Pred, (Tag ? Tag : Location.getTag()));
239*13fbcb42Sjoerg   }
240*13fbcb42Sjoerg 
24106f32e7eSjoerg   /// Emit the diagnostics report.
emitReport(std::unique_ptr<BugReport> R)24206f32e7eSjoerg   void emitReport(std::unique_ptr<BugReport> R) {
24306f32e7eSjoerg     Changed = true;
24406f32e7eSjoerg     Eng.getBugReporter().emitReport(std::move(R));
24506f32e7eSjoerg   }
24606f32e7eSjoerg 
24706f32e7eSjoerg   /// Produce a program point tag that displays an additional path note
24806f32e7eSjoerg   /// to the user. This is a lightweight alternative to the
24906f32e7eSjoerg   /// BugReporterVisitor mechanism: instead of visiting the bug report
25006f32e7eSjoerg   /// node-by-node to restore the sequence of events that led to discovering
25106f32e7eSjoerg   /// a bug, you can add notes as you add your transitions.
25206f32e7eSjoerg   ///
25306f32e7eSjoerg   /// @param Cb Callback with 'BugReporterContext &, BugReport &' parameters.
25406f32e7eSjoerg   /// @param IsPrunable Whether the note is prunable. It allows BugReporter
25506f32e7eSjoerg   ///        to omit the note from the report if it would make the displayed
25606f32e7eSjoerg   ///        bug path significantly shorter.
25706f32e7eSjoerg   const NoteTag *getNoteTag(NoteTag::Callback &&Cb, bool IsPrunable = false) {
25806f32e7eSjoerg     return Eng.getNoteTags().makeNoteTag(std::move(Cb), IsPrunable);
25906f32e7eSjoerg   }
26006f32e7eSjoerg 
26106f32e7eSjoerg   /// A shorthand version of getNoteTag that doesn't require you to accept
26206f32e7eSjoerg   /// the 'BugReporterContext' argument when you don't need it.
26306f32e7eSjoerg   ///
26406f32e7eSjoerg   /// @param Cb Callback only with 'BugReport &' parameter.
26506f32e7eSjoerg   /// @param IsPrunable Whether the note is prunable. It allows BugReporter
26606f32e7eSjoerg   ///        to omit the note from the report if it would make the displayed
26706f32e7eSjoerg   ///        bug path significantly shorter.
268*13fbcb42Sjoerg   const NoteTag
269*13fbcb42Sjoerg   *getNoteTag(std::function<std::string(PathSensitiveBugReport &)> &&Cb,
27006f32e7eSjoerg               bool IsPrunable = false) {
27106f32e7eSjoerg     return getNoteTag(
272*13fbcb42Sjoerg         [Cb](BugReporterContext &,
273*13fbcb42Sjoerg              PathSensitiveBugReport &BR) { return Cb(BR); },
27406f32e7eSjoerg         IsPrunable);
27506f32e7eSjoerg   }
27606f32e7eSjoerg 
27706f32e7eSjoerg   /// A shorthand version of getNoteTag that doesn't require you to accept
27806f32e7eSjoerg   /// the arguments when you don't need it.
27906f32e7eSjoerg   ///
28006f32e7eSjoerg   /// @param Cb Callback without parameters.
28106f32e7eSjoerg   /// @param IsPrunable Whether the note is prunable. It allows BugReporter
28206f32e7eSjoerg   ///        to omit the note from the report if it would make the displayed
28306f32e7eSjoerg   ///        bug path significantly shorter.
28406f32e7eSjoerg   const NoteTag *getNoteTag(std::function<std::string()> &&Cb,
28506f32e7eSjoerg                             bool IsPrunable = false) {
286*13fbcb42Sjoerg     return getNoteTag([Cb](BugReporterContext &,
287*13fbcb42Sjoerg                            PathSensitiveBugReport &) { return Cb(); },
28806f32e7eSjoerg                       IsPrunable);
28906f32e7eSjoerg   }
29006f32e7eSjoerg 
29106f32e7eSjoerg   /// A shorthand version of getNoteTag that accepts a plain note.
29206f32e7eSjoerg   ///
29306f32e7eSjoerg   /// @param Note The note.
29406f32e7eSjoerg   /// @param IsPrunable Whether the note is prunable. It allows BugReporter
29506f32e7eSjoerg   ///        to omit the note from the report if it would make the displayed
29606f32e7eSjoerg   ///        bug path significantly shorter.
29706f32e7eSjoerg   const NoteTag *getNoteTag(StringRef Note, bool IsPrunable = false) {
29806f32e7eSjoerg     return getNoteTag(
299*13fbcb42Sjoerg         [Note](BugReporterContext &,
300*13fbcb42Sjoerg                PathSensitiveBugReport &) { return std::string(Note); },
301*13fbcb42Sjoerg         IsPrunable);
302*13fbcb42Sjoerg   }
303*13fbcb42Sjoerg 
304*13fbcb42Sjoerg   /// A shorthand version of getNoteTag that accepts a lambda with stream for
305*13fbcb42Sjoerg   /// note.
306*13fbcb42Sjoerg   ///
307*13fbcb42Sjoerg   /// @param Cb Callback with 'BugReport &' and 'llvm::raw_ostream &'.
308*13fbcb42Sjoerg   /// @param IsPrunable Whether the note is prunable. It allows BugReporter
309*13fbcb42Sjoerg   ///        to omit the note from the report if it would make the displayed
310*13fbcb42Sjoerg   ///        bug path significantly shorter.
311*13fbcb42Sjoerg   const NoteTag *getNoteTag(
312*13fbcb42Sjoerg       std::function<void(PathSensitiveBugReport &BR, llvm::raw_ostream &OS)> &&Cb,
313*13fbcb42Sjoerg       bool IsPrunable = false) {
314*13fbcb42Sjoerg     return getNoteTag(
315*13fbcb42Sjoerg         [Cb](PathSensitiveBugReport &BR) -> std::string {
316*13fbcb42Sjoerg           llvm::SmallString<128> Str;
317*13fbcb42Sjoerg           llvm::raw_svector_ostream OS(Str);
318*13fbcb42Sjoerg           Cb(BR, OS);
319*13fbcb42Sjoerg           return std::string(OS.str());
320*13fbcb42Sjoerg         },
321*13fbcb42Sjoerg         IsPrunable);
32206f32e7eSjoerg   }
32306f32e7eSjoerg 
32406f32e7eSjoerg   /// Returns the word that should be used to refer to the declaration
32506f32e7eSjoerg   /// in the report.
32606f32e7eSjoerg   StringRef getDeclDescription(const Decl *D);
32706f32e7eSjoerg 
32806f32e7eSjoerg   /// Get the declaration of the called function (path-sensitive).
32906f32e7eSjoerg   const FunctionDecl *getCalleeDecl(const CallExpr *CE) const;
33006f32e7eSjoerg 
33106f32e7eSjoerg   /// Get the name of the called function (path-sensitive).
33206f32e7eSjoerg   StringRef getCalleeName(const FunctionDecl *FunDecl) const;
33306f32e7eSjoerg 
33406f32e7eSjoerg   /// Get the identifier of the called function (path-sensitive).
getCalleeIdentifier(const CallExpr * CE)33506f32e7eSjoerg   const IdentifierInfo *getCalleeIdentifier(const CallExpr *CE) const {
33606f32e7eSjoerg     const FunctionDecl *FunDecl = getCalleeDecl(CE);
33706f32e7eSjoerg     if (FunDecl)
33806f32e7eSjoerg       return FunDecl->getIdentifier();
33906f32e7eSjoerg     else
34006f32e7eSjoerg       return nullptr;
34106f32e7eSjoerg   }
34206f32e7eSjoerg 
34306f32e7eSjoerg   /// Get the name of the called function (path-sensitive).
getCalleeName(const CallExpr * CE)34406f32e7eSjoerg   StringRef getCalleeName(const CallExpr *CE) const {
34506f32e7eSjoerg     const FunctionDecl *FunDecl = getCalleeDecl(CE);
34606f32e7eSjoerg     return getCalleeName(FunDecl);
34706f32e7eSjoerg   }
34806f32e7eSjoerg 
34906f32e7eSjoerg   /// Returns true if the callee is an externally-visible function in the
35006f32e7eSjoerg   /// top-level namespace, such as \c malloc.
35106f32e7eSjoerg   ///
35206f32e7eSjoerg   /// If a name is provided, the function must additionally match the given
35306f32e7eSjoerg   /// name.
35406f32e7eSjoerg   ///
35506f32e7eSjoerg   /// Note that this deliberately excludes C++ library functions in the \c std
35606f32e7eSjoerg   /// namespace, but will include C library functions accessed through the
35706f32e7eSjoerg   /// \c std namespace. This also does not check if the function is declared
35806f32e7eSjoerg   /// as 'extern "C"', or if it uses C++ name mangling.
35906f32e7eSjoerg   static bool isCLibraryFunction(const FunctionDecl *FD,
36006f32e7eSjoerg                                  StringRef Name = StringRef());
36106f32e7eSjoerg 
36206f32e7eSjoerg   /// Depending on wither the location corresponds to a macro, return
36306f32e7eSjoerg   /// either the macro name or the token spelling.
36406f32e7eSjoerg   ///
36506f32e7eSjoerg   /// This could be useful when checkers' logic depends on whether a function
36606f32e7eSjoerg   /// is called with a given macro argument. For example:
36706f32e7eSjoerg   ///   s = socket(AF_INET,..)
36806f32e7eSjoerg   /// If AF_INET is a macro, the result should be treated as a source of taint.
36906f32e7eSjoerg   ///
37006f32e7eSjoerg   /// \sa clang::Lexer::getSpelling(), clang::Lexer::getImmediateMacroName().
37106f32e7eSjoerg   StringRef getMacroNameOrSpelling(SourceLocation &Loc);
37206f32e7eSjoerg 
37306f32e7eSjoerg private:
37406f32e7eSjoerg   ExplodedNode *addTransitionImpl(ProgramStateRef State,
37506f32e7eSjoerg                                  bool MarkAsSink,
37606f32e7eSjoerg                                  ExplodedNode *P = nullptr,
37706f32e7eSjoerg                                  const ProgramPointTag *Tag = nullptr) {
37806f32e7eSjoerg     // The analyzer may stop exploring if it sees a state it has previously
37906f32e7eSjoerg     // visited ("cache out"). The early return here is a defensive check to
38006f32e7eSjoerg     // prevent accidental caching out by checker API clients. Unless there is a
38106f32e7eSjoerg     // tag or the client checker has requested that the generated node be
38206f32e7eSjoerg     // marked as a sink, we assume that a client requesting a transition to a
38306f32e7eSjoerg     // state that is the same as the predecessor state has made a mistake. We
38406f32e7eSjoerg     // return the predecessor rather than cache out.
38506f32e7eSjoerg     //
38606f32e7eSjoerg     // TODO: We could potentially change the return to an assertion to alert
38706f32e7eSjoerg     // clients to their mistake, but several checkers (including
38806f32e7eSjoerg     // DereferenceChecker, CallAndMessageChecker, and DynamicTypePropagation)
38906f32e7eSjoerg     // rely upon the defensive behavior and would need to be updated.
39006f32e7eSjoerg     if (!State || (State == Pred->getState() && !Tag && !MarkAsSink))
39106f32e7eSjoerg       return Pred;
39206f32e7eSjoerg 
39306f32e7eSjoerg     Changed = true;
39406f32e7eSjoerg     const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
39506f32e7eSjoerg     if (!P)
39606f32e7eSjoerg       P = Pred;
39706f32e7eSjoerg 
39806f32e7eSjoerg     ExplodedNode *node;
39906f32e7eSjoerg     if (MarkAsSink)
40006f32e7eSjoerg       node = NB.generateSink(LocalLoc, State, P);
40106f32e7eSjoerg     else
40206f32e7eSjoerg       node = NB.generateNode(LocalLoc, State, P);
40306f32e7eSjoerg     return node;
40406f32e7eSjoerg   }
40506f32e7eSjoerg };
40606f32e7eSjoerg 
40706f32e7eSjoerg } // end GR namespace
40806f32e7eSjoerg 
40906f32e7eSjoerg } // end clang namespace
41006f32e7eSjoerg 
41106f32e7eSjoerg #endif
412