// 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
//  BSLS_DEPRECATE_FEATURE_HEADER: mark entire header file 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).
//
// * `BSLS_DEPRECATE_FEATURE_HEADER(UOR, FEATURE, MESSAGE)`
//   > This macro is used to annotate a header file to indicate that header
//   > has been deprecated, and is associated with the specified `UOR`
//   > (Unit-Of-Release), deprecated `FEATURE`, and `MESSAGE`.  This macro can
//   > be used for the headers that contain no actual code to generate compile
//   > warning when the header is included.
//
///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();
// };
// ```
//
///Example 2: 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);
//
//     // ...
// };
// ```
///Example 3: Deprecating a Header
///- - - - - - - - - - - - - - - -
// Once all the deprecated features has been removed from a header, the header
// itself cannot be removed as long as there are `#include`s with the header.
// To warn user about including the obsolete header, use the
// `BSLS_DEPRECATE_FEATURE_HEADER` macro:
// ```
// // bdet_date.h
//
// #include <bsls_deprecatefeature.h>
//
// BSLS_DEPRECATE_FEATURE_HEADER("bdet",
//                               "bdet_date",
//                               "Do not include obsolete bdet_date.h");
// ```

                       // ==============================
                       // 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
    // Settings are off. We should be doing nothing.

    #define BSLS_DEPRECATE_FEATURE_IMP(UOR, FEATURE, MESSAGE)
    #define BSLS_DEPRECATE_FEATURE_HEADER_IMP(UOR, FEATURE, MESSAGE)
#else
    // ------------------------------------------------------------------------
    // Utility macros

    #define BSLS_DEPRECATE_FEATURE_HEADER_IMP_STRINGIFY(...) #__VA_ARGS__

    // Lower level compiler macros are used as these macros may migrate out of
    // bde in the future.
    #if defined(__GNUC__) || defined(__clang__)
        #define BSLS_DEPRECATE_FEATURE_HEADER_IMP_PRAGMA_DO(x)                \
            _Pragma (#x)
    #else
        #define BSLS_DEPRECATE_FEATURE_HEADER_IMP_PRAGMA_DO(x)
    #endif

    // ------------------------------------------------------------------------
    // Main implementation macros

    #define BSLS_DEPRECATE_FEATURE_HEADER_IMP_PRAGMA(MESSAGE)                 \
        BSLS_DEPRECATE_FEATURE_HEADER_IMP_PRAGMA_DO(GCC warning MESSAGE)

    #if defined(BB_DEPRECATE_ENABLE_JSON_MESSAGE) ||                          \
        defined(BSLS_DEPRECATE_FEATURE_ENABLE_JSON_MESSAGE)

        // a. General c++ deprecation
        #define BSLS_DEPRECATE_FEATURE_IMP(UOR, FEATURE, MESSAGE)             \
            [[deprecated("{\"library\": \"" UOR "\", \"feature\": \"" FEATURE \
            "\", \"message\": \"" MESSAGE "\"}")]]

        // b. Deprecated header
        #define BSLS_DEPRECATE_FEATURE_HEADER_IMP(UOR, FEATURE, MESSAGE)      \
            BSLS_DEPRECATE_FEATURE_HEADER_IMP_PRAGMA(                         \
                BSLS_DEPRECATE_FEATURE_HEADER_IMP_STRINGIFY(                  \
            {                                                                 \
                "library": UOR,                                               \
                "feature": FEATURE,                                           \
                "message": MESSAGE                                            \
            }))
    #else
        // a. General c++ deprecation
        #define BSLS_DEPRECATE_FEATURE_IMP(UOR, FEATURE, MESSAGE)             \
            [[deprecated(MESSAGE)]]

        // b. Deprecated header
        #define BSLS_DEPRECATE_FEATURE_HEADER_IMP(UOR, FEATURE, MESSAGE)      \
            BSLS_DEPRECATE_FEATURE_HEADER_IMP_PRAGMA(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
                             // =================

// Usage: Macro for stating a general c++ deprecation (wraps c++'s
// [[deprecated]]) ex. BSLS_DEPRECATE_FEATURE("my_uor", "my_feature", "Please
// use y.h instead")
#define BSLS_DEPRECATE_FEATURE(UOR, FEATURE, MESSAGE)                         \
    BSLS_DEPRECATE_FEATURE_IMP(UOR, FEATURE, MESSAGE)

// Usage: Macro for stating a deprecated header
// ex. BSLS_DEPRECATE_FEATURE_HEADER("my_uor", "my_feature", "Please use y.h
// instead")
#define BSLS_DEPRECATE_FEATURE_HEADER(UOR, FEATURE, MESSAGE)                  \
    BSLS_DEPRECATE_FEATURE_HEADER_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 ----------------------------------
