def get_undefined_vars(nodes, resolved): """Get undefined variable. :param nodes: a list of dom nodes :param resolved: a set of names as strings that is assumed to be defined :return a set of names """ result = set() for node in nodes: if domutil.is_element(node): if node.tagName == 'decl_stmt': _,var_name,_ = syntaxutil.parse_decl_stmt(node) resolved.add(var_name) elif node.tagName == 'expr': # in #ifdef, there may be `#elif defined(__sun)` if domutil.in_node(node, 'cpp:ifdef', level=2) or\ domutil.in_node(node, 'cpp:elif', level=2) or\ domutil.in_node(node, 'cpp:ifndef', level=2): continue name_set = syntaxutil.parse_expr(node) for name in name_set: # uint8_t, false, true, NULL if sys.resolve_single(name): continue # here we find the undefined variable if name not in resolved and name not in result: result.add(name) elif node.tagName == 'for': init_node = domutil.get_first_child_by_tagname(node, 'init') if init_node: _, var = syntaxutil.parse_for_init(init_node) if var: resolved.add(var) elif node.tagName == 'parameter_list': params = syntaxutil.parse_parameter_list(node) for _,name in params: resolved.add(name) elif node.tagName == 'cpp:define': value_node = domutil.get_first_child_by_tagname(node, 'cpp:value') text = domutil.get_text_content(value_node) match = re.findall(r'([A-Z_]{2,})', text) for m in match: if m not in resolved: result.add(m) new_result = get_undefined_vars(node.childNodes, resolved | result) result.update(new_result) return result
def extract_to_resolve(node, resolved): """Extract functions, types, undefined global variables to resolve :param node: dom node that need to resolve :return a set """ functions = set() types = set() unknown = set() for n in node.getElementsByTagName('call'): # in #ifdef, there may be `#elif defined(__sun)` if domutil.in_node(n, 'cpp:ifdef', level=2) or\ domutil.in_node(n, 'cpp:elif', level=2) or\ domutil.in_node(n, 'cpp:ifndef', level=2): continue call_name_node = domutil.get_first_child_by_tagname(n, 'name') call_name = domutil.get_text_content(call_name_node) functions.add(call_name) for n in node.getElementsByTagName('type'): if domutil.in_node(n, 'cpp:define', level=4): continue name_node = domutil.get_first_child_by_tagname(n, 'name') name = domutil.get_text_content(name_node) types.add(name) for n in node.getElementsByTagName('cpp:value'): value = domutil.get_text_content(n) types |= syntaxutil.parse_type_cast(value) for n in node.getElementsByTagName('cpp:define'): functions |= syntaxutil.parse_cpp_define(n) for n in node.getElementsByTagName('cpp:value'): # now lets resolve every word value = domutil.get_text_content(n) for word in re.findall(r'\b\w+\b', value): unknown.add(word) # if function return type if enum, the function is not marked as <function> # but what if the enum is trully enum? This is addressed in resolver/localfunc.py for n in node.getElementsByTagName('enum'): name_node = domutil.get_first_child_by_tagname(n, 'name') name = domutil.get_text_content(name_node) functions.add(name) variables = io.get_undefined_vars([node], resolved) if '' in functions: functions.remove('') if '' in types: types.remove('') if '' in variables: variables.remove('') # return functions-resolved, types-resolved, variables return (functions | types | variables | unknown) - resolved
def resolve_undefined_vars(nodes, resolved): """Get undefined variable. Resolve its type. :param nodes: a list of dom nodes :param resolved: a set of names as strings that is assumed to be defined :return {var: type, ...} """ result = {} for node in nodes: if domutil.is_element(node): if node.tagName == 'decl_stmt': _,var_name,_ = syntaxutil.parse_decl_stmt(node) resolved.add(var_name) elif node.tagName == 'expr': # in #ifdef, there may be `#elif defined(__sun)` if domutil.in_node(node, 'cpp:ifdef', level=2) or\ domutil.in_node(node, 'cpp:elif', level=2) or\ domutil.in_node(node, 'cpp:ifndef', level=2): continue name_set = syntaxutil.parse_expr(node) for name in name_set: # uint8_t, false, true, NULL if sys.resolve_single(name): continue # here we find the undefined variable if name not in resolved and name not in result: type_name = resolve_local_type(name, node) if type_name: result[name] = type_name # if it is a global variable, do not print warning elif not local.check_global_variable(name): logger.warning('undefind variable ' + name + ' not resovled for local type.') elif node.tagName == 'for': init_node = domutil.get_first_child_by_tagname(node, 'init') if init_node: _, var = syntaxutil.parse_for_init(init_node) if var: resolved.add(var) new_result = resolve_undefined_vars(node.childNodes, resolved | result.keys()) result.update(new_result) return result