commit 6aa5979fe81194a1a962fa6007930cafda268605
Author: matt rice <ratmice(a)gmail.com>
Date: Sun Jun 3 19:57:15 2012 -0700
add attributes/methods to gcc.NamespaceDecl and is_builtin to gcc.Declaration
gcc.NamespaceDecl:
add attributes: alias_of, namespaces, and declarations.
add methods: unalias
gcc.Declaration
add is_builtin attribute.
docs/tree.rst:
fix gcc.NamespaceDecl.lookup which was documented as .locate.
document new attributes/methods
tests/plugin/namespace: New tests.
docs/tree.rst | 32 ++++++++++++++++-
gcc-python-tree.c | 58 ++++++++++++++++++++++++++++++
gcc-python-wrappers.h | 10 +++++
generate-tree-c.py | 18 +++++++++
tests/plugin/namespace/input.cc | 22 +++++++++++
tests/plugin/namespace/script.py | 71 +++++++++++++++++++++++++++++++++++++
tests/plugin/namespace/stdout.txt | 56 +++++++++++++++++++++++++++++
7 files changed, 266 insertions(+), 1 deletions(-)
---
diff --git a/docs/tree.rst b/docs/tree.rst
index 8c2c0a0..100c4ae 100644
--- a/docs/tree.rst
+++ b/docs/tree.rst
@@ -226,6 +226,10 @@ Declarations
arguments of C++ methods: the initial `this` argument is a
compiler-generated :py:class:`gcc.ParmDecl`.
+ .. py:attribute:: is_builtin
+
+ (bool) Is this declaration a compiler-builtin?
+
.. py:class:: gcc.FieldDecl
A subclass of :py:class:`gcc.Declaration` indicating the declaration of a
@@ -332,11 +336,37 @@ Declarations
A subclass of :py:class:`gcc.Declaration` representing a C++ namespace
- .. py:method:: locate(name)
+ .. py:attribute:: alias_of
+
+ The :py:class:`gcc.NamespaceDecl` which this namespace is an alias of
+ or None if this namespace is not an alias.
+
+ .. py:attribute:: declarations
+
+ .. note:: This attribute is only usable with non-alias namespaces.
+ Accessing it on an alias will lead to a RuntimeError exception.
+
+ List of :py:class:`gcc.Declaration` objects in this namespace.
+ This attribute is only valid for non-aliases
+
+ .. py:attribute:: namespaces
+
+ .. note:: This attribute is only usable with non-alias namespaces.
+ Accessing it on an alias will lead to a RuntimeError exception.
+
+ List of :py:class:`gcc.NamespaceDecl` objects nested in this namespace.
+ This attribute is only valid for non-aliases
+
+ .. py:method:: lookup(name)
Locate the given name within the namespace, returning a
:py:class:`gcc.Tree` or `None`
+ .. py:method:: unalias()
+
+ Always returns a :py:class:`gcc.NamespaceDecl` object which is not an alias.
+ Returns self if this namespace is not an alias.
+
.. Declaration
.. ClassMethodDecl
diff --git a/gcc-python-tree.c b/gcc-python-tree.c
index db35be6..179c0b2 100644
--- a/gcc-python-tree.c
+++ b/gcc-python-tree.c
@@ -21,6 +21,7 @@
#include "gcc-python.h"
#include "gcc-python-wrappers.h"
#include "gcc-python-compat.h"
+#include "cp/cp-tree.h"
#include "gimple.h"
#include "cp/cp-tree.h" /* for TFF_* for use by gcc_FunctionDecl_get_fullname
*/
@@ -43,6 +44,9 @@ __typeof__ (decl_as_string) decl_as_string __attribute__ ((weak));
/* Similar for namespace_binding: */
__typeof__ (namespace_binding) namespace_binding __attribute__ ((weak));
+/* And for cp_namespace_decls: */
+__typeof__ (cp_namespace_decls) cp_namespace_decls __attribute__ ((weak));
+
static PyObject *
raise_cplusplus_only(const char *what)
{
@@ -605,6 +609,60 @@ gcc_NamespaceDecl_lookup(struct PyGccTree * self, PyObject *args,
PyObject *kwar
return gcc_python_make_wrapper_tree(t_result);
}
+PyObject *
+gcc_NamespaceDecl_unalias(struct PyGccTree * self, PyObject *args, PyObject *kwargs)
+{
+ tree t = self->t;
+
+ if (NULL == DECL_NAMESPACE_ALIAS(t)) {
+ return (PyObject *)self;
+ }
+
+ while (DECL_NAMESPACE_ALIAS(t)) {
+ t = DECL_NAMESPACE_ALIAS(t);
+ }
+
+ return gcc_python_make_wrapper_tree(t);
+}
+
+static PyObject *
+raise_namespace_alias(const char *what)
+{
+ return PyErr_Format(PyExc_RuntimeError,
+ "%s is not valid for an alias",
+ what);
+}
+
+PyObject *
+gcc_python_namespace_decl_declarations(tree t)
+{
+ if (NULL == cp_namespace_decls)
+ return raise_cplusplus_only("gcc.NamespaceDecl.declarations");
+
+ /* throw if we are an alias,
+ if we unalias it, it may return a list containing itself. */
+ if (DECL_NAMESPACE_ALIAS(t))
+ return raise_namespace_alias("gcc.NamespaceDecl.declarations");
+
+ return gcc_tree_list_from_chain(cp_namespace_decls(t));
+}
+
+PyObject *
+gcc_python_namespace_decl_namespaces(tree t)
+{
+ /* We don't actually call cp_namespace_decls, but we only actually call
+ c++ specific macros, not sure what happens. */
+ if (NULL == cp_namespace_decls)
+ return raise_cplusplus_only("gcc.NamespaceDecl.namespaces");
+
+ /* throw if we are an alias,
+ if we unalias it, it may return a list containing itself. */
+ if (DECL_NAMESPACE_ALIAS(t))
+ return raise_namespace_alias("gcc.NamespaceDecl.namespaces");
+
+ return gcc_tree_list_from_chain(NAMESPACE_LEVEL(t)->namespaces);
+}
+
/*
GCC's debug_tree is implemented in:
gcc/print-tree.c
diff --git a/gcc-python-wrappers.h b/gcc-python-wrappers.h
index fb70fb4..f79a74b 100644
--- a/gcc-python-wrappers.h
+++ b/gcc-python-wrappers.h
@@ -185,6 +185,16 @@ gcc_TreeList_repr(struct PyGccTree * self);
PyObject *
gcc_NamespaceDecl_lookup(struct PyGccTree * self, PyObject *args, PyObject *kwargs);
+PyObject *
+gcc_NamespaceDecl_unalias(struct PyGccTree * self, PyObject *args, PyObject *kwargs);
+
+PyObject *
+gcc_python_namespace_decl_declarations(tree t);
+
+PyObject *
+gcc_python_namespace_decl_namespaces(tree t);
+
+
/* gcc-python-gimple.c: */
PyObject *
gcc_Gimple_repr(struct PyGccGimple * self);
diff --git a/generate-tree-c.py b/generate-tree-c.py
index 457b2de..2c07c71 100644
--- a/generate-tree-c.py
+++ b/generate-tree-c.py
@@ -31,7 +31,9 @@ cu.add_include('gcc-plugin.h')
cu.add_include("tree.h")
cu.add_include("function.h")
cu.add_include("basic-block.h")
+cu.add_include("cp/cp-tree.h")
cu.add_include("c-family/c-common.h")
+cu.add_include("cp/name-lookup.h")
modinit_preinit = ''
modinit_postinit = ''
@@ -186,6 +188,9 @@ gcc_Declaration_get_location(struct PyGccTree *self, void *closure)
add_simple_getter('is_artificial',
'PyBool_FromLong(DECL_ARTIFICIAL(self->t))',
"Is this a compiler-generated entity?")
+ add_simple_getter('is_builtin',
+ 'PyBool_FromLong(DECL_IS_BUILTIN(self->t))',
+ "Is this declaration built in by the compiler?")
pytype.tp_repr = '(reprfunc)gcc_Declaration_repr'
if localname == 'Type':
@@ -478,10 +483,23 @@ def generate_tree_code_classes():
"The list of gcc.Tree for the declarations and labels
in this block")
if tree_type.SYM == 'NAMESPACE_DECL':
+ add_simple_getter('alias_of',
+
'gcc_python_make_wrapper_tree(DECL_NAMESPACE_ALIAS(self->t))',
+ "None if not an alias, otherwise the gcc.NamespaceDecl
we alias")
+ add_simple_getter('declarations',
+
'gcc_python_namespace_decl_declarations(self->t)',
+ 'The list of gcc.Declarations within this
namespace')
+ add_simple_getter('namespaces',
+
'gcc_python_namespace_decl_namespaces(self->t)',
+ 'The list of gcc.NamespaceDecl objects and gcc.TypeDecl
of Unions nested in this namespace')
methods.add_method('lookup',
'(PyCFunction)gcc_NamespaceDecl_lookup',
'METH_VARARGS|METH_KEYWORDS',
"Look up the given string within this
namespace")
+ methods.add_method('unalias',
+ '(PyCFunction)gcc_NamespaceDecl_unalias',
+ 'METH_VARARGS|METH_KEYWORDS',
+ "A gcc.NamespaceDecl of this namespace that is not an
alias")
if tree_type.SYM == 'TYPE_DECL':
getsettable.add_gsdef('pointer',
diff --git a/tests/plugin/namespace/input.cc b/tests/plugin/namespace/input.cc
new file mode 100644
index 0000000..16cf4ea
--- /dev/null
+++ b/tests/plugin/namespace/input.cc
@@ -0,0 +1,22 @@
+namespace top {
+ union top_union{
+ int i;
+ char c;
+ float f;
+ };
+ namespace sub {
+ int subs_int;
+ void subs_function(void);
+ void *foo;
+ namespace sub_sub {
+ void foo();
+ }
+ }
+ namespace sub_alias = sub;
+ namespace sub_alias_alias = sub_alias;
+ namespace foo {
+ namespace bar {
+ }
+ }
+};
+namespace top_alias_of_alias = top::sub;
diff --git a/tests/plugin/namespace/script.py b/tests/plugin/namespace/script.py
new file mode 100644
index 0000000..9080790
--- /dev/null
+++ b/tests/plugin/namespace/script.py
@@ -0,0 +1,71 @@
+# Copyright 2012 Matt Rice <ratmice(a)gmail.com>
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <
http://www.gnu.org/licenses/>.
+
+# Test case for gcc.NamespaceDecl
+
+import gcc
+
+def indent_print(depth, thing):
+ for i in range(depth):
+ print " ",
+ print thing
+
+def print_namespace(ns, depth):
+ attributes = ("name", "alias_of", "declarations",
"namespaces")
+ # [(method, arg),...]
+ methods = [(gcc.NamespaceDecl.unalias, None),
+ (gcc.NamespaceDecl.lookup, "foo")]
+
+ for attr in attributes:
+ try:
+ indent_print(depth, (attr, ns.__getattribute__(attr)))
+ except Exception as e:
+ indent_print(depth, (attr, e))
+
+ for t in methods:
+ method_name = t[0].__name__
+ method = t[0]
+ try:
+ indent_print(depth, (method_name, method(ns, t[1])))
+ except Exception as e:
+ indent_print(depth, (method_name, e))
+
+ print "\n",
+
+def dump_namespaces(ns, depth):
+
+ # ignore builtin's they would just make stdout.txt painful.
+ if ns.is_builtin == False:
+ print_namespace(ns, depth)
+
+ # aliases of namespaces in particular will occur
+ # within declarations, but we don't want to call
+ # declarations on them (here).
+ if ns.alias_of == None:
+ for decl in ns.declarations:
+ if type(decl) == gcc.NamespaceDecl:
+ dump_namespaces(decl, depth + 1)
+
+ # nested namespaces..
+ for namespace in ns.namespaces:
+ dump_namespaces(namespace, depth + 1)
+
+def finish_unit_cb(*args, **kwargs):
+ # depth of -1 to ignore the global namespace itself (because its a builtin).
+ dump_namespaces(gcc.get_global_namespace(), -1)
+
+
+gcc.register_callback(gcc.PLUGIN_FINISH_UNIT, finish_unit_cb)
diff --git a/tests/plugin/namespace/stdout.txt b/tests/plugin/namespace/stdout.txt
new file mode 100644
index 0000000..c31e942
--- /dev/null
+++ b/tests/plugin/namespace/stdout.txt
@@ -0,0 +1,56 @@
+('name', 'top_alias_of_alias')
+('alias_of', gcc.NamespaceDecl('sub'))
+('declarations', RuntimeError('gcc.NamespaceDecl.declarations is not valid
for an alias',))
+('namespaces', RuntimeError('gcc.NamespaceDecl.namespaces is not valid for an
alias',))
+('unalias', gcc.NamespaceDecl('sub'))
+('lookup', gcc.VarDecl('foo'))
+
+('name', 'top')
+('alias_of', None)
+('declarations', [gcc.NamespaceDecl('sub_alias_alias'),
gcc.NamespaceDecl('sub_alias'), gcc.TypeDecl('top_union')])
+('namespaces', [gcc.NamespaceDecl('foo'),
gcc.NamespaceDecl('sub')])
+('unalias', gcc.NamespaceDecl('top'))
+('lookup', gcc.NamespaceDecl('foo'))
+
+ ('name', 'sub_alias_alias')
+ ('alias_of', gcc.NamespaceDecl('sub'))
+ ('declarations', RuntimeError('gcc.NamespaceDecl.declarations is not valid
for an alias',))
+ ('namespaces', RuntimeError('gcc.NamespaceDecl.namespaces is not valid for
an alias',))
+ ('unalias', gcc.NamespaceDecl('sub'))
+ ('lookup', gcc.VarDecl('foo'))
+
+ ('name', 'sub_alias')
+ ('alias_of', gcc.NamespaceDecl('sub'))
+ ('declarations', RuntimeError('gcc.NamespaceDecl.declarations is not valid
for an alias',))
+ ('namespaces', RuntimeError('gcc.NamespaceDecl.namespaces is not valid for
an alias',))
+ ('unalias', gcc.NamespaceDecl('sub'))
+ ('lookup', gcc.VarDecl('foo'))
+
+ ('name', 'foo')
+ ('alias_of', None)
+ ('declarations', [])
+ ('namespaces', [gcc.NamespaceDecl('bar')])
+ ('unalias', gcc.NamespaceDecl('foo'))
+ ('lookup', None)
+
+ ('name', 'bar')
+ ('alias_of', None)
+ ('declarations', [])
+ ('namespaces', [])
+ ('unalias', gcc.NamespaceDecl('bar'))
+ ('lookup', None)
+
+ ('name', 'sub')
+ ('alias_of', None)
+ ('declarations', [gcc.VarDecl('foo'),
gcc.FunctionDecl('subs_function'), gcc.VarDecl('subs_int')])
+ ('namespaces', [gcc.NamespaceDecl('sub_sub')])
+ ('unalias', gcc.NamespaceDecl('sub'))
+ ('lookup', gcc.VarDecl('foo'))
+
+ ('name', 'sub_sub')
+ ('alias_of', None)
+ ('declarations', [gcc.FunctionDecl('foo')])
+ ('namespaces', [])
+ ('unalias', gcc.NamespaceDecl('sub_sub'))
+ ('lookup', gcc.FunctionDecl('foo'))
+