clang: Add support for compile command databases

Relies on having bear (https://github.com/rizsotto/Bear).
Also refactor clang code to only have 1 instance per tab.
This commit is contained in:
Andy Williams 2017-02-17 22:49:27 +00:00
parent 25d5c6b7e6
commit f89f1bb0c6
7 changed files with 130 additions and 89 deletions

1
.gitignore vendored
View File

@ -47,6 +47,7 @@ stamp-h1
ar-lib
test-driver
test-suite.log
compile_commands.json
# gettext crap
ABOUT-NLS

View File

@ -31,6 +31,19 @@ AC_ARG_ENABLE([libclang],
],
[want_clang="yes"])
# Build EAR support
AC_ARG_ENABLE([bear],
[AS_HELP_STRING([--disable-bear], [Disable use of BuildEAR. @<:@default=enable@:>@])],
[
if test "x${enableval}" = "xyes" ; then
want_bear="yes"
else
want_bear="no"
fi
],
[want_bear="yes"])
### Checks for programs
@ -112,6 +125,12 @@ if test "${want_clang}" = "yes"; then
AC_CHECK_HEADERS([clang-c/Index.h], [have_clang="yes"], [have_clang="no"])
fi
if test "${want_bear}" = "yes"; then
AC_MSG_WARN([Checking...])
AC_CHECK_PROG([have_bear], [bear], [yes])
AC_MSG_WARN([got ${have_bear}])
fi
EFL_TESTS([${build_tests}])
# Checks for library functions.
@ -133,6 +152,14 @@ fi
CLANG_INCLUDE=`clang -E - -v < /dev/null 2>&1 | grep "^ /usr" | grep clang`
AC_SUBST([CLANG_INCLUDE])
BEAR_COMMAND=""
if test "${have_bear}" = "no"; then
AC_MSG_WARN([Could not find a usable bear command. Please install bear (BuildEAR) to enable better support for complex make projects.])
else
BEAR_COMMAND="bear"
fi
AC_SUBST([BEAR_COMMAND])
AC_CONFIG_FILES([
Makefile
data/Makefile
@ -168,6 +195,7 @@ echo " CFLAGS.................: $CFLAGS"
echo " LDFLAGS................: $LDFLAGS"
echo " edje_cc................: ${edje_cc}"
echo " highlighting (libclang): ${have_clang}"
echo " compilation db (bear)..: ${have_bear}"
echo
echo "eolian_gen...............: ${eolian_gen}"
echo

View File

@ -668,15 +668,15 @@ _edi_line_status_set(Edi_Editor *editor, unsigned int number, Elm_Code_Status_Ty
static void
_clang_load_highlighting(const char *path, Edi_Editor *editor)
{
CXFile cfile = clang_getFile(editor->tx_unit, path);
CXFile cfile = clang_getFile(editor->clang_unit, path);
CXSourceRange range = clang_getRange(
clang_getLocationForOffset(editor->tx_unit, cfile, 0),
clang_getLocationForOffset(editor->tx_unit, cfile, eina_file_size_get(eina_file_open(path, EINA_FALSE))));
clang_getLocationForOffset(editor->clang_unit, cfile, 0),
clang_getLocationForOffset(editor->clang_unit, cfile, ecore_file_size(path)));
clang_tokenize(editor->tx_unit, range, &editor->tokens, &editor->token_count);
clang_tokenize(editor->clang_unit, range, &editor->tokens, &editor->token_count);
editor->cursors = (CXCursor *) malloc(editor->token_count * sizeof(CXCursor));
clang_annotateTokens(editor->tx_unit, editor->tokens, editor->token_count, editor->cursors);
clang_annotateTokens(editor->clang_unit, editor->tokens, editor->token_count, editor->cursors);
}
static void
@ -689,7 +689,7 @@ _clang_show_highlighting(Edi_Editor *editor)
Edi_Range range;
Elm_Code_Token_Type type = ELM_CODE_TOKEN_TYPE_DEFAULT;
CXSourceRange tkrange = clang_getTokenExtent(editor->tx_unit, editor->tokens[i]);
CXSourceRange tkrange = clang_getTokenExtent(editor->clang_unit, editor->tokens[i]);
clang_getSpellingLocation(clang_getRangeStart(tkrange), NULL,
&range.start.line, &range.start.col, NULL);
clang_getSpellingLocation(clang_getRangeEnd(tkrange), NULL,
@ -742,15 +742,15 @@ static void
_clang_free_highlighting(Edi_Editor *editor)
{
free(editor->cursors);
clang_disposeTokens(editor->tx_unit, editor->tokens, editor->token_count);
clang_disposeTokens(editor->clang_unit, editor->tokens, editor->token_count);
}
static void
_clang_load_errors(const char *path EINA_UNUSED, Edi_Editor *editor)
_clang_load_errors(Edi_Editor *editor)
{
Elm_Code *code;
const char *filename;
unsigned n = clang_getNumDiagnostics(editor->tx_unit);
unsigned n = clang_getNumDiagnostics(editor->clang_unit);
unsigned i = 0;
ecore_thread_main_loop_begin();
@ -758,9 +758,9 @@ _clang_load_errors(const char *path EINA_UNUSED, Edi_Editor *editor)
filename = elm_code_file_path_get(code->file);
ecore_thread_main_loop_end();
for(i = 0, n = clang_getNumDiagnostics(editor->tx_unit); i != n; ++i)
for(i = 0, n = clang_getNumDiagnostics(editor->clang_unit); i != n; ++i)
{
CXDiagnostic diag = clang_getDiagnostic(editor->tx_unit, i);
CXDiagnostic diag = clang_getDiagnostic(editor->clang_unit, i);
CXFile file;
unsigned int line;
CXString path;
@ -809,9 +809,7 @@ _edi_clang_setup(void *data, Ecore_Thread *thread EINA_UNUSED)
{
Edi_Editor *editor;
Elm_Code *code;
const char *path, *args;
char **clang_argv;
unsigned int clang_argc;
const char *path;
ecore_thread_main_loop_begin();
@ -821,18 +819,7 @@ _edi_clang_setup(void *data, Ecore_Thread *thread EINA_UNUSED)
ecore_thread_main_loop_end();
/* Clang */
/* FIXME: index should probably be global. */
args = "-I/usr/inclue/ " EFL_CFLAGS " " CLANG_INCLUDES " -Wall -Wextra";
clang_argv = eina_str_split_full(args, " ", 0, &clang_argc);
editor->idx = clang_createIndex(0, 0);
/* FIXME: Possibly activate more options? */
editor->tx_unit = clang_parseTranslationUnit(editor->idx, path, (const char *const *)clang_argv, (int)clang_argc, NULL, 0,
clang_defaultEditingTranslationUnitOptions() | CXTranslationUnit_DetailedPreprocessingRecord);
_clang_load_errors(path, editor);
_clang_load_errors(editor);
_clang_load_highlighting(path, editor);
_clang_show_highlighting(editor);
}
@ -843,8 +830,6 @@ _edi_clang_dispose(void *data, Ecore_Thread *thread EINA_UNUSED)
Edi_Editor *editor = (Edi_Editor *)data;
_clang_free_highlighting(editor);
clang_disposeTranslationUnit(editor->tx_unit);
clang_disposeIndex(editor->idx);
editor->highlight_thread = NULL;
editor->highlight_cancel = EINA_FALSE;

View File

@ -51,14 +51,11 @@ struct _Edi_Editor
#if HAVE_LIBCLANG
/* Clang */
CXIndex idx;
CXTranslationUnit tx_unit;
CXIndex clang_idx;
CXTranslationUnit clang_unit;
CXToken *tokens;
CXCursor *cursors;
unsigned int token_count;
CXIndex as_idx;
CXTranslationUnit as_unit;
#endif
Ecore_Thread *highlight_thread;

View File

@ -4,6 +4,7 @@
#if HAVE_LIBCLANG
#include <clang-c/Index.h>
#include <clang-c/CXCompilationDatabase.h>
#endif
#include <Eina.h>
@ -16,35 +17,92 @@
#include "edi_private.h"
#if HAVE_LIBCLANG
static void
_clang_commands_fallback_get(const char ***args, unsigned int *argc)
{
const char *argstr;
argstr = "-I/usr/include/ " EFL_CFLAGS " " CLANG_INCLUDES " -Wall -Wextra";
*args = (const char **) eina_str_split_full(argstr, " ", 0, argc);
}
static void
_clang_commands_get(const char *path, const char ***args, unsigned int *argc)
{
CXCompilationDatabase_Error compilationDatabaseError;
CXCompilationDatabase compilationDatabase = clang_CompilationDatabase_fromDirectory(edi_project_get(), &compilationDatabaseError );
if ( compilationDatabaseError == CXCompilationDatabase_CanNotLoadDatabase)
{
INF("Could not load compile_commands.json in %s", edi_project_get());
_clang_commands_fallback_get(args, argc);
return;
}
CXCompileCommands compileCommands = clang_CompilationDatabase_getCompileCommands( compilationDatabase, path);
CXCompileCommand compileCommand = clang_CompileCommands_getCommand( compileCommands, 0 );
unsigned int numArguments = clang_CompileCommand_getNumArgs( compileCommand );
if (numArguments == 0)
{
INF("File %s not found in compile_commands.json", path);
_clang_commands_fallback_get(args, argc);
return;
}
const char** arguments = malloc(sizeof(char*) * numArguments);
arguments[0] = CLANG_INCLUDES;
for( unsigned int i = 1; numArguments > i + 4; i++ )
{
CXString argument = clang_CompileCommand_getArg( compileCommand, i + 1 );
const char * strArgument = clang_getCString( argument );
arguments[i] = strdup(strArgument);
clang_disposeString( argument );
}
*args = arguments;
*argc = numArguments <= 4 ? 1 : numArguments - 4;
clang_CompilationDatabase_dispose(compilationDatabase);
}
static void
_clang_autosuggest_setup(Edi_Editor *editor)
{
Elm_Code *code;
const char *path;
char **clang_argv;
const char *args;
unsigned int clang_argc;
const char **args;
unsigned int argc, end_row, end_col;
struct CXUnsavedFile unsaved_file;
code = elm_code_widget_code_get(editor->entry);
path = elm_code_file_path_get(code->file);
end_row = elm_code_file_lines_get(code->file);
end_col = elm_code_file_line_get(code->file, end_row)->length;
unsaved_file.Filename = path;
unsaved_file.Contents = elm_code_widget_text_between_positions_get(
editor->entry, 1, 1, end_row, end_col);
unsaved_file.Length = strlen(unsaved_file.Contents);
//Initialize Clang
args = "-I/usr/inclue/ " EFL_CFLAGS " " CLANG_INCLUDES " -Wall -Wextra";
clang_argv = eina_str_split_full(args, " ", 0, &clang_argc);
editor->as_idx = clang_createIndex(0, 0);
editor->as_unit = clang_parseTranslationUnit(editor->as_idx, path,
(const char *const *)clang_argv,
(int)clang_argc, NULL, 0,
clang_defaultEditingTranslationUnitOptions());
_clang_commands_get(path, &args, &argc);
editor->clang_idx = clang_createIndex(0, 0);
editor->clang_unit = clang_parseTranslationUnit(editor->clang_idx, path,
args, argc, NULL, 0, //&unsaved_file, 1,
clang_defaultEditingTranslationUnitOptions() | CXTranslationUnit_DetailedPreprocessingRecord);
}
static void
_clang_autosuggest_dispose(Edi_Editor *editor)
{
clang_disposeTranslationUnit(editor->as_unit);
clang_disposeIndex(editor->as_idx);
clang_disposeTranslationUnit(editor->clang_unit);
clang_disposeIndex(editor->clang_idx);
}
#endif
@ -112,7 +170,7 @@ _edi_language_c_lookup(Edi_Editor *editor, unsigned int row, unsigned int col)
Elm_Code *code;
const char *path = NULL;
if (!editor->as_unit)
if (!editor->clang_unit)
return list;
code = elm_code_widget_code_get(editor->entry);
@ -124,7 +182,7 @@ _edi_language_c_lookup(Edi_Editor *editor, unsigned int row, unsigned int col)
editor->entry, 1, 1, row, col);
unsaved_file.Length = strlen(unsaved_file.Contents);
res = clang_codeCompleteAt(editor->as_unit, path, row, col,
res = clang_codeCompleteAt(editor->clang_unit, path, row, col,
&unsaved_file, 1,
CXCodeComplete_IncludeMacros |
CXCodeComplete_IncludeCodePatterns);
@ -357,42 +415,20 @@ _edi_doc_dump(Edi_Language_Document *doc, CXComment comment, Eina_Strbuf *strbuf
}
static CXCursor
_edi_doc_cursor_get(Edi_Editor *editor, CXIndex idx, CXTranslationUnit unit,
unsigned int row, unsigned int col)
_edi_doc_cursor_get(Edi_Editor *editor, unsigned int row, unsigned int col)
{
CXFile cxfile;
CXSourceLocation location;
CXCursor cursor;
struct CXUnsavedFile unsaved_file;
Elm_Code *code;
const char *path, *args;
char **clang_argv;
unsigned int clang_argc, end_row, end_col;
const char *path;
code = elm_code_widget_code_get(editor->entry);
path = elm_code_file_path_get(code->file);
end_row = elm_code_file_lines_get(code->file);
end_col = elm_code_file_line_get(code->file, end_row)->length;
unsaved_file.Filename = path;
unsaved_file.Contents = elm_code_widget_text_between_positions_get(
editor->entry, 1, 1, end_row, end_col);
unsaved_file.Length = strlen(unsaved_file.Contents);
//Initialize Clang
args = "-I/usr/inclue/ " EFL_CFLAGS " " CLANG_INCLUDES " -Wall -Wextra";
clang_argv = eina_str_split_full(args, " ", 0, &clang_argc);
idx = clang_createIndex(0, 0);
unit = clang_parseTranslationUnit(idx, path, (const char *const *)clang_argv,
(int)clang_argc, &unsaved_file, 1,
clang_defaultEditingTranslationUnitOptions());
cxfile = clang_getFile(unit, path);
location = clang_getLocation(unit, cxfile, row, col);
cursor = clang_getCursor(unit, location);
cxfile = clang_getFile(editor->clang_unit, path);
location = clang_getLocation(editor->clang_unit, cxfile, row, col);
cursor = clang_getCursor(editor->clang_unit, location);
return clang_getCursorReferenced(cursor);
}
@ -403,18 +439,14 @@ _edi_language_c_lookup_doc(Edi_Editor *editor, unsigned int row, unsigned int co
{
Edi_Language_Document *doc = NULL;
#if HAVE_LIBCLANG
CXIndex idx = NULL;
CXTranslationUnit unit = NULL;
CXCursor cursor;
CXComment comment;
cursor = _edi_doc_cursor_get(editor, idx, unit, row, col);
cursor = _edi_doc_cursor_get(editor, row, col);
comment = clang_Cursor_getParsedComment(cursor);
if (clang_Comment_getKind(comment) == CXComment_Null)
{
clang_disposeTranslationUnit(unit);
clang_disposeIndex(idx);
return NULL;
}
@ -424,9 +456,6 @@ _edi_language_c_lookup_doc(Edi_Editor *editor, unsigned int row, unsigned int co
_edi_doc_dump(doc, comment, doc->detail);
_edi_doc_title_get(cursor, doc->title);
_edi_doc_trim(doc->detail);
clang_disposeTranslationUnit(unit);
clang_disposeIndex(idx);
#endif
return doc;
}

View File

@ -6,7 +6,8 @@ AM_CPPFLAGS = \
-DPACKAGE_LIB_DIR=\"$(libdir)\" \
-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
@EFL_CFLAGS@ \
-DEFL_EDI_BUILD
-DEFL_EDI_BUILD \
-DBEAR_COMMAND=\"$(BEAR_COMMAND)\"
lib_LTLIBRARIES = libedi.la

View File

@ -51,7 +51,7 @@ static void
_make_build_make(void)
{
chdir(edi_project_get());
ecore_exe_pipe_run("make", ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_PIPE_READ |
ecore_exe_pipe_run(BEAR_COMMAND " make", ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_PIPE_READ |
ECORE_EXE_PIPE_ERROR_LINE_BUFFERED | ECORE_EXE_PIPE_ERROR |
ECORE_EXE_PIPE_WRITE | ECORE_EXE_USE_SH, NULL);
}
@ -60,7 +60,7 @@ static void
_make_build_configure(void)
{
chdir(edi_project_get());
ecore_exe_pipe_run("./configure && make",
ecore_exe_pipe_run("./configure && " BEAR_COMMAND " make",
ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_PIPE_READ |
ECORE_EXE_PIPE_ERROR_LINE_BUFFERED | ECORE_EXE_PIPE_ERROR |
ECORE_EXE_PIPE_WRITE | ECORE_EXE_USE_SH, NULL);
@ -70,7 +70,7 @@ static void
_make_build_cmake(void)
{
chdir(edi_project_get());
ecore_exe_pipe_run("mkdir -p build && cd build && cmake .. && make && cd ..",
ecore_exe_pipe_run("mkdir -p build && cd build && cmake .. && " BEAR_COMMAND " make && cd ..",
ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_PIPE_READ |
ECORE_EXE_PIPE_ERROR_LINE_BUFFERED | ECORE_EXE_PIPE_ERROR |
ECORE_EXE_PIPE_WRITE | ECORE_EXE_USE_SH, NULL);
@ -80,7 +80,7 @@ static void
_make_build_autogen(void)
{
chdir(edi_project_get());
ecore_exe_pipe_run("./autogen.sh && make",
ecore_exe_pipe_run("./autogen.sh && " BEAR_COMMAND " make",
ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_PIPE_READ |
ECORE_EXE_PIPE_ERROR_LINE_BUFFERED | ECORE_EXE_PIPE_ERROR |
ECORE_EXE_PIPE_WRITE | ECORE_EXE_USE_SH, NULL);