void NonConstParameterCheck::check(const MatchFinder::MatchResult &Result) {
  if (const auto *Parm = Result.Nodes.getNodeAs<ParmVarDecl>("Parm")) {
    if (const DeclContext *D = Parm->getParentFunctionOrMethod()) {
      if (const auto *M = dyn_cast<CXXMethodDecl>(D)) {
        if (M->isVirtual() || M->size_overridden_methods() != 0)
          return;
      }
    }
    addParm(Parm);
  } else if (const auto *Ctor =
                 Result.Nodes.getNodeAs<CXXConstructorDecl>("Ctor")) {
    for (const auto *Parm : Ctor->parameters())
      addParm(Parm);
    for (const auto *Init : Ctor->inits())
      markCanNotBeConst(Init->getInit(), true);
  } else if (const auto *Ref = Result.Nodes.getNodeAs<DeclRefExpr>("Ref")) {
    setReferenced(Ref);
  } else if (const auto *S = Result.Nodes.getNodeAs<Stmt>("Mark")) {
    if (const auto *B = dyn_cast<BinaryOperator>(S)) {
      if (B->isAssignmentOp())
        markCanNotBeConst(B, false);
    } else if (const auto *CE = dyn_cast<CallExpr>(S)) {
      // Typically, if a parameter is const then it is fine to make the data
      // const. But sometimes the data is written even though the parameter
      // is const. Mark all data passed by address to the function.
      for (const auto *Arg : CE->arguments()) {
        markCanNotBeConst(Arg->IgnoreParenCasts(), true);
      }

      // Data passed by nonconst reference should not be made const.
      if (const FunctionDecl *FD = CE->getDirectCallee()) {
        unsigned ArgNr = 0U;
        for (const auto *Par : FD->parameters()) {
          if (ArgNr >= CE->getNumArgs())
            break;
          const Expr *Arg = CE->getArg(ArgNr++);
          // Is this a non constant reference parameter?
          const Type *ParType = Par->getType().getTypePtr();
          if (!ParType->isReferenceType() || Par->getType().isConstQualified())
            continue;
          markCanNotBeConst(Arg->IgnoreParenCasts(), false);
        }
      }
    } else if (const auto *CE = dyn_cast<CXXConstructExpr>(S)) {
      for (const auto *Arg : CE->arguments()) {
        markCanNotBeConst(Arg->IgnoreParenCasts(), true);
      }
    } else if (const auto *R = dyn_cast<ReturnStmt>(S)) {
      markCanNotBeConst(R->getRetValue(), true);
    } else if (const auto *U = dyn_cast<UnaryOperator>(S)) {
      markCanNotBeConst(U, true);
    }
  } else if (const auto *VD = Result.Nodes.getNodeAs<VarDecl>("Mark")) {
    const QualType T = VD->getType();
    if ((T->isPointerType() && !T->getPointeeType().isConstQualified()) ||
        T->isArrayType())
      markCanNotBeConst(VD->getInit(), true);
  }
}
void VariableSerializer::writeOverflow(void* ptr, bool isObject /* = false */) {
  bool wasRef = m_referenced;
  setReferenced(false);
  switch (m_type) {
  case PrintR:
    if (!m_objClass.empty()) {
      m_buf->append(m_objClass);
      m_buf->append(" Object\n");
    } else {
      m_buf->append("Array\n");
    }
    m_buf->append(" *RECURSION*");
    break;
  case VarExport:
    throw NestingLevelTooDeepException();
  case VarDump:
  case DebugDump:
  case DebuggerDump:
    indent();
    m_buf->append("*RECURSION*\n");
    break;
  case DebuggerSerialize:
    if (m_maxLevelDebugger > 0 && m_levelDebugger > m_maxLevelDebugger) {
      // Not recursion, just cut short of print
      m_buf->append("s:12:\"...(omitted)\";", 20);
      break;
    }
    // fall through
  case Serialize:
  case APCSerialize:
    {
      ASSERT(m_arrayIds);
      PointerCounterMap::const_iterator iter = m_arrayIds->find(ptr);
      ASSERT(iter != m_arrayIds->end());
      int id = iter->second;
      if (isObject) {
        m_buf->append("r:");
        m_buf->append(id);
        m_buf->append(';');
      } else if (wasRef) {
        m_buf->append("R:");
        m_buf->append(id);
        m_buf->append(';');
      } else {
        m_buf->append("N;");
      }
    }
    break;
  case JSON:
    raise_warning("json_encode(): recursion detected");
    m_buf->append("null");
    break;
  default:
    ASSERT(false);
    break;
  }
}
void VariableSerializer::write(CVarRef v, bool isArrayKey /* = false */) {
  if (!isArrayKey && v.isObject()) {
    write(v.toObject());
    return;
  }
  setReferenced(v.isReferenced());
  setRefCount(v.getRefCount());
  v.serialize(this, isArrayKey);
}
Пример #4
0
void VariableSerializer::writeOverflow(void* ptr, bool isObject /* = false */) {
  bool wasRef = m_referenced;
  setReferenced(false);
  switch (m_type) {
  case PrintR:
    *m_out << "*RECURSION*";
    break;
  case VarExport:
    throw NestingLevelTooDeepException();
  case VarDump:
  case DebugDump:
    indent();
    *m_out << "*RECURSION*\n";
    break;
  case Serialize:
    {
      map<void*, int>::const_iterator iter = m_arrayIds.find(ptr);
      ASSERT(iter != m_arrayIds.end());
      int id = iter->second;
      if (isObject) {
        *m_out << "r:" << id << ";";
      } else if (wasRef) {
        *m_out << "R:" << id << ";";
      } else {
        *m_out << "N;";
      }
    }
    break;
  case JSON:
    *m_out << "null";
    break;
  default:
    ASSERT(false);
    break;
  }
}