Hi, all
I have been working on implementing a tool-set of code assistance called
GCCSense, which enables code-completion for C/C++ in editors or a terminal.
http://cx4a.org/software/gccsense/
GCCSense depends on its own GCC which has special options for code
assistance such like -code-completion-at:
$ cat
#include <string>
int main()
{
std::string s;
s.
}
$ # Print completion candidates at line 5 and column 7 of a.cc
$ g++-code-assist -fsyntax-only -code-completion-at=a.cc:5:7 a.c
Now, I have the following problems:
* Hard to build that GCC for users
* Hard to maintain that GCC for me
Plugin might be a solution for them. Finally, however, I found that
there is no proper plugin entrances for code assistance. As you may
understand if you read an attached patch, GCCSense needs to handle
quickly a special token for code-completion after particular tokens such
as "." and "->" in parser phase.
Is there any good solution for this ?
Or could you implement such plugin entrances for code assistance ?
Thanks.
Tomohiro Matsuyama
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 88c40b6..ef22823 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1029,7 +1029,7 @@ C_AND_OBJC_OBJS = attribs.o c-errors.o c-lex.o c-pragma.o c-decl.o c-typeck.o \
c-convert.o c-aux-info.o c-common.o c-opts.o c-format.o c-semantics.o \
c-ppoutput.o c-cppbuiltin.o \
c-objc-common.o c-dump.o c-pch.o c-parser.o $(C_TARGET_OBJS) \
- c-gimplify.o tree-mudflap.o c-pretty-print.o c-omp.o
+ c-gimplify.o tree-mudflap.o c-pretty-print.o c-omp.o c-code-assist.o
# Language-specific object files for C.
C_OBJS = c-lang.o stub-objc.o $(C_AND_OBJC_OBJS)
@@ -1070,6 +1070,7 @@ OBJS-common = \
cfgloopanal.o \
cfgloopmanip.o \
cfgrtl.o \
+ code-assist-common.o \
combine.o \
combine-stack-adj.o \
convert.o \
@@ -1941,6 +1942,9 @@ c-omp.o : c-omp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(FUNCTION_H) $(C_COMMON_H) $(TOPLEV.H) $(GIMPLE_H) $(BITMAP_H) \
langhooks.h
+c-code-assist.o : c-code-assist.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
+ $(FUNCTION_H) $(C_COMMON_H) $(TOPLEV.H) $(GIMPLE_H) $(BITMAP_H)
+
# Language-independent files.
DRIVER_DEFINES = \
@@ -2807,6 +2811,7 @@ cfgloop.o : cfgloop.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) coretypes.h $(TM_H) \
cfgloopanal.o : cfgloopanal.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
$(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h $(TM_H) \
$(OBSTACK_H) output.h graphds.h $(PARAMS_H)
+code-assist-common.o : code-assist-common.c $(CONFIG_H) $(SYSTEM_H)
graphds.o : graphds.c graphds.h $(CONFIG_H) $(SYSTEM_H) $(BITMAP_H) $(OBSTACK_H) \
coretypes.h vec.h vecprim.h
loop-iv.o : loop-iv.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(BASIC_BLOCK_H) \
diff --git a/gcc/c-code-assist.c b/gcc/c-code-assist.c
new file mode 100644
index 0000000..de76100
--- /dev/null
+++ b/gcc/c-code-assist.c
@@ -0,0 +1,27 @@
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "toplev.h"
+#include "langhooks.h"
+#include "diagnostic.h"
+#include "debug.h"
+#include "opts.h"
+#include "options.h"
+#include "c-tree.h"
+#include "code-assist.h"
+
+void code_completion_decls (tree node, bool nonstatic)
+{
+ while (node)
+ {
+ print_completion (node);
+ node = TREE_CHAIN (node);
+ }
+}
+
+void code_completion_scope (tree scope)
+{
+}
diff --git a/gcc/c-opts.c b/gcc/c-opts.c
index 28bdc31..76b6388 100644
--- a/gcc/c-opts.c
+++ b/gcc/c-opts.c
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see
#include "mkdeps.h"
#include "target.h"
#include "tm_p.h"
+#include "code-assist.h"
#ifndef DOLLARS_IN_IDENTIFIERS
# define DOLLARS_IN_IDENTIFIERS true
@@ -550,6 +551,10 @@ c_common_handle_option (size_t scode, const char *arg, int value)
set_std_cxx98 (true);
break;
+ case OPT_code_completion_at_:
+ code_assist_setup (cpp_opts, CPP_CODE_COMPLETION, arg, "-code-completion-at");
+ break;
+
case OPT_d:
handle_OPT_d (arg);
break;
diff --git a/gcc/c-parser.c b/gcc/c-parser.c
index 0f047de..0c149b0 100644
--- a/gcc/c-parser.c
+++ b/gcc/c-parser.c
@@ -57,6 +57,7 @@ along with GCC; see the file COPYING3. If not see
#include "vec.h"
#include "target.h"
#include "cgraph.h"
+#include "code-assist.h"
/* Initialization routine for this file. */
@@ -5595,6 +5596,11 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
/* Structure element reference. */
c_parser_consume_token (parser);
expr = default_function_array_conversion (expr);
+ if (c_parser_next_token_is (parser, CPP_CODE_COMPLETION))
+ {
+ c_parser_consume_token (parser);
+ code_completion_expr (expr.value);
+ }
if (c_parser_next_token_is (parser, CPP_NAME))
ident = c_parser_peek_token (parser)->value;
else
@@ -5612,6 +5618,13 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
/* Structure element reference. */
c_parser_consume_token (parser);
expr = default_function_array_conversion (expr);
+ if (c_parser_next_token_is (parser, CPP_CODE_COMPLETION))
+ {
+ c_parser_consume_token (parser);
+ code_completion_expr (build_indirect_ref (loc,
+ expr.value,
+ "->"));
+ }
if (c_parser_next_token_is (parser, CPP_NAME))
ident = c_parser_peek_token (parser)->value;
else
diff --git a/gcc/c.opt b/gcc/c.opt
index 711710b..d7cc7bf 100644
--- a/gcc/c.opt
+++ b/gcc/c.opt
@@ -500,6 +500,10 @@ ansi
C ObjC C++ ObjC++
A synonym for -std=c89 (for C) or -std=c++98 (for C++)
+code-completion-at=
+C ObjC C++ ObjC++ Joined
+-code-completion-at=<line>:<column> Code completions at specified position by <line> and <column>
+
d
C ObjC C++ ObjC++ Joined
; Documented in common.opt. FIXME - what about -dI, -dD, -dN and -dD?
diff --git a/gcc/code-assist-common.c b/gcc/code-assist-common.c
new file mode 100644
index 0000000..1c9d2de
--- /dev/null
+++ b/gcc/code-assist-common.c
@@ -0,0 +1,111 @@
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "toplev.h"
+#include "langhooks.h"
+#include "diagnostic.h"
+#include "debug.h"
+#include "opts.h"
+#include "options.h"
+#include "c-tree.h"
+#include "code-assist.h"
+
+enum cpp_ttype code_assist_type;
+
+static const char *generic_node_name (tree node)
+{
+ enum tree_code code;
+ enum tree_code_class tclass;
+ const char *name = 0;
+
+ if (!node)
+ return 0;
+
+ code = TREE_CODE (node);
+ tclass = TREE_CODE_CLASS (code);
+
+ if (tclass == tcc_declaration)
+ {
+ if (DECL_NAME (node))
+ name = IDENTIFIER_POINTER (DECL_NAME (node));
+ }
+
+ return name;
+}
+
+static void code_completion_base_types (tree type, bool nonstatic)
+{
+ /* Base types. */
+ int i;
+ tree base_binfo;
+ tree binfo;
+
+ for (binfo = TYPE_BINFO (type), i = 0;
+ binfo && BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ {
+ tree basetype = TREE_TYPE (base_binfo);
+ code_completion_type (basetype, nonstatic);
+ }
+}
+
+void code_assist_setup (cpp_options *cpp_opts, enum cpp_ttype type, const char *arg, const char *opt)
+{
+ const char *p = strchr (arg, ':');
+ const char *q = 0;
+
+ if (p)
+ {
+ q = strchr (p + 1, ':');
+ }
+ if (!p || !q)
+ {
+ error ("%s must take a form of line:column", opt);
+ return;
+ }
+
+ code_assist_type = type;
+ cpp_opts->phantom_token.type = type;
+ cpp_opts->phantom_token.file = xstrndup (arg, p - arg);
+ cpp_opts->phantom_token.line = atoi (p + 1);
+ cpp_opts->phantom_token.column = atoi (q + 1);
+}
+
+void print_completion (tree node)
+{
+ const char *name = generic_node_name (node);
+ if (name)
+ printf ("completion: %s \"%s\"\n", name, lang_hooks.decl_printable_name (node, 2));
+}
+
+void code_completion_type (tree type, bool nonstatic)
+{
+ enum tree_code code;
+
+ if (!type)
+ return;
+
+ code = TREE_CODE (type);
+
+ switch (code)
+ {
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ code_completion_decls (TYPE_FIELDS (type), nonstatic);
+ code_completion_decls (TYPE_METHODS (type), nonstatic);
+ code_completion_base_types (type, nonstatic);
+ break;
+ default:
+ break;
+ }
+}
+
+void code_completion_expr (tree expr)
+{
+ if (!expr)
+ return;
+ code_completion_type (TREE_TYPE (expr), true);
+}
diff --git a/gcc/code-assist.h b/gcc/code-assist.h
new file mode 100644
index 0000000..20b8cb0
--- /dev/null
+++ b/gcc/code-assist.h
@@ -0,0 +1,16 @@
+#ifndef GCC_CODE_ASSIST_H
+#define GCC_CODE_ASSIST_H
+
+#include "cpplib.h"
+#include "input.h"
+
+extern enum cpp_ttype code_assist_type;
+
+extern void code_assist_setup (cpp_options *, enum cpp_ttype, const char *, const char *);
+extern void print_completion (tree);
+extern void code_completion_decls (tree, bool);
+extern void code_completion_type (tree, bool);
+extern void code_completion_expr (tree);
+extern void code_completion_scope (tree);
+
+#endif /* ! GCC_CODE_ASSIST_H */
diff --git a/gcc/common.opt b/gcc/common.opt
index 023d773..5391bb0 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -246,6 +246,10 @@ Common Separate
auxbase-strip
Common Separate
+code-completion-at=
+C ObjC C++ ObjC++ Joined
+-code-completion-at=<line>:<column> Code completions at specified position by <line> and <column>
+
d
Common Joined
-d<letters> Enable dumps from specific passes of the compiler
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 626a63e..18bb2c6 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -81,7 +81,7 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \
cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \
cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \
cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \
- cp/cp-gimplify.o tree-mudflap.o $(CXX_C_OBJS)
+ cp/cp-gimplify.o cp/cp-code-assist.o tree-mudflap.o $(CXX_C_OBJS)
# Language-specific object files for C++.
CXX_OBJS = cp/cp-lang.o stub-objc.o $(CXX_AND_OBJCXX_OBJS)
@@ -302,3 +302,6 @@ cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
cp/cxx-pretty-print.o: cp/cxx-pretty-print.c $(CXX_PRETTY_PRINT_H) \
$(CONFIG_H) $(SYSTEM_H) $(TM_H) coretypes.h $(CXX_TREE_H)
+
+cp/cp-code-assist.o: cp/cp-code-assist.c $(CXX_TREE_H) toplev.h $(C_COMMON_H) \
+ $(TM_H) coretypes.h pointer-set.h tree-iterator.h
diff --git a/gcc/cp/cp-code-assist.c b/gcc/cp/cp-code-assist.c
new file mode 100644
index 0000000..b9f00cf
--- /dev/null
+++ b/gcc/cp/cp-code-assist.c
@@ -0,0 +1,56 @@
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "flags.h"
+#include "tree.h"
+#include "cp-tree.h"
+#include "toplev.h"
+#include "langhooks.h"
+#include "diagnostic.h"
+#include "debug.h"
+#include "code-assist.h"
+#include "name-lookup.h"
+
+void code_completion_decls (tree node, bool nonstatic)
+{
+ while (node)
+ {
+ enum tree_code code = TREE_CODE (node);
+
+ if (nonstatic
+ ? (code == FIELD_DECL
+ || (code == FUNCTION_DECL
+ && !DECL_STATIC_FUNCTION_P (node)))
+ : ((code == VAR_DECL
+ || code == CONST_DECL
+ || code == TYPE_DECL)
+ || (code == FUNCTION_DECL
+ && DECL_STATIC_FUNCTION_P (node))))
+ print_completion (node);
+
+ node = TREE_CHAIN (node);
+ }
+}
+
+void code_completion_scope (tree scope)
+{
+ enum tree_code code;
+
+ if (!scope)
+ return;
+
+ code = TREE_CODE (scope);
+
+ if (code == NAMESPACE_DECL)
+ {
+ tree decls = cp_namespace_decls (scope);
+ while (decls)
+ {
+ print_completion (decls);
+ decls = TREE_CHAIN (decls);
+ }
+ }
+ else
+ code_completion_type (scope, false);
+}
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index eba1707..5bb2cea 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see
#include "timevar.h"
#include "tree-flow.h"
#include "pointer-set.h"
+#include "code-assist.h"
static tree grokparms (tree parmlist, tree *);
static const char *redeclaration_error_message (tree, tree);
@@ -12359,7 +12360,8 @@ finish_function (int flags)
&& !TREE_NO_WARNING (fndecl)
/* Structor return values (if any) are set by the compiler. */
&& !DECL_CONSTRUCTOR_P (fndecl)
- && !DECL_DESTRUCTOR_P (fndecl))
+ && !DECL_DESTRUCTOR_P (fndecl)
+ && !code_assist_type)
{
warning (OPT_Wreturn_type,
"no return statement in function returning non-void");
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 4f75606..a607f62 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see
#include "target.h"
#include "cgraph.h"
#include "c-common.h"
+#include "code-assist.h"
/* The lexer. */
@@ -4034,6 +4035,7 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
tree old_scope;
tree saved_qualifying_scope;
bool template_keyword_p;
+ bool code_completion_p = false;
/* Spot cases that cannot be the beginning of a
nested-name-specifier. */
@@ -4120,6 +4122,12 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
/* Look for the `::' token. */
cp_parser_require (parser, CPP_SCOPE, "%<::%>");
+ if (cp_lexer_next_token_is (parser->lexer, CPP_CODE_COMPLETION))
+ {
+ code_completion_p = true;
+ cp_lexer_consume_token (parser->lexer);
+ }
+
/* If we found what we wanted, we keep going; otherwise, we're
done. */
if (!cp_parser_parse_definitely (parser))
@@ -4231,6 +4239,10 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
/* Make sure we look in the right scope the next time through
the loop. */
parser->scope = new_scope;
+
+ /* Code completion here. */
+ if (code_completion_p)
+ code_completion_scope (parser->scope);
}
/* If parsing tentatively, replace the sequence of tokens that makes
@@ -4847,17 +4859,51 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
postfix-expression . pseudo-destructor-name
postfix-expression -> template [opt] id-expression
postfix-expression -> pseudo-destructor-name */
+ {
+ tree code_assist_expr = 0;
+
+ /* Consume the `.' or `->' operator. */
+ cp_lexer_consume_token (parser->lexer);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_CODE_COMPLETION))
+ {
+ code_assist_expr = postfix_expression;
+ cp_lexer_consume_token (parser->lexer);
+ }
- /* Consume the `.' or `->' operator. */
- cp_lexer_consume_token (parser->lexer);
+ postfix_expression
+ = cp_parser_postfix_dot_deref_expression (parser, token->type,
+ postfix_expression,
+ false, &idk,
+ token->location);
- postfix_expression
- = cp_parser_postfix_dot_deref_expression (parser, token->type,
- postfix_expression,
- false, &idk,
- token->location);
+ is_member_access = true;
+
+ if (code_assist_expr)
+ {
+ tree type;
+ tree expr = code_assist_expr;
+ if (token->type == CPP_DEREF)
+ {
+ tree e = build_x_arrow (expr);
+ if (!TREE_TYPE (e))
+ expr = TREE_TYPE (expr);
+ else
+ expr = e;
+ }
+ type = expr ? TREE_TYPE (expr) : NULL_TREE;
+ if (!type)
+ break;
- is_member_access = true;
+ /* Use approximate type if type is not completed. */
+ if (CLASS_TYPE_P (type)
+ && !COMPLETE_TYPE_P (type)
+ && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
+ type = TREE_TYPE (most_general_template (CLASSTYPE_TI_TEMPLATE (type)));
+
+ code_completion_type (type, true);
+ }
+ }
break;
case CPP_PLUS_PLUS:
@@ -14589,6 +14635,61 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p)
static void
cp_parser_function_body (cp_parser *parser)
{
+ if (code_assist_type)
+ {
+ unsigned nesting_depth = 1;
+
+ /* Skip the function body. */
+
+ /* Save tokens so that we can rollback if necessary to
+ parse the function body. */
+ cp_lexer_save_tokens (parser->lexer);
+
+ cp_parser_require (parser, CPP_OPEN_BRACE, "%<{%>");
+
+ /* Skip to a next outermost close brace. */
+ while (true)
+ {
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ switch (token->type)
+ {
+ case CPP_EOF:
+ case CPP_PRAGMA_EOL:
+ goto skipped;
+
+ case CPP_OPEN_BRACE:
+ nesting_depth++;
+ break;
+
+ case CPP_CLOSE_BRACE:
+ if (--nesting_depth == 0)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ goto skipped;
+ }
+ break;
+
+ case CPP_CODE_COMPLETION:
+ goto parse;
+
+ default:
+ break;
+ }
+
+ cp_lexer_consume_token (parser->lexer);
+ }
+
+ skipped:
+ /* No need to rollback. */
+ cp_lexer_commit_tokens (parser->lexer);
+ return;
+
+ parse:
+ /* Rollback to parse the function body. */
+ cp_lexer_rollback_tokens (parser->lexer);
+ }
+
cp_parser_compound_statement (parser, NULL, false);
}
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 1f1d85f..29d4ac3 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -836,7 +836,8 @@ static const char *cc1_options =
%{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
%{fsyntax-only:-o %j} %{-param*}\
%{fmudflap|fmudflapth:-fno-builtin -fno-merge-constants}\
- %{coverage:-fprofile-arcs -ftest-coverage}";
+ %{coverage:-fprofile-arcs -ftest-coverage}\
+ %{code-completion-at=*:-code-completion-at=%*}";
static const char *asm_options =
"%{--target-help:%:print-asm-header()} "
@@ -1106,6 +1107,7 @@ static const struct option_map option_map[] =
{"--classpath", "-fclasspath=", "aj"},
{"--bootclasspath", "-fbootclasspath=", "aj"},
{"--CLASSPATH", "-fclasspath=", "aj"},
+ {"--code-completion-at", "-code-completion-at=", "aj"},
{"--combine", "-combine", 0},
{"--comments", "-C", 0},
{"--comments-in-macros", "-CC", 0},