//===- Consumed.h -----------------------------------------------*- 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
 
//
 
//===----------------------------------------------------------------------===//
 
//
 
// A intra-procedural analysis for checking consumed properties.  This is based,
 
// in part, on research on linear types.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H
 
#define LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H
 
 
 
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
 
#include "clang/Analysis/CFG.h"
 
#include "clang/Basic/LLVM.h"
 
#include "clang/Basic/PartialDiagnostic.h"
 
#include "clang/Basic/SourceLocation.h"
 
#include "llvm/ADT/DenseMap.h"
 
#include "llvm/ADT/SmallVector.h"
 
#include "llvm/ADT/StringRef.h"
 
#include <list>
 
#include <memory>
 
#include <utility>
 
#include <vector>
 
 
 
namespace clang {
 
 
 
class AnalysisDeclContext;
 
class CXXBindTemporaryExpr;
 
class FunctionDecl;
 
class PostOrderCFGView;
 
class Stmt;
 
class VarDecl;
 
 
 
namespace consumed {
 
 
 
  class ConsumedStmtVisitor;
 
 
 
  enum ConsumedState {
 
    // No state information for the given variable.
 
    CS_None,
 
 
 
    CS_Unknown,
 
    CS_Unconsumed,
 
    CS_Consumed
 
  };
 
 
 
  using OptionalNotes = SmallVector<PartialDiagnosticAt, 1>;
 
  using DelayedDiag = std::pair<PartialDiagnosticAt, OptionalNotes>;
 
  using DiagList = std::list<DelayedDiag>;
 
 
 
  class ConsumedWarningsHandlerBase {
 
  public:
 
    virtual ~ConsumedWarningsHandlerBase();
 
 
 
    /// Emit the warnings and notes left by the analysis.
 
    virtual void emitDiagnostics() {}
 
 
 
    /// Warn that a variable's state doesn't match at the entry and exit
 
    /// of a loop.
 
    ///
 
    /// \param Loc -- The location of the end of the loop.
 
    ///
 
    /// \param VariableName -- The name of the variable that has a mismatched
 
    /// state.
 
    virtual void warnLoopStateMismatch(SourceLocation Loc,
 
                                       StringRef VariableName) {}
 
 
 
    /// Warn about parameter typestate mismatches upon return.
 
    ///
 
    /// \param Loc -- The SourceLocation of the return statement.
 
    ///
 
    /// \param ExpectedState -- The state the return value was expected to be
 
    /// in.
 
    ///
 
    /// \param ObservedState -- The state the return value was observed to be
 
    /// in.
 
    virtual void warnParamReturnTypestateMismatch(SourceLocation Loc,
 
                                                  StringRef VariableName,
 
                                                  StringRef ExpectedState,
 
                                                  StringRef ObservedState) {}
 
 
 
    // FIXME: Add documentation.
 
    virtual void warnParamTypestateMismatch(SourceLocation LOC,
 
                                            StringRef ExpectedState,
 
                                            StringRef ObservedState) {}
 
 
 
    // FIXME: This can be removed when the attr propagation fix for templated
 
    //        classes lands.
 
    /// Warn about return typestates set for unconsumable types.
 
    ///
 
    /// \param Loc -- The location of the attributes.
 
    ///
 
    /// \param TypeName -- The name of the unconsumable type.
 
    virtual void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
 
                                                        StringRef TypeName) {}
 
 
 
    /// Warn about return typestate mismatches.
 
    ///
 
    /// \param Loc -- The SourceLocation of the return statement.
 
    ///
 
    /// \param ExpectedState -- The state the return value was expected to be
 
    /// in.
 
    ///
 
    /// \param ObservedState -- The state the return value was observed to be
 
    /// in.
 
    virtual void warnReturnTypestateMismatch(SourceLocation Loc,
 
                                             StringRef ExpectedState,
 
                                             StringRef ObservedState) {}
 
 
 
    /// Warn about use-while-consumed errors.
 
    /// \param MethodName -- The name of the method that was incorrectly
 
    /// invoked.
 
    ///
 
    /// \param State -- The state the object was used in.
 
    ///
 
    /// \param Loc -- The SourceLocation of the method invocation.
 
    virtual void warnUseOfTempInInvalidState(StringRef MethodName,
 
                                             StringRef State,
 
                                             SourceLocation Loc) {}
 
 
 
    /// Warn about use-while-consumed errors.
 
    /// \param MethodName -- The name of the method that was incorrectly
 
    /// invoked.
 
    ///
 
    /// \param State -- The state the object was used in.
 
    ///
 
    /// \param VariableName -- The name of the variable that holds the unique
 
    /// value.
 
    ///
 
    /// \param Loc -- The SourceLocation of the method invocation.
 
    virtual void warnUseInInvalidState(StringRef MethodName,
 
                                       StringRef VariableName,
 
                                       StringRef State,
 
                                       SourceLocation Loc) {}
 
  };
 
 
 
  class ConsumedStateMap {
 
    using VarMapType = llvm::DenseMap<const VarDecl *, ConsumedState>;
 
    using TmpMapType =
 
        llvm::DenseMap<const CXXBindTemporaryExpr *, ConsumedState>;
 
 
 
  protected:
 
    bool Reachable = true;
 
    const Stmt *From = nullptr;
 
    VarMapType VarMap;
 
    TmpMapType TmpMap;
 
 
 
  public:
 
    ConsumedStateMap() = default;
 
    ConsumedStateMap(const ConsumedStateMap &Other)
 
        : Reachable(Other.Reachable), From(Other.From), VarMap(Other.VarMap) {}
 
 
 
    /// Warn if any of the parameters being tracked are not in the state
 
    /// they were declared to be in upon return from a function.
 
    void checkParamsForReturnTypestate(SourceLocation BlameLoc,
 
      ConsumedWarningsHandlerBase &WarningsHandler) const;
 
 
 
    /// Clear the TmpMap.
 
    void clearTemporaries();
 
 
 
    /// Get the consumed state of a given variable.
 
    ConsumedState getState(const VarDecl *Var) const;
 
 
 
    /// Get the consumed state of a given temporary value.
 
    ConsumedState getState(const CXXBindTemporaryExpr *Tmp) const;
 
 
 
    /// Merge this state map with another map.
 
    void intersect(const ConsumedStateMap &Other);
 
 
 
    void intersectAtLoopHead(const CFGBlock *LoopHead, const CFGBlock *LoopBack,
 
      const ConsumedStateMap *LoopBackStates,
 
      ConsumedWarningsHandlerBase &WarningsHandler);
 
 
 
    /// Return true if this block is reachable.
 
    bool isReachable() const { return Reachable; }
 
 
 
    /// Mark the block as unreachable.
 
    void markUnreachable();
 
 
 
    /// Set the source for a decision about the branching of states.
 
    /// \param Source -- The statement that was the origin of a branching
 
    /// decision.
 
    void setSource(const Stmt *Source) { this->From = Source; }
 
 
 
    /// Set the consumed state of a given variable.
 
    void setState(const VarDecl *Var, ConsumedState State);
 
 
 
    /// Set the consumed state of a given temporary value.
 
    void setState(const CXXBindTemporaryExpr *Tmp, ConsumedState State);
 
 
 
    /// Remove the temporary value from our state map.
 
    void remove(const CXXBindTemporaryExpr *Tmp);
 
 
 
    /// Tests to see if there is a mismatch in the states stored in two
 
    /// maps.
 
    ///
 
    /// \param Other -- The second map to compare against.
 
    bool operator!=(const ConsumedStateMap *Other) const;
 
  };
 
 
 
  class ConsumedBlockInfo {
 
    std::vector<std::unique_ptr<ConsumedStateMap>> StateMapsArray;
 
    std::vector<unsigned int> VisitOrder;
 
 
 
  public:
 
    ConsumedBlockInfo() = default;
 
 
 
    ConsumedBlockInfo(unsigned int NumBlocks, PostOrderCFGView *SortedGraph)
 
        : StateMapsArray(NumBlocks), VisitOrder(NumBlocks, 0) {
 
      unsigned int VisitOrderCounter = 0;
 
      for (const auto BI : *SortedGraph)
 
        VisitOrder[BI->getBlockID()] = VisitOrderCounter++;
 
    }
 
 
 
    bool allBackEdgesVisited(const CFGBlock *CurrBlock,
 
                             const CFGBlock *TargetBlock);
 
 
 
    void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap,
 
                 std::unique_ptr<ConsumedStateMap> &OwnedStateMap);
 
    void addInfo(const CFGBlock *Block,
 
                 std::unique_ptr<ConsumedStateMap> StateMap);
 
 
 
    ConsumedStateMap* borrowInfo(const CFGBlock *Block);
 
 
 
    void discardInfo(const CFGBlock *Block);
 
 
 
    std::unique_ptr<ConsumedStateMap> getInfo(const CFGBlock *Block);
 
 
 
    bool isBackEdge(const CFGBlock *From, const CFGBlock *To);
 
    bool isBackEdgeTarget(const CFGBlock *Block);
 
  };
 
 
 
  /// A class that handles the analysis of uniqueness violations.
 
  class ConsumedAnalyzer {
 
    ConsumedBlockInfo BlockInfo;
 
    std::unique_ptr<ConsumedStateMap> CurrStates;
 
 
 
    ConsumedState ExpectedReturnState;
 
 
 
    void determineExpectedReturnState(AnalysisDeclContext &AC,
 
                                      const FunctionDecl *D);
 
    bool splitState(const CFGBlock *CurrBlock,
 
                    const ConsumedStmtVisitor &Visitor);
 
 
 
  public:
 
    ConsumedWarningsHandlerBase &WarningsHandler;
 
 
 
    ConsumedAnalyzer(ConsumedWarningsHandlerBase &WarningsHandler)
 
        : WarningsHandler(WarningsHandler) {}
 
 
 
    ConsumedState getExpectedReturnState() const { return ExpectedReturnState; }
 
 
 
    /// Check a function's CFG for consumed violations.
 
    ///
 
    /// We traverse the blocks in the CFG, keeping track of the state of each
 
    /// value who's type has uniquness annotations.  If methods are invoked in
 
    /// the wrong state a warning is issued.  Each block in the CFG is traversed
 
    /// exactly once.
 
    void run(AnalysisDeclContext &AC);
 
  };
 
 
 
} // namespace consumed
 
 
 
} // namespace clang
 
 
 
#endif // LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H