diff --git a/doc/clang_complete.txt b/doc/clang_complete.txt index b31ae454..1d0a076f 100644 --- a/doc/clang_complete.txt +++ b/doc/clang_complete.txt @@ -236,6 +236,11 @@ Default: 0 *clang_complete-complete_patterns* *g:clang_complete_patterns* If clang should complete code patterns, i.e loop constructs etc. +Defaut: 0 + + *clang_complete-brief-comments + *g:clang_include_brief_comments +If clang should show brief comments in the completion results. Defaut: 0 *clang_complete-jumpto_declaration_key* diff --git a/plugin/clang/cindex.py b/plugin/clang/cindex.py index 70f4f36a..9b65bef2 100644 --- a/plugin/clang/cindex.py +++ b/plugin/clang/cindex.py @@ -266,6 +266,29 @@ def __eq__(self, other): def __ne__(self, other): return not self.__eq__(other) + def __contains__(self, other): + """Useful to detect the Token/Lexer bug""" + if not isinstance(other, SourceLocation): + return False + if other.file is None and self.start.file is None: + pass + elif ( self.start.file.name != other.file.name or + other.file.name != self.end.file.name): + # same file name + return False + # same file, in between lines + if self.start.line < other.line < self.end.line: + return True + elif self.start.line == other.line: + # same file first line + if self.start.column <= other.column: + return True + elif other.line == self.end.line: + # same file last line + if other.column <= self.end.column: + return True + return False + def __repr__(self): return "" % (self.start, self.end) @@ -508,7 +531,7 @@ def name(self): @staticmethod def from_id(id): if id >= len(CursorKind._kinds) or CursorKind._kinds[id] is None: - raise ValueError,'Unknown cursor kind' + raise ValueError,'Unknown cursor kind %d' % id return CursorKind._kinds[id] @staticmethod @@ -721,10 +744,14 @@ def __repr__(self): # A reference to a labeled statement. CursorKind.LABEL_REF = CursorKind(48) -# A reference toa a set of overloaded functions or function templates +# A reference to a set of overloaded functions or function templates # that has not yet been resolved to a specific function or function template. CursorKind.OVERLOADED_DECL_REF = CursorKind(49) +# A reference to a variable that occurs in some non-expression +# context, e.g., a C++ lambda capture list. +CursorKind.VARIABLE_REF = CursorKind(50) + ### # Invalid/Error Kinds @@ -908,6 +935,26 @@ def __repr__(self): # pack. CursorKind.SIZE_OF_PACK_EXPR = CursorKind(143) +# Represents a C++ lambda expression that produces a local function +# object. +# +# \code +# void abssort(float *x, unsigned N) { +# std::sort(x, x + N, +# [](float a, float b) { +# return std::abs(a) < std::abs(b); +# }); +# } +# \endcode +CursorKind.LAMBDA_EXPR = CursorKind(144) + +# Objective-c Boolean Literal. +CursorKind.OBJ_BOOL_LITERAL_EXPR = CursorKind(145) + +# Represents the "self" expression in a ObjC method. +CursorKind.OBJ_SELF_EXPR = CursorKind(146) + + # A statement whose specific kind is not exposed via this interface. # # Unexposed statements have the same operations as any other kind of statement; @@ -999,6 +1046,9 @@ def __repr__(self): # Windows Structured Exception Handling's finally statement. CursorKind.SEH_FINALLY_STMT = CursorKind(228) +# A MS inline assembly statement extension. +CursorKind.MS_ASM_STMT = CursorKind(229) + # The null statement. CursorKind.NULL_STMT = CursorKind(230) @@ -1028,6 +1078,7 @@ def __repr__(self): CursorKind.CXX_OVERRIDE_ATTR = CursorKind(405) CursorKind.ANNOTATE_ATTR = CursorKind(406) CursorKind.ASM_LABEL_ATTR = CursorKind(407) +CursorKind.PACKED_ATTR = CursorKind(408) ### # Preprocessing @@ -1036,6 +1087,12 @@ def __repr__(self): CursorKind.MACRO_INSTANTIATION = CursorKind(502) CursorKind.INCLUSION_DIRECTIVE = CursorKind(503) +### +# Extra declaration + +# A module import declaration. +CursorKind.MODULE_IMPORT_DECL = CursorKind(600) + ### Cursors ### class Cursor(Structure): @@ -1282,6 +1339,16 @@ def referenced(self): return self._referenced + @property + def brief_comment(self): + """Returns the brief comment text associated with that Cursor""" + return conf.lib.clang_Cursor_getBriefCommentText(self) + + @property + def raw_comment(self): + """Returns the raw comment text associated with that Cursor""" + return conf.lib.clang_Cursor_getRawCommentText(self) + def get_arguments(self): """Return an iterator for accessing the arguments of this cursor.""" num_args = conf.lib.clang_Cursor_getNumArguments(self) @@ -1314,6 +1381,18 @@ def get_tokens(self): """ return TokenGroup.get_tokens(self._tu, self.extent) + def is_bitfield(self): + """ + Check if the field is a bitfield. + """ + return conf.lib.clang_Cursor_isBitField(self) + + def get_bitfield_width(self): + """ + Retrieve the width of a bitfield. + """ + return conf.lib.clang_getFieldDeclBitWidth(self) + @staticmethod def from_result(res, fn, args): assert isinstance(res, Cursor) @@ -1438,6 +1517,54 @@ def __repr__(self): TypeKind.FUNCTIONPROTO = TypeKind(111) TypeKind.CONSTANTARRAY = TypeKind(112) TypeKind.VECTOR = TypeKind(113) +TypeKind.INCOMPLETEARRAY = TypeKind(114) +TypeKind.VARIABLEARRAY = TypeKind(115) +TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116) +TypeKind.MEMBERPOINTER = TypeKind(117) + +class RefQualifierKind(object): + """Describes a specific ref-qualifier of a type.""" + + # The unique kind objects, indexed by id. + _kinds = [] + _name_map = None + + def __init__(self, value): + if value >= len(RefQualifierKind._kinds): + num_kinds = value - len(RefQualifierKind._kinds) + 1 + RefQualifierKind._kinds += [None] * num_kinds + if RefQualifierKind._kinds[value] is not None: + raise ValueError, 'RefQualifierKind already loaded' + self.value = value + RefQualifierKind._kinds[value] = self + RefQualifierKind._name_map = None + + def from_param(self): + return self.value + + @property + def name(self): + """Get the enumeration name of this kind.""" + if self._name_map is None: + self._name_map = {} + for key, value in RefQualifierKind.__dict__.items(): + if isinstance(value, RefQualifierKind): + self._name_map[value] = key + return self._name_map[self] + + @staticmethod + def from_id(id): + if (id >= len(RefQualifierKind._kinds) or + RefQualifierKind._kinds[id] is None): + raise ValueError, 'Unknown type kind %d' % id + return RefQualifierKind._kinds[id] + + def __repr__(self): + return 'RefQualifierKind.%s' % (self.name,) + +RefQualifierKind.NONE = RefQualifierKind(0) +RefQualifierKind.LVALUE = RefQualifierKind(1) +RefQualifierKind.RVALUE = RefQualifierKind(2) class Type(Structure): """ @@ -1613,6 +1740,42 @@ def get_array_size(self): """ return conf.lib.clang_getArraySize(self) + def get_class_type(self): + """ + Retrieve the class type of the member pointer type. + """ + return conf.lib.clang_Type_getClassType(self) + + def get_align(self): + """ + Retrieve the alignment of the record. + """ + return conf.lib.clang_Type_getAlignOf(self) + + def get_size(self): + """ + Retrieve the size of the record. + """ + return conf.lib.clang_Type_getSizeOf(self) + + def get_offset(self, fieldname): + """ + Retrieve the offset of a field in the record. + """ + return conf.lib.clang_Type_getOffsetOf(self, c_char_p(fieldname)) + + def get_ref_qualifier(self): + """ + Retrieve the ref-qualifier of the type. + """ + return RefQualifierKind.from_id( + conf.lib.clang_Type_getCXXRefQualifier(self)) + + @property + def spelling(self): + """Retrieve the spelling of this Type.""" + return conf.lib.clang_getTypeSpelling(self) + def __eq__(self, other): if type(other) != type(self): return False @@ -1888,7 +2051,7 @@ def __del__(self): def read(self, path): """Load a TranslationUnit from the given AST file.""" - return TranslationUnit.from_ast(path, self) + return TranslationUnit.from_ast_file(path, self) def parse(self, path, args=None, unsaved_files=None, options = 0): """Load the translation unit from the given source code file by running @@ -2338,7 +2501,7 @@ class CompilationDatabaseError(Exception): constants in this class. """ - # An unknown error occured + # An unknown error occurred ERROR_UNKNOWN = 0 # The database could not be loaded @@ -2444,6 +2607,14 @@ def getCompileCommands(self, filename): return conf.lib.clang_CompilationDatabase_getCompileCommands(self, filename) + def getAllCompileCommands(self): + """ + Get an iterable object providing all the CompileCommands available from + the database. + """ + return conf.lib.clang_CompilationDatabase_getAllCompileCommands(self) + + class Token(Structure): """Represents a single token from the preprocessor. @@ -2510,6 +2681,11 @@ def cursor(self): c_object_p, CompilationDatabase.from_result), + ("clang_CompilationDatabase_getAllCompileCommands", + [c_object_p], + c_object_p, + CompileCommands.from_result), + ("clang_CompilationDatabase_getCompileCommands", [c_object_p, c_char_p], c_object_p, @@ -2560,6 +2736,10 @@ def cursor(self): [Index, c_char_p], c_object_p), + ("clang_CXXMethod_isPureVirtual", + [Cursor], + bool), + ("clang_CXXMethod_isStatic", [Cursor], bool), @@ -2623,6 +2803,10 @@ def cursor(self): [Type], c_longlong), + ("clang_getFieldDeclBitWidth", + [Cursor], + c_int), + ("clang_getCanonicalCursor", [Cursor], Cursor, @@ -2939,6 +3123,11 @@ def cursor(self): _CXString, _CXString.from_result), + ("clang_getTypeSpelling", + [Type], + _CXString, + _CXString.from_result), + ("clang_hashCursor", [Cursor], c_uint), @@ -3038,6 +3227,41 @@ def cursor(self): [Cursor, c_uint], Cursor, Cursor.from_result), + + ("clang_Cursor_isBitField", + [Cursor], + bool), + + ("clang_Cursor_getBriefCommentText", + [Cursor], + _CXString, + _CXString.from_result), + + ("clang_Cursor_getRawCommentText", + [Cursor], + _CXString, + _CXString.from_result), + + ("clang_Type_getAlignOf", + [Type], + c_longlong), + + ("clang_Type_getClassType", + [Type], + Type, + Type.from_result), + + ("clang_Type_getOffsetOf", + [Type, c_char_p], + c_longlong), + + ("clang_Type_getSizeOf", + [Type], + c_longlong), + + ("clang_Type_getCXXRefQualifier", + [Type], + c_uint), ] class LibclangError(Exception): diff --git a/plugin/clang_complete.vim b/plugin/clang_complete.vim index 2e496781..3a942c32 100644 --- a/plugin/clang_complete.vim +++ b/plugin/clang_complete.vim @@ -138,14 +138,12 @@ function! s:ClangCompleteInit() let b:clang_parameters .= '-header' endif - let g:clang_complete_lib_flags = 0 - if g:clang_complete_macros == 1 - let g:clang_complete_lib_flags = 1 + let g:clang_parameters = ' -code-completion-macros' endif if g:clang_complete_patterns == 1 - let g:clang_complete_lib_flags += 2 + let g:clang_parameters .= ' -code-completion-patterns' endif if s:initClangCompletePython() != 1 @@ -290,7 +288,12 @@ function! s:initClangCompletePython() return 0 endif - py vim.command('let l:res = ' + str(initClangComplete(vim.eval('g:clang_complete_lib_flags'), vim.eval('g:clang_compilation_database'), vim.eval('g:clang_library_path')))) + py vim.command('let l:res = ' + str(initClangComplete( + \ include_macros=vim.eval('g:clang_complete_macros'), + \ include_code_patterns=vim.eval('g:clang_complete_patterns'), + \ include_brief_comments=vim.eval('g:clang_include_brief_comments'), + \ clang_compilation_database=vim.eval('g:clang_compilation_database'), + \ library_path=vim.eval('g:clang_library_path')))) if l:res == 0 return 0 endif diff --git a/plugin/libclang.py b/plugin/libclang.py index 45ff92e4..79aabca2 100644 --- a/plugin/libclang.py +++ b/plugin/libclang.py @@ -52,9 +52,25 @@ def getBuiltinHeaderPath(library_path): return None -def initClangComplete(clang_complete_flags, clang_compilation_database, \ - library_path): +def initClangComplete(include_macros=False, include_code_patterns=False, + include_brief_comments = False, + clang_compilation_database=None, + library_path=None): global index + global complete_flags + + if (include_macros == "0"): + include_macros = False + if (include_code_patterns == "0"): + include_code_patterns = False + if (include_brief_comments == "0"): + include_brief_comments = False + + complete_flags = { + 'include_macros': include_macros, + 'include_code_patterns': include_code_patterns, + 'include_brief_comments': include_brief_comments, + } debug = int(vim.eval("g:clang_debug")) == 1 @@ -93,8 +109,6 @@ def initClangComplete(clang_complete_flags, clang_compilation_database, \ global translationUnits translationUnits = dict() - global complete_flags - complete_flags = int(clang_complete_flags) global compilation_database if clang_compilation_database != '': compilation_database = CompilationDatabase.fromDirectory(clang_compilation_database) @@ -172,7 +186,8 @@ def getCurrentTranslationUnit(args, currentFile, fileName, timer, return tu flags = TranslationUnit.PARSE_PRECOMPILED_PREAMBLE | \ - TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD + TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD | \ + TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION try: tu = index.parse(fileName, args, [currentFile], flags) timer.registerEvent("First parse") @@ -356,7 +371,7 @@ def getCurrentCompletionResults(line, column, args, currentFile, fileName, return None cr = tu.codeComplete(fileName, line, column, [currentFile], - complete_flags) + **complete_flags) timer.registerEvent("Code Complete") return cr @@ -366,6 +381,11 @@ def formatResult(result): abbr = "" word = "" info = "" + comment = "" + + commentstr = result.string.briefComment.spelling + if (commentstr and commentstr != ""): + comment = "// " + commentstr + "\n" for chunk in result.string: @@ -396,7 +416,7 @@ def formatResult(result): completion['word'] = snippetsAddSnippet(info, word, abbr) completion['abbr'] = abbr completion['menu'] = menu - completion['info'] = info + completion['info'] = comment + info completion['dup'] = 1 # Replace the number that represents a specific kind with a better @@ -491,7 +511,57 @@ def getCurrentCompletions(base): result = map(formatResult, results) timer.registerEvent("Format") - return (str(result), timer) + return (toVimRepr(result), timer) +import types + +# Convert python data structures to a vim-compatible string +# +# python's default str() conversion is very close to be parsable by vim, +# but certain patterns cause trouble. This conversion routines are written +# to be 100% vim compatible. This allows us to properly pass on newlines as +# well as strings that contain " or '. +def toVimRepr(v): + t = type(v) + if t in [types.IntType, types.LongType, types.FloatType]: + return repr(v) + if t in [types.StringType, types.UnicodeType]: + return stringToVimRepr(v) + if t is types.ListType: + return listToVimRepr(v) + if t is types.DictType: + return dictToVimRepr(v) + +def stringToVimRepr(s): + result = '\'' + for c in s: + if c != '\'': + result += c + else: + result += '\'\'' + result += '\'' + return result + +def listToVimRepr(l): + result = '[' + for i in xrange(len(l)): + result += toVimRepr(l[i]) + if i != len(l) - 1: + result += ', ' + result += ']' + return result + +def dictToVimRepr(d): + result = '{' + keys = d.keys() + for i in xrange(len(keys)): + k = keys[i] + result += toVimRepr(k) + result += ': ' + result += toVimRepr(d[k]) + if i != len(keys) - 1: + result += ', ' + result += '}' + return result def getAbbr(strings): for chunks in strings: