зеркало из https://github.com/mozilla/pjs.git
Bug 414063 - "annotate xpidl-generated c++ headers with attributes for scriptable and deprecated methods" [p=Pidgeot18@gmail.com (Joshua Cranmer) r=dbradley a1.9=damons]
This commit is contained in:
Родитель
7f695a27b2
Коммит
915cc2f649
|
@ -244,6 +244,26 @@
|
|||
ret (NS_STDCALL class::*name) args
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Deprecated declarations.
|
||||
*/
|
||||
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||
# define NS_DEPRECATED __attribute__((deprecated))
|
||||
#elif defined(_MSC_VER) && (_MSC_VER >= 1300)
|
||||
# define NS_DEPRECATED __declspec(deprecated)
|
||||
#else
|
||||
# define NS_DEPRECATED
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Attributes defined to help Dehydra GCC analysis.
|
||||
*/
|
||||
#ifdef DEHYDRA_GCC
|
||||
# define NS_SCRIPTABLE __attribute__((user("script")))
|
||||
#else
|
||||
# define NS_SCRIPTABLE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Generic API modifiers which return the standard XPCOM nsresult type
|
||||
*/
|
||||
|
|
|
@ -148,3 +148,13 @@ check::
|
|||
for f in $(CPP_UNIT_TESTS); do \
|
||||
XPCOM_DEBUG_BREAK=stack-and-abort $(RUN_TEST_PROGRAM) $(DIST)/bin/$$f; \
|
||||
done
|
||||
@echo "Running XPIDL tests"
|
||||
$(XPIDL_COMPILE) -m header $(srcdir)/TestScriptable.idl
|
||||
@if grep Notscriptable TestScriptable.h | grep -q NS_SCRIPTABLE ; then \
|
||||
echo "Nonscriptable object marked scriptable by xpidl"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@if test $$( grep 'NS_IMETHOD[^I].*Scriptable' TestScriptable.h | grep -v -c NS_SCRIPTABLE ) != 0 ; then \
|
||||
echo "Scriptable object marked nonscriptable by xpidl"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
[scriptable, uuid(76d74662-0eae-404c-9d1f-697c0e321c0a)]
|
||||
interface testScriptableInterface {
|
||||
readonly attribute long scriptable_attr1;
|
||||
attribute long scriptable_attr2;
|
||||
[noscript] readonly attribute long notscriptable_attr1;
|
||||
[noscript] attribute long notscriptable_attr2;
|
||||
|
||||
void scriptable_method1();
|
||||
[noscript] void notscriptable_method1();
|
||||
[notxpcom] void notscriptable_method2();
|
||||
[noscript, notxpcom] void notscriptable_method3();
|
||||
};
|
||||
|
||||
[uuid(76d74662-0eae-404c-9d1f-697c0e321c0a)]
|
||||
interface testNotscriptableInterface {
|
||||
readonly attribute long notscriptable_attr1;
|
||||
attribute long notscriptable_attr2;
|
||||
|
||||
void notscriptable_method1();
|
||||
};
|
|
@ -275,4 +275,7 @@ check_native(TreeState *state);
|
|||
void
|
||||
printlist(FILE *outfile, GSList *slist);
|
||||
|
||||
gboolean
|
||||
is_method_scriptable(IDL_tree method_tree, IDL_tree ident);
|
||||
|
||||
#endif /* __xpidl_h */
|
||||
|
|
|
@ -146,7 +146,7 @@ interface(TreeState *state)
|
|||
char *classNameImpl = NULL;
|
||||
char *cp;
|
||||
gboolean ok = TRUE;
|
||||
gboolean keepvtable;
|
||||
gboolean keepvtable, scriptable, deprecated;
|
||||
const char *iid;
|
||||
const char *name_space;
|
||||
struct nsID id;
|
||||
|
@ -233,11 +233,20 @@ interface(TreeState *state)
|
|||
if (IDL_NODE_TYPE(data) == IDLN_CODEFRAG)
|
||||
keepvtable = TRUE;
|
||||
}
|
||||
|
||||
|
||||
scriptable = deprecated = FALSE;
|
||||
if (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable"))
|
||||
scriptable = TRUE;
|
||||
if (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "deprecated"))
|
||||
deprecated = TRUE;
|
||||
|
||||
/* The interface declaration itself. */
|
||||
fprintf(state->file,
|
||||
"class %s%s",
|
||||
(keepvtable ? "" : "NS_NO_VTABLE "), className);
|
||||
"class %s%s%s%s",
|
||||
(keepvtable ? "" : "NS_NO_VTABLE "),
|
||||
(scriptable ? "NS_SCRIPTABLE " : ""),
|
||||
(deprecated ? "NS_DEPRECATED " : ""),
|
||||
className);
|
||||
|
||||
if ((iter = IDL_INTERFACE(iface).inheritance_spec)) {
|
||||
fputs(" : ", state->file);
|
||||
|
@ -746,8 +755,14 @@ write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
|
|||
{
|
||||
char *attrname = ATTR_IDENT(attr_tree).str;
|
||||
const char *binaryname;
|
||||
IDL_tree ident = IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).data;
|
||||
|
||||
if (mode == AS_DECL) {
|
||||
if (IDL_tree_property_get(ident, "deprecated"))
|
||||
fputs("NS_DEPRECATED ", outfile);
|
||||
if (is_method_scriptable(attr_tree, ident))
|
||||
fputs("NS_SCRIPTABLE ", outfile);
|
||||
|
||||
fputs("NS_IMETHOD ", outfile);
|
||||
} else if (mode == AS_IMPL) {
|
||||
fprintf(outfile, "NS_IMETHODIMP %s::", className);
|
||||
|
@ -1023,6 +1038,11 @@ write_method_signature(IDL_tree method_tree, FILE *outfile, int mode,
|
|||
IDL_tree iter;
|
||||
|
||||
if (mode == AS_DECL) {
|
||||
if (IDL_tree_property_get(op->ident, "deprecated"))
|
||||
fputs("NS_DEPRECATED ", outfile);
|
||||
if (is_method_scriptable(method_tree, op->ident))
|
||||
fputs("NS_SCRIPTABLE ", outfile);
|
||||
|
||||
if (op_notxpcom) {
|
||||
fputs("NS_IMETHOD_(", outfile);
|
||||
if (!write_type(op->op_type_spec, FALSE, outfile))
|
||||
|
|
|
@ -144,6 +144,55 @@ write_indent(FILE *outfile) {
|
|||
fputs(" ", outfile);
|
||||
}
|
||||
|
||||
static GSList*
|
||||
add_deprecated(GSList *comments)
|
||||
{
|
||||
GSList *last;
|
||||
char *buffer;
|
||||
char *replaced;
|
||||
const char deprecated[] = "* @deprecated */";
|
||||
|
||||
/* Handle the easy case: no documentation. */
|
||||
if (comments == NULL) {
|
||||
buffer = malloc(sizeof(deprecated)+2);
|
||||
buffer[0] = '/';
|
||||
buffer[1] = '*';
|
||||
strcpy(buffer+2, deprecated);
|
||||
|
||||
return g_slist_append(comments, buffer);
|
||||
}
|
||||
|
||||
/* xpidl is so nice in that they give us the data as a single node.
|
||||
* We are going to have to (very hackishly) strip out the the end of the
|
||||
* documentation comment, add the tag, and then pop it back together.
|
||||
*/
|
||||
|
||||
/* Step 1: Move the comment into a larger buffer, so that we can have
|
||||
* more space to work with.
|
||||
*/
|
||||
last = g_slist_last(comments);
|
||||
buffer = last->data;
|
||||
replaced = (char *)malloc(strlen(buffer) + sizeof(deprecated));
|
||||
strcpy(replaced, buffer);
|
||||
last->data = replaced;
|
||||
free(buffer);
|
||||
|
||||
/* Now replaced has the comment, with a large enough buffer to put in the
|
||||
* @deprecated tag. We search for the last / in hopes that the previous
|
||||
* character is the * we're looking for...
|
||||
*/
|
||||
buffer = strrchr(replaced, '/');
|
||||
if (buffer == NULL || buffer == replaced || buffer[-1] == '*') {
|
||||
/* We can't find a '/', so there's no comment, or this is not the end
|
||||
* of a comment, so we'll ignore adding the deprecated tag.
|
||||
*/
|
||||
return comments;
|
||||
}
|
||||
/* buffer now points to '*' '/'. Overwrite both. */
|
||||
strcpy(buffer-1, deprecated);
|
||||
return comments;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
write_classname_iid_define(FILE *file, const char *className)
|
||||
{
|
||||
|
@ -330,6 +379,13 @@ interface_declaration(TreeState *state)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add deprecated tags if the interface is deprecated
|
||||
*/
|
||||
if (IDL_tree_property_get(IDL_INTERFACE(interface).ident, "deprecated")) {
|
||||
doc_comments = add_deprecated(doc_comments);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write any interface comments
|
||||
*/
|
||||
|
@ -776,6 +832,13 @@ method_declaration(TreeState *state)
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Add deprecated tags if the interface is deprecated
|
||||
*/
|
||||
if (IDL_tree_property_get(method->ident, "deprecated")) {
|
||||
doc_comments = add_deprecated(doc_comments);
|
||||
}
|
||||
|
||||
if (doc_comments != NULL) {
|
||||
write_indent(state->file);
|
||||
printlist(state->file, doc_comments);
|
||||
|
@ -1013,6 +1076,14 @@ attribute_declaration(TreeState *state)
|
|||
doc_comments =
|
||||
IDL_IDENT(IDL_LIST(IDL_ATTR_DCL
|
||||
(state->tree).simple_declarations).data).comments;
|
||||
|
||||
/*
|
||||
* Add deprecated tags if the interface is deprecated
|
||||
*/
|
||||
if (IDL_tree_property_get(ATTR_PROPS(state->tree), "deprecated")) {
|
||||
doc_comments = add_deprecated(doc_comments);
|
||||
}
|
||||
|
||||
if (doc_comments != NULL) {
|
||||
write_indent(state->file);
|
||||
printlist(state->file, doc_comments);
|
||||
|
|
|
@ -277,13 +277,59 @@ matches_nsIFoo(const char* attribute_name)
|
|||
return matches_IFoo(attribute_name + 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if the method is probably scriptable, FALSE otherwise.
|
||||
* The first parameter may also be an attr_tree parameter, since these two are
|
||||
* the same with respect to discovering the interface node.
|
||||
*/
|
||||
gboolean
|
||||
is_method_scriptable(IDL_tree method_tree, IDL_tree ident)
|
||||
{
|
||||
IDL_tree iface;
|
||||
gboolean scriptable_interface;
|
||||
|
||||
/*
|
||||
* Look up the tree to find the interface. If we can't find the interface,
|
||||
* then the caller is being called on an incorrect tree. If we find it, we
|
||||
* see if it's [scriptable] and duly note it.
|
||||
*/
|
||||
if (IDL_NODE_UP(method_tree) && IDL_NODE_UP(IDL_NODE_UP(method_tree)) &&
|
||||
IDL_NODE_TYPE(iface = IDL_NODE_UP(IDL_NODE_UP(method_tree)))
|
||||
== IDLN_INTERFACE)
|
||||
{
|
||||
scriptable_interface =
|
||||
(IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable")
|
||||
!= NULL);
|
||||
} else {
|
||||
IDL_tree_error(method_tree,
|
||||
"is_method_scriptable called on a non-interface?");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* If the interface isn't scriptable, the method sure can't be... */
|
||||
if (!scriptable_interface)
|
||||
return FALSE;
|
||||
|
||||
/* [notxpcom] implies [noscript] */
|
||||
if (IDL_tree_property_get(ident, "notxpcom") != NULL)
|
||||
return FALSE;
|
||||
|
||||
/* [noscript] methods obviously aren't scriptable */
|
||||
if (IDL_tree_property_get(ident, "noscript") != NULL)
|
||||
return FALSE;
|
||||
|
||||
/* The interface is scriptable, so therefore the method is, if the
|
||||
* interfaces are accessible. That's good enough for this method.
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
verify_attribute_declaration(IDL_tree attr_tree)
|
||||
{
|
||||
IDL_tree iface;
|
||||
IDL_tree ident;
|
||||
IDL_tree attr_type;
|
||||
gboolean scriptable_interface;
|
||||
|
||||
/* We don't support attributes named IID, conflicts with static GetIID
|
||||
* member. The conflict is due to certain compilers (VC++) choosing a
|
||||
|
@ -299,22 +345,6 @@ verify_attribute_declaration(IDL_tree attr_tree)
|
|||
"ordering problems");
|
||||
return FALSE;
|
||||
}
|
||||
/*
|
||||
* Verify that we've been called on an interface, and decide if the
|
||||
* interface was marked [scriptable].
|
||||
*/
|
||||
if (IDL_NODE_UP(attr_tree) && IDL_NODE_UP(IDL_NODE_UP(attr_tree)) &&
|
||||
IDL_NODE_TYPE(iface = IDL_NODE_UP(IDL_NODE_UP(attr_tree)))
|
||||
== IDLN_INTERFACE)
|
||||
{
|
||||
scriptable_interface =
|
||||
(IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable")
|
||||
!= NULL);
|
||||
} else {
|
||||
IDL_tree_error(attr_tree,
|
||||
"verify_attribute_declaration called on a non-interface?");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Grab the first of the list of idents and hope that it'll
|
||||
|
@ -324,10 +354,10 @@ verify_attribute_declaration(IDL_tree attr_tree)
|
|||
|
||||
/*
|
||||
* If the interface isn't scriptable, or the attribute is marked noscript,
|
||||
* there's no need to check.
|
||||
* there's no need to check. This also verifies that we've been called on
|
||||
* an interface.
|
||||
*/
|
||||
if (!scriptable_interface ||
|
||||
IDL_tree_property_get(ident, "noscript") != NULL)
|
||||
if (!is_method_scriptable(attr_tree, ident))
|
||||
return TRUE;
|
||||
|
||||
/*
|
||||
|
@ -533,7 +563,6 @@ check_param_attribute(IDL_tree method_tree, IDL_tree param,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Common method verification code, called by *op_dcl in the various backends.
|
||||
*/
|
||||
|
@ -544,7 +573,6 @@ verify_method_declaration(IDL_tree method_tree)
|
|||
IDL_tree iface;
|
||||
IDL_tree iter;
|
||||
gboolean notxpcom;
|
||||
gboolean scriptable_interface;
|
||||
gboolean scriptable_method;
|
||||
gboolean seen_retval = FALSE;
|
||||
gboolean hasoptional = PR_FALSE;
|
||||
|
@ -568,36 +596,12 @@ verify_method_declaration(IDL_tree method_tree)
|
|||
}
|
||||
|
||||
/*
|
||||
* Verify that we've been called on an interface, and decide if the
|
||||
* interface was marked [scriptable].
|
||||
*/
|
||||
if (IDL_NODE_UP(method_tree) && IDL_NODE_UP(IDL_NODE_UP(method_tree)) &&
|
||||
IDL_NODE_TYPE(iface = IDL_NODE_UP(IDL_NODE_UP(method_tree)))
|
||||
== IDLN_INTERFACE)
|
||||
{
|
||||
scriptable_interface =
|
||||
(IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable")
|
||||
!= NULL);
|
||||
} else {
|
||||
IDL_tree_error(method_tree,
|
||||
"verify_method_declaration called on a non-interface?");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Require that any method in an interface marked as [scriptable], that
|
||||
* *isn't* scriptable because it refers to some native type, be marked
|
||||
* [noscript] or [notxpcom].
|
||||
*
|
||||
* Also check that iid_is points to nsid, and length_is, size_is points
|
||||
* to unsigned long.
|
||||
* Decide if we are a scriptable method, or if we were are notxpcom.
|
||||
* In doing so, we also verify that we've been called on an interface.
|
||||
*/
|
||||
scriptable_method = is_method_scriptable(method_tree, op->ident);
|
||||
notxpcom = IDL_tree_property_get(op->ident, "notxpcom") != NULL;
|
||||
|
||||
scriptable_method = scriptable_interface &&
|
||||
!notxpcom &&
|
||||
IDL_tree_property_get(op->ident, "noscript") == NULL;
|
||||
|
||||
/* Loop through the parameters and check. */
|
||||
for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) {
|
||||
IDL_tree param = IDL_LIST(iter).data;
|
||||
|
|
Загрузка…
Ссылка в новой задаче