summaryrefslogblamecommitdiff
path: root/src/analysis/collections.cpp
blob: c94c8af0fbf27b4bcab8838caa24937f9b89a4c6 (plain) (tree)


















                                                                         
                                 
 

                   
                              













                                                     







                                                      








                                            
                                      
         


     










                                                     
                                                                           












                                                                                       













                                                                                       















































                                                                             
                                                            
 



                                               




                                     





                                                  
         
                                           
         
            
         




                                                                

         









                                                       












                                                                     






                                                                          

 

                                          
 


                                   

                                 
                                    

 










                                       









                                          




                                          
                                                                      




















                                               
                             
 







                                                          






                                                                            





                                                  




                                     
















                                                                
     


                                       
                                                       
 

                                                                   

 






                                                                   
                                           
                                                          
 

                                                                         

 






                                                                         
                                      
                                                                         
 
                                          
     

                                              


     









                                                                         
                                          
                                                                            
 
                                             
     

                                                 


     









                                                                            







                                                                           



                                                                                        

                                     



















                                                                                           

                                     















                                                                         
















                                                                                     








                                                    







                                           
 
/*
 *  Copyright (C) 2015  Andrei Karas
 *
 *  This file is part of Paranoid null checker.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "analysis/collections.h"

#include "logger.h"

#include "analysis/analysis.h"
#include "analysis/walkitem.h"

#include "localconsts.h"

namespace Analysis
{

// add variables null pointer checks
void addNeedCheckNullVars(WalkItem &wi, WalkItem &wo)
{
    FOR_EACH (it, wi.addNullVars)
    {
        wo.needCheckNullVars.insert(it);
        wo.knownVars.insert(it);
    }
}

// add variables null pointer checks
void addNeedCheckNullVars2(WalkItem &wi, WalkItem &wo)
{
    FOR_EACH (it, wi.addNullVars)
    {
        if (isNotIn(it, wo.addNullVars))
        {
            wo.needCheckNullVars.insert(it);
            wo.knownVars.insert(it);
            wo.knownNonNullVars.erase(it);
            wo.knownNullVars.erase(it);
            wo.removeNullVars.erase(it);
            wo.removeNullVarsAll.erase(it);
            wo.addNullVars.insert(it);
            removeLinkVarOnly(wo, it);
        }
    }
}

void removeKnownNullVars2(WalkItem &wi, WalkItem &wo)
{
    FOR_EACH (it, wo.knownNullVars)
    {
        if (isNotIn(it, wi.knownNullVars))
        {
            wo.knownNullVars.erase(it);
        }
    }
}

void removeNeedCheckNullVarsThen(WalkItem &wco, WalkItem &wi, WalkItem &wo)
{
    FOR_EACH (it, wi.knownNonNullVars)
    {
        // check what it presend in if condition like if (!it) and in else like if (it)
        if (isIn(it, wco.checkedThenNullVars) &&
            isIn(it, wco.checkedElseNonNullVars))
        {
            removeNeedCheckNullVarOnly(wo, it);
            addNonNullVar(wo, it);
        }
    }
}

void removeNeedCheckNullVarsElse(WalkItem &wco, WalkItem &wi, WalkItem &wo)
{
    FOR_EACH (it, wi.knownNonNullVars)
    {
        // check what it presend in if condition like if (!it) and in else like if (it)
        if (isIn(it, wco.checkedElseNullVars) &&
            isIn(it, wco.checkedThenNonNullVars))
        {
            removeNeedCheckNullVarOnly(wo, it);
            addNonNullVar(wo, it);
        }
    }
}

// remove one variable from null pointer checks
void removeNeedCheckNullVar(WalkItem &wi, std::string str)
{
    if (isIn(str, wi.needCheckNullVars))
    {
        wi.needCheckNullVars.erase(str);
    }
    if (isIn(str, wi.addNullVars))
    {
        wi.addNullVars.erase(str);
    }
    auto it2 = wi.linkedVars.find(str);
    if (it2 != wi.linkedVars.end())
    {
        const StringSet &linked = (*it2).second;
        FOR_EACH (it3, linked)
        {
            if (isIn(it3, wi.needCheckNullVars))
            {
                wi.needCheckNullVars.erase(it3);
            }
            if (isIn(it3, wi.addNullVars))
            {
                wi.addNullVars.erase(it3);
            }
        }
    }
}

// remove vars from checks for null pointer with linked vars
void removeNeedCheckNullVarsSetAll(WalkItem &wi, std::set<std::string> &vars)
{
    FOR_EACH (it, vars)
    {
        // remove var if need
        removeNeedCheckNullVar(wi, it);
        // if need remove some linked var, search it parent,
        // and remove all linked vars for this parent
        auto it3 = wi.linkedReverseVars.find(it);
        if (it3 != wi.linkedReverseVars.end())
        {
            const std::string parent = (*it3).second;
            //wi.linkedVars.erase(parent);
            removeNeedCheckNullVar(wi, parent);
        }
    }
}

void removeLinkVarOnly(WalkItem &wi, const std::string &var)
{
    auto it2 = wi.linkedVars.find(var);
    if (it2 != wi.linkedVars.end())
    {
        const StringSet linked = (*it2).second;
        if (linked.empty())
        {
            wi.linkedVars.erase(var);
            return;
        }
        std::string newParent = *(linked.begin());
        wi.linkedReverseVars.erase(newParent);
        wi.linkedVars[newParent] = linked;
        wi.linkedVars.erase(var);
        wi.linkedVars[newParent].erase(newParent);
        if (wi.linkedVars[newParent].empty())
        {
            wi.linkedVars.erase(newParent);
        }
        else
        {
            const StringSet &linked2 = wi.linkedVars[newParent];
            FOR_EACH (it3, linked2)
            {
                wi.linkedReverseVars[it3] = newParent;
            }
        }
    }
    if (isIn(var, wi.linkedReverseVars))
    {
        std::string parent = wi.linkedReverseVars[var];
        wi.linkedVars[parent].erase(var);
        if (wi.linkedVars[parent].empty())
            wi.linkedVars.erase(parent);
    }
    wi.linkedReverseVars.erase(var);
}

void removeNeedCheckNullVarOnly(WalkItem &wi, const std::string &var)
{
    if (isIn(var, wi.needCheckNullVars))
    {
        wi.needCheckNullVars.erase(var);
    }
    if (isIn(var, wi.addNullVars))
    {
        wi.addNullVars.erase(var);
    }
    removeLinkVarOnly(wi, var);
}

// remove vars from checks for null pointer without linked vars
void removeNeedCheckNullVarsSet(WalkItem &wi, std::set<std::string> &vars)
{
    FOR_EACH (it, vars)
    {
        removeNeedCheckNullVarOnly(wi, it);
    }
}

void addUnknownVar(WalkItem &wi,
                   const std::string &var)
{
    wi.knownVars.insert(var);
    wi.knownNullVars.erase(var);
    wi.knownNonNullVars.erase(var);
    wi.addNullVars.insert(var);
    wi.removeNullVars.erase(var);
    wi.removeNullVarsAll.erase(var);
}

void addNullVar(WalkItem &wi,
                const std::string &var)
{
    wi.knownVars.insert(var);
    wi.knownNullVars.insert(var);
    wi.knownNonNullVars.erase(var);
    wi.addNullVars.insert(var);
    wi.removeNullVars.erase(var);
    wi.removeNullVarsAll.erase(var);
}

void addNonNullVar(WalkItem &wi,
                   const std::string &var)
{
    wi.knownVars.insert(var);
    wi.knownNullVars.erase(var);
    wi.knownNonNullVars.insert(var);
    wi.addNullVars.erase(var);
    wi.removeNullVars.insert(var);
}

// link var to parent. (type var = parent)
void addLinkedVar(WalkItem &wi,
                  std::string parent,
                  const std::string &var)
{
    //Log::log("addLinkedVar: %s, %s\n", parent.c_str(), var.c_str());
    if (isIn(parent, wi.addNullVars) ||
        isIn(parent, wi.needCheckNullVars))
    {
        wi.addNullVars.insert(var);
        wi.removeNullVars.erase(var);
    }
    if (isIn(parent, wi.removeNullVars))
    {
        wi.removeNullVars.insert(var);
        wi.addNullVars.erase(var);
    }
    if (isIn(parent, wi.knownNullVars))
    {
        wi.knownNullVars.insert(var);
        wi.knownNonNullVars.erase(var);
    }
    else if (isIn(parent, wi.knownNonNullVars))
    {
        wi.knownNonNullVars.insert(var);
        wi.knownNullVars.erase(var);
    }
    wi.knownVars.insert(var);

    if (isIn(var, wi.linkedReverseVars))
    {
        std::string oldParent = wi.linkedReverseVars[var];
        wi.linkedVars[oldParent].erase(var);
        if (wi.linkedVars.empty())
            wi.linkedVars.erase(oldParent);
    }

    // found parent as already linked var. need change parent to real parent
    if (isIn(parent, wi.linkedReverseVars))
        parent = wi.linkedReverseVars[parent];
    if (isNotIn(parent, wi.linkedVars))
        wi.linkedVars[parent] = std::set<std::string>();
    wi.linkedVars[parent].insert(var);
    wi.linkedReverseVars[var] = parent;

    // found what variable have linked vars to it.
    // Need move all this vars to new parent.
    if (isIn(var, wi.linkedVars))
    {
        StringSet linked = wi.linkedVars[var];
        if (linked.empty())
        {
            wi.linkedVars.erase(var);
            return;
        }
        std::string newParent = *(linked.begin());
        wi.linkedReverseVars.erase(newParent);
        wi.linkedVars[newParent] = linked;
        wi.linkedVars.erase(var);
        wi.linkedVars[newParent].erase(newParent);
        if (wi.linkedVars[newParent].empty())
        {
            wi.linkedVars.erase(newParent);
        }
        else
        {
            const StringSet &linked2 = wi.linkedVars[newParent];
            FOR_EACH (it3, linked2)
            {
                wi.linkedReverseVars[it3] = newParent;
            }
        }
    }
}

// merger two checked for null var sets
void mergeThenNullChecked(WalkItem &wi1, WalkItem &wi2)
{
    wi1.checkedThenNullVars.insert(wi2.checkedThenNullVars.begin(),
        wi2.checkedThenNullVars.end());
}

// merger two checked for null var sets
void mergeElseNullChecked(WalkItem &wi1, WalkItem &wi2)
{
    wi1.checkedElseNullVars.insert(wi2.checkedElseNullVars.begin(),
        wi2.checkedElseNullVars.end());
}

// merger two checked for non null var sets
void mergeThenNonNullChecked(WalkItem &wi1, WalkItem &wi2)
{
    wi1.checkedThenNonNullVars.insert(wi2.checkedThenNonNullVars.begin(),
        wi2.checkedThenNonNullVars.end());
}

// merger two checked for non null var sets
void mergeElseNonNullChecked(WalkItem &wi1, WalkItem &wi2)
{
    wi1.checkedElseNonNullVars.insert(wi2.checkedElseNonNullVars.begin(),
        wi2.checkedElseNonNullVars.end());
}

// intersect two checked for null sets
void intersectThenNullChecked(WalkItem &wi, WalkItem &wi1, WalkItem &wi2)
{
    FOR_EACH (it, wi1.checkedThenNullVars)
    {
        if (isIn(it, wi2.checkedThenNullVars))
            wi.checkedThenNullVars.insert(it);
    }
}

// intersect two checked for null sets
void intersectElseNullChecked(WalkItem &wi, WalkItem &wi1, WalkItem &wi2)
{
    FOR_EACH (it, wi1.checkedElseNullVars)
    {
        if (isIn(it, wi2.checkedElseNullVars))
            wi.checkedElseNullVars.insert(it);
    }
}

// intersect two checked for non null sets
void intersectThenNonNullChecked(WalkItem &wi, WalkItem &wi1, WalkItem &wi2)
{
    FOR_EACH (it, wi1.checkedThenNonNullVars)
    {
        if (isIn(it, wi2.checkedThenNonNullVars))
            wi.checkedThenNonNullVars.insert(it);
    }
}

// intersect two checked for non null sets
void intersectElseNonNullChecked(WalkItem &wi, WalkItem &wi1, WalkItem &wi2)
{
    FOR_EACH (it, wi1.checkedElseNonNullVars)
    {
        if (isIn(it, wi2.checkedElseNonNullVars))
            wi.checkedElseNonNullVars.insert(it);
    }
}

void removeFromNeedCheckNullVars(WalkItem &wi, std::set<std::string> &vars)
{
    FOR_EACH (it, vars)
    {
        wi.needCheckNullVars.erase(it);
    }
}

void addKnownNullVarsWithLinked(WalkItem &wo, WalkItem &wi, std::set<std::string> &vars)
{
    wo.knownNullVars.insert(vars.begin(),
        vars.end());
    wo.knownVars.insert(vars.begin(),
        vars.end());
    FOR_EACH (it, vars)
    {
        auto it2 = wi.linkedVars.find(it);
        if (it2 == wi.linkedVars.end() && isIn(it, wi.linkedReverseVars))
        {
            wo.knownNullVars.insert(wi.linkedReverseVars[it]);
            it2 = wi.linkedVars.find(wi.linkedReverseVars[it]);
        }
        if (it2 != wi.linkedVars.end())
        {
            const StringSet &linked = (*it2).second;
            wo.knownNullVars.insert(linked.begin(), linked.end());
        }
    }
}

void addKnownNonNullVarsWithLinked(WalkItem &wo, WalkItem &wi, std::set<std::string> &vars)
{
    wo.knownNonNullVars.insert(vars.begin(),
        vars.end());
    wo.knownVars.insert(vars.begin(),
        vars.end());
    FOR_EACH (it, vars)
    {
        auto it2 = wi.linkedVars.find(it);
        if (it2 == wi.linkedVars.end() && isIn(it, wi.linkedReverseVars))
        {
            wo.knownNonNullVars.insert(wi.linkedReverseVars[it]);
            it2 = wi.linkedVars.find(wi.linkedReverseVars[it]);
        }
        if (it2 != wi.linkedVars.end())
        {
            const StringSet &linked = (*it2).second;
            wo.knownNonNullVars.insert(linked.begin(), linked.end());
        }
    }
}

void addKnownNonNullVarWithLinked(WalkItem &wo, WalkItem &wi, const std::string &var)
{
    wo.knownNonNullVars.insert(var);
    auto it2 = wi.linkedVars.find(var);
    if (it2 == wi.linkedVars.end() &&
        isIn(var, wi.linkedReverseVars))
    {
        wo.knownNonNullVars.insert(wi.linkedReverseVars[var]);
        it2 = wi.linkedVars.find(wi.linkedReverseVars[var]);
    }
    if (it2 != wi.linkedVars.end())
    {
        const StringSet &linked = (*it2).second;
        wo.knownNonNullVars.insert(linked.begin(), linked.end());
    }
}

void removeVar(WalkItem &wi, const std::string &var)
{
    wi.removeNullVars.insert(var);
    wi.knownVars.erase(var);
    wi.knownNullVars.erase(var);
    wi.knownNonNullVars.erase(var);
    removeNeedCheckNullVarOnly(wi, var);
}

void enforceNeedCheckNullVars(WalkItem &wi)
{
    FOR_EACH (it, wi.needCheckNullVars)
    {
        wi.removeNullVars.erase(it);
    }
}

}