<commit_before>//===- CallGraphSCCPass.cpp - Pass that operates BU on call graph ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the CallGraphSCCPass class, which is used for passes
// which are implemented as bottom-up traversals on the call graph.  Because
// there may be cycles in the call graph, passes of this type operate on the
// call-graph in SCC order: that is, they process function bottom-up, except for
// recursive functions, which they process all at once.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "cgscc-passmgr"
#include "llvm/CallGraphSCCPass.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/ADT/SCCIterator.h"
#include "llvm/PassManagers.h"
#include "llvm/Function.h"
#include "llvm/Support/Debug.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

//===----------------------------------------------------------------------===//
// CGPassManager
//
/// CGPassManager manages FPPassManagers and CalLGraphSCCPasses.

namespace {

class CGPassManager : public ModulePass, public PMDataManager {
public:
  static char ID;
  explicit CGPassManager(int Depth)
    : ModulePass(&ID), PMDataManager(Depth) { }

  /// run - Execute all of the passes scheduled for execution.  Keep track of
  /// whether any of the passes modifies the module, and if so, return true.
  bool runOnModule(Module &M);

  bool doInitialization(CallGraph &CG);
  bool doFinalization(CallGraph &CG);

  /// Pass Manager itself does not invalidate any analysis info.
  void getAnalysisUsage(AnalysisUsage &Info) const {
    // CGPassManager walks SCC and it needs CallGraph.
    Info.addRequired<CallGraph>();
    Info.setPreservesAll();
  }

  virtual const char *getPassName() const {
    return "CallGraph Pass Manager";
  }

  // Print passes managed by this manager
  void dumpPassStructure(unsigned Offset) {
    errs().indent(Offset*2) << "Call Graph SCC Pass Manager\n";
    for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
      Pass *P = getContainedPass(Index);
      P->dumpPassStructure(Offset + 1);
      dumpLastUses(P, Offset+1);
    }
  }

  Pass *getContainedPass(unsigned N) {
    assert(N < PassVector.size() && "Pass number out of range!");
    return static_cast<Pass *>(PassVector[N]);
  }

  virtual PassManagerType getPassManagerType() const {
    return PMT_CallGraphPassManager;
  }

private:
  bool RunPassOnSCC(Pass *P, std::vector<CallGraphNode*> &CurSCC,
                    CallGraph &CG, bool &CallGraphUpToDate);
  void RefreshCallGraph(std::vector<CallGraphNode*> &CurSCC, CallGraph &CG,
                        bool IsCheckingMode);
};

} // end anonymous namespace.

char CGPassManager::ID = 0;

bool CGPassManager::RunPassOnSCC(Pass *P, std::vector<CallGraphNode*> &CurSCC,
                                 CallGraph &CG, bool &CallGraphUpToDate) {
  bool Changed = false;
  if (CallGraphSCCPass *CGSP = dynamic_cast<CallGraphSCCPass*>(P)) {
    if (!CallGraphUpToDate) {
      RefreshCallGraph(CurSCC, CG, false);
      CallGraphUpToDate = true;
    }

    StartPassTimer(CGSP);
    Changed = CGSP->runOnSCC(CurSCC);
    StopPassTimer(CGSP);

    // After the CGSCCPass is done, when assertions are enabled, use
    // RefreshCallGraph to verify that the callgraph was correctly updated.
#ifndef NDEBUG
    if (Changed)
      RefreshCallGraph(CurSCC, CG, true);
#endif

    return Changed;
  }

  StartPassTimer(P);
  FPPassManager *FPP = dynamic_cast<FPPassManager *>(P);
  assert(FPP && "Invalid CGPassManager member");

  // Run pass P on all functions in the current SCC.
  for (unsigned i = 0, e = CurSCC.size(); i != e; ++i) {
    if (Function *F = CurSCC[i]->getFunction()) {
      dumpPassInfo(P, EXECUTION_MSG, ON_FUNCTION_MSG, F->getName());
      Changed |= FPP->runOnFunction(*F);
    }
  }
  StopPassTimer(P);

  // The function pass(es) modified the IR, they may have clobbered the
  // callgraph.
  if (Changed && CallGraphUpToDate) {
    DEBUG(errs() << "CGSCCPASSMGR: Pass Dirtied SCC: "
                 << P->getPassName() << '\n');
    CallGraphUpToDate = false;
  }
  return Changed;
}

/// RefreshCallGraph - Scan the functions in the specified CFG and resync the
/// callgraph with the call sites found in it.  This is used after
/// FunctionPasses have potentially munged the callgraph, and can be used after
/// CallGraphSCC passes to verify that they correctly updated the callgraph.
///
void CGPassManager::RefreshCallGraph(std::vector<CallGraphNode*> &CurSCC,
                                     CallGraph &CG, bool CheckingMode) {
  DenseMap<Value*, CallGraphNode*> CallSites;

  DEBUG(errs() << "CGSCCPASSMGR: Refreshing SCC with " << CurSCC.size()
               << " nodes:\n";
        for (unsigned i = 0, e = CurSCC.size(); i != e; ++i)
          CurSCC[i]->dump();
        );

  bool MadeChange = false;

  // Scan all functions in the SCC.
  for (unsigned sccidx = 0, e = CurSCC.size(); sccidx != e; ++sccidx) {
    CallGraphNode *CGN = CurSCC[sccidx];
    Function *F = CGN->getFunction();
    if (F == 0 || F->isDeclaration()) continue;

    // Walk the function body looking for call sites.  Sync up the call sites in
    // CGN with those actually in the function.

    // Get the set of call sites currently in the function.
    for (CallGraphNode::iterator I = CGN->begin(), E = CGN->end(); I != E; ){
      // If this call site is null, then the function pass deleted the call
      // entirely and the WeakVH nulled it out.
      if (I->first == 0 ||
          // If we've already seen this call site, then the FunctionPass RAUW'd
          // one call with another, which resulted in two "uses" in the edge
          // list of the same call.
          CallSites.count(I->first) ||

          // If the call edge is not from a call or invoke, then the function
          // pass RAUW'd a call with another value.  This can happen when
          // constant folding happens of well known functions etc.
          CallSite::get(I->first).getInstruction() == 0) {
        assert(!CheckingMode &&
               "CallGraphSCCPass did not update the CallGraph correctly!");

        // Just remove the edge from the set of callees.
        CGN->removeCallEdge(I);
        E = CGN->end();
        continue;
      }

      assert(!CallSites.count(I->first) &&
             "Call site occurs in node multiple times");
      CallSites.insert(std::make_pair(I->first, I->second));
      ++I;
    }

    // Loop over all of the instructions in the function, getting the callsites.
    for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
      for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
        CallSite CS = CallSite::get(I);
        if (!CS.getInstruction() || isa<DbgInfoIntrinsic>(I)) continue;

        // If this call site already existed in the callgraph, just verify it
        // matches up to expectations and remove it from CallSites.
        DenseMap<Value*, CallGraphNode*>::iterator ExistingIt =
          CallSites.find(CS.getInstruction());
        if (ExistingIt != CallSites.end()) {
          CallGraphNode *ExistingNode = ExistingIt->second;

          // Remove from CallSites since we have now seen it.
          CallSites.erase(ExistingIt);

          // Verify that the callee is right.
          if (ExistingNode->getFunction() == CS.getCalledFunction())
            continue;

          // If we are in checking mode, we are not allowed to actually mutate
          // the callgraph.  If this is a case where we can infer that the
          // callgraph is less precise than it could be (e.g. an indirect call
          // site could be turned direct), don't reject it in checking mode, and
          // don't tweak it to be more precise.
          if (CheckingMode && CS.getCalledFunction() &&
              ExistingNode->getFunction() == 0)
            continue;

          assert(!CheckingMode &&
                 "CallGraphSCCPass did not update the CallGraph correctly!");

          // If not, we either went from a direct call to indirect, indirect to
          // direct, or direct to different direct.
          CallGraphNode *CalleeNode;
          if (Function *Callee = CS.getCalledFunction())
            CalleeNode = CG.getOrInsertFunction(Callee);
          else
            CalleeNode = CG.getCallsExternalNode();

          // Update the edge target in CGN.
          for (CallGraphNode::iterator I = CGN->begin(); ; ++I) {
            assert(I != CGN->end() && "Didn't find call entry");
            if (I->first == CS.getInstruction()) {
              I->second = CalleeNode;
              break;
            }
          }
          MadeChange = true;
          continue;
        }

        assert(!CheckingMode &&
               "CallGraphSCCPass did not update the CallGraph correctly!");

        // If the call site didn't exist in the CGN yet, add it.  We assume that
        // newly introduced call sites won't be indirect.  This could be fixed
        // in the future.
        CallGraphNode *CalleeNode;
        if (Function *Callee = CS.getCalledFunction())
          CalleeNode = CG.getOrInsertFunction(Callee);
        else
          CalleeNode = CG.getCallsExternalNode();

        CGN->addCalledFunction(CS, CalleeNode);
        MadeChange = true;
      }

    // After scanning this function, if we still have entries in callsites, then
    // they are dangling pointers.  WeakVH should save us for this, so abort if
    // this happens.
    assert(CallSites.empty() && "Dangling pointers found in call sites map");

    // Periodically do an explicit clear to remove tombstones when processing
    // large scc's.
    if ((sccidx & 15) == 0)
      CallSites.clear();
  }

  DEBUG(if (MadeChange) {
          errs() << "CGSCCPASSMGR: Refreshed SCC is now:\n";
          for (unsigned i = 0, e = CurSCC.size(); i != e; ++i)
            CurSCC[i]->dump();
         } else {
           errs() << "CGSCCPASSMGR: SCC Refresh didn't change call graph.\n";
         }
        );
}

/// run - Execute all of the passes scheduled for execution.  Keep track of
/// whether any of the passes modifies the module, and if so, return true.
bool CGPassManager::runOnModule(Module &M) {
  CallGraph &CG = getAnalysis<CallGraph>();
  bool Changed = doInitialization(CG);

  std::vector<CallGraphNode*> CurSCC;

  // Walk the callgraph in bottom-up SCC order.
  for (scc_iterator<CallGraph*> CGI = scc_begin(&CG), E = scc_end(&CG);
       CGI != E;) {
    // Copy the current SCC and increment past it so that the pass can hack
    // on the SCC if it wants to without invalidating our iterator.
    CurSCC = *CGI;
    ++CGI;

    // CallGraphUpToDate - Keep track of whether the callgraph is known to be
    // up-to-date or not.  The CGSSC pass manager runs two types of passes:
    // CallGraphSCC Passes and other random function passes.  Because other
    // random function passes are not CallGraph aware, they may clobber the
    // call graph by introducing new calls or deleting other ones.  This flag
    // is set to false when we run a function pass so that we know to clean up
    // the callgraph when we need to run a CGSCCPass again.
    bool CallGraphUpToDate = true;

    // Run all passes on current SCC.
    for (unsigned PassNo = 0, e = getNumContainedPasses();
         PassNo != e; ++PassNo) {
      Pass *P = getContainedPass(PassNo);

      dumpPassInfo(P, EXECUTION_MSG, ON_CG_MSG, "");
      dumpRequiredSet(P);

      initializeAnalysisImpl(P);

      // Actually run this pass on the current SCC.
      Changed |= RunPassOnSCC(P, CurSCC, CG, CallGraphUpToDate);

      if (Changed)
        dumpPassInfo(P, MODIFICATION_MSG, ON_CG_MSG, "");
      dumpPreservedSet(P);

      verifyPreservedAnalysis(P);
      removeNotPreservedAnalysis(P);
      recordAvailableAnalysis(P);
      removeDeadPasses(P, "", ON_CG_MSG);
    }

    // If the callgraph was left out of date (because the last pass run was a
    // functionpass), refresh it before we move on to the next SCC.
    if (!CallGraphUpToDate)
      RefreshCallGraph(CurSCC, CG, false);
  }
  Changed |= doFinalization(CG);
  return Changed;
}

/// Initialize CG
bool CGPassManager::doInitialization(CallGraph &CG) {
  bool Changed = false;
  for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
    Pass *P = getContainedPass(Index);
    if (CallGraphSCCPass *CGSP = dynamic_cast<CallGraphSCCPass *>(P)) {
      Changed |= CGSP->doInitialization(CG);
    } else {
      FPPassManager *FP = dynamic_cast<FPPassManager *>(P);
      assert (FP && "Invalid CGPassManager member");
      Changed |= FP->doInitialization(CG.getModule());
    }
  }
  return Changed;
}

/// Finalize CG
bool CGPassManager::doFinalization(CallGraph &CG) {
  bool Changed = false;
  for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
    Pass *P = getContainedPass(Index);
    if (CallGraphSCCPass *CGSP = dynamic_cast<CallGraphSCCPass *>(P)) {
      Changed |= CGSP->doFinalization(CG);
    } else {
      FPPassManager *FP = dynamic_cast<FPPassManager *>(P);
      assert (FP && "Invalid CGPassManager member");
      Changed |= FP->doFinalization(CG.getModule());
    }
  }
  return Changed;
}

/// Assign pass manager to manage this pass.
void CallGraphSCCPass::assignPassManager(PMStack &PMS,
                                         PassManagerType PreferredType) {
  // Find CGPassManager
  while (!PMS.empty() &&
         PMS.top()->getPassManagerType() > PMT_CallGraphPassManager)
    PMS.pop();

  assert (!PMS.empty() && "Unable to handle Call Graph Pass");
  CGPassManager *CGP = dynamic_cast<CGPassManager *>(PMS.top());

  // Create new Call Graph SCC Pass Manager if it does not exist.
  if (!CGP) {

    assert (!PMS.empty() && "Unable to create Call Graph Pass Manager");
    PMDataManager *PMD = PMS.top();

    // [1] Create new Call Graph Pass Manager
    CGP = new CGPassManager(PMD->getDepth() + 1);

    // [2] Set up new manager's top level manager
    PMTopLevelManager *TPM = PMD->getTopLevelManager();
    TPM->addIndirectPassManager(CGP);

    // [3] Assign manager to manage this new manager. This may create
    // and push new managers into PMS
    Pass *P = dynamic_cast<Pass *>(CGP);
    TPM->schedulePass(P);

    // [4] Push new manager into PMS
    PMS.push(CGP);
  }

  CGP->add(this);
}

/// getAnalysisUsage - For this class, we declare that we require and preserve
/// the call graph.  If the derived class implements this method, it should
/// always explicitly call the implementation here.
void CallGraphSCCPass::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<CallGraph>();
  AU.addPreserved<CallGraph>();
}
<commit_msg>Complicate Chris's simplification, avoiding complaints about singular iterators when building with expensive checks turned on.<commit_after>//===- CallGraphSCCPass.cpp - Pass that operates BU on call graph ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the CallGraphSCCPass class, which is used for passes
// which are implemented as bottom-up traversals on the call graph.  Because
// there may be cycles in the call graph, passes of this type operate on the
// call-graph in SCC order: that is, they process function bottom-up, except for
// recursive functions, which they process all at once.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "cgscc-passmgr"
#include "llvm/CallGraphSCCPass.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/ADT/SCCIterator.h"
#include "llvm/PassManagers.h"
#include "llvm/Function.h"
#include "llvm/Support/Debug.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

//===----------------------------------------------------------------------===//
// CGPassManager
//
/// CGPassManager manages FPPassManagers and CalLGraphSCCPasses.

namespace {

class CGPassManager : public ModulePass, public PMDataManager {
public:
  static char ID;
  explicit CGPassManager(int Depth)
    : ModulePass(&ID), PMDataManager(Depth) { }

  /// run - Execute all of the passes scheduled for execution.  Keep track of
  /// whether any of the passes modifies the module, and if so, return true.
  bool runOnModule(Module &M);

  bool doInitialization(CallGraph &CG);
  bool doFinalization(CallGraph &CG);

  /// Pass Manager itself does not invalidate any analysis info.
  void getAnalysisUsage(AnalysisUsage &Info) const {
    // CGPassManager walks SCC and it needs CallGraph.
    Info.addRequired<CallGraph>();
    Info.setPreservesAll();
  }

  virtual const char *getPassName() const {
    return "CallGraph Pass Manager";
  }

  // Print passes managed by this manager
  void dumpPassStructure(unsigned Offset) {
    errs().indent(Offset*2) << "Call Graph SCC Pass Manager\n";
    for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
      Pass *P = getContainedPass(Index);
      P->dumpPassStructure(Offset + 1);
      dumpLastUses(P, Offset+1);
    }
  }

  Pass *getContainedPass(unsigned N) {
    assert(N < PassVector.size() && "Pass number out of range!");
    return static_cast<Pass *>(PassVector[N]);
  }

  virtual PassManagerType getPassManagerType() const {
    return PMT_CallGraphPassManager;
  }

private:
  bool RunPassOnSCC(Pass *P, std::vector<CallGraphNode*> &CurSCC,
                    CallGraph &CG, bool &CallGraphUpToDate);
  void RefreshCallGraph(std::vector<CallGraphNode*> &CurSCC, CallGraph &CG,
                        bool IsCheckingMode);
};

} // end anonymous namespace.

char CGPassManager::ID = 0;

bool CGPassManager::RunPassOnSCC(Pass *P, std::vector<CallGraphNode*> &CurSCC,
                                 CallGraph &CG, bool &CallGraphUpToDate) {
  bool Changed = false;
  if (CallGraphSCCPass *CGSP = dynamic_cast<CallGraphSCCPass*>(P)) {
    if (!CallGraphUpToDate) {
      RefreshCallGraph(CurSCC, CG, false);
      CallGraphUpToDate = true;
    }

    StartPassTimer(CGSP);
    Changed = CGSP->runOnSCC(CurSCC);
    StopPassTimer(CGSP);

    // After the CGSCCPass is done, when assertions are enabled, use
    // RefreshCallGraph to verify that the callgraph was correctly updated.
#ifndef NDEBUG
    if (Changed)
      RefreshCallGraph(CurSCC, CG, true);
#endif

    return Changed;
  }

  StartPassTimer(P);
  FPPassManager *FPP = dynamic_cast<FPPassManager *>(P);
  assert(FPP && "Invalid CGPassManager member");

  // Run pass P on all functions in the current SCC.
  for (unsigned i = 0, e = CurSCC.size(); i != e; ++i) {
    if (Function *F = CurSCC[i]->getFunction()) {
      dumpPassInfo(P, EXECUTION_MSG, ON_FUNCTION_MSG, F->getName());
      Changed |= FPP->runOnFunction(*F);
    }
  }
  StopPassTimer(P);

  // The function pass(es) modified the IR, they may have clobbered the
  // callgraph.
  if (Changed && CallGraphUpToDate) {
    DEBUG(errs() << "CGSCCPASSMGR: Pass Dirtied SCC: "
                 << P->getPassName() << '\n');
    CallGraphUpToDate = false;
  }
  return Changed;
}

/// RefreshCallGraph - Scan the functions in the specified CFG and resync the
/// callgraph with the call sites found in it.  This is used after
/// FunctionPasses have potentially munged the callgraph, and can be used after
/// CallGraphSCC passes to verify that they correctly updated the callgraph.
///
void CGPassManager::RefreshCallGraph(std::vector<CallGraphNode*> &CurSCC,
                                     CallGraph &CG, bool CheckingMode) {
  DenseMap<Value*, CallGraphNode*> CallSites;

  DEBUG(errs() << "CGSCCPASSMGR: Refreshing SCC with " << CurSCC.size()
               << " nodes:\n";
        for (unsigned i = 0, e = CurSCC.size(); i != e; ++i)
          CurSCC[i]->dump();
        );

  bool MadeChange = false;

  // Scan all functions in the SCC.
  for (unsigned sccidx = 0, e = CurSCC.size(); sccidx != e; ++sccidx) {
    CallGraphNode *CGN = CurSCC[sccidx];
    Function *F = CGN->getFunction();
    if (F == 0 || F->isDeclaration()) continue;

    // Walk the function body looking for call sites.  Sync up the call sites in
    // CGN with those actually in the function.

    // Get the set of call sites currently in the function.
    for (CallGraphNode::iterator I = CGN->begin(), E = CGN->end(); I != E; ) {
      // If this call site is null, then the function pass deleted the call
      // entirely and the WeakVH nulled it out.
      if (I->first == 0 ||
          // If we've already seen this call site, then the FunctionPass RAUW'd
          // one call with another, which resulted in two "uses" in the edge
          // list of the same call.
          CallSites.count(I->first) ||

          // If the call edge is not from a call or invoke, then the function
          // pass RAUW'd a call with another value.  This can happen when
          // constant folding happens of well known functions etc.
          CallSite::get(I->first).getInstruction() == 0) {
        assert(!CheckingMode &&
               "CallGraphSCCPass did not update the CallGraph correctly!");

        // Just remove the edge from the set of callees.
        bool wasLast = I + 1 == E;
        CGN->removeCallEdge(I);
        if (wasLast)
          // I is now a singular iterator, do not compare with E.
          break;
        E = CGN->end();
        continue;
      }

      assert(!CallSites.count(I->first) &&
             "Call site occurs in node multiple times");
      CallSites.insert(std::make_pair(I->first, I->second));
      ++I;
    }

    // Loop over all of the instructions in the function, getting the callsites.
    for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
      for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
        CallSite CS = CallSite::get(I);
        if (!CS.getInstruction() || isa<DbgInfoIntrinsic>(I)) continue;

        // If this call site already existed in the callgraph, just verify it
        // matches up to expectations and remove it from CallSites.
        DenseMap<Value*, CallGraphNode*>::iterator ExistingIt =
          CallSites.find(CS.getInstruction());
        if (ExistingIt != CallSites.end()) {
          CallGraphNode *ExistingNode = ExistingIt->second;

          // Remove from CallSites since we have now seen it.
          CallSites.erase(ExistingIt);

          // Verify that the callee is right.
          if (ExistingNode->getFunction() == CS.getCalledFunction())
            continue;

          // If we are in checking mode, we are not allowed to actually mutate
          // the callgraph.  If this is a case where we can infer that the
          // callgraph is less precise than it could be (e.g. an indirect call
          // site could be turned direct), don't reject it in checking mode, and
          // don't tweak it to be more precise.
          if (CheckingMode && CS.getCalledFunction() &&
              ExistingNode->getFunction() == 0)
            continue;

          assert(!CheckingMode &&
                 "CallGraphSCCPass did not update the CallGraph correctly!");

          // If not, we either went from a direct call to indirect, indirect to
          // direct, or direct to different direct.
          CallGraphNode *CalleeNode;
          if (Function *Callee = CS.getCalledFunction())
            CalleeNode = CG.getOrInsertFunction(Callee);
          else
            CalleeNode = CG.getCallsExternalNode();

          // Update the edge target in CGN.
          for (CallGraphNode::iterator I = CGN->begin(); ; ++I) {
            assert(I != CGN->end() && "Didn't find call entry");
            if (I->first == CS.getInstruction()) {
              I->second = CalleeNode;
              break;
            }
          }
          MadeChange = true;
          continue;
        }

        assert(!CheckingMode &&
               "CallGraphSCCPass did not update the CallGraph correctly!");

        // If the call site didn't exist in the CGN yet, add it.  We assume that
        // newly introduced call sites won't be indirect.  This could be fixed
        // in the future.
        CallGraphNode *CalleeNode;
        if (Function *Callee = CS.getCalledFunction())
          CalleeNode = CG.getOrInsertFunction(Callee);
        else
          CalleeNode = CG.getCallsExternalNode();

        CGN->addCalledFunction(CS, CalleeNode);
        MadeChange = true;
      }

    // After scanning this function, if we still have entries in callsites, then
    // they are dangling pointers.  WeakVH should save us for this, so abort if
    // this happens.
    assert(CallSites.empty() && "Dangling pointers found in call sites map");

    // Periodically do an explicit clear to remove tombstones when processing
    // large scc's.
    if ((sccidx & 15) == 0)
      CallSites.clear();
  }

  DEBUG(if (MadeChange) {
          errs() << "CGSCCPASSMGR: Refreshed SCC is now:\n";
          for (unsigned i = 0, e = CurSCC.size(); i != e; ++i)
            CurSCC[i]->dump();
         } else {
           errs() << "CGSCCPASSMGR: SCC Refresh didn't change call graph.\n";
         }
        );
}

/// run - Execute all of the passes scheduled for execution.  Keep track of
/// whether any of the passes modifies the module, and if so, return true.
bool CGPassManager::runOnModule(Module &M) {
  CallGraph &CG = getAnalysis<CallGraph>();
  bool Changed = doInitialization(CG);

  std::vector<CallGraphNode*> CurSCC;

  // Walk the callgraph in bottom-up SCC order.
  for (scc_iterator<CallGraph*> CGI = scc_begin(&CG), E = scc_end(&CG);
       CGI != E;) {
    // Copy the current SCC and increment past it so that the pass can hack
    // on the SCC if it wants to without invalidating our iterator.
    CurSCC = *CGI;
    ++CGI;

    // CallGraphUpToDate - Keep track of whether the callgraph is known to be
    // up-to-date or not.  The CGSSC pass manager runs two types of passes:
    // CallGraphSCC Passes and other random function passes.  Because other
    // random function passes are not CallGraph aware, they may clobber the
    // call graph by introducing new calls or deleting other ones.  This flag
    // is set to false when we run a function pass so that we know to clean up
    // the callgraph when we need to run a CGSCCPass again.
    bool CallGraphUpToDate = true;

    // Run all passes on current SCC.
    for (unsigned PassNo = 0, e = getNumContainedPasses();
         PassNo != e; ++PassNo) {
      Pass *P = getContainedPass(PassNo);

      dumpPassInfo(P, EXECUTION_MSG, ON_CG_MSG, "");
      dumpRequiredSet(P);

      initializeAnalysisImpl(P);

      // Actually run this pass on the current SCC.
      Changed |= RunPassOnSCC(P, CurSCC, CG, CallGraphUpToDate);

      if (Changed)
        dumpPassInfo(P, MODIFICATION_MSG, ON_CG_MSG, "");
      dumpPreservedSet(P);

      verifyPreservedAnalysis(P);
      removeNotPreservedAnalysis(P);
      recordAvailableAnalysis(P);
      removeDeadPasses(P, "", ON_CG_MSG);
    }

    // If the callgraph was left out of date (because the last pass run was a
    // functionpass), refresh it before we move on to the next SCC.
    if (!CallGraphUpToDate)
      RefreshCallGraph(CurSCC, CG, false);
  }
  Changed |= doFinalization(CG);
  return Changed;
}

/// Initialize CG
bool CGPassManager::doInitialization(CallGraph &CG) {
  bool Changed = false;
  for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
    Pass *P = getContainedPass(Index);
    if (CallGraphSCCPass *CGSP = dynamic_cast<CallGraphSCCPass *>(P)) {
      Changed |= CGSP->doInitialization(CG);
    } else {
      FPPassManager *FP = dynamic_cast<FPPassManager *>(P);
      assert (FP && "Invalid CGPassManager member");
      Changed |= FP->doInitialization(CG.getModule());
    }
  }
  return Changed;
}

/// Finalize CG
bool CGPassManager::doFinalization(CallGraph &CG) {
  bool Changed = false;
  for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
    Pass *P = getContainedPass(Index);
    if (CallGraphSCCPass *CGSP = dynamic_cast<CallGraphSCCPass *>(P)) {
      Changed |= CGSP->doFinalization(CG);
    } else {
      FPPassManager *FP = dynamic_cast<FPPassManager *>(P);
      assert (FP && "Invalid CGPassManager member");
      Changed |= FP->doFinalization(CG.getModule());
    }
  }
  return Changed;
}

/// Assign pass manager to manage this pass.
void CallGraphSCCPass::assignPassManager(PMStack &PMS,
                                         PassManagerType PreferredType) {
  // Find CGPassManager
  while (!PMS.empty() &&
         PMS.top()->getPassManagerType() > PMT_CallGraphPassManager)
    PMS.pop();

  assert (!PMS.empty() && "Unable to handle Call Graph Pass");
  CGPassManager *CGP = dynamic_cast<CGPassManager *>(PMS.top());

  // Create new Call Graph SCC Pass Manager if it does not exist.
  if (!CGP) {

    assert (!PMS.empty() && "Unable to create Call Graph Pass Manager");
    PMDataManager *PMD = PMS.top();

    // [1] Create new Call Graph Pass Manager
    CGP = new CGPassManager(PMD->getDepth() + 1);

    // [2] Set up new manager's top level manager
    PMTopLevelManager *TPM = PMD->getTopLevelManager();
    TPM->addIndirectPassManager(CGP);

    // [3] Assign manager to manage this new manager. This may create
    // and push new managers into PMS
    Pass *P = dynamic_cast<Pass *>(CGP);
    TPM->schedulePass(P);

    // [4] Push new manager into PMS
    PMS.push(CGP);
  }

  CGP->add(this);
}

/// getAnalysisUsage - For this class, we declare that we require and preserve
/// the call graph.  If the derived class implements this method, it should
/// always explicitly call the implementation here.
void CallGraphSCCPass::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<CallGraph>();
  AU.addPreserved<CallGraph>();
}
<|endoftext|>


<commit_before>//===--- LogDiagnosticPrinter.cpp - Log Diagnostic Printer ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/LogDiagnosticPrinter.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;

LogDiagnosticPrinter::LogDiagnosticPrinter(llvm::raw_ostream &os,
                                           const DiagnosticOptions &diags,
                                           bool _OwnsOutputStream)
  : OS(os), LangOpts(0), DiagOpts(&diags),
    OwnsOutputStream(_OwnsOutputStream) {
}

LogDiagnosticPrinter::~LogDiagnosticPrinter() {
  if (OwnsOutputStream)
    delete &OS;
}

static llvm::StringRef getLevelName(Diagnostic::Level Level) {
  switch (Level) {
  default:
    return "<unknown>";
  case Diagnostic::Ignored: return "ignored";
  case Diagnostic::Note:    return "note";
  case Diagnostic::Warning: return "warning";
  case Diagnostic::Error:   return "error";
  case Diagnostic::Fatal:   return "fatal error";
  }
}

void LogDiagnosticPrinter::EndSourceFile() {
  // We emit all the diagnostics in EndSourceFile. However, we don't emit any
  // entry if no diagnostics were present.
  //
  // Note that DiagnosticClient has no "end-of-compilation" callback, so we will
  // miss any diagnostics which are emitted after and outside the translation
  // unit processing.
  if (Entries.empty())
    return;

  // Write to a temporary string to ensure atomic write of diagnostic object.
  llvm::SmallString<512> Msg;
  llvm::raw_svector_ostream OS(Msg);

  OS << "{\n";
  // FIXME: Output main translation unit file name.
  // FIXME: Include the invocation, if dwarf-debug-flags is available.
  OS << "  \"diagnostics\" : [\n";
  for (unsigned i = 0, e = Entries.size(); i != e; ++i) {
    DiagEntry &DE = Entries[i];

    OS << "    {\n";
    OS << "      \"filename\" : \"" << DE.Filename << "\",\n";
    OS << "      \"line\" : " << DE.Line << ",\n";
    OS << "      \"column\" : " << DE.Column << ",\n";
    OS << "      \"message\" : \"" << DE.Message << "\",\n";
    OS << "      \"level\" : \"" << getLevelName(DE.DiagnosticLevel) << "\"\n";
    OS << "    }" << ((i + 1 != e) ? "," : "") << '\n';
  }
  OS << "  ]\n";
  OS << "},\n";

  this->OS << OS.str();
}

void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
                                            const DiagnosticInfo &Info) {
  // Default implementation (Warnings/errors count).
  DiagnosticClient::HandleDiagnostic(Level, Info);

  // Create the diag entry.
  DiagEntry DE;
  DE.DiagnosticID = Info.getID();
  DE.DiagnosticLevel = Level;

  // Format the message.
  llvm::SmallString<100> MessageStr;
  Info.FormatDiagnostic(MessageStr);
  DE.Message = MessageStr.str();

  // Set the location information.
  DE.Filename = "";
  DE.Line = DE.Column = 0;
  if (Info.getLocation().isValid()) {
    const SourceManager &SM = Info.getSourceManager();
    PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());

    if (PLoc.isInvalid()) {
      // At least print the file name if available:
      FileID FID = SM.getFileID(Info.getLocation());
      if (!FID.isInvalid()) {
        const FileEntry *FE = SM.getFileEntryForID(FID);
        if (FE && FE->getName())
          DE.Filename = FE->getName();
      }
    } else {
      DE.Filename = PLoc.getFilename();
      DE.Line = PLoc.getLine();
      DE.Column = PLoc.getColumn();
    }
  }

  // Record the diagnostic entry.
  Entries.push_back(DE);
}
<commit_msg>Fronted/CC_LOG_DIAGNOSTICS: Tweak output form to be plist chunks, and don't output missing data.<commit_after>//===--- LogDiagnosticPrinter.cpp - Log Diagnostic Printer ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/LogDiagnosticPrinter.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;

LogDiagnosticPrinter::LogDiagnosticPrinter(llvm::raw_ostream &os,
                                           const DiagnosticOptions &diags,
                                           bool _OwnsOutputStream)
  : OS(os), LangOpts(0), DiagOpts(&diags),
    OwnsOutputStream(_OwnsOutputStream) {
}

LogDiagnosticPrinter::~LogDiagnosticPrinter() {
  if (OwnsOutputStream)
    delete &OS;
}

static llvm::StringRef getLevelName(Diagnostic::Level Level) {
  switch (Level) {
  default:
    return "<unknown>";
  case Diagnostic::Ignored: return "ignored";
  case Diagnostic::Note:    return "note";
  case Diagnostic::Warning: return "warning";
  case Diagnostic::Error:   return "error";
  case Diagnostic::Fatal:   return "fatal error";
  }
}

void LogDiagnosticPrinter::EndSourceFile() {
  // We emit all the diagnostics in EndSourceFile. However, we don't emit any
  // entry if no diagnostics were present.
  //
  // Note that DiagnosticClient has no "end-of-compilation" callback, so we will
  // miss any diagnostics which are emitted after and outside the translation
  // unit processing.
  if (Entries.empty())
    return;

  // Write to a temporary string to ensure atomic write of diagnostic object.
  llvm::SmallString<512> Msg;
  llvm::raw_svector_ostream OS(Msg);

  OS << "<dict>\n";
  // FIXME: Output main translation unit file name.
  // FIXME: Include the invocation, if dwarf-debug-flags is available.
  OS << "  <key>diagnostics</key>\n";
  OS << "  <array>\n";
  for (unsigned i = 0, e = Entries.size(); i != e; ++i) {
    DiagEntry &DE = Entries[i];

    OS << "    <dict>\n";
    OS << "      <key>level</key>\n"
       << "      <string>" << getLevelName(DE.DiagnosticLevel) << "</string>\n";
    if (!DE.Filename.empty()) {
      OS << "      <key>filename</key>\n"
         << "      <string>" << DE.Filename << "</string>\n";
    }
    if (DE.Line != 0) {
      OS << "      <key>line</key>\n"
         << "      <integer>" << DE.Line << "</integer>\n";
    }
    if (DE.Column != 0) {
      OS << "      <key>column</key>\n"
         << "      <integer>" << DE.Column << "</integer>\n";
    }
    if (!DE.Message.empty()) {
      OS << "      <key>message</key>\n"
         << "      <string>" << DE.Message << "</string>\n";
    }
    OS << "    </dict>\n";
  }
  OS << "  </array>\n";
  OS << "</dict>\n";

  this->OS << OS.str();
}

void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
                                            const DiagnosticInfo &Info) {
  // Default implementation (Warnings/errors count).
  DiagnosticClient::HandleDiagnostic(Level, Info);

  // Create the diag entry.
  DiagEntry DE;
  DE.DiagnosticID = Info.getID();
  DE.DiagnosticLevel = Level;

  // Format the message.
  llvm::SmallString<100> MessageStr;
  Info.FormatDiagnostic(MessageStr);
  DE.Message = MessageStr.str();

  // Set the location information.
  DE.Filename = "";
  DE.Line = DE.Column = 0;
  if (Info.getLocation().isValid()) {
    const SourceManager &SM = Info.getSourceManager();
    PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());

    if (PLoc.isInvalid()) {
      // At least print the file name if available:
      FileID FID = SM.getFileID(Info.getLocation());
      if (!FID.isInvalid()) {
        const FileEntry *FE = SM.getFileEntryForID(FID);
        if (FE && FE->getName())
          DE.Filename = FE->getName();
      }
    } else {
      DE.Filename = PLoc.getFilename();
      DE.Line = PLoc.getLine();
      DE.Column = PLoc.getColumn();
    }
  }

  // Record the diagnostic entry.
  Entries.push_back(DE);
}
<|endoftext|>


<commit_before>//=== Taint.cpp - Taint tracking and basic propagation rules. ------*- 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
//
//===----------------------------------------------------------------------===//
//
// Defines basic, non-domain-specific mechanisms for tracking tainted values.
//
//===----------------------------------------------------------------------===//

#include "Taint.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"

using namespace clang;
using namespace ento;
using namespace taint;

// Fully tainted symbols.
REGISTER_MAP_WITH_PROGRAMSTATE(TaintMap, SymbolRef, TaintTagType)

// Partially tainted symbols.
REGISTER_MAP_FACTORY_WITH_PROGRAMSTATE(TaintedSubRegions, const SubRegion *,
                                       TaintTagType);
REGISTER_MAP_WITH_PROGRAMSTATE(DerivedSymTaint, SymbolRef, TaintedSubRegions)

void taint::printTaint(ProgramStateRef State, raw_ostream &Out, const char *NL,
                       const char *Sep) {
  TaintMapTy TM = State->get<TaintMap>();

  if (!TM.isEmpty())
    Out << "Tainted symbols:" << NL;

  for (const auto &I : TM)
    Out << I.first << " : " << I.second << NL;
}

void dumpTaint(ProgramStateRef State) {
  printTaint(State, llvm::errs());
}

ProgramStateRef taint::addTaint(ProgramStateRef State, const Stmt *S,
                                const LocationContext *LCtx,
                                TaintTagType Kind) {
  return addTaint(State, State->getSVal(S, LCtx), Kind);
}

ProgramStateRef taint::addTaint(ProgramStateRef State, SVal V,
                                TaintTagType Kind) {
  SymbolRef Sym = V.getAsSymbol();
  if (Sym)
    return addTaint(State, Sym, Kind);

  // If the SVal represents a structure, try to mass-taint all values within the
  // structure. For now it only works efficiently on lazy compound values that
  // were conjured during a conservative evaluation of a function - either as
  // return values of functions that return structures or arrays by value, or as
  // values of structures or arrays passed into the function by reference,
  // directly or through pointer aliasing. Such lazy compound values are
  // characterized by having exactly one binding in their captured store within
  // their parent region, which is a conjured symbol default-bound to the base
  // region of the parent region.
  if (auto LCV = V.getAs<nonloc::LazyCompoundVal>()) {
    if (Optional<SVal> binding =
            State->getStateManager().getStoreManager()
                                    .getDefaultBinding(*LCV)) {
      if (SymbolRef Sym = binding->getAsSymbol())
        return addPartialTaint(State, Sym, LCV->getRegion(), Kind);
    }
  }

  const MemRegion *R = V.getAsRegion();
  return addTaint(State, R, Kind);
}

ProgramStateRef taint::addTaint(ProgramStateRef State, const MemRegion *R,
                                TaintTagType Kind) {
  if (const SymbolicRegion *SR = dyn_cast_or_null<SymbolicRegion>(R))
    return addTaint(State, SR->getSymbol(), Kind);
  return State;
}

ProgramStateRef taint::addTaint(ProgramStateRef State, SymbolRef Sym,
                                TaintTagType Kind) {
  // If this is a symbol cast, remove the cast before adding the taint. Taint
  // is cast agnostic.
  while (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym))
    Sym = SC->getOperand();

  ProgramStateRef NewState = State->set<TaintMap>(Sym, Kind);
  assert(NewState);
  return NewState;
}

ProgramStateRef taint::addPartialTaint(ProgramStateRef State,
                                       SymbolRef ParentSym,
                                       const SubRegion *SubRegion,
                                       TaintTagType Kind) {
  // Ignore partial taint if the entire parent symbol is already tainted.
  if (const TaintTagType *T = State->get<TaintMap>(ParentSym))
    if (*T == Kind)
      return State;

  // Partial taint applies if only a portion of the symbol is tainted.
  if (SubRegion == SubRegion->getBaseRegion())
    return addTaint(State, ParentSym, Kind);

  const TaintedSubRegions *SavedRegs = State->get<DerivedSymTaint>(ParentSym);
  TaintedSubRegions::Factory &F = State->get_context<TaintedSubRegions>();
  TaintedSubRegions Regs = SavedRegs ? *SavedRegs : F.getEmptyMap();

  Regs = F.add(Regs, SubRegion, Kind);
  ProgramStateRef NewState = State->set<DerivedSymTaint>(ParentSym, Regs);
  assert(NewState);
  return NewState;
}

bool taint::isTainted(ProgramStateRef State, const Stmt *S,
                      const LocationContext *LCtx, TaintTagType Kind) {
  SVal val = State->getSVal(S, LCtx);
  return isTainted(State, val, Kind);
}

bool taint::isTainted(ProgramStateRef State, SVal V, TaintTagType Kind) {
  if (const SymExpr *Sym = V.getAsSymExpr())
    return isTainted(State, Sym, Kind);
  if (const MemRegion *Reg = V.getAsRegion())
    return isTainted(State, Reg, Kind);
  return false;
}

bool taint::isTainted(ProgramStateRef State, const MemRegion *Reg,
                      TaintTagType K) {
  if (!Reg)
    return false;

  // Element region (array element) is tainted if either the base or the offset
  // are tainted.
  if (const ElementRegion *ER = dyn_cast<ElementRegion>(Reg))
    return isTainted(State, ER->getSuperRegion(), K) ||
           isTainted(State, ER->getIndex(), K);

  if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg))
    return isTainted(State, SR->getSymbol(), K);

  if (const SubRegion *ER = dyn_cast<SubRegion>(Reg))
    return isTainted(State, ER->getSuperRegion(), K);

  return false;
}

bool taint::isTainted(ProgramStateRef State, SymbolRef Sym, TaintTagType Kind) {
  if (!Sym)
    return false;

  // Traverse all the symbols this symbol depends on to see if any are tainted.
  for (SymExpr::symbol_iterator SI = Sym->symbol_begin(),
                                SE = Sym->symbol_end(); SI != SE; ++SI) {
    if (!isa<SymbolData>(*SI))
      continue;

    if (const TaintTagType *Tag = State->get<TaintMap>(*SI)) {
      if (*Tag == Kind)
        return true;
    }

    if (const auto *SD = dyn_cast<SymbolDerived>(*SI)) {
      // If this is a SymbolDerived with a tainted parent, it's also tainted.
      if (isTainted(State, SD->getParentSymbol(), Kind))
        return true;

      // If this is a SymbolDerived with the same parent symbol as another
      // tainted SymbolDerived and a region that's a sub-region of that tainted
      // symbol, it's also tainted.
      if (const TaintedSubRegions *Regs =
              State->get<DerivedSymTaint>(SD->getParentSymbol())) {
        const TypedValueRegion *R = SD->getRegion();
        for (auto I : *Regs) {
          // FIXME: The logic to identify tainted regions could be more
          // complete. For example, this would not currently identify
          // overlapping fields in a union as tainted. To identify this we can
          // check for overlapping/nested byte offsets.
          if (Kind == I.second && R->isSubRegionOf(I.first))
            return true;
        }
      }
    }

    // If memory region is tainted, data is also tainted.
    if (const auto *SRV = dyn_cast<SymbolRegionValue>(*SI)) {
      if (isTainted(State, SRV->getRegion(), Kind))
        return true;
    }

    // If this is a SymbolCast from a tainted value, it's also tainted.
    if (const auto *SC = dyn_cast<SymbolCast>(*SI)) {
      if (isTainted(State, SC->getOperand(), Kind))
        return true;
    }
  }

  return false;
}

std::shared_ptr<PathDiagnosticPiece>
TaintBugVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
                           BugReport &BR) {

  // Find the ExplodedNode where the taint was first introduced
  if (!isTainted(N->getState(), V) ||
      isTainted(N->getFirstPred()->getState(), V))
    return nullptr;

  const Stmt *S = PathDiagnosticLocation::getStmt(N);
  if (!S)
    return nullptr;

  const LocationContext *NCtx = N->getLocationContext();
  PathDiagnosticLocation L =
      PathDiagnosticLocation::createBegin(S, BRC.getSourceManager(), NCtx);
  if (!L.isValid() || !L.asLocation().isValid())
    return nullptr;

  return std::make_shared<PathDiagnosticEventPiece>(L, "Taint originated here");
}
<commit_msg>Fix compiler warning, remove extra ";" [NFC]<commit_after>//=== Taint.cpp - Taint tracking and basic propagation rules. ------*- 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
//
//===----------------------------------------------------------------------===//
//
// Defines basic, non-domain-specific mechanisms for tracking tainted values.
//
//===----------------------------------------------------------------------===//

#include "Taint.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"

using namespace clang;
using namespace ento;
using namespace taint;

// Fully tainted symbols.
REGISTER_MAP_WITH_PROGRAMSTATE(TaintMap, SymbolRef, TaintTagType)

// Partially tainted symbols.
REGISTER_MAP_FACTORY_WITH_PROGRAMSTATE(TaintedSubRegions, const SubRegion *,
                                       TaintTagType)
REGISTER_MAP_WITH_PROGRAMSTATE(DerivedSymTaint, SymbolRef, TaintedSubRegions)

void taint::printTaint(ProgramStateRef State, raw_ostream &Out, const char *NL,
                       const char *Sep) {
  TaintMapTy TM = State->get<TaintMap>();

  if (!TM.isEmpty())
    Out << "Tainted symbols:" << NL;

  for (const auto &I : TM)
    Out << I.first << " : " << I.second << NL;
}

void dumpTaint(ProgramStateRef State) {
  printTaint(State, llvm::errs());
}

ProgramStateRef taint::addTaint(ProgramStateRef State, const Stmt *S,
                                const LocationContext *LCtx,
                                TaintTagType Kind) {
  return addTaint(State, State->getSVal(S, LCtx), Kind);
}

ProgramStateRef taint::addTaint(ProgramStateRef State, SVal V,
                                TaintTagType Kind) {
  SymbolRef Sym = V.getAsSymbol();
  if (Sym)
    return addTaint(State, Sym, Kind);

  // If the SVal represents a structure, try to mass-taint all values within the
  // structure. For now it only works efficiently on lazy compound values that
  // were conjured during a conservative evaluation of a function - either as
  // return values of functions that return structures or arrays by value, or as
  // values of structures or arrays passed into the function by reference,
  // directly or through pointer aliasing. Such lazy compound values are
  // characterized by having exactly one binding in their captured store within
  // their parent region, which is a conjured symbol default-bound to the base
  // region of the parent region.
  if (auto LCV = V.getAs<nonloc::LazyCompoundVal>()) {
    if (Optional<SVal> binding =
            State->getStateManager().getStoreManager()
                                    .getDefaultBinding(*LCV)) {
      if (SymbolRef Sym = binding->getAsSymbol())
        return addPartialTaint(State, Sym, LCV->getRegion(), Kind);
    }
  }

  const MemRegion *R = V.getAsRegion();
  return addTaint(State, R, Kind);
}

ProgramStateRef taint::addTaint(ProgramStateRef State, const MemRegion *R,
                                TaintTagType Kind) {
  if (const SymbolicRegion *SR = dyn_cast_or_null<SymbolicRegion>(R))
    return addTaint(State, SR->getSymbol(), Kind);
  return State;
}

ProgramStateRef taint::addTaint(ProgramStateRef State, SymbolRef Sym,
                                TaintTagType Kind) {
  // If this is a symbol cast, remove the cast before adding the taint. Taint
  // is cast agnostic.
  while (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym))
    Sym = SC->getOperand();

  ProgramStateRef NewState = State->set<TaintMap>(Sym, Kind);
  assert(NewState);
  return NewState;
}

ProgramStateRef taint::addPartialTaint(ProgramStateRef State,
                                       SymbolRef ParentSym,
                                       const SubRegion *SubRegion,
                                       TaintTagType Kind) {
  // Ignore partial taint if the entire parent symbol is already tainted.
  if (const TaintTagType *T = State->get<TaintMap>(ParentSym))
    if (*T == Kind)
      return State;

  // Partial taint applies if only a portion of the symbol is tainted.
  if (SubRegion == SubRegion->getBaseRegion())
    return addTaint(State, ParentSym, Kind);

  const TaintedSubRegions *SavedRegs = State->get<DerivedSymTaint>(ParentSym);
  TaintedSubRegions::Factory &F = State->get_context<TaintedSubRegions>();
  TaintedSubRegions Regs = SavedRegs ? *SavedRegs : F.getEmptyMap();

  Regs = F.add(Regs, SubRegion, Kind);
  ProgramStateRef NewState = State->set<DerivedSymTaint>(ParentSym, Regs);
  assert(NewState);
  return NewState;
}

bool taint::isTainted(ProgramStateRef State, const Stmt *S,
                      const LocationContext *LCtx, TaintTagType Kind) {
  SVal val = State->getSVal(S, LCtx);
  return isTainted(State, val, Kind);
}

bool taint::isTainted(ProgramStateRef State, SVal V, TaintTagType Kind) {
  if (const SymExpr *Sym = V.getAsSymExpr())
    return isTainted(State, Sym, Kind);
  if (const MemRegion *Reg = V.getAsRegion())
    return isTainted(State, Reg, Kind);
  return false;
}

bool taint::isTainted(ProgramStateRef State, const MemRegion *Reg,
                      TaintTagType K) {
  if (!Reg)
    return false;

  // Element region (array element) is tainted if either the base or the offset
  // are tainted.
  if (const ElementRegion *ER = dyn_cast<ElementRegion>(Reg))
    return isTainted(State, ER->getSuperRegion(), K) ||
           isTainted(State, ER->getIndex(), K);

  if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg))
    return isTainted(State, SR->getSymbol(), K);

  if (const SubRegion *ER = dyn_cast<SubRegion>(Reg))
    return isTainted(State, ER->getSuperRegion(), K);

  return false;
}

bool taint::isTainted(ProgramStateRef State, SymbolRef Sym, TaintTagType Kind) {
  if (!Sym)
    return false;

  // Traverse all the symbols this symbol depends on to see if any are tainted.
  for (SymExpr::symbol_iterator SI = Sym->symbol_begin(),
                                SE = Sym->symbol_end(); SI != SE; ++SI) {
    if (!isa<SymbolData>(*SI))
      continue;

    if (const TaintTagType *Tag = State->get<TaintMap>(*SI)) {
      if (*Tag == Kind)
        return true;
    }

    if (const auto *SD = dyn_cast<SymbolDerived>(*SI)) {
      // If this is a SymbolDerived with a tainted parent, it's also tainted.
      if (isTainted(State, SD->getParentSymbol(), Kind))
        return true;

      // If this is a SymbolDerived with the same parent symbol as another
      // tainted SymbolDerived and a region that's a sub-region of that tainted
      // symbol, it's also tainted.
      if (const TaintedSubRegions *Regs =
              State->get<DerivedSymTaint>(SD->getParentSymbol())) {
        const TypedValueRegion *R = SD->getRegion();
        for (auto I : *Regs) {
          // FIXME: The logic to identify tainted regions could be more
          // complete. For example, this would not currently identify
          // overlapping fields in a union as tainted. To identify this we can
          // check for overlapping/nested byte offsets.
          if (Kind == I.second && R->isSubRegionOf(I.first))
            return true;
        }
      }
    }

    // If memory region is tainted, data is also tainted.
    if (const auto *SRV = dyn_cast<SymbolRegionValue>(*SI)) {
      if (isTainted(State, SRV->getRegion(), Kind))
        return true;
    }

    // If this is a SymbolCast from a tainted value, it's also tainted.
    if (const auto *SC = dyn_cast<SymbolCast>(*SI)) {
      if (isTainted(State, SC->getOperand(), Kind))
        return true;
    }
  }

  return false;
}

std::shared_ptr<PathDiagnosticPiece>
TaintBugVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
                           BugReport &BR) {

  // Find the ExplodedNode where the taint was first introduced
  if (!isTainted(N->getState(), V) ||
      isTainted(N->getFirstPred()->getState(), V))
    return nullptr;

  const Stmt *S = PathDiagnosticLocation::getStmt(N);
  if (!S)
    return nullptr;

  const LocationContext *NCtx = N->getLocationContext();
  PathDiagnosticLocation L =
      PathDiagnosticLocation::createBegin(S, BRC.getSourceManager(), NCtx);
  if (!L.isValid() || !L.asLocation().isValid())
    return nullptr;

  return std::make_shared<PathDiagnosticEventPiece>(L, "Taint originated here");
}
<|endoftext|>


<commit_before>#include "gtest/gtest.h"

#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>

#include <pistache/listener.h>
#include <pistache/http.h>
class SocketWrapper {

public:
    explicit SocketWrapper(int fd): fd_(fd) {}
    ~SocketWrapper() { close(fd_);}

    uint16_t port() {
        sockaddr_in sin;
        socklen_t len = sizeof(sin);

        uint16_t port = 0;
        if (getsockname(fd_, (struct sockaddr *)&sin, &len) == -1) {
            perror("getsockname");
        } else {
            port = ntohs(sin.sin_port);
        }
        return port;
    }
private:
    int fd_;
};

// Just there for show.
class DummyHandler : public Pistache::Http::Handler {
public:

HTTP_PROTOTYPE(DummyHandler)

    void onRequest(const Pistache::Http::Request& request, Pistache::Http::ResponseWriter response) override {
        UNUSED(request);
        response.send(Pistache::Http::Code::Ok, "I am a dummy handler\n");
    }
};

/*
 * Will try to get a free port by binding port 0.
 */
SocketWrapper bind_free_port() {
    int sockfd;  // listen on sock_fd, new connection on new_fd
    addrinfo hints, *servinfo, *p;

    int yes=1;
    int rv;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE; // use my IP

    if ((rv = getaddrinfo(nullptr, "0", &hints, &servinfo)) != 0) {
        std::cerr << "getaddrinfo: " << gai_strerror(rv) << "\n";
        exit(1);
    }

    // loop through all the results and bind to the first we can
    for(p = servinfo; p != nullptr; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                             p->ai_protocol)) == -1) {
            perror("server: socket");
            continue;
        }

        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
                       sizeof(int)) == -1) {
            perror("setsockopt");
            exit(1);
        }

        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
            close(sockfd);
            perror("server: bind");
            continue;
        }

        break;
    }

    freeaddrinfo(servinfo); // all done with this structure

    if (p == nullptr)  {
        fprintf(stderr, "server: failed to bind\n");
        exit(1);
    }
    return SocketWrapper(sockfd);
}

TEST(listener_test, listener_bind_port_free) {
    uint16_t port_nb;

    // This is just done to get the value of a free port. The socket will be closed
    // after the closing curly bracket and the port will be free again (SO_REUSEADDR option).
    // In theory, it is possible that some application grab this port before we bind it again...
    {
        SocketWrapper s = bind_free_port();
        port_nb = s.port();
    }

    if (port_nb == 0) {
        FAIL() << "Could not find a free port. Abort test.\n";
    }

    Pistache::Port port(port_nb);
    Pistache::Address address(Pistache::Ipv4::any(), port);

    Pistache::Tcp::Listener listener;
    Pistache::Flags<Pistache::Tcp::Options> options;
    listener.init(1, options);
    listener.setHandler(Pistache::Http::make_handler<DummyHandler>());
    listener.bind(address);
    ASSERT_TRUE(true);
}

TEST(listener_test, listener_bind_ephemeral_v6_port) {
    Pistache::Port port(0);
    Pistache::Address address(Pistache::Ipv6::any(), port);

    Pistache::Tcp::Listener listener;
    if (not listener.systemSupportsIpv6()) {
        Pistache::Flags<Pistache::Tcp::Options> options;
        listener.init(1, options);
        listener.setHandler(Pistache::Http::make_handler<DummyHandler>());
        listener.bind(address);
    }
    ASSERT_TRUE(true);
}

// Listener should not crash if an additional member is added to the listener class. This test
// is there to prevent regression for PR 303
TEST(listener_test, listener_uses_default) {
    uint16_t port_nb;

    // This is just done to get the value of a free port. The socket will be closed
    // after the closing curly bracket and the port will be free again (SO_REUSEADDR option).
    // In theory, it is possible that some application grab this port before we bind it again...
    {
        SocketWrapper s = bind_free_port();
        port_nb = s.port();
    }

    if (port_nb == 0) {
        FAIL() << "Could not find a free port. Abort test.\n";
    }

    Pistache::Port port(port_nb);
    Pistache::Address address(Pistache::Ipv4::any(), port);

    Pistache::Tcp::Listener listener;
    listener.setHandler(Pistache::Http::make_handler<DummyHandler>());
    listener.bind(address);
    ASSERT_TRUE(true);
}

TEST(listener_test, listener_bind_port_not_free_throw_runtime) {

    SocketWrapper s = bind_free_port();
    uint16_t port_nb = s.port();

    if (port_nb == 0) {
        FAIL() << "Could not find a free port. Abort test.\n";
    }

    Pistache::Port port(port_nb);
    Pistache::Address address(Pistache::Ipv4::any(), port);

    Pistache::Tcp::Listener listener;
    Pistache::Flags<Pistache::Tcp::Options> options;
    listener.init(1, options);
    listener.setHandler(Pistache::Http::make_handler<DummyHandler>());

    try {
        listener.bind(address);
        FAIL() << "Expected std::runtime_error while binding, got nothing";
    } catch (std::runtime_error const & err) {
        std::cout << err.what() << std::endl;
        ASSERT_STREQ("Address already in use", err.what());
    } catch ( ... ) {
        FAIL() << "Expected std::runtime_error";
    }
}

// Listener should be able to bind port 0 directly to get an ephemeral port.
TEST(listener_test, listener_bind_ephemeral_port) {
    Pistache::Port port(0);
    Pistache::Address address(Pistache::Ipv4::any(), port);

    Pistache::Tcp::Listener listener;
    listener.setHandler(Pistache::Http::make_handler<DummyHandler>());
    listener.bind(address);

    Pistache::Port bound_port = listener.getPort();
    ASSERT_TRUE(bound_port > (uint16_t)0);
}
<commit_msg>Rebased onto upstream/master and modified test<commit_after>#include "gtest/gtest.h"

#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>

#include <pistache/listener.h>
#include <pistache/http.h>
class SocketWrapper {

public:
    explicit SocketWrapper(int fd): fd_(fd) {}
    ~SocketWrapper() { close(fd_);}

    uint16_t port() {
        sockaddr_in sin;
        socklen_t len = sizeof(sin);

        uint16_t port = 0;
        if (getsockname(fd_, (struct sockaddr *)&sin, &len) == -1) {
            perror("getsockname");
        } else {
            port = ntohs(sin.sin_port);
        }
        return port;
    }
private:
    int fd_;
};

// Just there for show.
class DummyHandler : public Pistache::Http::Handler {
public:

HTTP_PROTOTYPE(DummyHandler)

    void onRequest(const Pistache::Http::Request& request, Pistache::Http::ResponseWriter response) override {
        UNUSED(request);
        response.send(Pistache::Http::Code::Ok, "I am a dummy handler\n");
    }
};

/*
 * Will try to get a free port by binding port 0.
 */
SocketWrapper bind_free_port() {
    int sockfd;  // listen on sock_fd, new connection on new_fd
    addrinfo hints, *servinfo, *p;

    int yes=1;
    int rv;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE; // use my IP

    if ((rv = getaddrinfo(nullptr, "0", &hints, &servinfo)) != 0) {
        std::cerr << "getaddrinfo: " << gai_strerror(rv) << "\n";
        exit(1);
    }

    // loop through all the results and bind to the first we can
    for(p = servinfo; p != nullptr; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                             p->ai_protocol)) == -1) {
            perror("server: socket");
            continue;
        }

        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
                       sizeof(int)) == -1) {
            perror("setsockopt");
            exit(1);
        }

        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
            close(sockfd);
            perror("server: bind");
            continue;
        }

        break;
    }

    freeaddrinfo(servinfo); // all done with this structure

    if (p == nullptr)  {
        fprintf(stderr, "server: failed to bind\n");
        exit(1);
    }
    return SocketWrapper(sockfd);
}

TEST(listener_test, listener_bind_port_free) {
    uint16_t port_nb;

    // This is just done to get the value of a free port. The socket will be closed
    // after the closing curly bracket and the port will be free again (SO_REUSEADDR option).
    // In theory, it is possible that some application grab this port before we bind it again...
    {
        SocketWrapper s = bind_free_port();
        port_nb = s.port();
    }

    if (port_nb == 0) {
        FAIL() << "Could not find a free port. Abort test.\n";
    }

    Pistache::Port port(port_nb);
    Pistache::Address address(Pistache::Ipv4::any(), port);

    Pistache::Tcp::Listener listener;
    Pistache::Flags<Pistache::Tcp::Options> options;
    listener.init(1, options);
    listener.setHandler(Pistache::Http::make_handler<DummyHandler>());
    listener.bind(address);
    ASSERT_TRUE(true);
}

// Listener should not crash if an additional member is added to the listener class. This test
// is there to prevent regression for PR 303
TEST(listener_test, listener_uses_default) {
    uint16_t port_nb;

    // This is just done to get the value of a free port. The socket will be closed
    // after the closing curly bracket and the port will be free again (SO_REUSEADDR option).
    // In theory, it is possible that some application grab this port before we bind it again...
    {
        SocketWrapper s = bind_free_port();
        port_nb = s.port();
    }

    if (port_nb == 0) {
        FAIL() << "Could not find a free port. Abort test.\n";
    }

    Pistache::Port port(port_nb);
    Pistache::Address address(Pistache::Ipv4::any(), port);

    Pistache::Tcp::Listener listener;
    listener.setHandler(Pistache::Http::make_handler<DummyHandler>());
    listener.bind(address);
    ASSERT_TRUE(true);
}

TEST(listener_test, listener_bind_port_not_free_throw_runtime) {

    SocketWrapper s = bind_free_port();
    uint16_t port_nb = s.port();

    if (port_nb == 0) {
        FAIL() << "Could not find a free port. Abort test.\n";
    }

    Pistache::Port port(port_nb);
    Pistache::Address address(Pistache::Ipv4::any(), port);

    Pistache::Tcp::Listener listener;
    Pistache::Flags<Pistache::Tcp::Options> options;
    listener.init(1, options);
    listener.setHandler(Pistache::Http::make_handler<DummyHandler>());

    try {
        listener.bind(address);
        FAIL() << "Expected std::runtime_error while binding, got nothing";
    } catch (std::runtime_error const & err) {
        std::cout << err.what() << std::endl;
        ASSERT_STREQ("Address already in use", err.what());
    } catch ( ... ) {
        FAIL() << "Expected std::runtime_error";
    }
}

// Listener should be able to bind port 0 directly to get an ephemeral port.
TEST(listener_test, listener_bind_ephemeral_port) {
    Pistache::Port port(0);
    Pistache::Address address(Pistache::Ipv4::any(), port);

    Pistache::Tcp::Listener listener;
    listener.setHandler(Pistache::Http::make_handler<DummyHandler>());
    listener.bind(address);

    Pistache::Port bound_port = listener.getPort();
    ASSERT_TRUE(bound_port > (uint16_t)0);
}

TEST(listener_test, listener_bind_ephemeral_v6_port) {
    Pistache::Port port(0);
    Pistache::Address address(Pistache::Ipv6::any(), port);

    Pistache::Tcp::Listener listener;
    if (not listener.systemSupportsIpv6()) {
        Pistache::Flags<Pistache::Tcp::Options> options;
        listener.setHandler(Pistache::Http::make_handler<DummyHandler>());
        listener.bind(address);

        Pistache::Port bound_port = listener.getPort();
        ASSERT_TRUE(bound_port > (uint16_t)0);
    }
    ASSERT_TRUE(true);
}
<|endoftext|>


<commit_before>// TODO: make cursor the fixed point of the zoom
// TODO: compute area for selfintersecting polygons
// TODO: polygon editing: move caption, change color, move segments (?), add points (?), delete points (?)
// TODO: set scale by two points GPS coordinates
// TODO: result printing
// TODO: make it possible to reset selection; perhaps, it's time to use 3 modes instead of 2: normal draw, draw etalon, edit?
// TODO: won't it be easier to use weak pointers (e.g., QPointers) to figures?

#include <cassert>
#include <cmath>

#include <QInputDialog>
#include <QLabel>
#include <QPainter>
#include <QPaintEvent>
#include <QScrollArea>
#include <QScrollBar>

#include "canvaswidget.h"
#include "mainwindow.h"
#include "paint_utils.h"
#include "shape.h"

const int rulerMargin         = 16;
const int rulerThickness      = 2;
const int rulerFrameThickness = 1;
const int rulerTextMargin     = 3;
const int rulerSerifsSize     = 8;
const int rulerMaxLength      = 180;
const int rulerMinLength      = 40;
const QColor rulerBodyColor   = Qt::black;
const QColor rulerFrameColor  = Qt::white;

const int maxImageSize = 4096;

CanvasWidget::CanvasWidget(const QPixmap* image, MainWindow* mainWindow, QScrollArea* scrollArea,
                           QLabel* scaleLabel, QLabel* statusLabel, QWidget* parent) :
  QWidget(parent),
  mainWindow_(mainWindow),
  scrollArea_(scrollArea),
  scaleLabel_(scaleLabel),
  statusLabel_(statusLabel),
  originalImage_(image)
{
  acceptableScales_ << 0.01 << 0.015 << 0.02 << 0.025 << 0.03 << 0.04 << 0.05 << 0.06 << 0.07 << 0.08 << 0.09;
  acceptableScales_ << 0.10 << 0.12 << 0.14 << 0.17 << 0.20 << 0.23 << 0.26 << 0.30 << 0.35 << 0.40 << 0.45;
  acceptableScales_ << 0.50 << 0.60 << 0.70 << 0.80 << 0.90;
  acceptableScales_ << 1.00 << 1.25 << 1.50 << 1.75 << 2.00 << 2.50 << 3.00 << 4.00;
  iScale_ = acceptableScales_.indexOf(1.00);

  scrollArea_->viewport()->installEventFilter(this);
  setFocusPolicy(Qt::StrongFocus);
  setMouseTracking(true);
  shapeType_ = DEFAULT_TYPE;
  isDefiningEtalon_ = true;
  showRuler_ = false;
  etalonFigure_ = 0;
  activeFigure_ = 0;
  clearEtalon();
  scaleChanged();
}

CanvasWidget::~CanvasWidget()
{
  delete originalImage_;
}

void CanvasWidget::paintEvent(QPaintEvent* event)
{
  QPainter painter(this);
  painter.setFont(mainWindow_->getInscriptionFont());
  painter.setRenderHint(QPainter::Antialiasing, true);
  painter.drawPixmap(event->rect().topLeft(), image_, event->rect());
  foreach (const Figure& figure, figures_)
    figure.draw(painter);
  if (showRuler_)
    drawRuler(painter, event->rect());
  event->accept();
}

void CanvasWidget::keyPressEvent(QKeyEvent* event)
{
  if (event->key() == Qt::Key_Delete) {
    if (!selection_.isEmpty() && !selection_.figure->isEtalon()) {
      removeFigure(selection_.figure);
      updateAll();
    }
  }
  else {
    QWidget::keyPressEvent(event);
  }
}

void CanvasWidget::mousePressEvent(QMouseEvent* event)
{
  updateMousePos(event->pos());
  if (event->buttons() == Qt::LeftButton) {
    selection_ = hover_;
    if (hover_.isEmpty()) {
      if (!activeFigure_) {
        if (isDefiningEtalon_) {
          clearEtalon();
          removeFigure(etalonFigure_);
        }
        addActiveFigure();
      }
      bool polygonFinished = activeFigure_->addPoint(originalPointUnderMouse_);
      if (polygonFinished)
        finishPlotting();
      else
        updateAll();
    }
    else {
      update();
    }
  }
  else if (event->buttons() == Qt::RightButton) {
    scrollStartPoint_ = event->globalPos();
    scrollStartHValue_ = scrollArea_->horizontalScrollBar()->value();
    scrollStartVValue_ = scrollArea_->verticalScrollBar()  ->value();
  }
  event->accept();
}

void CanvasWidget::mouseReleaseEvent(QMouseEvent* /*event*/)
{
  updateHover();
}

void CanvasWidget::mouseMoveEvent(QMouseEvent* event)
{
  if (event->buttons() == Qt::NoButton) {
    updateMousePos(event->pos());
    updateAll();
  }
  else if (event->buttons() == Qt::LeftButton) {
    updateMousePos(event->pos());
    selection_.dragTo(originalPointUnderMouse_);
    if (!selection_.isEmpty() && selection_.figure->isEtalon())
      defineEtalon(selection_.figure);
    updateAll();
  }
  else if (event->buttons() == Qt::RightButton) {
    QPoint scrollBy = scrollStartPoint_ - event->globalPos();
    scrollArea_->horizontalScrollBar()->setValue(scrollStartHValue_ + scrollBy.x());
    scrollArea_->verticalScrollBar()  ->setValue(scrollStartVValue_ + scrollBy.y());
  }
  event->accept();
}

void CanvasWidget::mouseDoubleClickEvent(QMouseEvent* event)
{
  finishPlotting();
  event->accept();
}

bool CanvasWidget::eventFilter(QObject* object, QEvent* event__)
{
  if (object == scrollArea_->viewport() && event__->type() == QEvent::Wheel) {
    QWheelEvent* event = static_cast<QWheelEvent*>(event__);
    int numSteps = event->delta() / 120;
    iScale_ = qBound(0, iScale_ + numSteps, acceptableScales_.size() - 1);
    int size = qMax(originalImage_->width(), originalImage_->height());
    while (size * acceptableScales_[iScale_] > maxImageSize && acceptableScales_[iScale_] > 1.)
      iScale_--;
    scaleChanged();
    return true;
  }
  return false;
}

void CanvasWidget::setMode(ShapeType newMode)
{
  shapeType_ = newMode;
  resetAll();
}

bool CanvasWidget::hasEtalon() const
{
  return originalMetersPerPixel_ > 0.;
}

QPixmap CanvasWidget::getModifiedImage()
{
  int oldIScale = iScale_;
  iScale_ = acceptableScales_.indexOf(1.00);
  scaleChanged();
  QPixmap resultingImage(size());
  render(&resultingImage);
  iScale_ = oldIScale;
  scaleChanged();
  return resultingImage;
}

void CanvasWidget::toggleEtalonDefinition(bool isDefiningEtalon)
{
  if (isDefiningEtalon_ == isDefiningEtalon)
    return;
  isDefiningEtalon_ = isDefiningEtalon;
  resetAll();
}

void CanvasWidget::toggleRuler(bool showRuler)
{
  if (showRuler_ == showRuler)
    return;
  showRuler_ = showRuler;
  update();
}

void CanvasWidget::addActiveFigure()
{
  assert(!activeFigure_);
  figures_.append(Figure(shapeType_, isDefiningEtalon_, this));
  activeFigure_ = &figures_.last();
}

void CanvasWidget::removeFigure(const Figure* figure)
{
  if (!figure)
    return;

  if (etalonFigure_ == figure)
    etalonFigure_ = 0;
  if (activeFigure_ == figure)
    activeFigure_ = 0;
  if (selection_.figure == figure)
    selection_.reset();
  if (hover_.figure == figure)
    hover_.reset();

  bool erased = false;
  for (auto it = figures_.begin(); it != figures_.end(); ++it) {
    if (&(*it) == figure) {
      figures_.erase(it);
      erased = true;
      break;
    }
  }
  assert(erased);
}

void CanvasWidget::drawRuler(QPainter& painter, const QRect& rect)
{
  int maxLength = qMin(rulerMaxLength, rect.width() - 2 * rulerMargin);
  if (!hasEtalon() || maxLength < rulerMinLength)
    return;

  double pixelLengthF;
  double metersLength;
  double base = 1e10;
  while (base > 1e-10) {
    if ((pixelLengthF = (metersLength = base * 5.) / metersPerPixel_) < maxLength)
      break;
    if ((pixelLengthF = (metersLength = base * 2.) / metersPerPixel_) < maxLength)
      break;
    if ((pixelLengthF = (metersLength = base * 1.) / metersPerPixel_) < maxLength)
      break;
    base /= 10.;
  }
  int pixelLength = pixelLengthF;

  QList<QRect> ruler;
  int rulerLeft = rect.left()   + rulerMargin;
  int rulerY    = rect.bottom() - rulerMargin;
  ruler.append(QRect(rulerLeft, rulerY - rulerThickness / 2, pixelLength, rulerThickness));
  ruler.append(QRect(rulerLeft - rulerThickness, rulerY - rulerSerifsSize / 2, rulerThickness, rulerSerifsSize));
  ruler.append(QRect(rulerLeft + pixelLength   , rulerY - rulerSerifsSize / 2, rulerThickness, rulerSerifsSize));
  drawFramed(painter, ruler, rulerFrameThickness, rulerBodyColor, rulerFrameColor);

  QString rulerLabel = QString::number(metersLength) + " " + linearUnitSuffix;
  QPoint labelPos(rulerLeft + rulerFrameThickness + rulerTextMargin,
                  rulerY - rulerThickness / 2 - rulerFrameThickness - rulerTextMargin - painter.fontMetrics().descent());
  drawTextWithBackground(painter, rulerLabel, labelPos);
}

void CanvasWidget::updateMousePos(QPoint mousePos)
{
  pointUnderMouse_ = mousePos;
  originalPointUnderMouse_ = pointUnderMouse_ / scale_;
}

void CanvasWidget::updateHover()
{
  Selection newHover;
  if (activeFigure_) {
    newHover.reset();
  }
  else {
    SelectionFinder selectionFinder(pointUnderMouse_);
    for (auto it = figures_.begin(); it != figures_.end(); ++it)
      if (it->isFinished())
        it->testSelection(selectionFinder);
    newHover = selectionFinder.bestSelection();
  }
  if (hover_ != newHover) {
    hover_ = newHover;
    update();
  }
}

void CanvasWidget::defineEtalon(Figure* newEtalonFigure)
{
  assert(newEtalonFigure && newEtalonFigure->isFinished());
  bool isResizing = (etalonFigure_ == newEtalonFigure);
  etalonFigure_ = newEtalonFigure;
  const Shape originalShapeDrawn = newEtalonFigure->originalShape();
  double originalEtalonPixelLength = 0.;
  QString prompt;
  switch (originalShapeDrawn.dimensionality()) {
    case SHAPE_1D:
      originalEtalonPixelLength = originalShapeDrawn.length();
      prompt = QString::fromUtf8("Укажите длину эталона (%1): ").arg(linearUnitSuffix);
      break;
    case SHAPE_2D:
      originalEtalonPixelLength = std::sqrt(originalShapeDrawn.area());
      prompt = QString::fromUtf8("Укажите площадь эталона (%1): ").arg(squareUnitSuffix);
      break;
  }
  bool userInputIsOk = true;
  if (!isResizing)
    etalonMetersSize_ = QInputDialog::getDouble(this, mainWindow_->appName(), prompt, 1., 0.001, 1e9, 3, &userInputIsOk);
  if (originalShapeDrawn.isValid() && originalEtalonPixelLength > 0. && userInputIsOk) {
    double etalonMetersLength;
    switch (originalShapeDrawn.dimensionality()) {
      case SHAPE_1D: etalonMetersLength = etalonMetersSize_;            break;
      case SHAPE_2D: etalonMetersLength = std::sqrt(etalonMetersSize_); break;
    }
    originalMetersPerPixel_ = etalonMetersLength / originalEtalonPixelLength;
    metersPerPixel_ = originalMetersPerPixel_ / scale_;
  }
  else {
    clearEtalon(true);
  }
  if (!isResizing)
    mainWindow_->toggleEtalonDefinition(false);
}

void CanvasWidget::clearEtalon(bool invalidateOnly)
{
  if (!invalidateOnly)
    etalonMetersSize_ = 0;
  originalMetersPerPixel_ = 0.;
  metersPerPixel_ = 0.;
}

void CanvasWidget::finishPlotting()
{
  assert(activeFigure_);
  activeFigure_->finish();
  Figure *oldActiveFigure = activeFigure_;
  activeFigure_ = 0;
  if (isDefiningEtalon_)
    defineEtalon(oldActiveFigure);
  updateAll();
}

void CanvasWidget::resetAll()
{
  removeFigure(activeFigure_);
  updateAll();
}

void CanvasWidget::scaleChanged()
{
  scale_ = acceptableScales_[iScale_];
  image_ = originalImage_->scaled(originalImage_->size() * scale_, Qt::KeepAspectRatio, Qt::SmoothTransformation);
  metersPerPixel_ = originalMetersPerPixel_ / scale_;
  setFixedSize(image_.size());
  scaleLabel_->setText(QString::number(scale_ * 100.) + "%");
  updateAll();
}

void CanvasWidget::updateAll()
{
  updateHover();
  statusLabel_->setText(activeFigure_ ? activeFigure_->statusString() : QString());
  update();
}
<commit_msg>Fix finishing drawing on double-clicking non-left button<commit_after>// TODO: make cursor the fixed point of the zoom
// TODO: compute area for selfintersecting polygons
// TODO: polygon editing: move caption, change color, move segments (?), add points (?), delete points (?)
// TODO: set scale by two points GPS coordinates
// TODO: result printing
// TODO: make it possible to reset selection; perhaps, it's time to use 3 modes instead of 2: normal draw, draw etalon, edit?
// TODO: won't it be easier to use weak pointers (e.g., QPointers) to figures?

#include <cassert>
#include <cmath>

#include <QInputDialog>
#include <QLabel>
#include <QPainter>
#include <QPaintEvent>
#include <QScrollArea>
#include <QScrollBar>

#include "canvaswidget.h"
#include "mainwindow.h"
#include "paint_utils.h"
#include "shape.h"

const int rulerMargin         = 16;
const int rulerThickness      = 2;
const int rulerFrameThickness = 1;
const int rulerTextMargin     = 3;
const int rulerSerifsSize     = 8;
const int rulerMaxLength      = 180;
const int rulerMinLength      = 40;
const QColor rulerBodyColor   = Qt::black;
const QColor rulerFrameColor  = Qt::white;

const int maxImageSize = 4096;

CanvasWidget::CanvasWidget(const QPixmap* image, MainWindow* mainWindow, QScrollArea* scrollArea,
                           QLabel* scaleLabel, QLabel* statusLabel, QWidget* parent) :
  QWidget(parent),
  mainWindow_(mainWindow),
  scrollArea_(scrollArea),
  scaleLabel_(scaleLabel),
  statusLabel_(statusLabel),
  originalImage_(image)
{
  acceptableScales_ << 0.01 << 0.015 << 0.02 << 0.025 << 0.03 << 0.04 << 0.05 << 0.06 << 0.07 << 0.08 << 0.09;
  acceptableScales_ << 0.10 << 0.12 << 0.14 << 0.17 << 0.20 << 0.23 << 0.26 << 0.30 << 0.35 << 0.40 << 0.45;
  acceptableScales_ << 0.50 << 0.60 << 0.70 << 0.80 << 0.90;
  acceptableScales_ << 1.00 << 1.25 << 1.50 << 1.75 << 2.00 << 2.50 << 3.00 << 4.00;
  iScale_ = acceptableScales_.indexOf(1.00);

  scrollArea_->viewport()->installEventFilter(this);
  setFocusPolicy(Qt::StrongFocus);
  setMouseTracking(true);
  shapeType_ = DEFAULT_TYPE;
  isDefiningEtalon_ = true;
  showRuler_ = false;
  etalonFigure_ = 0;
  activeFigure_ = 0;
  clearEtalon();
  scaleChanged();
}

CanvasWidget::~CanvasWidget()
{
  delete originalImage_;
}

void CanvasWidget::paintEvent(QPaintEvent* event)
{
  QPainter painter(this);
  painter.setFont(mainWindow_->getInscriptionFont());
  painter.setRenderHint(QPainter::Antialiasing, true);
  painter.drawPixmap(event->rect().topLeft(), image_, event->rect());
  foreach (const Figure& figure, figures_)
    figure.draw(painter);
  if (showRuler_)
    drawRuler(painter, event->rect());
  event->accept();
}

void CanvasWidget::keyPressEvent(QKeyEvent* event)
{
  if (event->key() == Qt::Key_Delete) {
    if (!selection_.isEmpty() && !selection_.figure->isEtalon()) {
      removeFigure(selection_.figure);
      updateAll();
    }
  }
  else {
    QWidget::keyPressEvent(event);
  }
}

void CanvasWidget::mousePressEvent(QMouseEvent* event)
{
  updateMousePos(event->pos());
  if (event->buttons() == Qt::LeftButton) {
    selection_ = hover_;
    if (hover_.isEmpty()) {
      if (!activeFigure_) {
        if (isDefiningEtalon_) {
          clearEtalon();
          removeFigure(etalonFigure_);
        }
        addActiveFigure();
      }
      bool polygonFinished = activeFigure_->addPoint(originalPointUnderMouse_);
      if (polygonFinished)
        finishPlotting();
      else
        updateAll();
    }
    else {
      update();
    }
  }
  else if (event->buttons() == Qt::RightButton) {
    scrollStartPoint_ = event->globalPos();
    scrollStartHValue_ = scrollArea_->horizontalScrollBar()->value();
    scrollStartVValue_ = scrollArea_->verticalScrollBar()  ->value();
  }
  event->accept();
}

void CanvasWidget::mouseReleaseEvent(QMouseEvent* /*event*/)
{
  updateHover();
}

void CanvasWidget::mouseMoveEvent(QMouseEvent* event)
{
  if (event->buttons() == Qt::NoButton) {
    updateMousePos(event->pos());
    updateAll();
  }
  else if (event->buttons() == Qt::LeftButton) {
    updateMousePos(event->pos());
    selection_.dragTo(originalPointUnderMouse_);
    if (!selection_.isEmpty() && selection_.figure->isEtalon())
      defineEtalon(selection_.figure);
    updateAll();
  }
  else if (event->buttons() == Qt::RightButton) {
    QPoint scrollBy = scrollStartPoint_ - event->globalPos();
    scrollArea_->horizontalScrollBar()->setValue(scrollStartHValue_ + scrollBy.x());
    scrollArea_->verticalScrollBar()  ->setValue(scrollStartVValue_ + scrollBy.y());
  }
  event->accept();
}

// TODO: deal with case when double-click is the first click
void CanvasWidget::mouseDoubleClickEvent(QMouseEvent* event)
{
  if (event->buttons() == Qt::LeftButton)
    finishPlotting();
  event->accept();
}

bool CanvasWidget::eventFilter(QObject* object, QEvent* event__)
{
  if (object == scrollArea_->viewport() && event__->type() == QEvent::Wheel) {
    QWheelEvent* event = static_cast<QWheelEvent*>(event__);
    int numSteps = event->delta() / 120;
    iScale_ = qBound(0, iScale_ + numSteps, acceptableScales_.size() - 1);
    int size = qMax(originalImage_->width(), originalImage_->height());
    while (size * acceptableScales_[iScale_] > maxImageSize && acceptableScales_[iScale_] > 1.)
      iScale_--;
    scaleChanged();
    return true;
  }
  return false;
}

void CanvasWidget::setMode(ShapeType newMode)
{
  shapeType_ = newMode;
  resetAll();
}

bool CanvasWidget::hasEtalon() const
{
  return originalMetersPerPixel_ > 0.;
}

QPixmap CanvasWidget::getModifiedImage()
{
  int oldIScale = iScale_;
  iScale_ = acceptableScales_.indexOf(1.00);
  scaleChanged();
  QPixmap resultingImage(size());
  render(&resultingImage);
  iScale_ = oldIScale;
  scaleChanged();
  return resultingImage;
}

void CanvasWidget::toggleEtalonDefinition(bool isDefiningEtalon)
{
  if (isDefiningEtalon_ == isDefiningEtalon)
    return;
  isDefiningEtalon_ = isDefiningEtalon;
  resetAll();
}

void CanvasWidget::toggleRuler(bool showRuler)
{
  if (showRuler_ == showRuler)
    return;
  showRuler_ = showRuler;
  update();
}

void CanvasWidget::addActiveFigure()
{
  assert(!activeFigure_);
  figures_.append(Figure(shapeType_, isDefiningEtalon_, this));
  activeFigure_ = &figures_.last();
}

void CanvasWidget::removeFigure(const Figure* figure)
{
  if (!figure)
    return;

  if (etalonFigure_ == figure)
    etalonFigure_ = 0;
  if (activeFigure_ == figure)
    activeFigure_ = 0;
  if (selection_.figure == figure)
    selection_.reset();
  if (hover_.figure == figure)
    hover_.reset();

  bool erased = false;
  for (auto it = figures_.begin(); it != figures_.end(); ++it) {
    if (&(*it) == figure) {
      figures_.erase(it);
      erased = true;
      break;
    }
  }
  assert(erased);
}

void CanvasWidget::drawRuler(QPainter& painter, const QRect& rect)
{
  int maxLength = qMin(rulerMaxLength, rect.width() - 2 * rulerMargin);
  if (!hasEtalon() || maxLength < rulerMinLength)
    return;

  double pixelLengthF;
  double metersLength;
  double base = 1e10;
  while (base > 1e-10) {
    if ((pixelLengthF = (metersLength = base * 5.) / metersPerPixel_) < maxLength)
      break;
    if ((pixelLengthF = (metersLength = base * 2.) / metersPerPixel_) < maxLength)
      break;
    if ((pixelLengthF = (metersLength = base * 1.) / metersPerPixel_) < maxLength)
      break;
    base /= 10.;
  }
  int pixelLength = pixelLengthF;

  QList<QRect> ruler;
  int rulerLeft = rect.left()   + rulerMargin;
  int rulerY    = rect.bottom() - rulerMargin;
  ruler.append(QRect(rulerLeft, rulerY - rulerThickness / 2, pixelLength, rulerThickness));
  ruler.append(QRect(rulerLeft - rulerThickness, rulerY - rulerSerifsSize / 2, rulerThickness, rulerSerifsSize));
  ruler.append(QRect(rulerLeft + pixelLength   , rulerY - rulerSerifsSize / 2, rulerThickness, rulerSerifsSize));
  drawFramed(painter, ruler, rulerFrameThickness, rulerBodyColor, rulerFrameColor);

  QString rulerLabel = QString::number(metersLength) + " " + linearUnitSuffix;
  QPoint labelPos(rulerLeft + rulerFrameThickness + rulerTextMargin,
                  rulerY - rulerThickness / 2 - rulerFrameThickness - rulerTextMargin - painter.fontMetrics().descent());
  drawTextWithBackground(painter, rulerLabel, labelPos);
}

void CanvasWidget::updateMousePos(QPoint mousePos)
{
  pointUnderMouse_ = mousePos;
  originalPointUnderMouse_ = pointUnderMouse_ / scale_;
}

void CanvasWidget::updateHover()
{
  Selection newHover;
  if (activeFigure_) {
    newHover.reset();
  }
  else {
    SelectionFinder selectionFinder(pointUnderMouse_);
    for (auto it = figures_.begin(); it != figures_.end(); ++it)
      if (it->isFinished())
        it->testSelection(selectionFinder);
    newHover = selectionFinder.bestSelection();
  }
  if (hover_ != newHover) {
    hover_ = newHover;
    update();
  }
}

void CanvasWidget::defineEtalon(Figure* newEtalonFigure)
{
  assert(newEtalonFigure && newEtalonFigure->isFinished());
  bool isResizing = (etalonFigure_ == newEtalonFigure);
  etalonFigure_ = newEtalonFigure;
  const Shape originalShapeDrawn = newEtalonFigure->originalShape();
  double originalEtalonPixelLength = 0.;
  QString prompt;
  switch (originalShapeDrawn.dimensionality()) {
    case SHAPE_1D:
      originalEtalonPixelLength = originalShapeDrawn.length();
      prompt = QString::fromUtf8("Укажите длину эталона (%1): ").arg(linearUnitSuffix);
      break;
    case SHAPE_2D:
      originalEtalonPixelLength = std::sqrt(originalShapeDrawn.area());
      prompt = QString::fromUtf8("Укажите площадь эталона (%1): ").arg(squareUnitSuffix);
      break;
  }
  bool userInputIsOk = true;
  if (!isResizing)
    etalonMetersSize_ = QInputDialog::getDouble(this, mainWindow_->appName(), prompt, 1., 0.001, 1e9, 3, &userInputIsOk);
  if (originalShapeDrawn.isValid() && originalEtalonPixelLength > 0. && userInputIsOk) {
    double etalonMetersLength;
    switch (originalShapeDrawn.dimensionality()) {
      case SHAPE_1D: etalonMetersLength = etalonMetersSize_;            break;
      case SHAPE_2D: etalonMetersLength = std::sqrt(etalonMetersSize_); break;
    }
    originalMetersPerPixel_ = etalonMetersLength / originalEtalonPixelLength;
    metersPerPixel_ = originalMetersPerPixel_ / scale_;
  }
  else {
    clearEtalon(true);
  }
  if (!isResizing)
    mainWindow_->toggleEtalonDefinition(false);
}

void CanvasWidget::clearEtalon(bool invalidateOnly)
{
  if (!invalidateOnly)
    etalonMetersSize_ = 0;
  originalMetersPerPixel_ = 0.;
  metersPerPixel_ = 0.;
}

void CanvasWidget::finishPlotting()
{
  assert(activeFigure_);
  activeFigure_->finish();
  Figure *oldActiveFigure = activeFigure_;
  activeFigure_ = 0;
  if (isDefiningEtalon_)
    defineEtalon(oldActiveFigure);
  updateAll();
}

void CanvasWidget::resetAll()
{
  removeFigure(activeFigure_);
  updateAll();
}

void CanvasWidget::scaleChanged()
{
  scale_ = acceptableScales_[iScale_];
  image_ = originalImage_->scaled(originalImage_->size() * scale_, Qt::KeepAspectRatio, Qt::SmoothTransformation);
  metersPerPixel_ = originalMetersPerPixel_ / scale_;
  setFixedSize(image_.size());
  scaleLabel_->setText(QString::number(scale_ * 100.) + "%");
  updateAll();
}

void CanvasWidget::updateAll()
{
  updateHover();
  statusLabel_->setText(activeFigure_ ? activeFigure_->statusString() : QString());
  update();
}
<|endoftext|>