Commit 05a26cc4 authored by Philip Makedonski's avatar Philip Makedonski
Browse files

+ #80 Fix processing of parameters in data flow validator

+ #81 Fix updating of variable status for template variables
+ related refactorings and renames
parent 9612aa39
Loading
Loading
Loading
Loading
+174 −96
Original line number Diff line number Diff line
@@ -6,18 +6,26 @@ import de.ugoe.cs.swe.common.ConfigTools
import de.ugoe.cs.swe.common.logging.LoggingInterface.MessageClass
import de.ugoe.cs.swe.tTCN3.AltConstruct
import de.ugoe.cs.swe.tTCN3.AltstepDef
import de.ugoe.cs.swe.tTCN3.AltstepInstance
import de.ugoe.cs.swe.tTCN3.AltstepLocalDef
import de.ugoe.cs.swe.tTCN3.Assignment
import de.ugoe.cs.swe.tTCN3.BasicStatements
import de.ugoe.cs.swe.tTCN3.BehaviourStatements
import de.ugoe.cs.swe.tTCN3.BooleanExpression
import de.ugoe.cs.swe.tTCN3.CallStatement
import de.ugoe.cs.swe.tTCN3.CommunicationStatements
import de.ugoe.cs.swe.tTCN3.ComponentDef
import de.ugoe.cs.swe.tTCN3.ComponentElementDef
import de.ugoe.cs.swe.tTCN3.ConditionalConstruct
import de.ugoe.cs.swe.tTCN3.ControlStatement
import de.ugoe.cs.swe.tTCN3.EnumDefNamed
import de.ugoe.cs.swe.tTCN3.Expression
import de.ugoe.cs.swe.tTCN3.ExtFunctionDef
import de.ugoe.cs.swe.tTCN3.Fdecvalue
import de.ugoe.cs.swe.tTCN3.FdecvalueUnichar
import de.ugoe.cs.swe.tTCN3.Fint2enum
import de.ugoe.cs.swe.tTCN3.FormalTemplatePar
import de.ugoe.cs.swe.tTCN3.FunctionActualPar
import de.ugoe.cs.swe.tTCN3.FunctionDef
import de.ugoe.cs.swe.tTCN3.FunctionDefList
import de.ugoe.cs.swe.tTCN3.FunctionFormalPar
@@ -30,13 +38,20 @@ import de.ugoe.cs.swe.tTCN3.InterleavedConstruct
import de.ugoe.cs.swe.tTCN3.InterleavedGuardList
import de.ugoe.cs.swe.tTCN3.LoopConstruct
import de.ugoe.cs.swe.tTCN3.ModuleControlBody
import de.ugoe.cs.swe.tTCN3.OpCall
import de.ugoe.cs.swe.tTCN3.RecordDefNamed
import de.ugoe.cs.swe.tTCN3.RecordOfDefNamed
import de.ugoe.cs.swe.tTCN3.ReferencedValue
import de.ugoe.cs.swe.tTCN3.SelectCaseConstruct
import de.ugoe.cs.swe.tTCN3.SetDefNamed
import de.ugoe.cs.swe.tTCN3.SetOfDefNamed
import de.ugoe.cs.swe.tTCN3.SingleTempVarInstance
import de.ugoe.cs.swe.tTCN3.SingleVarInstance
import de.ugoe.cs.swe.tTCN3.StatementBlock
import de.ugoe.cs.swe.tTCN3.TemplateBody
import de.ugoe.cs.swe.tTCN3.TimerInstance
import de.ugoe.cs.swe.tTCN3.TimerStatements
import de.ugoe.cs.swe.tTCN3.UnionDefNamed
import de.ugoe.cs.swe.tTCN3.Value
import de.ugoe.cs.swe.tTCN3.VarInstance
import de.ugoe.cs.swe.tTCN3.VariableRef
@@ -54,28 +69,17 @@ import org.eclipse.xtext.validation.EValidatorRegistrar

import static extension de.ugoe.cs.swe.common.TTCN3ScopeHelper.*
import static extension org.eclipse.xtext.EcoreUtil2.*
import de.ugoe.cs.swe.tTCN3.Fint2enum
import de.ugoe.cs.swe.tTCN3.FdecvalueUnichar
import de.ugoe.cs.swe.tTCN3.OpCall
import de.ugoe.cs.swe.tTCN3.Expression
import de.ugoe.cs.swe.tTCN3.BooleanExpression
import de.ugoe.cs.swe.tTCN3.AltstepInstance
import de.ugoe.cs.swe.tTCN3.FunctionActualPar
import de.ugoe.cs.swe.tTCN3.RecordDefNamed
import de.ugoe.cs.swe.tTCN3.RecordOfDefNamed
import de.ugoe.cs.swe.tTCN3.SetDefNamed
import de.ugoe.cs.swe.tTCN3.SetOfDefNamed
import de.ugoe.cs.swe.tTCN3.UnionDefNamed
import de.ugoe.cs.swe.tTCN3.EnumDefNamed
import de.ugoe.cs.swe.tTCN3.TemplateBody
import de.ugoe.cs.swe.tTCN3.Enumeration
import de.ugoe.cs.swe.tTCN3.FormalValuePar

class DataFlowValidator extends AbstractDeclarativeValidator {
    val debug = false;
    var debug = false;
    val ConfigTools configTools = ConfigTools.getInstance;
    var QualityCheckProfile activeProfile = configTools.selectedProfile as QualityCheckProfile

    //TODO: check if this can be removed
    @Inject
    private IGlobalScopeProvider globalScopeProvider;
    IGlobalScopeProvider globalScopeProvider;

    override register(EValidatorRegistrar registrar) {
        // not needed for classes used as ComposedCheck
@@ -373,12 +377,12 @@ class DataFlowValidator extends AbstractDeclarativeValidator {
        if (timer.start !== null) {
            val target = timer.start.ref
            if (target instanceof SingleVarInstance) {
                dfh.checkVariableStatus(target,timer);
                dfh.checkComponentVariableStatus(target,timer);
            }
        } else if (timer.stop !== null && timer.stop.ref !== null && timer.stop.ref.ref !== null) {
            val target = timer.stop.ref.ref
            if (target instanceof SingleVarInstance) {
                dfh.checkVariableStatus(target,timer);
                dfh.checkComponentVariableStatus(target,timer);
            }
        }
    }
@@ -519,16 +523,37 @@ class DataFlowValidator extends AbstractDeclarativeValidator {
            if (p.template!==null) {
                //get corresponding formal parameter
                val fp = formalParameters.get(i);
                if (fp.value !== null && fp.value.inOut !== null) {
                    if (fp.value.inOut.equals("out")) {
                //TODO: figure out to factor out repetitive code below
                if (fp.value !== null) {
                    val fpp = fp.value
                    if (fpp.inOut === null) {
                        fpp.inOut = "in"
                    }
                    if (fpp.inOut.equals("out")) {
                        //update
                        dfh.updateVariableStatus(p.eAllOfType(ReferencedValue).get(0))
                    } else if (fpp.inOut.equals("in")) {
                        //check
                        dfh.checkVariableStatus(p.eAllOfType(ReferencedValue))
                    }
                    //TODO: how to handle inout?
                } else if (fp.template !== null) {
                    val fpp = fp.template
                    if (fpp.inOut === null) {
                        fpp.inOut = "in"
                    }
                    if (fpp.inOut.equals("out")) {
                        //update
                        dfh.updateVariableStatus(p.eAllOfType(ReferencedValue).get(0))
                    } else if (fp.value.inOut.equals("in")) {
                    } else if (fpp.inOut.equals("in")) {
                        //check
                        dfh.checkVariableStatus(p.eAllOfType(ReferencedValue))
                    }
                    //TODO: how to handle inout?
                } else {
                    //TODO: other kinds of parameters?
                }
                
            }
            i++;
        }
@@ -815,23 +840,18 @@ class DataFlowValidator extends AbstractDeclarativeValidator {
        }
    }
    

    protected def void updateVariableStatus(DataFlowHelper dfh, SingleVarInstance target) {
        if (dfh.getState(target) === STATUS.UNDECLARED) {
            if (target.expr !== null) {
                dfh.states.put(target,STATUS.INITIALISED)
            } else {
                dfh.states.put(target,STATUS.DECLARED)
            }
//            println("###     "+USE.DEFINE+"->"+dfh.states.get(target)+": "+target.name)
        } else {
//            println("###   ERROR: "+target.name+" already declared!")
        }
        dfh.updateVariableStatus(target, target.expr)
    }

    protected def void updateVariableStatus(DataFlowHelper dfh, SingleTempVarInstance target) {
        dfh.updateVariableStatus(target, target.template)
    }

    protected def void updateVariableStatus(DataFlowHelper dfh, EObject target, EObject targetValue) {
        //factored out from above
        if (dfh.getState(target) === STATUS.UNDECLARED) {
            if (target.template !== null) {
            if (targetValue !== null) {
                dfh.states.put(target,STATUS.INITIALISED)
            } else {
                dfh.states.put(target,STATUS.DECLARED)
@@ -842,11 +862,20 @@ class DataFlowValidator extends AbstractDeclarativeValidator {
        }
    }
    

    
    protected def void updateVariableStatus(DataFlowHelper dfh, ReferencedValue value) {
        val target = value.head.target
        if (target instanceof SingleVarInstance) {
            dfh.updateVariableStatusRV(target, value)
        } else if (target instanceof SingleTempVarInstance) {
            dfh.updateVariableStatusRV(target, value)
        } else if (target instanceof FormalTemplatePar) {
            //TODO: handle?
        } else {
            //TODO: report?
        }
    }
    
    protected def void updateVariableStatusRV(DataFlowHelper dfh, EObject target, EObject context) {
        if (dfh.getState(target) !== STATUS.UNDECLARED) {
            if (dfh.getState(target) === STATUS.DECLARED) {
                dfh.setState(target,STATUS.INITIALISED)
@@ -854,11 +883,9 @@ class DataFlowValidator extends AbstractDeclarativeValidator {
            //println("###     "+USE.DEFINE+"->"+dfh.getState(target)+": "+target.name)
        } else {
            //println("###   ERROR: "+target.name+" not declared!")

            if (!(target.eContainer.eContainer.eContainer instanceof ComponentElementDef)) {
                //println("###   ERROR: "+target.name+" not declared!")
                    target.uninitialisedVariableWarning("declared", value)
                }
                target.uninitialisedVariableWarning("declared", context)
            }
        }
    }
@@ -871,39 +898,72 @@ class DataFlowValidator extends AbstractDeclarativeValidator {
        ]) {
            //check states
            val target = value.head.target
//            println(
//                NodeModelUtils.getNode(value).startLine+" -> "+target.getName
//            )
            //TODO: skip if reference to FormalPar
            if (target.eContainer instanceof FunctionFormalPar) {
                //TODO: handle? likely elsewhere - formal pars need to be marked as declared
                //TODO: altstep is covered but what about testcase parameters?                
            } else if (target instanceof Enumeration) {
                //TODO: handle?
            } else {
//                println(
//                    NodeModelUtils.getNode(value).startLine+" -> "+target.getName
//                )
                checkVariableStatus(dfh, target, value)
            }
        }
    }

    protected def String getName(EObject target) {
        var name = target.eClass.name+" : "
        if (target instanceof SingleVarInstance) {
            name += target.name
        } else if (target instanceof SingleTempVarInstance) {
            name += target.name
        } else if (target instanceof FormalValuePar) {
            name += target.name
        } else if (target instanceof FormalTemplatePar) {
            name += target.name
        } else {
            name += "TODO"
        }
        return name
    }
    
    protected def void checkVariableStatus(DataFlowHelper dfh, EObject target, EObject context) {
        //TODO: perform type checks? SingleVarInstance and SingleTempVarInstance only?
        if (dfh.getState(target) !== STATUS.UNDECLARED) {
            //println("###     "+dfh.getState(target)+"->"+USE.REFERENCE+": "+target.name)                                       

            if (dfh.getState(target) === STATUS.DECLARED) {
                        target.uninitialisedVariableWarning("initialised", value)
                target.uninitialisedVariableWarning("initialised", context)
            }

        } else {
            //println("###   ERROR: "+target.name+" not declared!")

            //special handling of timers and components due to ambiguity
            if (target.eContainer !== null) {
                val parent = target.eContainer.eContainer
                if (!(parent instanceof TimerInstance) && !(parent.eContainer instanceof ComponentElementDef)) {
                        target.uninitialisedVariableWarning("declared", value)
                    }
                    target.uninitialisedVariableWarning("declared", context)
                }
            } else {
                //TODO: likely unresolved, handle?                
            }
        }
    }

    protected def void checkVariableStatus(DataFlowHelper dfh, SingleVarInstance target, EObject context) {
    protected def void checkComponentVariableStatus(DataFlowHelper dfh, EObject target, EObject context) {
        //special handling of component variables due to incorrect parsing and peculiar design decisions
        //TODO: check if template variables in components work as well
        val parent = target.eContainer.eContainer
        if (parent instanceof VarInstance) {
            if (parent.listType.ref.head instanceof ComponentDef) {
                if (dfh.getState(target) !== STATUS.UNDECLARED) {
                    //println("###     "+dfh.getState(target)+"->"+USE.REFERENCE+": "+target.name)                                       

                    if (dfh.getState(target) === STATUS.DECLARED) {
                        target.uninitialisedVariableWarning("initialised", context)
                    }

                } else {
                    //println("###   ERROR: "+target.name+" not declared!")
                    if (!(parent.eContainer instanceof ComponentElementDef)) {
@@ -914,9 +974,17 @@ class DataFlowValidator extends AbstractDeclarativeValidator {
        }
    }
    
    protected def Boolean checkIfExcluded(SingleVarInstance target) {
    protected def Boolean checkIfExcluded(EObject target) {
        var filter = false
        if (!activeProfile.checkNoUninitialisedVariablesExclude.empty) {
            filter = target.checkExclusionForVarInstance()
        }
        return filter        
    }
    
    protected def boolean checkExclusionForVarInstance(EObject target) {
        //factored out from above
        var filter = false
        var vi = target.findDesiredParent(VarInstance)
        if (vi !== null) {
            var type = vi.listType
@@ -942,14 +1010,25 @@ class DataFlowValidator extends AbstractDeclarativeValidator {
                }
            } 
        }
        }
        return filter
    }
        
    protected def void uninitialisedVariableWarning(SingleVarInstance target, String status, EObject context) {
    protected def void uninitialisedVariableWarning(EObject target, String status, EObject context) {
        if (checkIfExcluded(target)) {
            return
        }
        if (target instanceof SingleVarInstance) {
            target.name.uninitialisedVariableWarning(status, context)
        } else if (target instanceof SingleTempVarInstance) {
            target.name.uninitialisedVariableWarning(status, context)
        } else {
            //TODO: handle?
            //println("ERROR: UVW: Not handled: "+target)
        }
    }

    protected def void uninitialisedVariableWarning(String targetName, String status, EObject context) {
        //factored out from above
        TTCN3StatisticsProvider.getInstance.incrementCountStyle
        
        var parentName = "Module Control Part"
@@ -962,7 +1041,7 @@ class DataFlowValidator extends AbstractDeclarativeValidator {
                parentName = asd.name
            } 
        }            
        val message = "Local definition for \"" + target.name + "\" in definition of \"" + parentName +
        val message = "Local definition for \"" + targetName + "\" in definition of \"" + parentName +
            "\" is not "+status+"!"
        val INode node = NodeModelUtils.getNode(context)
        warning(
@@ -977,5 +1056,4 @@ class DataFlowValidator extends AbstractDeclarativeValidator {
    }

    
    
}
 No newline at end of file