This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Code assistance with GCC


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},

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]