// bsls_deprecatefeature.h -*-C++-*- #ifndef INCLUDED_BSLS_DEPRECATEFEATURE #define INCLUDED_BSLS_DEPRECATEFEATURE //@PURPOSE: Provide machinery to deprecate entities in C++ code. // //@MACROS: // BSLS_DEPRECATE_FEATURE: mark a C++ entity as deprecated // //@DESCRIPTION: This component provides facilities to identify deprecated C++ // entities. The deprecation annotations supplied by this component may, // depending on the build configuration, instantiate as C++ '[[deprecated]]' // annotations for which the compiler will emit a warning. Each deprecated // entity annotated by the macros in this component is identified by a 'UOR' // and 'FEATURE', allowing the use of that deprecated entity to be more easily // uniquely identified and tracked over time via tooling. Here "UOR" means // Unit-Of-Release, which is typically a package, package-group or library. // // **WARNING**: The build configuration flag, // 'BB_DEPRECATE_ENABLE_ALL_DEPRECATIONS_FOR_TESTING', that enables compiler // warnings for 'BSLS_DEPRECATE_FEATURE' should not be used in // cross-organizational integration builds such as a production 'unstable' // dpkg build. // ///Concerns with Compiler Warnings ///- - - - - - - - - - - - - - - - // In large development organization, where many teams may enable "warnings as // errors", enabling deprecation warnings in a cross-organizational integration // build will frequently prevent lower-level software from applying the // deprecation annotation to any newly deprecated code. // // Instead this component is designed to support static analysis tools that // identify deprecated entities, and allow them to be tracked and reported by // systems outside of the normal compilation process. The expectation is that // developers would use configuration options that generate compiler warnings // in local builds when they are actively working to remove the use of // deprecated code. // ///Macro Reference ///--------------- // This section documents the preprocessor macros defined in this component. // //: 'BSLS_DEPRECATE_FEATURE(UOR, FEATURE, MESSAGE)': //: This macro is used to annotate code to indicate that a name or entity //: has been deprecated, and is associated with the specified 'UOR' //: (Unit-Of-Release), deprecated 'FEATURE', and 'MESSAGE'. This macro can //: be used as if it were the C++ standard attribute '[[deprecated]]', and //: in appropriate build configurations will instantiate as a C++ //: '[[deprecated]]' annotation. 'UOR' and 'FEATURE' are character strings //: intended to uniquely identify one or more related entities that have //: been deprecated. 'MESSAGE' is a descriptive text intended for the a //: user of the deprecated feature (for example informing them of a //: replacement feature). For example, if several of the date and time //: types in the 'bde' library were deprecated they might be marked with the //: annotation: //: 'BSLS_DEPRECATE_FEATURE("bde", "date-and-time", "Use bdlt instead")'. //: 'UOR' and 'FEATURE' are meant to help uniquely identify a deprecation in //: external systems (e.g., a dashboard monitoring the state of a //: deprecation) so the supplied strings should start with a letter, and //: contain only letters, numbers, underscore, and dash characters (i.e., //: matching the regular expression "[a-zA-Z][\w\-]*"). //: //: 'BSLS_DEPRECATE_FEATURE_IS_SUPPORTED': This macro is defined if the //: current platform supports instantiating the deprecation annotation //: macros into annotation understood by the compiler. //: //: 'BSLS_DEPRECATE_FEATURE_ANNOTATION_IS_ACTIVE': This macro is defined if //: deprecation annotation macros defined in this component *will* be //: instantiated into annotations understood by the compiler (i.e., this //: will be defined if 'BSLS_DEPRECATE_FEATURE_SUPPORTED_PLATFORM' is //: defined and the build configuration macros are configured in a way //: that the annotations will instantiate as the '[[deprecated]]' //: attribute). // ///Configuration Reference ///----------------------- // There are a set of macros, not defined by this component, that users may // supply (e.g., to their build system) to configure the behavior of the // deprecation annotation macros provided by this component. // // The available configuration macros are described below: //.. // * 'BB_DEPRECATE_ENABLE_ALL_DEPRECATIONS_FOR_TESTING': This macro, when // defined, enables the instantiation of every deprecation macro as a C++ // '[[deprecated]]' annotation. This *MUST* *NOT* be defined as part of // cross-organization integration build such as an 'unstable' dpkg build // (see {Concerns with Compiler Warnings}). // // * 'BB_DEPRECATE_ENABLE_JSON_MESSAGE': Changes the messages reported by // compiler deprecation annotations to be a JSON document intended to // be useful for tools looking to identify and categorize deprecations. // // * 'BSLS_DEPRECATE_FEATURE_ENABLE_ALL_DEPRECATIONS_FOR_TESTING': This macro // is a synonym for 'BB_DEPRECATE_ENABLE_ALL_DEPRECATIONS_FOR_TESTING'. // // * 'BSLS_DEPRECATE_FEATURE_ENABLE_JSON_MESSAGE': This macro is a synonym for // 'BB_DEPRECATE_ENABLE_JSON_MESSAGE'. //.. // ///Usage ///----- // In this section we show intended usage of this component. // ///Example 1: Deprecating a Feature /// - - - - - - - - - - - - - - - - // The following example demonstrates using the 'BSLS_DEPRECATE_FEATURE' macro // to deprecate several C++ entities. // // The 'BSLS_DEPRECATE_FEATURE' macro can be applied in the same way as the C++ // '[[deprecated]]' annotation. For example, imagine we are deprecating a // function 'oldFunction' in the 'bsl' library as part of migrating software to // the linux platform, we might write: //.. // BSLS_DEPRECATE_FEATURE("bsl", "oldFunction", "Use newFunction instead") // void oldFunction(); //.. // Here the string "bsl" refers to the library or Unit-Of-Release (UOR) that // the deprecation occurs in. "oldFunction" is an arbitrary identifier for // the feature being deprecated. Together the 'UOR' and 'FEATURE' are // intended to form a unique enterprise-wide identifier for the feature being // deprecated. Finally the string "Use newFunction instead" is a message for // users of the deprecated feature. // // Marking 'oldFunction' in this way makes the deprecation of 'oldFunction' // visible to code analysis tools. In addition, in a local build, warnings // for uses of the deprecated entity can be enabled using a build macro // 'BB_DEPRECATE_ENABLE_ALL_DEPRECATIONS_FOR_TESTING' (this macro *MUST* *NOT* // be used as part of a cross-organization integration build such as a // 'unstable' dpkg build, see {Concerns with Compiler Warnings}). // // Similarly, if we were deprecating a class 'OldType' we might write: //.. // // class BSLS_DEPRECATE_FEATURE("bsl", "OldType", "Use NewType instead") // OldType { // // ... // }; //.. // Frequently, more than one C++ related entity may be associated with a // deprecated feature. In that case we would want to use the same identifier // for each entity we mark deprecated. To simplify this we might create a // deprecation macro that is local to the component. For example, if we were // deprecating a queue and its iterator in the 'bde' library we might write: //.. // #define BDEC_QUEUE_DEPRECATE \. // BSLS_DEPRECATE_FEATURE("bde", "bdec_queue", "Use bsl::queue instead") // // class BDEC_QUEUE_DEPRECATE bdec_Queue { // //... // }; // // class BDEC_QUEUE_DEPRECATE bdec_QueueIterator { // //... // }; //.. // Sometimes several entities are deprecated as part of the same feature where // separate messages are appropriate. For example, imagine we had a component // 'bsls_measurementutil' that we were converting from imperial to metric // units: //.. // #define BSLS_MEASUREMEANTUTIL_DEPRECATE_IMPERIAL(MESSAGE) \. // BSLS_DEPRECATE_FEATURE("bsl", "deprecate-imperial-units", MESSAGE) // // struct MeasurementUtil { // // BSLS_MEASUREMEANTUTIL_DEPRECATE_IMPERIAL("Use getKilometers instead") // static double getMiles(); // // BSLS_MEASUREMEANTUTIL_DEPRECATE_IMPERIAL("Use getKilograms instead") // static double getPounds(); // }; //.. // ///Deprecating a Feature Across Multiple Headers ///- - - - - - - - - - - - - - - - - - - - - - - // Frequently a feature being deprecated may span multiple components. For // example, we may want to deprecate all the date and time types in the 'bde' // library. In those instances one may define a macro in the lowest level // component (e.g., define 'BDET_DATE_DEPRECATE_DATE_AND_TIME' in 'bdet_date'). // Alternatively, one might create a component specifically for the deprecation // (e.g., define 'BDET_DEPRECATE_DATE_AND_TIME' in a newly created // 'bdet_deprecate' component). The following code shows the latter, creating // a new component, 'bdet_deprecate' in which to provide macros to deprecate // code across 'bdet'. // // First, we create a new component, 'bdet_deprecate` and define the following // macro: //.. // // bdet_deprecate.h // // #define BDET_DEPRECATE_DATE_AND_TIME(MESSAGE) \. // BSLS_DEPRECATE_FEATURE("bde", "date-and-time", MESSAGE) //.. // We can use that macro to mark various components deprecated. Next, we mark // an old type name as deprecated: //.. // // bdet_date.h // // BDET_DEPRECATE_DATE_AND_TIME("Use bdlt::Date") typedef bdlt::Date Date; //.. // Then we mark a class declaration as deprecated: //.. // // bdet_calendar.h // // class BDET_DEPRECATE_DATE_AND_TIME("Use bdlt::PackedCalendar") Calendar { // // ... // }; //.. // Finally we mark a function as deprecated: //.. // // bdet_dateimputil.h // // struct DateUtil { // // BDET_DEPRECATE_DATE_AND_TIME("Use bdlt::DateUtil instead") // static bool isValidYYYYMMDD(int yyyymmddValue); // // // ... // }; //.. // ============================== // Component Configuration Macros // ============================== // This could be replaced with BSLS_COMPILERFEATURES_CPLUSPLUS, but for the // moment, this header has 0 dependencies, which may be a useful feature to // maintain. #if (defined(__cplusplus) && (__cplusplus >= 201703L)) || \ (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)) #define BSLS_DEPRECATE_FEATURE_IS_SUPPORTED #endif #if defined(BSLS_DEPRECATE_FEATURE_IS_SUPPORTED) && \ (defined(BB_DEPRECATE_ENABLE_ALL_DEPRECATIONS_FOR_TESTING) || \ defined(BSLS_DEPRECATE_FEATURE_ENABLE_ALL_DEPRECATIONS_FOR_TESTING)) #define BSLS_DEPRECATE_FEATURE_ANNOTATION_IS_ACTIVE #else #undef BSLS_DEPRECATE_FEATURE_ANNOTATION_IS_ACTIVE #endif // ==================================== // Implementation Details: Do *NOT* Use // ==================================== #ifndef BSLS_DEPRECATE_FEATURE_ANNOTATION_IS_ACTIVE #define BSLS_DEPRECATE_FEATURE_IMP(UOR, FEATURE, MESSAGE) #else #if defined(BB_DEPRECATE_ENABLE_JSON_MESSAGE) || \ defined(BSLS_DEPRECATE_FEATURE_ENABLE_JSON_MESSAGE) #define BSLS_DEPRECATE_FEATURE_IMP(UOR, FEATURE, MESSAGE) \ [[deprecated("{\"library\": \"" UOR "\", \"feature\": \"" FEATURE \ "\", \"message\": \"" MESSAGE "\"}")]] #else #define BSLS_DEPRECATE_FEATURE_IMP(UOR, FEATURE, MESSAGE) \ [[deprecated(MESSAGE)]] #endif // BB_DEPRECATE_ENABLE_JSON_MESSAGE #endif // If the number of arguments needs to be expanded, commit // abd14c70a7c9fb38d9bf3fe225eb0966cb036c9f contains a variadic implementation // similar to 'BSLIM_TESTUTIL_ASSERTV'. // ================= // Annotation Macros // ================= #define BSLS_DEPRECATE_FEATURE(UOR, FEATURE, MESSAGE) \ BSLS_DEPRECATE_FEATURE_IMP(UOR, FEATURE, MESSAGE) #endif // INCLUDED_BSLS_DEPRECATEFEATURE // ---------------------------------------------------------------------------- // Copyright 2022 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------