def generateDoxygenForSourceLocation(line, col): filename = vim.current.buffer.name index = Index.create() tu = index.parse(filename, vim.eval("g:clang_doxygen_clang_args"), [(filename, "\n".join(vim.current.buffer[:]))]) # Skip whitespace at beginning of line indent = re.match(r'^\s*', vim.current.buffer[line - 1]).span()[1] col = max(col, indent + 1) c = Cursor.from_location(tu, SourceLocation.from_position(tu, File.from_name(tu, filename), line, col)) # If there is no declaration at the source location try to find the nearest one. while c is not None: # If cursor is on a TypeRef in a FunctionTemplate, manually go backward in the source. if c.kind == CursorKind.TYPE_REF: pLine, pCol = previousSourceLocation(c.extent.start.line, c.extent.start.column) c = Cursor.from_location(tu, SourceLocation.from_position(tu, File.from_name(tu, filename), pLine, pCol)) continue # If cursor is on a NamespaceRef, manually go forward in the source. elif c.kind == CursorKind.NAMESPACE_REF: nLine, nCol = nextSourceLocation(c.extent.end.line, c.extent.end.column) c = Cursor.from_location(tu, SourceLocation.from_position(tu, File.from_name(tu, filename), nLine, nCol)) continue elif c.kind == CursorKind.FUNCTION_DECL: return handleFunctionDecl(c) elif c.kind == CursorKind.CXX_METHOD: return handleFunctionDecl(c) elif c.kind == CursorKind.CONSTRUCTOR: return handleFunctionDecl(c) elif c.kind == CursorKind.DESTRUCTOR: return handleFunctionDecl(c) elif c.kind == CursorKind.FUNCTION_TEMPLATE: return handleFunctionTemplate(c) elif c.kind == CursorKind.CLASS_DECL: return handleClassDecl(c) elif c.kind == CursorKind.CLASS_TEMPLATE: return handleClassDecl(c) elif c.kind == CursorKind.OBJC_INSTANCE_METHOD_DECL: return handleFunctionDecl(c) elif c.kind == CursorKind.OBJC_INTERFACE_DECL: return handleClassDecl(c) elif c.kind == CursorKind.OBJC_CATEGORY_DECL: return handleClassDecl(c) elif c.kind == CursorKind.OBJC_IMPLEMENTATION_DECL: return handleClassDecl(c) # Cursor is not on a supported type, go to the lexical parent else: c = c.lexical_parent if c is None: print "Error: No supported declaration found at %s:%i,%i.\n" % (filename, line, col) return (None, None)
def test_file(): index = Index.create() tu = index.parse('t.c', unsaved_files = [('t.c', "")]) file = File.from_name(tu, "t.c") assert str(file) == "t.c" assert file.name == "t.c" assert repr(file) == "<File: t.c>"
def gotoDeclaration(preview=True): global debug debug = int(vim.eval("g:clang_debug")) == 1 params = getCompileParams(vim.current.buffer.name) line, col = vim.current.window.cursor timer = CodeCompleteTimer(debug, vim.current.buffer.name, line, col, params) with libclangLock: tu = getCurrentTranslationUnit(params['args'], getCurrentFile(), vim.current.buffer.name, timer, update=True) if tu is None: print("Couldn't get the TranslationUnit") return f = File.from_name(tu, vim.current.buffer.name) loc = SourceLocation.from_position(tu, f, line, col + 1) cursor = Cursor.from_location(tu, loc) defs = [cursor.get_definition(), cursor.referenced] for d in defs: if d is not None and loc != d.location: loc = d.location if loc.file is not None: jumpToLocation(loc.file.name, loc.line, loc.column, preview) break timer.finish()
def test_extent(self): tu = get_tu(baseInput) one = get_cursor(tu, 'one') two = get_cursor(tu, 'two') self.assert_location(one.extent.start, line=1, column=1, offset=0) self.assert_location(one.extent.end, line=1, column=8, offset=7) self.assertEqual( baseInput[one.extent.start.offset:one.extent.end.offset], "int one") self.assert_location(two.extent.start, line=2, column=1, offset=9) self.assert_location(two.extent.end, line=2, column=8, offset=16) self.assertEqual( baseInput[two.extent.start.offset:two.extent.end.offset], "int two") file = File.from_name(tu, 't.c') location1 = SourceLocation.from_position(tu, file, 1, 1) location2 = SourceLocation.from_position(tu, file, 1, 8) range1 = SourceRange.from_locations(location1, location2) range2 = SourceRange.from_locations(location1, location2) self.assertEqual(range1, range2) location3 = SourceLocation.from_position(tu, file, 1, 6) range3 = SourceRange.from_locations(location1, location3) self.assertNotEqual(range1, range3)
def test_file(self): index = Index.create() tu = index.parse('t.c', unsaved_files=[('t.c', "")]) file = File.from_name(tu, "t.c") self.assertEqual(str(file), "t.c") self.assertEqual(file.name, "t.c") self.assertEqual(repr(file), "<File: t.c>")
def get_usr_under_cursor(self, file_name, line, col): with self.c_parse_lock: if file_name not in self.current_file_tus: return "" tu = self.current_file_tus[file_name] f = File.from_name(tu, file_name) loc = SourceLocation.from_position(tu, f, int(line), int(col)) cursor = Cursor.from_location(tu, loc) while cursor is not None and (not cursor.referenced or not cursor.referenced.get_usr()): nextCursor = cursor.lexical_parent if nextCursor is not None and nextCursor == cursor: return "" cursor = nextCursor if cursor is None: return "" cursor = cursor.referenced if cursor is None: return "" return { 'usr': cursor.get_usr(), 'file': str(cursor.location.file), 'line': cursor.location.line, 'column': cursor.location.column }
def gotoDeclaration(preview=True): global debug debug = int(vim.eval("g:clang_debug")) == 1 params = getCompileParams(vim.current.buffer.name) line, col = vim.current.window.cursor timer = CodeCompleteTimer(debug, vim.current.buffer.name, line, col, params) with libclangLock: tu = getCurrentTranslationUnit(params['args'], getCurrentFile(), vim.current.buffer.name, timer, update = True) if tu is None: print("Couldn't get the TranslationUnit") return f = File.from_name(tu, vim.current.buffer.name) loc = SourceLocation.from_position(tu, f, line, col + 1) cursor = Cursor.from_location(tu, loc) defs = [cursor.get_definition(), cursor.referenced] for d in defs: if d is not None and loc != d.location: loc = d.location if loc.file is not None: jumpToLocation(loc.file.name, loc.line, loc.column, preview) break timer.finish()
def test_file(self): index = Index.create() tu = index.parse('t.c', unsaved_files = [('t.c', "")]) file = File.from_name(tu, "t.c") self.assertEqual(str(file), "t.c") self.assertEqual(file.name, "t.c") self.assertEqual(repr(file), "<File: t.c>")
def test_extent(): tu = get_tu(baseInput) one = get_cursor(tu, 'one') two = get_cursor(tu, 'two') assert_location(one.extent.start, line=1, column=1, offset=0) assert_location(one.extent.end, line=1, column=8, offset=7) assert baseInput[one.extent.start.offset:one.extent.end. offset] == "int one" assert_location(two.extent.start, line=2, column=1, offset=9) assert_location(two.extent.end, line=2, column=8, offset=16) assert baseInput[two.extent.start.offset:two.extent.end. offset] == "int two" file = File.from_name(tu, 't.c') location1 = SourceLocation.from_position(tu, file, 1, 1) location2 = SourceLocation.from_position(tu, file, 1, 8) range1 = SourceRange.from_locations(location1, location2) range2 = SourceRange.from_locations(location1, location2) assert range1 == range2 location3 = SourceLocation.from_position(tu, file, 1, 6) range3 = SourceRange.from_locations(location1, location3) assert range1 != range3
def test_location(): tu = get_tu(baseInput) one = get_cursor(tu, 'one') two = get_cursor(tu, 'two') assert one is not None assert two is not None assert_location(one.location, line=1, column=5, offset=4) assert_location(two.location, line=2, column=5, offset=13) # adding a linebreak at top should keep columns same tu = get_tu('\n' + baseInput) one = get_cursor(tu, 'one') two = get_cursor(tu, 'two') assert one is not None assert two is not None assert_location(one.location, line=2, column=5, offset=5) assert_location(two.location, line=3, column=5, offset=14) # adding a space should affect column on first line only tu = get_tu(' ' + baseInput) one = get_cursor(tu, 'one') two = get_cursor(tu, 'two') assert_location(one.location, line=1, column=6, offset=5) assert_location(two.location, line=2, column=5, offset=14) # define the expected location ourselves and see if it matches # the returned location tu = get_tu(baseInput) file = File.from_name(tu, 't.c') location = SourceLocation.from_position(tu, file, 1, 5) cursor = Cursor.from_location(tu, location) one = get_cursor(tu, 'one') assert one is not None assert one == cursor # Ensure locations referring to the same entity are equivalent. location2 = SourceLocation.from_position(tu, file, 1, 5) assert location == location2 location3 = SourceLocation.from_position(tu, file, 1, 4) assert location2 != location3 offset_location = SourceLocation.from_offset(tu, file, 5) cursor = Cursor.from_location(tu, offset_location) verified = False for n in [n for n in tu.cursor.get_children() if n.spelling == 'one']: assert n == cursor verified = True assert verified
def GetCurrentUsrCursor(tu): line, col = vim.current.window.cursor col = col + 1 f = File.from_name(tu, vim.current.buffer.name) loc = SourceLocation.from_position(tu, f, line, col) cursor = Cursor.from_location(tu, loc) while cursor is not None and (not cursor.referenced or not cursor.referenced.get_usr()): nextCursor = cursor.lexical_parent if nextCursor is not None and nextCursor == cursor: return None cursor = nextCursor if cursor is None: return None return cursor.referenced
def find_declaration(self, data, lines): self.join_queue() context = data['context'] src = self.get_src("\n".join(lines), context) filepath = context['filepath'] bcol = context['bcol'] lnum = context['lnum'] args, directory = self.get_args_dir(data) tu = self.get_tu(filepath, args, directory, src) f = File.from_name(tu, filepath) location = SourceLocation.from_position(tu, f, lnum, bcol) cursor = Cursor.from_location(tu, location) defs = [cursor.get_definition(), cursor.referenced] for d in defs: if d is None: logger.info("d None") continue d_loc = d.location if d_loc.file is None: logger.info("location.file None") continue ret = {} ret['file'] = d_loc.file.name ret['lnum'] = d_loc.line ret['bcol'] = d_loc.column return ret # we failed finding the declaration, maybe there's some syntax error # stopping us. Report it to the user. logger.info('reading Diagnostic for this tu, args: %s', args) for diag in tu.diagnostics: # type: Diagnostic if diag.severity < diag.Error: pass self.nvim.call('ncm2_pyclang#error', diag.format()) return {}
def get_usr_under_cursor(self, file_name, line, col): with self.c_parse_lock: if file_name not in self.current_file_tus: return "" tu = self.current_file_tus[file_name] f = File.from_name(tu, file_name) loc = SourceLocation.from_position(tu, f, int(line), int(col)) cursor = Cursor.from_location(tu, loc) while cursor is not None and (not cursor.referenced or not cursor.referenced.get_usr()): nextCursor = cursor.lexical_parent if nextCursor is not None and nextCursor == cursor: return "" cursor = nextCursor if cursor is None: return "" cursor = cursor.referenced if cursor is None: return "" return {'usr': cursor.get_usr(), 'file': str(cursor.location.file), 'line': cursor.location.line, 'column': cursor.location.column}
def gotoDeclaration(self, preview=True): params = self.getCompileParams(self.vim.current.buffer.name) line, col = self.vim.current.window.cursor tu = self.getCurrentTranslationUnit(params['args'], self.getCurrentFile(), self.vim.current.buffer.name, update = True) if tu is None: print("Couldn't get the TranslationUnit") return f = File.from_name(tu, self.vim.current.buffer.name) loc = SourceLocation.from_position(tu, f, line, col + 1) cursor = Cursor.from_location(tu, loc) defs = [cursor.get_definition(), cursor.referenced] for d in defs: if d is not None and loc != d.location: loc = d.location if loc.file is not None: self.jumpToLocation(loc.file.name, loc.line, loc.column, preview) break
def test_location(): index = Index.create() tu = index.parse('t.c', unsaved_files = [('t.c',baseInput)]) for n in tu.cursor.get_children(): if n.spelling == 'one': assert_location(n.location,line=1,column=5,offset=4) if n.spelling == 'two': assert_location(n.location,line=2,column=5,offset=13) # adding a linebreak at top should keep columns same tu = index.parse('t.c', unsaved_files = [('t.c',"\n"+baseInput)]) for n in tu.cursor.get_children(): if n.spelling == 'one': assert_location(n.location,line=2,column=5,offset=5) if n.spelling == 'two': assert_location(n.location,line=3,column=5,offset=14) # adding a space should affect column on first line only tu = index.parse('t.c', unsaved_files = [('t.c'," "+baseInput)]) for n in tu.cursor.get_children(): if n.spelling == 'one': assert_location(n.location,line=1,column=6,offset=5) if n.spelling == 'two': assert_location(n.location,line=2,column=5,offset=14) # define the expected location ourselves and see if it matches # the returned location tu = index.parse('t.c', unsaved_files = [('t.c',baseInput)]) file = File.from_name(tu, 't.c') location = SourceLocation.from_position(tu, file, 1, 5) cursor = Cursor.from_location(tu, location) for n in tu.cursor.get_children(): if n.spelling == 'one': assert n == cursor
def test_extent(self): tu = get_tu(baseInput) one = get_cursor(tu, 'one') two = get_cursor(tu, 'two') self.assert_location(one.extent.start,line=1,column=1,offset=0) self.assert_location(one.extent.end,line=1,column=8,offset=7) self.assertEqual(baseInput[one.extent.start.offset:one.extent.end.offset], "int one") self.assert_location(two.extent.start,line=2,column=1,offset=9) self.assert_location(two.extent.end,line=2,column=8,offset=16) self.assertEqual(baseInput[two.extent.start.offset:two.extent.end.offset], "int two") file = File.from_name(tu, 't.c') location1 = SourceLocation.from_position(tu, file, 1, 1) location2 = SourceLocation.from_position(tu, file, 1, 8) range1 = SourceRange.from_locations(location1, location2) range2 = SourceRange.from_locations(location1, location2) self.assertEqual(range1, range2) location3 = SourceLocation.from_position(tu, file, 1, 6) range3 = SourceRange.from_locations(location1, location3) self.assertNotEqual(range1, range3)
def test_extent(): tu = get_tu(baseInput) one = get_cursor(tu, 'one') two = get_cursor(tu, 'two') assert_location(one.extent.start, line=1, column=1, offset=0) assert_location(one.extent.end, line=1, column=8, offset=7) assert baseInput[one.extent.start.offset:one.extent.end.offset] == "int one" assert_location(two.extent.start, line=2, column=1, offset=9) assert_location(two.extent.end, line=2, column=8, offset=16) assert baseInput[two.extent.start.offset:two.extent.end.offset] == "int two" file = File.from_name(tu, 't.c') location1 = SourceLocation.from_position(tu, file, 1, 1) location2 = SourceLocation.from_position(tu, file, 1, 8) range1 = SourceRange.from_locations(location1, location2) range2 = SourceRange.from_locations(location1, location2) assert range1 == range2 location3 = SourceLocation.from_position(tu, file, 1, 6) range3 = SourceRange.from_locations(location1, location3) assert range1 != range3
def get_static_locations(dynamic_locations, clang_include_paths): """ Get locations for certain constructs which are only available statically. - Variable declarations without any executable code "int i;" - Case statements "case foo:" - Default statements "default: " """ static_locations = [] def ancestor_node(n): """ Get the nearest significant ancestor. """ if n.kind == CursorKind.FUNCTION_DECL: return n else: if n.semantic_parent is None: return n else: return ancestor_node(n.semantic_parent) def good(n): """ Node should be added to the trace. """ if n.kind in (CursorKind.VAR_DECL, CursorKind.CASE_STMT, CursorKind.DEFAULT_STMT): return True else: return False filepaths = defaultdict(list) for l in dynamic_locations: filepaths[l.filepath].append(l) for filepath, locations in filepaths.items(): log.debug( f'Parsing source file {filepath} with args {clang_include_paths}') root = nodeutils.parse(filepath, clang_include_paths) ancestors = [] file = File.from_name(root.translation_unit, filepath) for l in locations: source_location = SourceLocation.from_position( root.translation_unit, file, l.lineno, l.column) node = Cursor.from_location(root.translation_unit, source_location) l.node = node if node.kind.is_invalid(): continue ancestor = ancestor_node(node) if ancestor not in ancestors: log.debug( f'node {nodeutils.pp(node)} has ancestor {nodeutils.pp(ancestor)}' ) ancestors.append(ancestor) for a in ancestors: if a.kind.is_translation_unit(): continue # Do not include global constructs else: nodes = nodeutils.find(a, good) locations = [ Location(n.location.file.name, n.location.line, n.location.column, n) for n in nodes ] for l in locations: log.debug(f'static location {l}') static_locations += locations return static_locations