// bsla_nonnullarg.h                                                  -*-C++-*-
#ifndef INCLUDED_BSLA_NONNULLARG
#define INCLUDED_BSLA_NONNULLARG

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide macros to hint at null arguments to functions.
//
//@MACROS:
//  BSLA_NONNULLARGS: warn if any pointer arguments are null
//  BSLA_NONNULLARG(...): warn if indexed arguments are null
//  BSLA_NONNULLARGS_IS_ACTIVE: 1 if 'BSLA_NONNULLARGS' is active, 0 otherwise
//  BSLA_NONNULLARG_IS_ACTIVE:  1 if 'BSLA_NONNULLARG' is active, 0 otherwise
//
//@SEE_ALSO: bsla_annotations
//
//@DESCRIPTION: This component provides preprocessor macros that define
// compiler-specific compile-time annotations.  These macros instruct the
// compiler to warn if null is passed to certain arguments to a function, or,
// on platforms where the feature is not supported, expand to nothing.
//
// Note that the annotations cause warnings to be emitted if the covered
// argument is passed:
//: o 'NULL'
//: o 0
//: o 'static_cast<TYPE *>(0)'
//: o 'nullptr' (with C++11)
//: o a 'const' variable known to be 0 (clang only, no warning with g++)
//
///Macro Reference
///---------------
//: 'BSLA_NONNULLARGS'
//:     This annotation indicates that a compiler warning is to be issued if
//:     any of the pointer arguments to this function are passed null.
//
//: 'BSLA_NONNULLARG(...)'
//:     This annotation, passed a variable-length list of positive integers,
//:     indicates that a compiler warning is to be issued if null is passed to
//:     a pointer argument at any of the specified indices, where the first
//:     argument of the annotated function has an index of 1. Note that for
//:     non-static member functions, the implicit 'this' argument has index 1.
//
//: 'BSLA_NONNULLARG_IS_ACTIVE'
//: 'BSLS_NONNULLARGS_IS_ACTIVE'
//:     In these two cases, 'X_IS_ACTIVE' is defined to 0 if 'X' expands to
//:     nothing and 1 otherwise.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Passing Null to Arguments Annotated as Non-Null
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// First, we define a function, 'usagePrint1', annotated such that a compiler
// warning will occur if the first argument of the annotated function is passed
// 0, 'NULL', 'nullptr', or (on clang) a null pointer constant expression:
//..
//  void usagePrint1(const char *string, int repetition) BSLA_NONNULLARG(1);
//      // Print the specified 'string' the specified 'repetition' times.
//
//  void usagePrint1(const char *string, int repetition)
//  {
//      for (int ii = 0; ii < repetition; ++ii) {
//          printf("%s\n", string);
//      }
//  }
//..
// Then, we define a nearly identical function annotated with
// 'BSLA_NONNULLARGS' instead.  Note that only pointer arguments are affected
// by this annotation -- 'repetition' is not affected and may be passed 0
// without a warning being emitted:
//..
//  void usagePrint2(const char *string, int repetition) BSLA_NONNULLARGS;
//      // Print the specified 'string' the specified 'repetition' times.
//
//  void usagePrint2(const char *string, int repetition)
//  {
//      for (int ii = 0; ii < repetition; ++ii) {
//          printf("%s\n", string);
//      }
//  }
//..
// So the two different annotations on these functions have an identical
// effect -- affecting the 'string' argument but not the 'repetition' argument.
//
// Next, in 'main', we call both functions with a non-null first argument, and
// observe that no warning occurs.  Note that even though 0 is passed to the
// integer argument to 'usagePrint2' and the 'BSLA_NONNULLARGS' annotation was
// used, non-pointer arguments are not affected by that annotation:
//..
//      usagePrint1("woof", 0);
//      usagePrint2("meow", 0);
//..
// Then, we call both functions passing the first argument a variable whose
// value is known by the compiler to be null, but since 'np1' is a non-'const'
// variable, no warning is issued:
//..
//      char *np1 = NULL;
//      usagePrint1(np1,    0);
//      usagePrint2(np1,    0);
//..
// Now, we call both functions passing various forms of constant null pointer
// expressions to the first argument:
//..
//      usagePrint1(   0, -10);
//      usagePrint2(   0, -10);
//
//      usagePrint1(NULL, -20);
//      usagePrint2(NULL, -20);
//
//      usagePrint1(static_cast<char *>(0), -30);
//      usagePrint2(static_cast<char *>(0), -30);
//
//      #if __cplusplus >= 201103L
//          usagePrint1(nullptr, -40);
//          usagePrint2(nullptr, -40);
//      #endif
//
//      char * const np2 = 0;   // 'np2', unlike 'np1' above, is 'const'.
//      usagePrint1(np2, -50);    // Warning with clang, not g++
//      usagePrint2(np2, -50);    // Warning with clang, not g++
//..
// Finally, we observe that the above calls result in the following warnings
// with clang w/C++11 support:
//..
//  .../bsla_nonnullarg.t.cpp:376:30: warning: null passed to a callee that
//  requires a non-null argument [-Wnonnull]
//      usagePrint1(   0, -10);
//                     ~     ^
//  .../bsla_nonnullarg.t.cpp:377:30: warning: null passed to a callee that
//  requires a non-null argument [-Wnonnull]
//      usagePrint2(   0, -10);
//                     ~     ^
//  .../bsla_nonnullarg.t.cpp:379:30: warning: null passed to a callee that
//  requires a non-null argument [-Wnonnull]
//      usagePrint1(NULL, -20);
//                  ~~~~     ^
//  .../bsla_nonnullarg.t.cpp:380:30: warning: null passed to a callee that
//  requires a non-null argument [-Wnonnull]
//      usagePrint2(NULL, -20);
//                  ~~~~     ^
//  .../bsla_nonnullarg.t.cpp:382:48: warning: null passed to a callee that
//  requires a non-null argument [-Wnonnull]
//      usagePrint1(static_cast<char *>(0), -30);
//                  ~~~~~~~~~~~~~~~~~~~~~~     ^
//  .../bsla_nonnullarg.t.cpp:383:48: warning: null passed to a callee that
//  requires a non-null argument [-Wnonnull]
//      usagePrint2(static_cast<char *>(0), -30);
//                  ~~~~~~~~~~~~~~~~~~~~~~     ^
//  .../bsla_nonnullarg.t.cpp:386:37: warning: null passed to a callee that
//  requires a non-null argument [-Wnonnull]
//          usagePrint1(nullptr, -40);
//                      ~~~~~~~     ^
//  .../bsla_nonnullarg.t.cpp:387:37: warning: null passed to a callee that
//  requires a non-null argument [-Wnonnull]
//          usagePrint2(nullptr, -40);
//                      ~~~~~~~     ^
//  .../bsla_nonnullarg.t.cpp:391:29: warning: null passed to a callee that
//  requires a non-null argument [-Wnonnull]
//      usagePrint1(np2, -50);    // Warning with clang, not g++
//                  ~~~     ^
//  .../bsla_nonnullarg.t.cpp:392:29: warning: null passed to a callee that
//  requires a non-null argument [-Wnonnull]
//      usagePrint2(np2, -50);    // Warning with clang, not g++
//                  ~~~     ^
//..

#include <bsls_platform.h>

#if defined(BSLS_PLATFORM_CMP_GNU) || defined(BSLS_PLATFORM_CMP_CLANG)
    #define BSLA_NONNULLARG(...)   __attribute__((__nonnull__(__VA_ARGS__)))
    #define BSLA_NONNULLARGS       __attribute__((__nonnull__))

    #define BSLA_NONNULLARG_IS_ACTIVE  1
    #define BSLA_NONNULLARGS_IS_ACTIVE 1
#else
    #define BSLA_NONNULLARG(...)
    #define BSLA_NONNULLARGS

    #define BSLA_NONNULLARG_IS_ACTIVE  0
    #define BSLA_NONNULLARGS_IS_ACTIVE 0
#endif

#endif

// ----------------------------------------------------------------------------
// Copyright 2019 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 ----------------------------------