diff --git a/src/Attr.cc b/src/Attr.cc index 13106b02b7..fc8d3000d1 100644 --- a/src/Attr.cc +++ b/src/Attr.cc @@ -18,7 +18,7 @@ const char* attr_name(attr_tag t) "&encrypt", "&raw_output", "&mergeable", "&priority", "&group", "&log", "&error_handler", "&type_column", - "(&tracked)", + "(&tracked)", "&deprecated", }; return attr_names[int(t)]; @@ -212,6 +212,7 @@ void Attributes::DescribeReST(ODesc* d) const void Attributes::CheckAttr(Attr* a) { switch ( a->Tag() ) { + case ATTR_DEPRECATED: case ATTR_OPTIONAL: case ATTR_REDEF: break; diff --git a/src/Attr.h b/src/Attr.h index 228bc2e5fc..63f2524c21 100644 --- a/src/Attr.h +++ b/src/Attr.h @@ -34,7 +34,8 @@ typedef enum { ATTR_ERROR_HANDLER, ATTR_TYPE_COLUMN, // for input framework ATTR_TRACKED, // hidden attribute, tracked by NotifierRegistry -#define NUM_ATTRS (int(ATTR_TRACKED) + 1) + ATTR_DEPRECATED, +#define NUM_ATTRS (int(ATTR_DEPRECATED) + 1) } attr_tag; class Attr : public BroObj { diff --git a/src/Expr.cc b/src/Expr.cc index 671f9b2d41..d2dcb1585b 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -3213,6 +3213,10 @@ FieldExpr::FieldExpr(Expr* arg_op, const char* arg_field_name) { SetType(rt->FieldType(field)->Ref()); td = rt->FieldDecl(field); + + if ( td->FindAttr(ATTR_DEPRECATED) ) + reporter->Warning("deprecated (%s$%s)", rt->GetName().c_str(), + field_name); } } } @@ -3333,6 +3337,9 @@ HasFieldExpr::HasFieldExpr(Expr* arg_op, const char* arg_field_name) if ( field < 0 ) ExprError("no such field in record"); + else if ( rt->FieldDecl(field)->FindAttr(ATTR_DEPRECATED) ) + reporter->Warning("deprecated (%s?$%s)", rt->GetName().c_str(), + field_name); SetType(base_type(TYPE_BOOL)); } @@ -4147,16 +4154,28 @@ RecordCoerceExpr::RecordCoerceExpr(Expr* op, RecordType* r) } for ( i = 0; i < map_size; ++i ) - if ( map[i] == -1 && - ! t_r->FieldDecl(i)->FindAttr(ATTR_OPTIONAL) ) + { + if ( map[i] == -1 ) { - char buf[512]; - safe_snprintf(buf, sizeof(buf), - "non-optional field \"%s\" missing", t_r->FieldName(i)); - Error(buf); - SetError(); - break; + if ( ! t_r->FieldDecl(i)->FindAttr(ATTR_OPTIONAL) ) + { + char buf[512]; + safe_snprintf(buf, sizeof(buf), + "non-optional field \"%s\" missing", + t_r->FieldName(i)); + Error(buf); + SetError(); + break; + } } + else + { + if ( t_r->FieldDecl(i)->FindAttr(ATTR_DEPRECATED) ) + reporter->Warning("deprecated (%s$%s)", + t_r->GetName().c_str(), + t_r->FieldName(i)); + } + } } } diff --git a/src/ID.h b/src/ID.h index 31cfad4191..ca5d222373 100644 --- a/src/ID.h +++ b/src/ID.h @@ -80,6 +80,9 @@ public: Attr* FindAttr(attr_tag t) const { return attrs ? attrs->FindAttr(t) : 0; } + bool IsDeprecated() const + { return FindAttr(ATTR_DEPRECATED) != 0; } + void Error(const char* msg, const BroObj* o2 = 0); void Describe(ODesc* d) const; diff --git a/src/Type.cc b/src/Type.cc index ead31f1b7d..b5466c27ba 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -1434,7 +1434,7 @@ EnumType::~EnumType() // Note, we use reporter->Error() here (not Error()) to include the current script // location in the error message, rather than the one where the type was // originally defined. -void EnumType::AddName(const string& module_name, const char* name, bool is_export) +void EnumType::AddName(const string& module_name, const char* name, bool is_export, bool deprecated) { /* implicit, auto-increment */ if ( counter < 0) @@ -1443,11 +1443,11 @@ void EnumType::AddName(const string& module_name, const char* name, bool is_expo SetError(); return; } - CheckAndAddName(module_name, name, counter, is_export); + CheckAndAddName(module_name, name, counter, is_export, deprecated); counter++; } -void EnumType::AddName(const string& module_name, const char* name, bro_int_t val, bool is_export) +void EnumType::AddName(const string& module_name, const char* name, bro_int_t val, bool is_export, bool deprecated) { /* explicit value specified */ if ( counter > 0 ) @@ -1457,11 +1457,11 @@ void EnumType::AddName(const string& module_name, const char* name, bro_int_t va return; } counter = -1; - CheckAndAddName(module_name, name, val, is_export); + CheckAndAddName(module_name, name, val, is_export, deprecated); } void EnumType::CheckAndAddName(const string& module_name, const char* name, - bro_int_t val, bool is_export) + bro_int_t val, bool is_export, bool deprecated) { if ( Lookup(val) ) { @@ -1477,6 +1477,14 @@ void EnumType::CheckAndAddName(const string& module_name, const char* name, id = install_ID(name, module_name.c_str(), true, is_export); id->SetType(this->Ref()); id->SetEnumConst(); + + if ( deprecated ) + { + attr_list* attr = new attr_list; + attr->append(new Attr(ATTR_DEPRECATED)); + id->AddAttrs(new Attributes(attr, id->Type(), false)); + } + broxygen_mgr->Identifier(id); } else diff --git a/src/Type.h b/src/Type.h index a9f1e42a6d..f902b0d907 100644 --- a/src/Type.h +++ b/src/Type.h @@ -554,12 +554,12 @@ public: // The value of this name is next internal counter value, starting // with zero. The internal counter is incremented. - void AddName(const string& module_name, const char* name, bool is_export); + void AddName(const string& module_name, const char* name, bool is_export, bool deprecated); // The value of this name is set to val. Once a value has been // explicitly assigned using this method, no further names can be // added that aren't likewise explicitly initalized. - void AddName(const string& module_name, const char* name, bro_int_t val, bool is_export); + void AddName(const string& module_name, const char* name, bro_int_t val, bool is_export, bool deprecated); // -1 indicates not found. bro_int_t Lookup(const string& module_name, const char* name) const; @@ -580,7 +580,8 @@ protected: const char* name, bro_int_t val, bool is_export); void CheckAndAddName(const string& module_name, - const char* name, bro_int_t val, bool is_export); + const char* name, bro_int_t val, bool is_export, + bool deprecated); typedef std::map< const char*, bro_int_t, ltstr > NameMap; NameMap names; diff --git a/src/builtin-func.y b/src/builtin-func.y index 1b22436fff..0f895ced52 100644 --- a/src/builtin-func.y +++ b/src/builtin-func.y @@ -287,7 +287,7 @@ void record_bif_item(const char* id, const char* type) %left ',' ':' -%type TOK_C_TOKEN TOK_ID TOK_CSTR TOK_WS TOK_COMMENT TOK_ATTR TOK_INT opt_ws type attr_list opt_attr_list +%type TOK_C_TOKEN TOK_ID TOK_CSTR TOK_WS TOK_COMMENT TOK_ATTR TOK_INT opt_ws type attr_list opt_attr_list opt_func_attrs %type TOK_ATOM TOK_BOOL %union { @@ -372,7 +372,13 @@ type_def_types: TOK_RECORD { set_definition_type(TYPE_DEF, "Table"); } ; -event_def: event_prefix opt_ws plain_head opt_attr_list +opt_func_attrs: attr_list opt_ws + { $$ = $1; } + | /* nothing */ + { $$ = ""; } + ; + +event_def: event_prefix opt_ws plain_head opt_func_attrs { fprintf(fp_bro_init, "%s", $4); } end_of_head ';' { print_event_c_prototype(fp_func_h, true); @@ -380,13 +386,16 @@ event_def: event_prefix opt_ws plain_head opt_attr_list print_event_c_body(fp_func_def); } -func_def: func_prefix opt_ws typed_head end_of_head body +func_def: func_prefix opt_ws typed_head opt_func_attrs + { fprintf(fp_bro_init, "%s", $4); } end_of_head body ; -enum_def: enum_def_1 enum_list TOK_RPB +enum_def: enum_def_1 enum_list TOK_RPB opt_attr_list { // First, put an end to the enum type decl. - fprintf(fp_bro_init, "};\n"); + fprintf(fp_bro_init, "} "); + fprintf(fp_bro_init, "%s", $4); + fprintf(fp_bro_init, ";\n"); if ( decl.module_name != GLOBAL_MODULE_NAME ) fprintf(fp_netvar_h, "}; } }\n"); else diff --git a/src/parse.y b/src/parse.y index 83760dbbf0..9261775932 100644 --- a/src/parse.y +++ b/src/parse.y @@ -2,7 +2,7 @@ // See the file "COPYING" in the main distribution directory for copyright. %} -%expect 75 +%expect 78 %token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY %token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF @@ -24,7 +24,7 @@ %token TOK_ATTR_PERSISTENT TOK_ATTR_SYNCHRONIZED %token TOK_ATTR_RAW_OUTPUT TOK_ATTR_MERGEABLE %token TOK_ATTR_PRIORITY TOK_ATTR_LOG TOK_ATTR_ERROR_HANDLER -%token TOK_ATTR_TYPE_COLUMN +%token TOK_ATTR_TYPE_COLUMN TOK_ATTR_DEPRECATED %token TOK_DEBUG @@ -44,7 +44,7 @@ %right '!' %left '$' '[' ']' '(' ')' TOK_HAS_FIELD TOK_HAS_ATTR -%type opt_no_test opt_no_test_block +%type opt_no_test opt_no_test_block opt_deprecated %type TOK_ID TOK_PATTERN_TEXT single_pattern %type local_id global_id def_global_id event_id global_or_event_id resolve_id begin_func %type local_id_list @@ -671,6 +671,9 @@ expr: } else $$ = new NameExpr(id); + + if ( id->IsDeprecated() ) + reporter->Warning("deprecated (%s)", id->Name()); } } @@ -759,7 +762,7 @@ enum_body_elem: error messages if someboy tries to use constant variables as enumerator. */ - TOK_ID '=' TOK_CONSTANT + TOK_ID '=' TOK_CONSTANT opt_deprecated { set_location(@1, @3); assert(cur_enum_type); @@ -768,7 +771,7 @@ enum_body_elem: reporter->Error("enumerator is not a count constant"); else cur_enum_type->AddName(current_module, $1, - $3->InternalUnsigned(), is_export); + $3->InternalUnsigned(), is_export, $4); } | TOK_ID '=' '-' TOK_CONSTANT @@ -780,11 +783,11 @@ enum_body_elem: reporter->Error("enumerator is not a count constant"); } - | TOK_ID + | TOK_ID opt_deprecated { set_location(@1); assert(cur_enum_type); - cur_enum_type->AddName(current_module, $1, is_export); + cur_enum_type->AddName(current_module, $1, is_export, $2); } ; @@ -963,7 +966,12 @@ type: $$ = error_type(); } else + { Ref($$); + + if ( $1->IsDeprecated() ) + reporter->Warning("deprecated (%s)", $1->Name()); + } } ; @@ -1265,6 +1273,8 @@ attr: { $$ = new Attr(ATTR_LOG); } | TOK_ATTR_ERROR_HANDLER { $$ = new Attr(ATTR_ERROR_HANDLER); } + | TOK_ATTR_DEPRECATED + { $$ = new Attr(ATTR_DEPRECATED); } ; stmt: @@ -1450,6 +1460,10 @@ event: { set_location(@1, @4); $$ = new EventExpr($1, $3); + ID* id = lookup_ID($1, current_module.c_str()); + + if ( id && id->IsDeprecated() ) + reporter->Warning("deprecated (%s)", id->Name()); } ; @@ -1556,6 +1570,9 @@ global_or_event_id: if ( ! $$->IsGlobal() ) $$->Error("already a local identifier"); + if ( $$->IsDeprecated() ) + reporter->Warning("deprecated (%s)", $$->Name()); + delete [] $1; } @@ -1597,6 +1614,12 @@ opt_no_test_block: | { $$ = false; } +opt_deprecated: + TOK_ATTR_DEPRECATED + { $$ = true; } + | + { $$ = false; } + %% int yyerror(const char msg[]) diff --git a/src/plugin/ComponentManager.h b/src/plugin/ComponentManager.h index 7337cf069a..0069c77359 100644 --- a/src/plugin/ComponentManager.h +++ b/src/plugin/ComponentManager.h @@ -243,7 +243,8 @@ void ComponentManager::RegisterComponent(C* component, // Install an identfier for enum value string id = fmt("%s%s", prefix.c_str(), cname.c_str()); tag_enum_type->AddName(module, id.c_str(), - component->Tag().AsEnumVal()->InternalInt(), true); + component->Tag().AsEnumVal()->InternalInt(), true, + false); } } // namespace plugin diff --git a/src/scan.l b/src/scan.l index 0820567c30..ae11382fb3 100644 --- a/src/scan.l +++ b/src/scan.l @@ -260,6 +260,7 @@ when return TOK_WHEN; &create_expire return TOK_ATTR_EXPIRE_CREATE; &default return TOK_ATTR_DEFAULT; &delete_func return TOK_ATTR_DEL_FUNC; +&deprecated return TOK_ATTR_DEPRECATED; &raw_output return TOK_ATTR_RAW_OUTPUT; &encrypt return TOK_ATTR_ENCRYPT; &error_handler return TOK_ATTR_ERROR_HANDLER; diff --git a/testing/btest/Baseline/language.deprecated/out b/testing/btest/Baseline/language.deprecated/out new file mode 100644 index 0000000000..9587bf033f --- /dev/null +++ b/testing/btest/Baseline/language.deprecated/out @@ -0,0 +1,26 @@ +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 30: deprecated (ONE) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 31: deprecated (TWO) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 33: deprecated (GREEN) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 34: deprecated (BLUE) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 36: deprecated (blah) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 40: deprecated (my_event) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 41: deprecated (my_event) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 42: deprecated (my_hook) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 44: deprecated (my_record$b) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 45: deprecated (my_record$b) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 46: deprecated (my_record$b) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 48: deprecated (my_record?$b) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 49: deprecated (my_record$b) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 52: deprecated (my_record$b) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 55: deprecated (my_event) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 60: deprecated (my_hook) +warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.bro, line 65: deprecated (blah) +ZERO +ONE +TWO +RED +GREEN +BLUE +generate my_hook please +generate my_event please +schedule my_event please diff --git a/testing/btest/language/deprecated.bro b/testing/btest/language/deprecated.bro new file mode 100644 index 0000000000..0a6d269fad --- /dev/null +++ b/testing/btest/language/deprecated.bro @@ -0,0 +1,68 @@ +# @TEST-EXEC: bro -b %INPUT >out 2>&1 +# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out + +type blah: string &deprecated; + +global my_event: event(arg: string) &deprecated; + +global my_hook: hook(arg: string) &deprecated; + +type my_record: record { + a: count &default = 1; + b: string &optional &deprecated; +}; + +type my_enum: enum { + RED, + GREEN &deprecated, + BLUE &deprecated +}; + +type my_other_enum: enum { + ZERO = 0, + ONE = 1 &deprecated, + TWO = 2 &deprecated +}; + +event bro_init() + { + print ZERO; + print ONE; + print TWO; + print RED; + print GREEN; + print BLUE; + + local l: blah = "testing"; + + local ls: string = " test"; + + event my_event("generate my_event please"); + schedule 1sec { my_event("schedule my_event please") }; + hook my_hook("generate my_hook please"); + + local mr = my_record($a = 3, $b = "yeah"); + mr = [$a = 4, $b = "ye"]; + mr = record($a = 5, $b = "y"); + + if ( ! mr?$b ) + mr$b = "nooooooo"; + + mr$a = 2; + mr$b = "noooo"; + } + +event my_event(arg: string) + { + print arg; + } + +hook my_hook(arg: string) + { + print arg; + } + +function hmm(b: blah) + { + print b; + }