def extract_attr_annotations(c: Cursor) -> AnnotationSet: d = annotation_set() for cc in c.find_descendants(lambda c: c.kind in attr_annotation_relevant_kinds): annotation_nodes = [ strip_nw(a.spelling) for a in cc.get_children() if a.kind == CursorKind.ANNOTATE_ATTR and a.spelling.startswith(NIGHTWATCH_PREFIX) ] for s in annotation_nodes: name, value = parse_annotation(s) d[name] = value return d
def extract_annotations(cursor: Cursor) -> AnnotationSet: ret = annotation_set() for c in cursor.find_descendants(lambda c: c.kind in annotation_relevant_kinds): with location(convert_location(c.location)): ret["depends_on"] = set(c.referenced_parameters) | ret.get("depends_on", set()) if c.kind == CursorKind.VAR_DECL: ret.update(extract_attr_annotations(c).pushdown(c.displayname)) if c.kind == CursorKind.VAR_DECL and c.displayname.startswith(NIGHTWATCH_PREFIX): name = strip_prefix(NIGHTWATCH_PREFIX, c.displayname) if len(c.children) > 0 and c.children[-1].kind.is_expression(): expr = c.children[-1] ret[name] = annotation_parser(name)(expr.unparsed) # ret["depends_on"] = set(expr.referenced_parameters) | ret.get("depends_on", set()) else: parse_assert( name == "type_cast", f"Missing value for annotation variable declaration: {c.unparsed}" ) ret[name] = c.type elif c.kind == CursorKind.IF_STMT: pred = extract_predicate(c.children[0]) then_branch = extract_annotations(c.children[1]) else_branch = extract_annotations(c.children[2]) if len(c.children) > 2 else annotation_set() if isinstance(pred, tuple) and pred[0] == "argument_block": assert not else_branch ret.update(then_branch.pushdown(pred[1])) elif isinstance(pred, tuple) and pred[0] == "return_value_block": assert not else_branch ret.update(then_branch.pushdown("return_value")) elif isinstance(pred, tuple) and pred[0] == "element_block": assert not else_branch ret.update(then_branch.pushdown("element")) elif isinstance(pred, tuple) and pred[0].startswith("field_block_"): name = strip_prefix("field_block_", pred[0]) ret.update(then_branch.pushdown(Field(name))) else: ret.update(then_branch.if_else(pred, else_branch)) return ret