示例#1
0
def visit_cursor(path, cursor):
    # Skip symbols from other files.
    if cursor.location.file is None or cursor.location.file.name != path:
        return None

    kind = cursor.kind.name
    if kind not in ALL_KINDS:
        return None

    # Names of function parameters.
    params = None
    # Names of template parameters.
    tparams = None
    children = None
    name = cursor.spelling
    # Display types for variables and typedefs.
    cursor_type = cursor.type.spelling if kind in VAR_KINDS else None
    if kind in FUNCTION_KINDS:
        # We can't use displayname as it also includes the arguments.
        params = []
        tparams = []
        for child in cursor.get_children():
            if child.kind == CursorKind.PARM_DECL:
                # Use the param name, but fall back to the raw type if unnamed.
                params.append(child.spelling or child.type.spelling)
            elif child.kind == CursorKind.TEMPLATE_TYPE_PARAMETER:
                tparams.append(child.spelling)
            # TODO(hansonw): non-type and "template template" params?

    if kind in MEMBER_KINDS:
        # Name should be fully qualified if outside the parent.
        if cursor.semantic_parent != cursor.lexical_parent:
            name = cursor.semantic_parent.spelling + "::" + name
    elif kind in CLASS_KINDS:
        # Include template information.
        name = cursor.displayname
        children = []
        for child in cursor.get_children():
            child_outline = visit_cursor(path, child)
            if child_outline is not None:
                children.append(child_outline)

    ret = {
        "name": name,
        "cursor_kind": kind,
        "cursor_type": cursor_type,
        "extent": range_dict_relative(cursor.extent),
        "params": params,
        "tparams": tparams,
        "children": children,
    }
    return {k: v for k, v in ret.items() if v is not None}
示例#2
0
def visit_cursor(path, cursor):
    # Skip symbols from other files.
    if cursor.location.file is None or cursor.location.file.name != path:
        return None

    kind = cursor.kind.name
    if kind not in ALL_KINDS:
        return None

    # Names of function parameters.
    params = None
    # Names of template parameters.
    tparams = None
    children = None
    name = cursor.spelling
    # Display types for variables and typedefs.
    cursor_type = cursor.type.spelling if kind in VAR_KINDS else None
    if kind in FUNCTION_KINDS:
        # We can't use displayname as it also includes the arguments.
        params = []
        tparams = []
        for child in cursor.get_children():
            if child.kind == CursorKind.PARM_DECL:
                # Use the param name, but fall back to the raw type if unnamed.
                params.append(child.spelling or child.type.spelling)
            elif child.kind == CursorKind.TEMPLATE_TYPE_PARAMETER:
                tparams.append(child.spelling)
            # TODO(hansonw): non-type and "template template" params?

    if kind in MEMBER_KINDS:
        # Name should be fully qualified if outside the parent.
        if cursor.semantic_parent != cursor.lexical_parent:
            name = cursor.semantic_parent.spelling + '::' + name
    elif kind in CLASS_KINDS:
        # Include template information.
        name = cursor.displayname
        children = []
        for child in cursor.get_children():
            child_outline = visit_cursor(path, child)
            if child_outline is not None:
                children.append(child_outline)

    ret = {
        'name': name,
        'cursor_kind': kind,
        'cursor_type': cursor_type,
        'extent': range_dict_relative(cursor.extent),
        'params': params,
        'tparams': tparams,
        'children': children,
    }
    return {k: v for k, v in ret.items() if v is not None}
示例#3
0
    def get_declaration_info_for_cursor(self, cursor):
        '''Returns string id in clang-callgraph-service format for entity under the
        cursor. Currently works only for definitions of class methods, instance
        methods and functions. Returns None for everything else.
        '''
        result = []
        while cursor is not None and not cursor.kind.is_translation_unit():
            file = cursor.location.file
            result.append({
                'name': self.get_name_for_cursor(cursor),
                'type': cursor.kind.name,
                'cursor_usr': cursor.get_usr(),
                'file': resolve_file(file),
                'extent': range_dict_relative(cursor.extent),
            })
            cursor = cursor.semantic_parent

        return result
示例#4
0
    def get_declaration_info_for_cursor(self, cursor):
        '''Returns string id in clang-callgraph-service format for entity under the
        cursor. Currently works only for definitions of class methods, instance
        methods and functions. Returns None for everything else.
        '''
        result = []
        while cursor is not None and not cursor.kind.is_translation_unit():
            file = cursor.location.file
            result.append({
                'name': self.get_name_for_cursor(cursor),
                'type': cursor.kind.name,
                'cursor_usr': cursor.get_usr(),
                'file': resolve_file(file),
                'extent': range_dict_relative(cursor.extent),
            })
            cursor = cursor.semantic_parent

        return result
示例#5
0
def visit_cursor(libclang, cursor):
    kind = cursor.kind.name
    if kind not in ALL_KINDS:
        return None

    # Skip symbols from other files.
    if not libclang.clang_Location_isFromMainFile(cursor.location):
        return None

    # Names of function parameters.
    params = None
    # Names of template parameters.
    tparams = None
    children = None
    name = cursor.spelling
    # Display types for variables and typedefs.
    cursor_type = cursor.type.spelling if kind in VAR_KINDS else None
    if kind in FUNCTION_KINDS:
        # We can't use displayname as it also includes the arguments.
        params = []
        tparams = []
        for child in cursor.get_children():
            if child.kind == CursorKind.PARM_DECL:
                # Use the param name, but fall back to the raw type if unnamed.
                params.append(child.spelling or child.type.spelling)
            elif child.kind == CursorKind.TEMPLATE_TYPE_PARAMETER:
                tparams.append(child.spelling)
            # TODO(hansonw): non-type and "template template" params?

    if kind in MEMBER_KINDS:
        # Name should be fully qualified if outside the parent.
        if cursor.semantic_parent != cursor.lexical_parent:
            name = cursor.semantic_parent.spelling + '::' + name
    elif kind in CLASS_KINDS:
        # Include template information.
        name = cursor.displayname
        children = []
        for child in cursor.get_children():
            child_outline = visit_cursor(libclang, child)
            if child_outline is not None:
                children.append(child_outline)

    if kind == MACRO_INSTANTIATION:
        params = []
        if name in GTEST_MACROS:
            # Should look like TEST(id, id).
            tokens = list(itertools.islice(cursor.get_tokens(), 1, 6))
            if len(tokens) == 5 and (
                tokens[0].kind == TokenKind.PUNCTUATION and
                tokens[1].kind == TokenKind.IDENTIFIER and
                tokens[2].kind == TokenKind.PUNCTUATION and
                tokens[3].kind == TokenKind.IDENTIFIER and
                tokens[4].kind == TokenKind.PUNCTUATION
            ):
                params = [tokens[1].spelling, tokens[3].spelling]
            else:
                return None
        else:
            # TODO(hansonw): Handle other special macros like DEFINE_ params.
            return None

    ret = {
        'name': name,
        'cursor_kind': kind,
        'cursor_type': cursor_type,
        'extent': range_dict_relative(cursor.extent),
        'params': params,
        'tparams': tparams,
        'children': children,
    }
    return {k: v for k, v in ret.items() if v is not None}
示例#6
0
def visit_cursor(libclang, cursor):
    kind = cursor.kind.name
    if kind not in ALL_KINDS:
        return None

    # Skip symbols from other files.
    if not libclang.clang_Location_isFromMainFile(cursor.location):
        return None

    # Names of function parameters.
    params = None
    # Names of template parameters.
    tparams = None
    children = None
    name = cursor.spelling
    # Display types for variables and typedefs.
    cursor_type = cursor.type.spelling if kind in VAR_KINDS else None
    if kind in FUNCTION_KINDS:
        # We can't use displayname as it also includes the arguments.
        params = []
        tparams = []
        for child in cursor.get_children():
            if child.kind == CursorKind.PARM_DECL:
                # Use the param name, but fall back to the raw type if unnamed.
                params.append(child.spelling or child.type.spelling)
            elif child.kind == CursorKind.TEMPLATE_TYPE_PARAMETER:
                tparams.append(child.spelling)
            # TODO(hansonw): non-type and "template template" params?

    if kind in MEMBER_KINDS:
        # Name should be fully qualified if outside the parent.
        if cursor.semantic_parent != cursor.lexical_parent:
            name = cursor.semantic_parent.spelling + '::' + name
    elif kind in CLASS_KINDS:
        # Include template information.
        name = cursor.displayname
        children = []
        for child in cursor.get_children():
            child_outline = visit_cursor(libclang, child)
            if child_outline is not None:
                children.append(child_outline)

    if kind == MACRO_INSTANTIATION:
        params = []
        if name in GTEST_MACROS:
            # Should look like TEST(id, id).
            tokens = list(itertools.islice(cursor.get_tokens(), 1, 6))
            if len(tokens) == 5 and (
                    tokens[0].kind == TokenKind.PUNCTUATION
                    and tokens[1].kind == TokenKind.IDENTIFIER
                    and tokens[2].kind == TokenKind.PUNCTUATION
                    and tokens[3].kind == TokenKind.IDENTIFIER
                    and tokens[4].kind == TokenKind.PUNCTUATION):
                params = [tokens[1].spelling, tokens[3].spelling]
            else:
                return None
        else:
            # TODO(hansonw): Handle other special macros like DEFINE_ params.
            return None

    ret = {
        'name': name,
        'cursor_kind': kind,
        'cursor_type': cursor_type,
        'extent': range_dict_relative(cursor.extent),
        'params': params,
        'tparams': tparams,
        'children': children,
    }
    return {k: v for k, v in ret.items() if v is not None}
示例#7
0
 def visitor(_context, cursor, source_range):
     references.append(range_dict_relative(source_range))
     return 1  # continue
示例#8
0
 def visitor(_context, cursor, source_range):
     range_dict = range_dict_relative(source_range)
     # The end location is non-inclusive.
     range_dict['end']['column'] -= 1
     references.append(range_dict)
     return 1  # continue
示例#9
0
def get_declaration_location_and_spelling(translation_unit, contents, flags,
                                          absolute_path, line, column):
    def log(s):
        logger.info('%s:%d:%d - %s',
                    os.path.basename(absolute_path), line, column, s)

    source_location = translation_unit.get_location(
        absolute_path, (line, column))
    cursor = Cursor.from_location(translation_unit, source_location)
    if cursor is None:
        log('No cursor')
        return None

    # Don't allow clicks/tooltips on most declarations, as their content is usually obvious.
    # Make an exception for variable declarations, as these can often have auto types.
    if cursor.kind != CursorKind.VAR_DECL and cursor.kind.is_declaration():
        log('Ignoring declaration')
        return None

    referenced = cursor.referenced
    if referenced is None or referenced.location is None or referenced.location.file is None:
        # If cursor is over an include statement, attempt to resolve the location
        # of the included file.
        line_text = get_line(contents, line)
        bounds = get_include_path_extent(line_text)

        if bounds is not None:
            start_col, end_col = bounds
            # Don't allow hyperclick if cursor is not over the include name, i.e.:
            # #include "header.h"
            #          ^^^^^^^^
            if column < start_col or column > end_col:
                return None

            filename = resolve_include(absolute_path, line_text, flags)
            if filename is None:
                return None
            # Point location to beginning of the found included file (line 0, column 0)
            location = {
                'file': filename,
                'point': {
                    'row': 0,
                    'column': 0,
                },
                # Show destination file of hyperclick in hover popover
                'type': filename,
                'spelling': None,
                'extent': {
                    'start': {'row': line - 1, 'column': start_col},
                    'end': {'row': line - 1, 'column': end_col}
                }
            }
            return location
        else:
            log('No referenced information')
            return None

    loc = referenced.location
    log('Returning {0}:{1}:{2}'.format(
        os.path.basename(loc.file.name), loc.line, loc.column))

    # An extent has a `start` and `end` property, each of which have a `line`
    # and `column` property.
    extent = cursor.extent

    type = None
    try:
        type = cursor.type and cursor.type.spelling
    except:
        logger.warn('Was not able to get cursor type')
        pass

    location = location_dict(loc)
    location['spelling'] = cursor.spelling
    location['type'] = type
    location['extent'] = range_dict_relative(extent)
    return location
示例#10
0
def get_declaration_location_and_spelling(translation_unit, contents, flags,
                                          absolute_path, line, column):
    def log(s):
        logger.info('%s:%d:%d - %s', os.path.basename(absolute_path), line,
                    column, s)

    source_location = translation_unit.get_location(absolute_path,
                                                    (line, column))
    cursor = Cursor.from_location(translation_unit, source_location)
    if cursor is None:
        log('No cursor')
        return None

    # Don't allow clicks/tooltips on most declarations, as their content is usually obvious.
    # Make an exception for variable declarations, as these can often have auto types.
    if cursor.kind != CursorKind.VAR_DECL and cursor.kind.is_declaration():
        log('Ignoring declaration')
        return None

    referenced = cursor.referenced
    if referenced is None or referenced.location is None or referenced.location.file is None:
        # If cursor is over an include statement, attempt to resolve the location
        # of the included file.
        line_text = get_line(contents, line)
        bounds = get_include_path_extent(line_text)

        if bounds is not None:
            start_col, end_col = bounds
            # Don't allow hyperclick if cursor is not over the include name, i.e.:
            # #include "header.h"
            #          ^^^^^^^^
            if column < start_col or column > end_col:
                return None

            filename = resolve_include(absolute_path, line_text, flags)
            if filename is None:
                return None
            # Point location to beginning of the found included file (line 0, column 0)
            location = {
                'file': filename,
                'point': {
                    'row': 0,
                    'column': 0,
                },
                # Show destination file of hyperclick in hover popover
                'type': filename,
                'spelling': None,
                'extent': {
                    'start': {
                        'row': line - 1,
                        'column': start_col
                    },
                    'end': {
                        'row': line - 1,
                        'column': end_col
                    }
                }
            }
            return location
        else:
            log('No referenced information')
            return None

    loc = referenced.location
    log('Returning {0}:{1}:{2}'.format(os.path.basename(loc.file.name),
                                       loc.line, loc.column))

    # An extent has a `start` and `end` property, each of which have a `line`
    # and `column` property.
    extent = cursor.extent

    type = None
    try:
        type = cursor.type and cursor.type.spelling
    except:
        logger.warn('Was not able to get cursor type')
        pass

    location = location_dict(loc)
    location['spelling'] = cursor.spelling
    location['type'] = type
    location['extent'] = range_dict_relative(extent)
    return location