diff --git a/gcc-python-callbacks.c b/gcc-python-callbacks.c index e8a42aa8..1aeb8655 100644 --- a/gcc-python-callbacks.c +++ b/gcc-python-callbacks.c @@ -197,6 +197,18 @@ PyGcc_CallbackFor_tree(void *gcc_data, void *user_data) user_data); } +static void +PyGcc_CallbackFor_string(void *gcc_data, void *user_data) +{ + PyGILState_STATE gstate; + const char *str = (const char *)gcc_data; + + gstate = PyGILState_Ensure(); + + PyGcc_FinishInvokingCallback(gstate, + 1, PyGccString_FromString(str), + user_data); +} static void PyGcc_CallbackFor_PLUGIN_ATTRIBUTES(void *gcc_data, void *user_data) @@ -375,7 +387,18 @@ PyGcc_RegisterCallback(PyObject *self, PyObject *args, PyObject *kwargs) PyGcc_CallbackFor_GGC_END, closure); break; - + case PLUGIN_FINISH_PARSE_FUNCTION: + register_callback("python", // FIXME + (enum plugin_event)event, + PyGcc_CallbackFor_tree, + closure); + break; + case PLUGIN_INCLUDE_FILE: + register_callback("python", // FIXME + (enum plugin_event)event, + PyGcc_CallbackFor_string, + closure); + break; /* PLUGIN_FINISH_DECL was added in gcc 4.7 onwards: */ #ifdef GCC_PYTHON_PLUGIN_CONFIG_has_PLUGIN_FINISH_DECL case PLUGIN_FINISH_DECL: diff --git a/gcc-python-location.c b/gcc-python-location.c index 0857694f..696d3704 100644 --- a/gcc-python-location.c +++ b/gcc-python-location.c @@ -190,7 +190,7 @@ PyGccLocation_richcompare(PyObject *o1, PyObject *o2, int op) long PyGccLocation_hash(struct PyGccLocation * self) { - return self->loc.inner; + return (unsigned long)(LOCATION_FILE(self->loc.inner)) ^ LOCATION_LINE(self->loc.inner); } #if (GCC_VERSION >= 5000) diff --git a/gcc-python-tree.c b/gcc-python-tree.c index e5f81012..c36d569b 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 "gcc-python-closure.h" #include "cp/cp-tree.h" #include "gimple.h" @@ -121,6 +122,30 @@ do_pretty_print(struct PyGccTree * self, int spc, dump_flags_t flags) if (!result) { goto error; } + + Py_XDECREF(ppobj); + return result; + + error: + Py_XDECREF(ppobj); + return NULL; +} + +static PyObject * +do_decl_print(struct PyGccTree * self, int spc, dump_flags_t flags) +{ + PyObject *ppobj = PyGccPrettyPrinter_New(); + PyObject *result = NULL; + if (!ppobj) { + return NULL; + } + + print_declaration (PyGccPrettyPrinter_as_pp(ppobj), + self->t.inner, spc, flags); + result = PyGccPrettyPrinter_as_string(ppobj); + if (!result) { + goto error; + } Py_XDECREF(ppobj); return result; @@ -284,6 +309,12 @@ PyGccTree_get_str_no_uid(struct PyGccTree *self, void *closure) return do_pretty_print(self, 0, TDF_NOUID); } +PyObject * +PyGccTree_get_str_decl(struct PyGccTree *self, void *closure) +{ + return do_decl_print(self, 0, TDF_NOUID); +} + PyObject * PyGccTree_get_symbol(PyObject *cls, PyObject *args) { @@ -298,6 +329,84 @@ PyGccTree_get_symbol(PyObject *cls, PyObject *args) return PyGccString_FromString(op_symbol_code(code)); } +static tree +tree_walk_callback(tree *tree_ptr, int *walk_subtree, void *data) +{ + struct callback_closure *closure = (struct callback_closure*)data; + PyObject *tree_obj = NULL; + PyObject *args = NULL; + PyObject *result = NULL; + + assert(closure); + assert(*tree_ptr); + tree_obj = PyGccTree_New(gcc_private_make_tree(*tree_ptr)); + if (!tree_obj) { + goto error; + } + + args = PyGcc_Closure_MakeArgs(closure, 0, tree_obj); + if (!args) { + goto error; + } + + /* Invoke the python callback: */ + result = PyObject_Call(closure->callback, args, closure->kwargs); + if (!result) { + goto error; + } + + Py_DECREF(tree_obj); + Py_DECREF(args); + + if (PyObject_IsTrue(result)) { + Py_DECREF(result); + return *tree_ptr; + } else { + Py_DECREF(result); + return NULL; + } + +error: + /* On and exception, terminate the traversal: */ + *walk_subtree = 0; + Py_XDECREF(tree_obj); + Py_XDECREF(args); + Py_XDECREF(result); + return NULL; +} + +PyObject * +PyGccTree_walk_tree(struct PyGccTree * self, PyObject *args, PyObject *kwargs) +{ + PyObject *callback; + PyObject *extraargs = NULL; + struct callback_closure *closure; + tree result; + + callback = PyTuple_GetItem(args, 0); + extraargs = PyTuple_GetSlice(args, 1, PyTuple_Size(args)); + + closure = PyGcc_closure_new_generic(callback, extraargs, kwargs); + + if (!closure) { + Py_DECREF(callback); + Py_DECREF(extraargs); + return NULL; + } + + result = walk_tree (&self->t.inner, + tree_walk_callback, + closure, NULL); + + PyGcc_closure_free(closure); + + if (PyErr_Occurred()) { + return NULL; + } + + return PyGccTree_New(gcc_private_make_tree(result)); +} + PyObject * PyGccDeclaration_repr(struct PyGccTree * self) { @@ -426,6 +535,56 @@ PyGccIdentifierNode_repr(struct PyGccTree * self) } } +PyObject * +PyGccDeclaration_get_attributes(struct PyGccTree *self, void *closure) +{ + /* gcc/tree.h defines TYPE_ATTRIBUTES(NODE) as: + "A TREE_LIST of IDENTIFIER nodes of the attributes that apply + to this type" + + Looking at: + typedef int (example3)(const char *, const char *, const char *) + __attribute__((nonnull(1))) + __attribute__((nonnull(3))); + (which is erroneous), we get this for TYPE_ATTRIBUTES: + gcc.TreeList(purpose=gcc.IdentifierNode(name='nonnull'), + value=gcc.TreeList(purpose=None, + value=gcc.IntegerCst(3), + chain=None), + chain=gcc.TreeList(purpose=gcc.IdentifierNode(name='nonnull'), + value=gcc.TreeList(purpose=None, + value=gcc.IntegerCst(1), + chain=None), + chain=None) + ) + */ + tree attr; + PyObject *result = PyDict_New(); + if (!result) { + return NULL; + } + for (attr = DECL_ATTRIBUTES(self->t.inner); attr; attr = TREE_CHAIN(attr)) { + const char *attrname = IDENTIFIER_POINTER(TREE_PURPOSE(attr)); + PyObject *values; + values = PyGcc_TreeMakeListFromTreeList(TREE_VALUE(attr)); + if (!values) { + goto error; + } + + if (-1 == PyDict_SetItemString(result, attrname, values)) { + Py_DECREF(values); + goto error; + } + Py_DECREF(values); + } + + return result; + + error: + Py_DECREF(result); + return NULL; +} + PyObject * PyGccType_get_attributes(struct PyGccTree *self, void *closure) { @@ -1103,6 +1262,15 @@ PyGcc_GetMethods(struct PyGccTree *self) #endif } +PyObject * PyGcc_GetStubDecl(struct PyGccTree *self) +{ + return PyGccTree_New(gcc_private_make_tree(TYPE_STUB_DECL(self->t.inner))); +} + +PyObject * PyGcc_MainVariant(struct PyGccTree *self) +{ + return PyGccTree_New(gcc_private_make_tree(TYPE_MAIN_VARIANT(self->t.inner))); +} /* GCC's debug_tree is implemented in: gcc/print-tree.c diff --git a/gcc-python-variable.c b/gcc-python-variable.c index bab1ec2f..198b2687 100644 --- a/gcc-python-variable.c +++ b/gcc-python-variable.c @@ -51,6 +51,56 @@ PyGcc_WrtpMarkForPyGccVariable(PyGccVariable *wrapper) gcc_variable_mark_in_use(wrapper->var); } +IMPL_APPENDER(add_var_to_list, + gcc_variable, + PyGccVariable_New) + + +GCC_IMPLEMENT_PUBLIC_API (bool) gcc_variable_get_referring (gcc_variable var, + bool (*cb) (gcc_variable var, void *user_data), + void *user_data) +{ + ipa_ref *ref = NULL; + int i; + for (i = 0; var.inner->iterate_referring(i, ref); i++) { + if (cb(gcc_private_make_variable((varpool_node*)ref->referring), user_data)) + return true; + } + + return false; +} + +GCC_IMPLEMENT_PUBLIC_API (PyObject *) +PyGccVariable_get_referring(struct PyGccVariable * self) +{ + IMPL_LIST_MAKER(gcc_variable_get_referring, + self->var, + add_var_to_list) +} + + +GCC_IMPLEMENT_PUBLIC_API (bool) gcc_variable_get_reference (gcc_variable var, + bool (*cb) (gcc_variable var, void *user_data), + void *user_data) +{ + ipa_ref *ref = NULL; + int i; + for (i = 0; var.inner->iterate_reference(i, ref); i++) { + if (cb(gcc_private_make_variable((varpool_node*)ref->referred), user_data)) + return true; + } + + return false; +} + +GCC_IMPLEMENT_PUBLIC_API (PyObject *) +PyGccVariable_get_reference(struct PyGccVariable * self) +{ + IMPL_LIST_MAKER(gcc_variable_get_reference, + self->var, + add_var_to_list) +} + /* PEP-7 Local variables: diff --git a/gcc-python-wrappers.h b/gcc-python-wrappers.h index 1816b193..8bc2e22f 100644 --- a/gcc-python-wrappers.h +++ b/gcc-python-wrappers.h @@ -244,6 +244,9 @@ PyGccTree_richcompare(PyObject *o1, PyObject *o2, int op); PyObject * PyGccTree_get_str_no_uid(struct PyGccTree *self, void *closure); +PyObject * +PyGccTree_get_str_decl(struct PyGccTree *self, void *closure); + PyObject * PyGccTree_get_symbol(PyObject *cls, PyObject *args); @@ -265,9 +268,15 @@ PyGccComponentRef_repr(PyObject *self); PyObject * PyGccDeclaration_get_name(struct PyGccTree *self, void *closure); +PyObject * +PyGccTree_walk_tree(struct PyGccTree * self, PyObject *args, PyObject *kwargs); + PyObject * PyGccDeclaration_repr(struct PyGccTree * self); +PyObject * +PyGccDeclaration_get_attributes(struct PyGccTree *self, void *closure); + PyObject * PyGccFunctionDecl_get_fullname(struct PyGccTree *self, void *closure); @@ -355,6 +364,12 @@ PyGcc_GetFields(struct PyGccTree *self); PyObject * PyGcc_GetMethods(struct PyGccTree *self); +PyObject * +PyGcc_GetStubDecl(struct PyGccTree *self); + +PyObject * +PyGcc_MainVariant(struct PyGccTree *self); + /* gcc-python-gimple.c: */ extern gcc_gimple_asm PyGccGimple_as_gcc_gimple_asm(struct PyGccGimple *self); diff --git a/gcc-python.c b/gcc-python.c index 104d412a..591142de 100644 --- a/gcc-python.c +++ b/gcc-python.c @@ -28,6 +28,7 @@ #include "gcc-c-api/gcc-declaration.h" #include "gcc-c-api/gcc-diagnostics.h" #include "gcc-c-api/gcc-option.h" +#include "gcc-c-api/gcc-function.h" int plugin_is_GPL_compatible; @@ -133,6 +134,12 @@ PyGcc_define_macro(PyObject *self, Py_RETURN_NONE; } +static PyObject * +PyGcc_get_location(PyObject *self, PyObject *args) +{ + return PyGccLocation_New(gcc_private_make_location(input_location)); +} + static PyObject * PyGcc_set_location(PyObject *self, PyObject *args) { @@ -148,6 +155,12 @@ PyGcc_set_location(PyObject *self, PyObject *args) Py_RETURN_NONE; } +static PyObject * +PyGcc_get_current_function(PyObject *self, PyObject *args) +{ + return PyGccFunction_New(gcc_get_current_function()); +} + static bool add_option_to_list(gcc_option opt, void *user_data) { PyObject *result = (PyObject*)user_data; @@ -365,6 +378,12 @@ PyGcc_dump(PyObject *self, PyObject *arg) Py_RETURN_NONE; } +static PyObject * +PyGcc_get_main_input_filename(PyObject *self, PyObject *args) +{ + return PyGccStringOrNone(main_input_filename); +} + static PyObject * PyGcc_get_dump_file_name(PyObject *self, PyObject *noargs) { @@ -438,10 +457,18 @@ static PyMethodDef GccMethods[] = { (METH_VARARGS | METH_KEYWORDS), ("Report an information message\n" "FIXME\n")}, + {"get_location", + (PyCFunction)PyGcc_get_location, + METH_VARARGS, + ("Get the default location for error reports\n")}, {"set_location", (PyCFunction)PyGcc_set_location, METH_VARARGS, ("Temporarily set the default location for error reports\n")}, + {"get_current_function", + (PyCFunction)PyGcc_get_current_function, + METH_VARARGS, + ("Get the current function declaration\n")}, /* Options: */ {"get_option_list", @@ -484,6 +511,9 @@ static PyMethodDef GccMethods[] = { {"get_callgraph_nodes", PyGcc_get_callgraph_nodes, METH_VARARGS, "Get a list of all gcc.CallgraphNode instances"}, + {"get_main_input_filename", PyGcc_get_main_input_filename, METH_NOARGS, + "Get main_input_filename"}, + /* Dump files */ {"dump", PyGcc_dump, METH_O, "Dump str() of the argument to the current dump file (or silently discard it when no dump file is open)"}, diff --git a/generate-tree-c.py b/generate-tree-c.py index faf3faf1..2f87c30c 100644 --- a/generate-tree-c.py +++ b/generate-tree-c.py @@ -76,6 +76,8 @@ def generate_tree(): 'Instance of gcc.Tree giving the type of the node'), PyGetSetDef('addr', 'PyGccTree_get_addr', None, 'The address of the underlying GCC object in memory'), + PyGetSetDef('str_decl', 'PyGccTree_get_str_decl', None, + 'A string representation of this declaration of the object.'), PyGetSetDef('str_no_uid', 'PyGccTree_get_str_no_uid', None, 'A string representation of this object, like str(), but without including any internal UID')], identifier_prefix='PyGccTree', @@ -94,6 +96,10 @@ def generate_tree(): tp_str = '(reprfunc)PyGccTree_str', tp_richcompare = 'PyGccTree_richcompare') methods = PyMethodTable('PyGccTree_methods', []) + methods.add_method('walk_tree', + '(PyCFunction)PyGccTree_walk_tree', + 'METH_VARARGS | METH_KEYWORDS', + 'Walk the tree of the declaration') methods.add_method('debug', 'PyGccTree_debug', 'METH_VARARGS', @@ -171,6 +177,39 @@ def add_simple_getter(name, c_expression, doc): doc) if localname == 'Declaration': + getter = cu.add_simple_getter('PyGccTree_get_static', + 'PyGccTree', + 'PyBool_FromLong(TREE_STATIC(self->t.inner))') + setter = cu.add_simple_int_setter('PyGccTree_set_static', + 'PyGccTree', + 'static', + 'TREE_STATIC(self->t.inner) = PyGccInt_AsLong(value)') + getsettable.add_gsdef('static', + getter, setter, + "(bool/bool)") + + getter = cu.add_simple_getter('PyGccTree_get_initial', + 'PyGccTree', + 'PyGccTree_New(gcc_constructor_as_gcc_tree(gcc_var_decl_get_initial(PyGccTree_as_gcc_var_decl(self))))') + setter = cu.add_simple_int_setter('PyGccTree_set_initial', + 'PyGccTree', + 'initial', + 'DECL_INITIAL(self->t.inner) = NULL;') + getsettable.add_gsdef('initial', + getter, setter, + "(ptr/None)") + getter = cu.add_simple_getter('PyGccTree_get_public', + 'PyGccTree', + 'PyBool_FromLong(TREE_PUBLIC(self->t.inner))') + setter = cu.add_simple_int_setter('PyGccTree_set_public', + 'PyGccTree', + 'public', + 'TREE_PUBLIC(self->t.inner) = PyGccInt_AsLong(value)') + getsettable.add_gsdef('public', + getter, setter, + "(bool/bool)") + + cu.add_defn(""" PyObject * PyGccDeclaration_get_name(struct PyGccTree *self, void *closure) @@ -187,6 +226,16 @@ def add_simple_getter(name, c_expression, doc): return PyGccLocation_New(gcc_decl_get_location(PyGccTree_as_gcc_decl(self))); } """) + getter = cu.add_simple_getter('PyGccTree_get_external', + 'PyGccTree', + 'PyBool_FromLong(DECL_EXTERNAL(self->t.inner))') + setter = cu.add_simple_int_setter('PyGccTree_set_', + 'PyGccTree', + 'external', + 'DECL_EXTERNAL(self->t.inner) = PyGccInt_AsLong(value)') + getsettable.add_gsdef('external', + getter, setter, + "(bool/bool)") getsettable.add_gsdef('name', 'PyGccDeclaration_get_name', @@ -196,15 +245,25 @@ def add_simple_getter(name, c_expression, doc): 'PyGccDeclaration_get_location', None, 'The gcc.Location for this declaration') + getsettable.add_gsdef('attributes', + 'PyGccDeclaration_get_attributes', + None, + 'The user-defined attributes on this decl') add_simple_getter('is_artificial', 'PyBool_FromLong(gcc_decl_is_artificial(PyGccTree_as_gcc_decl(self)))', "Is this a compiler-generated entity?") + add_simple_getter('context', + 'PyGccTree_New(gcc_function_decl_as_gcc_tree(gcc_private_make_function_decl(DECL_CONTEXT (PyGccTree_as_gcc_decl(self).inner))))', + "context") add_simple_getter('is_builtin', 'PyBool_FromLong(gcc_decl_is_builtin(PyGccTree_as_gcc_decl(self)))', "Is this declaration built in by the compiler?") pytype.tp_repr = '(reprfunc)PyGccDeclaration_repr' if localname == 'Type': + add_simple_getter('context', + 'PyGccTree_New(gcc_function_decl_as_gcc_tree(gcc_private_make_function_decl(DECL_CONTEXT (PyGccTree_as_gcc_decl(self).inner))))', + "context") add_simple_getter('name', 'PyGccTree_New(gcc_type_get_name(PyGccTree_as_gcc_type(self)))', "The name of the type as a gcc.Tree, or None") @@ -398,6 +457,9 @@ def add_complex_getter(name, doc): add_simple_getter('%s_equivalent' % qual, 'PyGccTree_New(gcc_private_make_tree(build_qualified_type(self->t.inner, TYPE_QUALS(self->t.inner) | TYPE_QUAL_%s)))' % qual.upper(), 'The gcc.Type for the %s version of this type' % qual) + add_simple_getter('main_variant', + 'PyGcc_MainVariant(self)', + "The main vairant of this type") add_simple_getter('unqualified_equivalent', 'PyGccTree_New(gcc_private_make_tree(build_qualified_type(self->t.inner, 0)))', 'The gcc.Type for the unqualified version of this type') @@ -484,11 +546,20 @@ def add_complex_getter(name, doc): add_simple_getter('methods', 'PyGcc_GetMethods(self)', "The methods of this type") + add_simple_getter('stub', + 'PyGcc_GetStubDecl(self)', + "The stub decl of this type") + add_simple_getter('main_variant', + 'PyGcc_MainVariant(self)', + "The main vairant of this type") if tree_type.SYM == 'ENUMERAL_TYPE': add_simple_getter('values', 'PyGcc_TreeMakeListOfPairsFromTreeListChain(TYPE_VALUES(self->t.inner))', "The values of this type") + add_simple_getter('stub', + 'PyGcc_GetStubDecl(self)', + "The stub decl of this type") if tree_type.SYM == 'IDENTIFIER_NODE': add_simple_getter('name', @@ -497,12 +568,9 @@ def add_complex_getter(name, doc): tp_repr = '(reprfunc)PyGccIdentifierNode_repr' if tree_type.SYM == 'VAR_DECL': - add_simple_getter('initial', - 'PyGccTree_New(gcc_constructor_as_gcc_tree(gcc_var_decl_get_initial(PyGccTree_as_gcc_var_decl(self))))', - "The initial value for this variable as a gcc.Constructor, or None") - add_simple_getter('static', - 'PyBool_FromLong(gcc_var_decl_is_static(PyGccTree_as_gcc_var_decl(self)))', - "Boolean: is this variable to be allocated with static storage") + add_simple_getter('node', + 'PyGccVariable_New(gcc_private_make_variable(varpool_node::get (self->t.inner)))', + 'Node which contains this var decl') if tree_type.SYM == 'CONSTRUCTOR': add_complex_getter('elements', @@ -584,6 +652,9 @@ def add_complex_getter(name, doc): add_simple_getter('result', 'PyGccTree_New(gcc_private_make_tree(DECL_RESULT_FLD(self->t.inner)))', 'The gcc.ResultDecl for the return value') + add_simple_getter('inline', + 'PyBool_FromLong(DECL_DECLARED_INLINE_P(self->t.inner))', + 'If function is declared as inline') getsettable.add_gsdef('callgraph_node', 'PyGccFunctionDecl_get_callgraph_node', None, diff --git a/generate-variable-c.py b/generate-variable-c.py index aed8955b..498b2cb7 100644 --- a/generate-variable-c.py +++ b/generate-variable-c.py @@ -44,6 +44,19 @@ def add_simple_getter(name, c_expression, doc): 'PyGccTree_New(gcc_variable_get_decl(self->var))', 'The declaration of this variable, as a gcc.Tree') + cu.add_decl('GCC_IMPLEMENT_PUBLIC_API (PyObject *) PyGccVariable_get_referring(struct PyGccVariable * self);') + cu.add_decl('GCC_IMPLEMENT_PUBLIC_API (PyObject *) PyGccVariable_get_reference(struct PyGccVariable * self);') + + getsettable.add_gsdef('referring', + 'PyGccVariable_get_referring', + None, + 'Referencing this var') + + getsettable.add_gsdef('reference', + 'PyGccVariable_get_reference', + None, + 'Referenced by this var') + cu.add_defn(getsettable.c_defn()) pytype = PyGccWrapperTypeObject(identifier = 'PyGccVariable_TypeObj', diff --git a/tests/examples/find-global-state/stderr.txt b/tests/examples/find-global-state/stderr.txt index 1385ef1e..8a24a156 100644 --- a/tests/examples/find-global-state/stderr.txt +++ b/tests/examples/find-global-state/stderr.txt @@ -1,5 +1,4 @@ tests/examples/find-global-state/input.c:41:nn: note: use of global state "int q" here -tests/examples/find-global-state/input.c:41:nn: note: use of global state "int q" here tests/examples/find-global-state/input.c:42:nn: note: use of global state "int q" here tests/examples/find-global-state/input.c:53:nn: note: use of global state "int foo" here tests/examples/find-global-state/input.c:58:nn: note: use of global state "struct