def error_check_logical_operators(self, sorted_analysis_unit_dict): ''' ERR CHECK UNITS DURING LOGICAL OPERATIONS input: sorted analysis unit dictionary of functions returns: none side_effects: might add UnitError objects to self.all_errors list ''' for function_dict in sorted_analysis_unit_dict.values(): tw = TreeWalker(None) for root_token in function_dict['root_tokens']: tw.generic_recurse_and_apply_function( root_token, self.error_check_logical_recursive)
def error_check_comparisons(self, sorted_analysis_unit_dict): ''' ERR CHECK COMPARISION OF UNITS OVER LOGICAL OPERATORS input: sorted analysis unit dictionary of functions returns: none side_effects: might add UnitError objects to self.all_errors list ''' for function_dict in sorted_analysis_unit_dict.values(): tw = TreeWalker(None) for root_token in function_dict['root_tokens']: tw.generic_recurse_and_apply_function( root_token, self.error_check_comparison_recursive)
def error_check_logical_operators(self, sorted_analysis_unit_dict): ''' ERR CHECK UNITS DURING LOGICAL OPERATIONS input: cppcheck configuration unit from dump returns: none side_effects: might add UnitError objects to self.all_errors list ''' for function_dict in sorted_analysis_unit_dict.values(): tw = TreeWalker( function_dict ) # ARGUMENT 'FUNCTION DICTIONARY' IS USED BY SYMBOL TABLE for root_token in function_dict['root_tokens']: tw.generic_recurse_and_apply_function( root_token, self.error_check_logical_recursive_target)
def error_check_addition_of_incompatible_units(self, sorted_analysis_unit_dict): ''' ERROR CHECK ADDITION OF INCOMPATIBLE UNITS input: sorted analysis unit dictionary of functions returns: none side_effects: might add UnitError objects to self.all_errors list ''' for function_dict in sorted_analysis_unit_dict.values(): tw = TreeWalker(None) for root_token in function_dict['root_tokens']: self.have_found_addition_error_on_this_line = False tw.generic_recurse_and_apply_function( root_token, self.error_check_addition_of_incompatible_units_recursive)
def _get_walker(config, storage, list_format): if list_format == Config.LIST_FORMAT_TREE: return TreeWalker(config, storage) elif list_format == Config.LIST_FORMAT_CSV: return CsvWalker(config, storage) else: raise ValueError( 'Unrecognised value for list-format: {}'.format(list_format))
def error_check_addition_of_incompatible_units(self, sorted_analysis_unit_dict): ''' ERROR CHECK ADDITIONAL OF INCOMPATIBLE UNITS input: cppcheck configuration unit from dump returns: none side_effects: might add UnitError objects to self.all_errors list ''' if self.debug: print 'call to error_check_addition_of_incompatible_units' for function_dict in sorted_analysis_unit_dict.values(): tw = TreeWalker( function_dict ) # ARGUMENT 'FUNCTION DICTIONARY' IS USED BY SYMBOL TABLE self.have_found_addition_error_on_this_line = False for root_token in function_dict['root_tokens']: # tw.is_assignment_statement = False # tw.generic_recurse_and_apply_function(root_token, tw.find_assignment_tokens_recursive_target) # if not tw.is_assignment_statement: tw.generic_recurse_and_apply_function( root_token, self. error_check_addition_of_incompatible_units_recursive_target )
def print_unit_errors(self, errors_file, show_high_confidence=True, show_low_confidence=False): error_type_text = [ 'VARIABLE_MULTIPLE_UNITS', 'COMPARISON_INCOMPATIBLE_UNITS', 'VARIABLE_BECAME_UNITLESS', 'FUNCTION_CALLED_WITH_DIFFERENT_UNIT_ARGUMENTS', 'VARIABLE_WITH_UNUSUAL_UNITS', 'ADDITION_OF_INCOMPATIBLE_UNITS', 'LOGICAL_OPERATOR_USED_ON_UNITS', 'UNIT_SMELL', ] tw = TreeWalker(None) with open(errors_file, 'w') as f: for e in self.all_errors: is_high_confidence = not e.is_warning is_low_confidence = e.is_warning if is_high_confidence and not show_high_confidence: continue if is_low_confidence and not show_low_confidence: continue linenr = e.linenr etype = error_type_text[e.ERROR_TYPE] name = e.var_name f.write("%s, %s, %s\n" % (linenr, name, etype)) if e.ERROR_TYPE == UnitErrorTypes.FUNCTION_CALLED_WITH_DIFFERENT_UNIT_ARGUMENTS: tw.generic_recurse_and_apply_function( e.token_left, self.collect_var_units_for_check) tw.generic_recurse_and_apply_function( e.token_right, self.collect_var_units_for_check) else: tw.generic_recurse_and_apply_function( e.token, self.collect_var_units_for_check)
def recheck_unit_errors(self, correction_file, dump_file, source_file): with open(correction_file) as f: for var_result in (line.rstrip('\n') for line in f): var_name, var_unit = var_result.split(',', 1) var_name, var_unit = var_name.strip(), var_unit.strip() var_unit = eval(var_unit) con.phys_corrections[var_name] = var_unit #print "phys_corrections: %s" % con.phys_corrections a_cppcheck_configuration = self.get_cppcheck_config_data_structure( dump_file) errors, varlist = self.load_state(a_cppcheck_configuration) err_checker = ErrorChecker(dump_file, source_file) show_high_confidence = True show_low_confidence = False for e in errors: is_high_confidence = not e.is_warning is_low_confidence = e.is_warning if is_high_confidence and not show_high_confidence: continue if is_low_confidence and not show_low_confidence: continue if e.ERROR_TYPE == UnitErrorTypes.VARIABLE_MULTIPLE_UNITS: tw = TreeWalker(None) self.apply_and_propagate_units(tw, e.token) # TRACK VARIABLE WITH MULTIPLE UNITS if len(e.token.astOperand2.units) > 1: e.units_when_multiple_happened = e.token.astOperand2.units err_checker.all_errors.append(e) if e.token_left.isKnown: # TRACK VARIABLE WITH MULTIPLE UNITS if (len(e.token.astOperand2.units) == 1) and ( e.token_left.units != e.token.astOperand2.units): units = [] units.extend(e.token_left.units) units.extend(e.token.astOperand2.units) e.units_when_multiple_happened = units err_checker.all_errors.append(e) elif e.ERROR_TYPE == UnitErrorTypes.FUNCTION_CALLED_WITH_DIFFERENT_UNIT_ARGUMENTS: tw = TreeWalker(None) self.apply_and_propagate_units(tw, e.token_left) self.apply_and_propagate_units(tw, e.token_right) # UPDATE UNITS AT BOTH CALL POINTS e.units_at_first_assignment = e.token_left.units e.units_when_multiple_happened = e.token_right.units # CHECK UNITS OF FIRST CALL POINT AGAINST THE OTHER CALL POINT if e.units_when_multiple_happened != e.units_at_first_assignment: err_checker.all_errors.append(e) elif e.ERROR_TYPE == UnitErrorTypes.ADDITION_OF_INCOMPATIBLE_UNITS: tw = TreeWalker(None) self.apply_and_propagate_units(tw, e.token) err_checker.have_found_addition_error_on_this_line = False tw.generic_recurse_and_apply_function( e.token, err_checker. error_check_addition_of_incompatible_units_recursive) elif e.ERROR_TYPE == UnitErrorTypes.COMPARISON_INCOMPATIBLE_UNITS: tw = TreeWalker(None) self.apply_and_propagate_units(tw, e.token) tw.generic_recurse_and_apply_function( e.token, err_checker.error_check_comparison_recursive) else: err_checker.all_errors.append(e) print "Error_Rechecker:" err_checker.pretty_print() err_checker.print_unit_errors('errors_2.txt') self.print_var_units_to_check(err_checker, varlist, 'variable_units_to_check_2.txt')
def propagate_units(self, function_dict): tw = TreeWalker(self.type_miner) # ASSUME THE TOKENS COME BACK AS A SORTED LIST break_point = 1000 i=0 for root_token in function_dict['root_tokens']: #print root_token.str, root_token.linenr tw.is_unit_propagation_based_on_constants = False tw.is_unit_propagation_based_on_unknown_variable = False tw.found_arg_var = False tw.found_non_arg_var = False # RESET THE TREE WALKER'S LINE NUMBERS tw.reset_min_max_line_numbers() # FIND THE MIN AND MAX LINE NUMBERS IN THIS AST : USED TO PROTECT LOOP FROM MULTI-LINE STATEMENTS tw.generic_recurse_and_apply_function(root_token, tw.find_min_max_line_numbers) # SCAN VARIABLES tw.generic_recurse_and_apply_function(root_token, tw.scan_variables) # APPLY ROS UNITS TO VARIABLES tw.generic_recurse_and_apply_function(root_token, tw.apply_ROS_units) # APPLY UNITS TO KNOWN SYMBOLS tw.generic_recurse_and_apply_function(root_token, tw.apply_known_symbols_units) # APPLY UNITS FROM KNOWN FUNCTION - getX, getY, getZ tw.generic_recurse_and_apply_function(root_token, tw.apply_units_getXYZ) # APPLY UNITS TO CONVERSION FACTORS tw.generic_recurse_and_apply_function(root_token, tw.apply_conversion_factor_units) # APPLY FUNCTION RETURN UNITS tw.generic_recurse_and_apply_function(root_token, tw.apply_function_return_units) # APPLY UNITS FROM PREVIOUS ROUND tw.generic_recurse_and_apply_function(root_token, tw.apply_previous_round_units) # APPLY DIMENSIONLESS UNITS tw.generic_recurse_and_apply_function(root_token, tw.apply_dimensionless_units) if (not tw.was_some_unit_changed): tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_across_return) # CONTINUE TO ATTEMPT CHANGES UNTIL CHANGES CEASE while tw.was_some_unit_changed: if i>break_point: s = "BREAKING WHILE LOOP AT %d" % break_point raise ValueError(s) return i+=1 tw.was_some_unit_changed = False # LOOK FOR EARLY ABANDONMENT OF THIS AST if not tw.found_units_in_this_tree and self.should_abandon_early: break ### PROPAGATE UNITS tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_across_dot_connectors) tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_across_double_colon) tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_across_square_brackets) tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_across_assignment) tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_math_abs_fabs_floor_ceil) tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_math_min_max) tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_math_fmod_fmodf_fmodl) tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_sqrt) # tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_getXYZ) tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_ternary) tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_pow) tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_inverse_trig) tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_across_operators) tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_across_return) tw.generic_recurse_and_apply_function(root_token, tw.collect_function_param_units_and_decorate_function) tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_across_parenthesis) # END -- WHILE LOOP #RETURN STATEMENT WITH UNITS - STORE UNITS if root_token.str == 'return' and root_token.units: if function_dict['scopeObject'].function: function_return_units = function_dict['scopeObject'].function.return_units for u in root_token.units: if u not in function_return_units: function_return_units.append(u) #ASSIGNMENT STATEMENT WITH UNITS - COLLECT MULTIPLE ASSIGNMENT INCONSISTENCY if root_token.isAssignmentOp: tw.collect_lhs_unit_constraint(root_token)
def collect_constraints(self, function_dict): tw = TreeWalker(self.type_miner, self.vnh) tw.current_file = self.current_file_under_analysis tw.source_file_lines = self.source_file_lines tw.source_file = self.source_file # ASSUME THE TOKENS COME BACK AS A SORTED LIST break_point = 1000 i = 0 found_units = False for root_token in function_dict['root_tokens']: #print root_token.str, root_token.linenr tw.is_unit_propagation_based_on_constants = False tw.is_unit_propagation_based_on_unknown_variable = False tw.current_child_vars = [] tw.found_arg_var = False tw.found_non_arg_var = False # RESET THE TREE WALKER'S LINE NUMBERS tw.reset_min_max_line_numbers() # FIND THE MIN AND MAX LINE NUMBERS IN THIS AST : USED TO PROTECT LOOP FROM MULTI-LINE STATEMENTS tw.generic_recurse_and_apply_function(root_token, tw.find_min_max_line_numbers) # SCAN VARIABLES tw.generic_recurse_and_apply_function(root_token, tw.scan_variables) # APPLY ROS UNITS TO VARIABLES tw.generic_recurse_and_apply_function(root_token, tw.apply_ROS_units) # APPLY UNITS TO KNOWN SYMBOLS tw.generic_recurse_and_apply_function(root_token, tw.apply_known_symbols_units) # APPLY UNITS FROM KNOWN FUNCTION - getX, getY, getZ tw.generic_recurse_and_apply_function(root_token, tw.apply_units_getXYZ) # APPLY UNITS TO CONVERSION FACTORS tw.generic_recurse_and_apply_function( root_token, tw.apply_conversion_factor_units) # APPLY FUNCTION RETURN UNITS tw.generic_recurse_and_apply_function( root_token, tw.apply_function_return_units) # APPLY DIMENSIONLESS UNITS tw.generic_recurse_and_apply_function(root_token, tw.apply_dimensionless_units) if (tw.found_units_in_this_tree): found_units = True if (not tw.was_some_unit_changed): tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_return) # CONTINUE TO ATTEMPT CHANGES UNTIL CHANGES CEASE while tw.was_some_unit_changed: if i > break_point: s = "BREAKING WHILE LOOP AT %d" % break_point raise ValueError(s) return i += 1 tw.was_some_unit_changed = False # LOOK FOR EARLY ABANDONMENT OF THIS AST if not tw.found_units_in_this_tree and self.should_abandon_early: break ### PROPAGATE UNITS tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_dot_connectors) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_double_colon) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_square_brackets) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_assignment) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_math_abs_fabs_floor_ceil) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_math_min_max) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_math_fmod_fmodf_fmodl) tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_sqrt) # tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_getXYZ) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_ternary) tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_pow) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_inverse_trig) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_operators) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_return) tw.generic_recurse_and_apply_function( root_token, tw.collect_function_param_units_and_decorate_function) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_parenthesis) # END -- WHILE LOOP #RETURN STATEMENT WITH UNITS - STORE UNITS if root_token.str == 'return' and root_token.units: if function_dict['scopeObject'].function: function_return_units = function_dict[ 'scopeObject'].function.return_units for u in root_token.units: if u not in function_return_units: function_return_units.append(u) #ASSIGNMENT STATEMENT WITH UNITS - RIGHT TO LEFT PROPAGATION CONSTRAINT if root_token.isAssignmentOp: tw.collect_lhs_unit_constraint(root_token) #tw.generic_recurse_and_apply_function(root_token, tw.collect_implied_non_unit_variables) #SAME UNIT CONSTRAINTS tw.generic_recurse_and_apply_function( root_token, tw.collect_same_unit_constraints) tw.generic_recurse_and_apply_function( root_token, tw.collect_same_unit_constraints_II) tw.generic_recurse_and_apply_function( root_token, tw.collect_same_unit_constraints_III) #CONVERSION FACTOR CONSTRAINTS #tw.generic_recurse_and_apply_function(root_token, tw.collect_conversion_factor_constraints) tw.generic_recurse_and_apply_function( root_token, tw.collect_angle_unit_constraints) #KNOWN SYMBOL CONSTRAINTS tw.generic_recurse_and_apply_function( root_token, tw.collect_known_symbol_constraints) if not self.SHOULD_USE_DEEP_LEARNING_VAR_NAME_HEURISTIC: #NAMING CONSTRAINTS tw.generic_recurse_and_apply_function( root_token, tw.collect_naming_constraints) else: #DEEP LEARNING NAMING CONSTRAINTS tw.generic_recurse_and_apply_function( root_token, tw.collect_deep_network_naming_constraints) # END -- FOR LOOP if (not found_units) and function_dict['scopeObject'].function \ and ((not tw.found_var) or (tw.found_arg_or_local_var)): #and function_dict['scopeObject'].function.argument: function_dict['scopeObject'].function.maybe_generic_function = True
def check_error_when_top3_units(self, root_token): tw = TreeWalker(None) # ASSUME THE TOKENS COME BACK AS A SORTED LIST break_point = 1000 i = 0 tw.is_unit_propagation_based_on_constants = False tw.is_unit_propagation_based_on_unknown_variable = False # RESET THE TREE WALKER'S LINE NUMBERS tw.reset_min_max_line_numbers() # FIND THE MIN AND MAX LINE NUMBERS IN THIS AST : USED TO PROTECT LOOP FROM MULTI-LINE STATEMENTS tw.generic_recurse_and_apply_function(root_token, tw.find_min_max_line_numbers) # APPLY ROS UNITS TO VARIABLES tw.generic_recurse_and_apply_function(root_token, tw.apply_ROS_units) # APPLY UNITS TO KNOWN SYMBOLS tw.generic_recurse_and_apply_function(root_token, tw.apply_known_symbols_units) # APPLY UNITS FROM KNOWN FUNCTION - getX, getY, getZ tw.generic_recurse_and_apply_function(root_token, tw.apply_units_getXYZ) # APPLY UNITS TO CONVERSION FACTORS tw.generic_recurse_and_apply_function(root_token, tw.apply_conversion_factor_units) # APPLY FUNCTION RETURN UNITS tw.generic_recurse_and_apply_function(root_token, tw.apply_function_return_units) # APPLY UNITS FROM PREVIOUS ROUND tw.generic_recurse_and_apply_function( root_token, tw.apply_previous_round_top3_units) # APPLY DIMENSIONLESS UNITS tw.generic_recurse_and_apply_function(root_token, tw.apply_dimensionless_units) if (not tw.was_some_unit_changed): tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_return) # CONTINUE TO ATTEMPT CHANGES UNTIL CHANGES CEASE while tw.was_some_unit_changed: if i > break_point: s = "BREAKING WHILE LOOP AT %d" % break_point raise ValueError(s) return i += 1 tw.was_some_unit_changed = False # LOOK FOR EARLY ABANDONMENT OF THIS AST if not tw.found_units_in_this_tree: break ### PROPAGATE UNITS tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_dot_connectors) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_double_colon) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_square_brackets) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_assignment) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_math_abs_fabs_floor_ceil) tw.perform_intersection = True tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_math_min_max) tw.perform_intersection = False tw.perform_intersection = True tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_math_fmod_fmodf_fmodl) tw.perform_intersection = False tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_sqrt) # tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_getXYZ) tw.perform_intersection = True tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_ternary) tw.perform_intersection = False tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_pow) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_inverse_trig) tw.perform_intersection = True tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_operators) tw.perform_intersection = False tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_return) tw.generic_recurse_and_apply_function( root_token, tw.collect_function_param_units_and_decorate_function) tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_parenthesis)
def check_errors_with_low_confidence_when_top3_units( self, cppcheck_configuration_unit, sorted_analysis_unit_dict): # need to work on another copy of cppcheckdata # check after all errors are collected con.print_known_unit_variables() data = cppcheckdata.parsedump(self.dump_file) for c in data.configurations[:1]: break # copy token and function data from original config tokenlist = {} for t in cppcheck_configuration_unit.tokenlist: tokenlist[t.Id] = (t.isRoot, t.isDimensionless) functionlist = {} returnexprtokenlist = {} for f in cppcheck_configuration_unit.functions: functionlist[f.Id] = ( f.return_units, f.arg_units, f.return_arg_var_nr, f.return_expr_root_token, f.is_unit_propagation_based_on_constants, f.is_unit_propagation_based_on_unknown_variable, f.is_unit_propagation_based_on_weak_inference, f.maybe_generic_function) if f.return_expr_root_token: returnexprtokenlist[f.return_expr_root_token.Id] = None returntokenlist = {} for t in c.tokenlist: (isRoot, isDimensionless) = tokenlist[t.Id] t.units = [] t.isKnown = False t.is_unit_propagation_based_on_constants = False t.is_unit_propagation_based_on_unknown_variable = False t.is_unit_propagation_based_on_weak_inference = False t.isRoot = isRoot t.isDimensionless = isDimensionless if t.str == "return": returntokenlist[t.Id] = t if t.Id in returnexprtokenlist: returnexprtokenlist[t.Id] = t for f in c.functions: (return_units, arg_units, return_arg_var_nr, return_expr_root_token, is_unit_propagation_based_on_constants, is_unit_propagation_based_on_unknown_variable, is_unit_propagation_based_on_weak_inference, maybe_generic_function) = functionlist[f.Id] if return_expr_root_token: return_expr_root_token = returnexprtokenlist[ return_expr_root_token.Id] f.return_units = [] #return_units f.arg_units = [] #arg_units f.return_arg_var_nr = return_arg_var_nr f.return_expr_root_token = return_expr_root_token f.is_unit_propagation_based_on_constants = is_unit_propagation_based_on_constants f.is_unit_propagation_based_on_unknown_variable = is_unit_propagation_based_on_unknown_variable f.is_unit_propagation_based_on_weak_inference = is_unit_propagation_based_on_weak_inference f.maybe_generic_function = maybe_generic_function for arg_number in f.argument.keys(): f.arg_units.append([]) # collect return units of all functions returnlist = {} for function_dict in sorted_analysis_unit_dict.values(): if not function_dict['scopeObject'].function: continue if function_dict['scopeObject'].function.return_arg_var_nr: continue if function_dict['scopeObject'].function.maybe_generic_function: continue returnlist[function_dict['scopeObject'].function.Id] = [] for root_token in function_dict['root_tokens']: if root_token.str == 'return': t = returntokenlist[root_token.Id] self.check_error_when_top3_units(t) #RETURN STATEMENT WITH UNITS - STORE UNITS if t.units: for u in t.units: if u not in returnlist[ function_dict['scopeObject'].function.Id]: returnlist[function_dict['scopeObject']. function.Id].append(u) tw = TreeWalker(None) tw.generic_recurse_and_apply_function(t, tw.reset_tokens) for f in c.functions: return_units = returnlist.get(f.Id) if return_units: f.return_units = return_units # check all errors for e in self.all_errors: con.FOUND_DERIVED_CU_VARIABLE = False if e.is_warning: continue if e.dont_check_for_warning: continue if e.ERROR_TYPE == UnitErrorTypes.ADDITION_OF_INCOMPATIBLE_UNITS or \ e.ERROR_TYPE == UnitErrorTypes.COMPARISON_INCOMPATIBLE_UNITS: root_token = None # find token in the copy for t in c.tokenlist: if t.Id == e.token.Id: root_token = t break if not root_token: continue self.check_error_when_top3_units(root_token) if e.ERROR_TYPE == UnitErrorTypes.ADDITION_OF_INCOMPATIBLE_UNITS: if con.FOUND_DERIVED_CU_VARIABLE: if len(root_token.units) > 2: e.is_warning = True elif root_token.units: e.is_warning = True else: units = [] if root_token.astOperand1 and root_token.astOperand2: left_units = root_token.astOperand1.units right_units = root_token.astOperand2.units if not left_units: pass #units = right_units elif not right_units: pass #units = left_units else: for lu in left_units: if lu in right_units: units.append(lu) if con.FOUND_DERIVED_CU_VARIABLE: if len(units) > 2: e.is_warning = True elif units: e.is_warning = True tw = TreeWalker(None) tw.generic_recurse_and_apply_function(root_token, tw.reset_tokens) elif e.ERROR_TYPE == UnitErrorTypes.VARIABLE_MULTIPLE_UNITS: i = 0 root_token = None left_token = None # find token in the copy for t in c.tokenlist: if t.Id == e.token.Id: root_token = t i = i + 1 elif t.Id == e.token_left.Id: left_token = t i = i + 1 if i == 2: break if (not root_token) or (not left_token): continue elif not root_token.astOperand2: continue elif not root_token.astOperand1: continue self.check_error_when_top3_units(root_token.astOperand1) self.check_error_when_top3_units(root_token.astOperand2) if (not left_token.isKnown ): #and root_token.astOperand2.units: if con.FOUND_DERIVED_CU_VARIABLE: if len(root_token.astOperand2.units) > 2: e.is_warning = True elif root_token.astOperand2.units: e.is_warning = True else: if root_token.astOperand2.units and ( root_token.astOperand1.units == root_token.astOperand2.units): e.is_warning = True if (not e.is_warning) and ( root_token.astOperand1. is_unit_propagation_based_on_weak_inference): units = [] for lu in root_token.astOperand1.units: if lu in root_token.astOperand2.units: units.append(lu) if con.FOUND_DERIVED_CU_VARIABLE: if len(units) > 2: e.is_warning = True elif units: e.is_warning = True #if not con.is_df_constraint_present(e.token_left, e.var_name): # if root_token.astOperand2.units: #and (root_token.astOperand1.units == root_token.astOperand2.units): # units = [] # for lu in root_token.astOperand1.units: # if lu in root_token.astOperand2.units: # units.append(lu) # if con.FOUND_DERIVED_CU_VARIABLE: # if len(units) > 2: # e.is_warning = True # elif units: # e.is_warning = True tw = TreeWalker(None) tw.generic_recurse_and_apply_function(root_token, tw.reset_tokens)
def get_left_right_units(self, token, left_token, right_token): units = [] left_units = [] right_units = [] if left_token: if left_token.str in [ '*', '/' ] and left_token.astOperand1 and left_token.astOperand2: if left_token.astOperand1.units == [{'nounit': 0.0}]: left_token = left_token.astOperand2 elif left_token.astOperand2.units == [{'nounit': 0.0}]: left_token = left_token.astOperand1 if left_token.str in ['+', '-', '*', '/']: left_units = self.get_left_right_units(left_token, left_token.astOperand1, left_token.astOperand2) else: left_units = left_token.units left_name = left_token.str if left_token.str == '.' or left_token.str == '[': ( left_token, left_name ) = self.symbol_helper.find_compound_variable_and_name_for_dot_operand( left_token) if (left_token.variable, left_name) in con.variable2unitproba: n = 3 if con.is_only_known_unit_variable(left_token.variable, left_name): n = 1 left_units = con.variable2unitproba[(left_token.variable, left_name)][:n] left_units = filter( lambda (u, p): p > con.unit_prob_threshold, left_units) left_units = map(lambda (u, p): u, left_units) if con.ENABLE_UNIT_LIST_FLATTENING: left_units = con.flatten_unit_list(left_units) if right_token: if right_token.str in [ '*', '/' ] and right_token.astOperand1 and right_token.astOperand2: if right_token.astOperand1.units == [{'nounit': 0.0}]: right_token = right_token.astOperand2 elif right_token.astOperand2.units == [{'nounit': 0.0}]: right_token = right_token.astOperand1 if right_token.str in ['+', '-', '*', '/']: right_units = self.get_left_right_units( right_token, right_token.astOperand1, right_token.astOperand2) else: right_units = right_token.units right_name = right_token.str if right_token.str == '.' or right_token.str == '[': ( right_token, right_name ) = self.symbol_helper.find_compound_variable_and_name_for_dot_operand( right_token) if (right_token.variable, right_name) in con.variable2unitproba: n = 3 if con.is_only_known_unit_variable(right_token.variable, right_name): n = 1 right_units = con.variable2unitproba[(right_token.variable, right_name)][:n] right_units = filter( lambda (u, p): p > con.unit_prob_threshold, right_units) right_units = map(lambda (u, p): u, right_units) if con.ENABLE_UNIT_LIST_FLATTENING: right_units = con.flatten_unit_list(right_units) if not left_units: return right_units elif not right_units: return left_units else: if token.str in ['*', '/']: tw = TreeWalker(None) all_unit_dicts_from_multiplication = [] for unit_dict_left in left_units: for unit_dict_right in right_units: result_units = tw.apply_multiplication_to_unit_dicts( unit_dict_left, unit_dict_right, token.str) if result_units: all_unit_dicts_from_multiplication.append( result_units) for u in all_unit_dicts_from_multiplication: if u not in units: units.append(u) else: for lu in left_units: if lu in right_units: units.append(lu) return units
def analyze_function(self, function_dict): if self.debug_verbose: print inspect.stack()[0][3] tw = TreeWalker( function_dict ) # ARGUMENT 'FUNCTION DICTIONARY' IS USED BY SYMBOL TABLE tw.cps_unit_checker = self tw.my_symbol_helper.cps_unit_checker = self self.tw = tw # LINK CURRENT Tree Walker to self tw.debug = self.debug tw.debug_verbose = self.debug_verbose tw.current_file = self.current_file_under_analysis tw.source_file_lines = self.source_file_lines tw.source_file = self.source_file tw.should_check_unitless_during_multiplication = False # UNITLESS tw.my_symbol_helper.should_match_on_heuristic_variable_names = False tw.current_function_dict = function_dict found_units_in_this_function = False # ASSUME THE TOKENS COME BACK AS A SORTED LIST break_point = 1000 i = 0 for root_token in function_dict['root_tokens']: # INITIALIZAE TREE WALKER FOR THIS ROOT TOKEN tw.was_some_unit_changed = True tw.is_unit_propagation_based_on_constants = False tw.is_unit_propagation_based_on_unknown_variable = False if self.SHOULD_ONLY_FIND_FILES_WITH_UNITS and self.found_ros_units_in_this_file and not self.SHOULD_FIND_ALL_UNITS: return # RESET THE TREE WALKER'S LINE NUMBERS tw.reset_min_max_line_numbers() # FIND THE MIN AND MAX LINE NUMBERS IN THIS AST : USED TO PROTECT LOOP FROM MULTI-LINE STATEMENTS tw.generic_recurse_and_apply_function(root_token, tw.find_min_max_line_numbers) # APPLY ROS UNITS TO VARIABLES tw.generic_recurse_and_apply_function(root_token, tw.apply_ROS_units) # APPLY UNITS FROM PREVIOUS ASSIGNMENTS IN SCOPE tw.generic_recurse_and_apply_function(root_token, tw.apply_units_from_scope) # APPLY UNITS FROM KNOWN FUNCTIONS - atan2 tw.generic_recurse_and_apply_function(root_token, tw.apply_units_inverse_trig) # APPLY UNITS FROM KNOWN SYMBOLS - M_PI tw.generic_recurse_and_apply_function(root_token, tw.apply_units_known_symbols) # APPLY UNITS FROM KNOWN FUNCTION - toSec tw.generic_recurse_and_apply_function(root_token, tw.apply_units_toSec) # APPLY UNITS FROM KNOWN FUNCTION - getX, getY, getZ tw.generic_recurse_and_apply_function(root_token, tw.apply_units_getXYZ) # APPLY UNITS FROM KNOWN FUNCTION - quatToRPY tw.generic_recurse_and_apply_function(root_token, tw.apply_units_quatToRPY) # CONTINUE TO ATTEMPT CHANGES UNTIL CHANGES CEASE while tw.was_some_unit_changed: if i > break_point: if self.debug_verbose: s = "BREAKING QUIESSENCE (WHILE) LOOP AT %d" % break_point raise ValueError(s) return break i += 1 tw.was_some_unit_changed = False # LOOK FOR EARLY ABANDONMENT OF THIS AST if not tw.found_units_in_this_tree and self.should_abandon_early: break # SPECIAL MODE - JUST FIND ROS FILES if self.SHOULD_ONLY_FIND_FILES_WITH_UNITS: break ### PROPAGATE ACROSS '.' tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_dot_connectors) ### PROPAGATE ACROSS + - * / += -= *= /= tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_operators) ### PROPAGATE ACROSS ( tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_parenthesis) ### PROPAGATE ACROSS [ tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_square_brackets) ### PROPAGATE INTO f(meters, arg2) into function - FUTURE: CONSTRAINT MODE #tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_into_function_args) ### PROPAGATE ACROSS '=' tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_assignment) ### PROPAGATE ACROSS 'std::abs' 'std::fabs' 'abs' 'fabs' tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_math_abs_fabs_floor_ceil) ### PROPAGATE ACROSS 'std::min' 'std::max' 'min' 'max' tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_math_min_max) ### PROPAGATE ACROSS 'sqrt' tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_sqrt) ### PROPAGATE ACROSS 'getXYZ # tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_getXYZ) ### PROPAGATE ACROSS TERNARY tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_ternary) ### PROPAGATE ACROSS 'pow' tw.generic_recurse_and_apply_function(root_token, tw.propagate_units_pow) ### PROPAGATE ACROSS 'atan2', 'acos', 'asin' tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_inverse_trig) ### PROPAGATE ACROSS 'return' tw.generic_recurse_and_apply_function( root_token, tw.propagate_units_across_return) ### COLLECT UNITS FROM FUNCTION CALL POINTS tw.generic_recurse_and_apply_function( root_token, tw. collect_function_parameters_units_and_decorate_function_objects ) #FUNCTIONS todo: # END -- WHILE LOOP #ASSIGNMENT STATEMENTS WITH UNITS - RIGHT TO LEFT PROPAGATION if root_token.isAssignmentOp and root_token.units: # COLLECT LEFT SIDE OF ASSIGNMENT lhs_compound_name = tw.recurse_and_collect_string( root_token.astOperand1) # ADD UNITS TO VARIABLE IN SCOPE tw.return_value_list = [] tw.generic_recurse_and_apply_function(root_token.astOperand1, tw.find_first_variable) if len(tw.return_value_list) != 1: if len(tw.return_value_list) == 0: if self.debug and self.debug_LHS: print "%s %s LHS no variable found not found" % ( root_token.file, root_token.linenr) else: if self.debug and self.debug_LHS: for value in tw.return_value_list: print "%s %s LHS Variable found: %s" % ( root_token.file, root_token.linenr, value) continue # todo track count of this error lhs_var = tw.return_value_list[0] lhs_scope = lhs_var.nameToken.scope if lhs_var.isArgument: lhs_scope = function_dict['scopeObject'] line_num = int(root_token.linenr) if lhs_compound_name in lhs_scope.var_ordered_dict: # ALREADY HAS ASSIGNMENT, ADD TO IT lhs_scope.var_ordered_dict[lhs_compound_name][line_num] = { 'units': root_token.units, # THIS IS A LIST 'token': root_token, 'is_unit_propagation_based_on_constants': tw.is_unit_propagation_based_on_constants, 'is_unit_propagation_based_on_unknown_variable': tw.is_unit_propagation_based_on_unknown_variable } else: lhs_scope.var_ordered_dict[lhs_compound_name] = { line_num: { 'units': root_token.units, 'token': root_token, 'is_unit_propagation_based_on_constants': tw.is_unit_propagation_based_on_constants, 'is_unit_propagation_based_on_unknown_variable': tw.is_unit_propagation_based_on_unknown_variable } } if self.debug and self.debug_scope: print "ADDED to SCOPE %s : %s has units %s at %s" % ( lhs_scope.Id, lhs_compound_name, root_token.units, line_num) print 'constants-based? %s unknown-based? %s' % ( tw.is_unit_propagation_based_on_constants, tw.is_unit_propagation_based_on_unknown_variable) # EXTRACT UNITS FROM RETURN STATEMENT AND APPLY TO FUNCTION if root_token.str == 'return' and root_token.units: if function_dict['scopeObject'].function: function_return_units = function_dict[ 'scopeObject'].function.return_units for u in root_token.units: if u not in function_return_units: function_return_units.append(u) function_dict[ 'scopeObject'].function.is_unit_propagation_based_on_constants = tw.is_unit_propagation_based_on_constants function_dict[ 'scopeObject'].function.is_unit_propagation_based_on_unknown_variable = tw.is_unit_propagation_based_on_unknown_variable found_units_in_this_function = found_units_in_this_function or tw.found_units_in_this_tree # LOOK FOR EARLY ABANDONMENT if not found_units_in_this_function and not self.debug_print_AST and self.should_abandon_early: return # DEBUG PRINTING for root_token in function_dict['root_tokens']: if self.debug_print_AST: tw.debug_walk(root_token) self.found_ros_units_in_this_file = self.found_ros_units_in_this_file or found_units_in_this_function