void ImplicitListChecker::preCheckNode(const ast::Exp & e, SLintContext & context, SLintResult & result)
{
    const ast::ListExp & le = static_cast<const ast::ListExp &>(e);
    if (le.getStart().isDoubleExp() && le.getStep().isDoubleExp() && le.getEnd().isDoubleExp())
    {
        const double start = static_cast<const ast::DoubleExp &>(le.getStart()).getValue();
        const double step = static_cast<const ast::DoubleExp &>(le.getStep()).getValue();
        const double end = static_cast<const ast::DoubleExp &>(le.getEnd()).getValue();
        if (ISNAN(start) || ISNAN(step) || ISNAN(end) || !finite(start) || !finite(step) || !finite(end))
        {
            result.report(context, e.getLocation(), *this, _("Invalid list, it contains NaN or Inf."));
        }
        else
        {
            if (start == end)
            {
                result.report(context, e.getLocation(), *this, _("List has the same start and end."));
            }
            if (step == 0)
            {
                result.report(context, e.getLocation(), *this, _("List has a null step."));
            }
            if ((start > end && step > 0) || (start < end && step < 0))
            {
                result.report(context, e.getLocation(), *this, _("List is empty."));
            }
        }
    }
    else if (le.getStart().isListExp() || le.getStep().isListExp() || le.getEnd().isListExp())
    {
        result.report(context, e.getLocation(), *this, _("Bad use of ':' operator."));
    }
}
Example #2
0
void DeprecatedChecker::preCheckNode(const ast::Exp & e, SLintContext & context, SLintResult & result)
{
    const ast::CallExp & ce = static_cast<const ast::CallExp &>(e);
    if (ce.getName().isSimpleVar())
    {
        const std::wstring & name = static_cast<const ast::SimpleVar &>(ce.getName()).getSymbol().getName();
        const auto i = deprecated.find(name);
        if (i != deprecated.end())
        {
            if (i->second.empty())
            {
                result.report(context, e.getLocation(), *this, _("Deprecated function: %s."), name);
            }
            else
            {
                result.report(context, e.getLocation(), *this, _("Deprecated function %s: use %s instead."), name, i->second);
            }
        }
        else
        {
            const auto i = partiallyDeprecated.find(name);
            if (i != partiallyDeprecated.end())
            {
                i->second->preCheckNode(e, context, result);
            }
        }
    }
}
Example #3
0
    bool OperAnalyzer::analyze(AnalysisVisitor & visitor, ast::Exp & e)
    {
        ast::OpExp & oe = static_cast<ast::OpExp &>(e);
        const ast::OpExp::Oper oper = oe.getOper();
        if (oper == ast::OpExp::plus || oper == ast::OpExp::minus || oper == ast::OpExp::times)
        {
            if (ast::MemfillExp * mfe = analyzeMemfill(visitor, oe))
	    {
		mfe->setVerbose(e.isVerbose());
		e.replace(mfe);

		return true;
	    }
        }

	/*if (ast::ExtendedOpExp * eoe = analyzeMemfill(visitor, oe))
	{
	    eoe->setVerbose(e.isVerbose());
	    e.replace(eoe);
	    
	    return true;
	    }*/
	
	return false;
    }
void EmptyBlockChecker::preCheckNode(const ast::Exp & e, SLintContext & context, SLintResult & result)
{
    if (e.isSeqExp())
    {
        const ast::exps_t & exps = static_cast<const ast::SeqExp &>(e).getExps();
        bool empty = exps.empty();
        if (!empty)
        {
            empty = true;
            for (const auto exp : exps)
            {
                if (!exp->isCommentExp())
                {
                    empty = false;
                    break;
                }
            }
        }

        if (empty)
        {
            result.report(context, e.getLocation(), *this, _("Empty block."));
        }
    }
}
void IllegalCallsChecker::preCheckNode(const ast::Exp & e, SLintContext & context, SLintResult & result)
{
    if (e.getParent()->isCallExp() || e.getParent()->isSeqExp())
    {
        const std::wstring & name = static_cast<const ast::SimpleVar &>(e).getSymbol().getName();
        if (illegal.find(name) != illegal.end())
        {
            result.report(context, e.getLocation(), *this, _("Illegal call: %s."), name);
        }
    }
}
void FunctionArgsOrderChecker::preCheckNode(const ast::Exp & e, SLintContext & context, SLintResult & result)
{
    const ast::CallExp & ce = static_cast<const ast::CallExp &>(e);
    if (ce.getName().isSimpleVar())
    {
        ast::exps_t args = ce.getArgs();
        std::map<symbol::Symbol, unsigned int> assignments;
        unsigned int pos = 1;
        for (const auto arg : args)
        {
            if (arg->isAssignExp())
            {
                const ast::AssignExp & ae = *static_cast<const ast::AssignExp *>(arg);
                if (ae.getLeftExp().isSimpleVar())
                {
                    assignments.emplace(static_cast<ast::SimpleVar &>(ae.getLeftExp()).getSymbol(), pos);
                }
            }
            else if (!assignments.empty())
            {
                result.report(context, e.getLocation(), *this, _("Argument at position %d must be an assignment."), pos);
            }
            ++pos;
        }
        if (!assignments.empty())
        {
            const std::wstring & name = static_cast<const ast::SimpleVar &>(ce.getName()).getSymbol().getName();
            const ast::FunctionDec * fundec = context.getPublicFunction(name);
            if (!fundec)
            {
                fundec = context.getPrivateFunction(name);
            }

            if (fundec)
            {
                const ast::exps_t & funargs = fundec->getArgs().getVars();
                pos = 1;
                for (const auto arg : funargs)
                {
                    const symbol::Symbol & sym = static_cast<const ast::SimpleVar *>(arg)->getSymbol();
                    auto i = assignments.find(sym);
                    if (i != assignments.end())
                    {
                        if (pos != i->second)
                        {
                            result.report(context, e.getLocation(), *this, _("Argument %s declared at position %d and assigned at position %d."), sym.getName(), pos, i->second);
                        }
                    }
                    ++pos;
                }
            }
        }
    }
}
void UselessRetChecker::postCheckNode(const ast::Exp & e, SLintContext & context, SLintResult & result)
{
    if (e.isFunctionDec())
    {
        const std::map<symbol::Symbol, Location> & map = useless.top();
        for (const auto & p : map)
        {
            result.report(context, p.second, *this, _("Function returned value might be unused: %s."), p.first);
        }
        useless.pop();
    }
}
Example #8
0
void DeprecatedChecker::__Mfprintf::preCheckNode(const ast::Exp & e, SLintContext & context, SLintResult & result)
{
    const ast::CallExp & ce = static_cast<const ast::CallExp &>(e);
    const ast::exps_t args = ce.getArgs();
    if (args.size() != 0)
    {
        const ast::Exp & first = *args.front();
        if (first.isDoubleExp() && static_cast<const ast::DoubleExp &>(first).getValue() == -1)
        {
            result.report(context, e.getLocation(), *this, _("mfprintf(-1, ...) is deprecated."));
        }
    }
}
Example #9
0
void DeprecatedChecker::__Svd::preCheckNode(const ast::Exp & e, SLintContext & context, SLintResult & result)
{
    const ast::CallExp & ce = static_cast<const ast::CallExp &>(e);
    const ast::exps_t args = ce.getArgs();
    if (args.size() == 2)
    {
        const ast::Exp & second = *args.back();
        if (second.isDoubleExp() && static_cast<const ast::DoubleExp &>(second).getValue() == 0)
        {
            result.report(context, e.getLocation(), *this, _("svd(..., 0) is deprecated."));
        }
    }
}
void UselessRetChecker::preCheckNode(const ast::Exp & e, SLintContext & context, SLintResult & result)
{
    if (e.isFunctionDec())
    {
        const ast::exps_t & rets = static_cast<const ast::FunctionDec &>(e).getReturns().getVars();
        useless.push(std::map<symbol::Symbol, Location>());
        std::map<symbol::Symbol, Location> & map = useless.top();
        for (const auto ret : rets)
        {
            const ast::SimpleVar & var = *static_cast<const ast::SimpleVar *>(ret);
            map.emplace(var.getSymbol(), var.getLocation());
        }
    }
    else if (e.isSimpleVar())
    {
        const ast::SimpleVar & var = static_cast<const ast::SimpleVar &>(e);
        if (context.isFunOut(var.getSymbol()) && context.isAssignedVar(var))
        {
            useless.top().erase(var.getSymbol());
        }
    }
}
Example #11
0
void VariablesChecker::postCheckNode(const ast::Exp & e, SLintContext & context, SLintResult & result)
{
    if (e.isFunctionDec())
    {
        const ast::FunctionDec & fd = static_cast<const ast::FunctionDec &>(e);
        auto & map = assigned.top();
        const auto & out = context.getFunOut();
        for (const auto & n : out)
        {
            map.erase(n);
        }
        map.erase(fd.getSymbol().getName());
        for (const auto & p : map)
        {
            result.report(context, p.second.first, *this, _("Declared variable and might be unused: %s."), p.first);
        }
        assigned.pop();
        used.pop();
    }
}
void UnreachableCodeChecker::preCheckNode(const ast::Exp & e, SLintContext & context, SLintResult & result)
{
    const ast::exps_t & exps = e.getExps();
    const ast::Exp * returnExp = nullptr;
    for (const auto exp : exps)
    {
        if (returnExp)
        {
            if (!exp->isCommentExp())
            {
                result.report(context, returnExp->getLocation(), *this, _("The code after the return statement is unreachable."));
                return;
            }
        }
        else if (exp->isReturnExp())
        {
            returnExp = exp;
        }
    }
}
bool ImplicitList::invoke(typed_list & in, optional_list & /*opt*/, int /*_iRetCount*/, typed_list & out, const ast::Exp & e)
{
    if (in.size() == 0)
    {
        out.push_back(this);
    }
    else
    {
        InternalType * _out = extract(&in);
        if (!_out)
        {
            std::wostringstream os;
            os << _W("Invalid index.\n");
            throw ast::InternalError(os.str(), 999, e.getLocation());
        }
        out.push_back(_out);
    }

    return true;
}
void FunctionTestReturnChecker::preCheckNode(const ast::Exp & e, SLintContext & context, SLintResult & result)
{
    const ast::CallExp & ce = static_cast<const ast::CallExp &>(e);
    if (ce.getName().isSimpleVar())
    {
        const std::wstring & name = static_cast<const ast::SimpleVar &>(ce.getName()).getSymbol().getName();
        auto i = funs.find(name);
        if (i != funs.end())
        {
            const std::vector<unsigned int> & positions = i->second;
            if (!positions.empty())
            {
                const ast::AssignListExp * ale = nullptr;
                const ast::AssignExp * ae = context.getAssignExp();
                if (ae)
                {
                    if (ae->getLeftExp().isAssignListExp())
                    {
                        ale = &static_cast<const ast::AssignListExp &>(ae->getLeftExp());
                    }

                    // syms will contain the symbols associated to returned error code
                    std::set<symbol::Symbol> syms;
                    if (ale)
                    {
                        const ast::exps_t & exps = ale->getExps();
                        for (const auto pos : positions)
                        {
                            if (pos > exps.size())
                            {
                                result.report(context, e.getLocation(), *this, _("Function %s requires an error checking just after call."), name);
                                return;
                            }
                            else
                            {
                                if (exps[pos - 1] && exps[pos - 1]->isSimpleVar())
                                {
                                    syms.emplace(static_cast<ast::SimpleVar *>(exps[pos - 1])->getSymbol());
                                }
                            }
                        }
                    }
                    else if (ae->getLeftExp().isSimpleVar())
                    {
                        if (positions.size() > 1 || positions.back() != 1)
                        {
                            result.report(context, e.getLocation(), *this, _("Function %s requires an error checking just after call."), name);
                            return;
                        }
                        syms.emplace(static_cast<ast::SimpleVar &>(ae->getLeftExp()).getSymbol());
                    }
                    if (const ast::Exp * next = context.getNextRelevantExp())
                    {
                        if (next->isIfExp())
                        {
                            const ast::IfExp * ie = static_cast<const ast::IfExp *>(next);
                            // We look for syms in the test: found syms are removed from syms
                            FindSymVisitor(syms, ie->getTest());
                            if (!syms.empty())
                            {
                                result.report(context, e.getLocation(), *this, _("Function %s requires an error checking just after call."), name);
                                return;
                            }
                        }
                    }
                }
                else
                {
                    result.report(context, e.getLocation(), *this, _("Function %s requires an error checking just after call."), name);
                    return;
                }
            }
        }
    }
}
Example #15
0
void VariablesChecker::preCheckNode(const ast::Exp & e, SLintContext & context, SLintResult & result)
{
    if (e.isFunctionDec())
    {
        const ast::FunctionDec & fd = static_cast<const ast::FunctionDec &>(e);
        if (!assigned.empty())
        {
            // we declare the function in the current scope
            std::pair<Location, ast::AssignListExp *> p = { e.getLocation(), nullptr };
            assigned.top().emplace(fd.getSymbol().getName(), p);
        }

        assigned.emplace(std::unordered_map<std::wstring, std::pair<Location, ast::AssignListExp *>>());
        used.emplace(std::unordered_map<std::wstring, const ast::Exp *>());

        // a function cans refer to itself
        std::pair<Location, ast::AssignListExp *> p = { e.getLocation(), nullptr };
        assigned.top().emplace(fd.getSymbol().getName(), p);
    }
    else
    {
        if (!used.empty())
        {
            if (e.isSimpleVar())
            {
                const ast::SimpleVar & var = static_cast<const ast::SimpleVar &>(e);
                if (context.isAssignedVar(var))
                {
                    // if we are not in the context on a nested assignment in a function call (foo(a,b=2))
                    if (!var.getParent()->getParent() || !var.getParent()->getParent()->isCallExp())
                    {
                        const std::wstring & name = var.getSymbol().getName();
                        auto i = used.top().find(name);
                        if (!context.topLoop() || (i == used.top().end()) || !isParentOf(context.topLoop(), i->second))
                        {
                            // the variable has never been used or the last time it wasn't in a loop
                            if (i != used.top().end())
                            {
                                used.top().erase(i);
                            }
                            if (var.getParent() == context.getLHSExp() && var.getParent()->isAssignListExp())
                            {
                                // we have something like [lhs, rhs] = argn(0)
                                // if rhs is used and lhs is not used then this not an "error":
                                // we are obliged to define lhs just to get rhs.
                                // So when rhs is used lhs is "used" too.
                                std::pair<Location, ast::AssignListExp *> p = { var.getLocation(), static_cast<ast::AssignListExp *>(var.getParent()) };
                                assigned.top().emplace(name, p);
                            }
                            else
                            {
                                std::pair<Location, ast::AssignListExp *> p = { var.getLocation(), nullptr };
                                assigned.top().emplace(name, p);
                            }
                        }
                        else /*if (context.topLoop() && i != used.top.end() && isParentOf(context.topLoop(), i->second))*/
                        {
                            // Just to remember...
                            // Here the variable has already been used in the current loop and we reassign it
                            // something like:
                            // while (...)
                            //  ... use i
                            //  ...
                            //  i = ...
                            // end
                            // In general the loop will looping so the assignment is implicitly destroyed by the use in the next iteration
                            // so we don't add this assignment !
                        }
                    }
                }
                else if (!e.getParent()->isFieldExp() || static_cast<const ast::FieldExp *>(e.getParent())->getTail() != &e)
                {
                    const symbol::Symbol & sym = var.getSymbol();
                    const std::wstring & name = sym.getName();
                    if (used.top().find(name) == used.top().end())
                    {
                        used.top().emplace(name, context.topLoop());
                        auto i = assigned.top().find(name);
                        if (i == assigned.top().end())
                        {
                            if (!context.isFunIn(name) && !SLintChecker::isScilabConstant(name))
                            {
                                types::InternalType * pIT = symbol::Context::getInstance()->get(sym);
                                if (pIT)
                                {
                                    if (!pIT->isFunction() && !pIT->isMacroFile() && !pIT->isMacro())
                                    {
                                        result.report(context, e.getLocation(), *this, _("Use of non-initialized variable \'%s\' may have any side-effects."), name);
                                    }
                                }
                                else if (!context.isPrivateFunction(sym))
                                {
                                    /* The symbol doesn't correspond to a private function:
                                       function tata()
                                       titi()
                                       end

                                       function titi()
                                       ...
                                       end

                                       titi is private but usable in tata.
                                    */
                                    std::wstring fname;
                                    if (context.isExternPrivateFunction(sym, fname))
                                    {
                                        result.report(context, e.getLocation(), *this, _("Use of a private macro \'%s\' defined in an other file %s."), name, fname);
                                    }
                                    else if (!context.getPublicFunction(fname))
                                    {
                                        // The macro has not been declared somewhere in the project
                                        result.report(context, e.getLocation(), *this, _("Use of non-initialized variable \'%s\' may have any side-effects."), name);
                                    }
                                }
                            }
                        }
                        else
                        {
                            if (ast::AssignListExp * ale = i->second.second)
                            {
                                // the variable is in an AssignListExp
                                // so we must "use" the variables which preceed it too
                                for (auto e : ale->getExps())
                                {
                                    if (e->isSimpleVar())
                                    {
                                        const std::wstring & prevName = static_cast<ast::SimpleVar *>(e)->getSymbol().getName();
                                        assigned.top().erase(prevName);
                                        if (prevName == name)
                                        {
                                            break;
                                        }
                                        else
                                        {
                                            used.top().emplace(prevName, context.topLoop());
                                        }
                                    }
                                }
                            }
                            else
                            {
                                assigned.top().erase(i);
                            }
                        }
                    }
                }
            }
            // for i=1:10... end even if i is not used, i is useful to make the loop
            /*else if (e.isVarDec())
            {
                const ast::VarDec & vd = static_cast<const ast::VarDec &>(e);
                const std::wstring & name = vd.getSymbol().getName();
                std::pair<Location, ast::AssignListExp *> p = { vd.getLocation(), nullptr };
                assigned.top().emplace(name, p);
                used.top().erase(name);
            }*/
        }
    }
}
bool AnalysisVisitor::getDimension(SymbolicDimension & dim, ast::Exp & arg, bool & safe, SymbolicDimension & out)
{
    switch (arg.getType())
    {
        case ast::Exp::COLONVAR :
        {
            out = dim;
            safe = true;
            arg.getDecorator().setDollarInfo(argIndices.top());
            return true;
        }
        case ast::Exp::DOLLARVAR : // a($)
        {
            out = SymbolicDimension(getGVN(), 1.);
            safe = true;
            arg.getDecorator().setDollarInfo(argIndices.top());
            return true;
        }
        case ast::Exp::DOUBLEEXP : // a(12) or a([1 2])
        {
            ast::DoubleExp & de = static_cast<ast::DoubleExp &>(arg);
            if (types::InternalType * const pIT = de.getConstant())
            {
                if (pIT->isDouble())
                {
                    types::Double * const pDbl = static_cast<types::Double *>(pIT);
                    if (pDbl->isEmpty())
                    {
                        out = SymbolicDimension(getGVN(), 0.);
                        safe = true;
                        return true;
                    }

                    const double * real = pDbl->getReal();
                    const int size = pDbl->getSize();
                    int64_t max;
                    if (tools::asInteger(real[0], max))
                    {
                        int64_t min = max;
                        if (!pDbl->isComplex())
                        {
                            for (int i = 0; i < size; ++i)
                            {
                                int64_t _real;
                                if (tools::asInteger(real[i], _real))
                                {
                                    if (_real < min)
                                    {
                                        min = _real;
                                    }
                                    else if (_real > max)
                                    {
                                        max = _real;
                                    }
                                }
                                else
                                {
                                    return false;
                                }
                            }

                            out = SymbolicDimension(getGVN(), size);
                            safe = (min >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max));
                            return true;
                        }
                        else
                        {
                            const double * imag = pDbl->getImg();
                            int i;
                            for (i = 0; i < size; ++i)
                            {
                                if (imag[i])
                                {
                                    break;
                                }
                                int64_t _real;
                                if (tools::asInteger(real[i], _real))
                                {
                                    if (_real < min)
                                    {
                                        min = _real;
                                    }
                                    else if (_real > max)
                                    {
                                        max = _real;
                                    }
                                }
                            }

                            if (i == size)
                            {
                                out = SymbolicDimension(getGVN(), size);
                                safe = (min >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max));
                                return true;
                            }
                            else
                            {
                                return false;
                            }
                        }
                    }
                    else
                    {
                        return false;
                    }
                }
                else if (pIT->isImplicitList())
                {
                    types::ImplicitList * const pIL = static_cast<types::ImplicitList *>(pIT);
                    double start, step, end;
                    if (AnalysisVisitor::asDouble(pIL->getStart(), start) && AnalysisVisitor::asDouble(pIL->getStep(), step) && AnalysisVisitor::asDouble(pIL->getEnd(), end))
                    {
                        double single;
                        const int type = ForList64::checkList(start, end, step, single);

                        switch (type)
                        {
                            case 0 :
                            {
                                out = SymbolicDimension(getGVN(), 0.);
                                safe = true;
                                return true;
                            }
                            case 1 :
                            {
                                out = SymbolicDimension(getGVN(), 1.);
                                safe = false;
                                return true;
                            }
                            case 2 :
                            {
                                const uint64_t N = ForList64::size(start, end, step);
                                uint64_t max, min;
                                if (step > 0)
                                {
                                    min = start;
                                    max = (uint64_t)(start + (N - 1) * step);
                                }
                                else
                                {
                                    max = start;
                                    min = (uint64_t)(start + (N - 1) * step);
                                }

                                out = SymbolicDimension(getGVN(), N);
                                safe = (min >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue((int64_t)max));
                                return true;
                            }
                        }
                    }
                }
            }
            else
            {
                out = SymbolicDimension(getGVN(), 1.);
                safe = (de.getValue() >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(de.getValue()));
                return true;
            }
            return false;
        }
        case ast::Exp::BOOLEXP : // a(a > 1) => a([%f %t %t]) => a([2 3])
        {
            ast::BoolExp & be = static_cast<ast::BoolExp &>(arg);
            if (types::InternalType * const pIT = be.getConstant())
            {
                if (pIT->isBool())
                {
                    types::Bool * const pBool = static_cast<types::Bool *>(pIT);
                    const int size = pBool->getSize();
                    const int * data = pBool->get();
                    int64_t max = -1;
                    int64_t count = 0;
                    for (int i = 0; i < size; ++i)
                    {
                        if (data[i])
                        {
                            ++count;
                            max = i;
                        }
                    }

                    out = SymbolicDimension(getGVN(), count);
                    safe = getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max));
                    return true;
                }
            }
            else
            {
                if (be.getValue())
                {
                    out = SymbolicDimension(getGVN(), int64_t(1));
                }
                else
                {
                    out = SymbolicDimension(getGVN(), int64_t(0));
                }
                safe = true;
                return true;
            }
            return false;
        }
        case ast::Exp::LISTEXP :
        {
            ast::ListExp & le = static_cast<ast::ListExp &>(arg);
            SymbolicList sl;
            if (SymbolicList::get(*this, le, sl))
            {
                if (sl.isSymbolic())
                {
                    sl.evalDollar(getGVN(), dim.getValue());
                }
                TIType typ;
                if (sl.getType(getGVN(), typ))
                {
                    out = SymbolicDimension(getGVN(), typ.cols.getValue());
                    safe = false;//getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max));
                    return true;
                }
            }
            return false;
        }
        default :
        {
            arg.accept(*this);
            Result & _res = getResult();
            SymbolicRange & range = _res.getRange();
            if (range.isValid())
            {
                //std::wcerr << *range.getStart()->poly << ":" << *range.getEnd()->poly << ",," << *dim.getValue()->poly << std::endl;
                safe = getCM().check(ConstraintManager::VALID_RANGE, range.getStart(), range.getEnd(), getGVN().getValue(int64_t(1)), dim.getValue());
                out = _res.getType().rows * _res.getType().cols;

                return true;
            }

            if (GVN::Value * const v = _res.getConstant().getGVNValue())
            {
                GVN::Value * w = v;
                if (GVN::Value * const dollar = getGVN().getExistingValue(symbol::Symbol(L"$")))
                {
                    if (GVN::Value * const x = SymbolicList::evalDollar(getGVN(), v, dollar, dim.getValue()))
                    {
                        w = x;
                    }
                }
                bool b = getCM().check(ConstraintManager::GREATER, dim.getValue(), w);
                if (b)
                {
                    safe = getCM().check(ConstraintManager::STRICT_POSITIVE, w);
                }
                else
                {
                    safe = false;
                }
                out = SymbolicDimension(getGVN(), 1);
                return true;
            }

            // To use with find
            // e.g. a(find(a > 0)): find(a > 0) return a matrix where the max index is rc(a) so the extraction is safe
            if (_res.getType().ismatrix() && _res.getType().type != TIType::BOOLEAN)
            {
                out = _res.getType().rows * _res.getType().cols;
                SymbolicDimension & maxIndex = _res.getMaxIndex();
                if (maxIndex.isValid())
                {
                    safe = getCM().check(ConstraintManager::GREATER, dim.getValue(), maxIndex.getValue());
                }
                else
                {
                    safe = false;
                }
                return true;
            }
            return false;
        }
    }
}