[cppdap] Merge from upstream for response cb fixes
Change-Id: Id4faf9ffce7babf93fec89bf9ba67f323edf126b
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2ec3ac0..47cb5df 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -221,6 +221,7 @@
${CPPDAP_SRC_DIR}/rwmutex_test.cpp
${CPPDAP_SRC_DIR}/session_test.cpp
${CPPDAP_SRC_DIR}/socket_test.cpp
+ ${CPPDAP_SRC_DIR}/traits_test.cpp
${CPPDAP_SRC_DIR}/typeinfo_test.cpp
${CPPDAP_SRC_DIR}/variant_test.cpp
${CPPDAP_GOOGLETEST_DIR}/googletest/src/gtest-all.cc
diff --git a/include/dap/protocol.h b/include/dap/protocol.h
index c45d421..0d13547 100644
--- a/include/dap/protocol.h
+++ b/include/dap/protocol.h
@@ -15,7 +15,7 @@
// Generated with protocol_gen.go -- do not edit this file.
// go run scripts/protocol_gen/protocol_gen.go
//
-// DAP version 1.41.0
+// DAP version 1.43.0
#ifndef dap_protocol_h
#define dap_protocol_h
@@ -102,7 +102,7 @@
// If sourceReference > 0 the contents of the source must be retrieved through
// the SourceRequest (even if a path is specified). A sourceReference is only
// valid for a session, so it must not be used to persist a source. The value
- // should be less than or equal to 2147483647 (2^31 - 1).
+ // should be less than or equal to 2147483647 (2^31-1).
optional<integer> sourceReference;
// An optional list of sources that are related to this source. These may be
// the source that generated this source.
@@ -269,16 +269,20 @@
DAP_DECLARE_STRUCT_TYPEINFO(ColumnDescriptor);
-// An ExceptionBreakpointsFilter is shown in the UI as an option for configuring
-// how exceptions are dealt with.
+// An ExceptionBreakpointsFilter is shown in the UI as an filter option for
+// configuring how exceptions are dealt with.
struct ExceptionBreakpointsFilter {
- // Initial value of the filter. If not specified a value 'false' is assumed.
+ // Initial value of the filter option. If not specified a value 'false' is
+ // assumed.
optional<boolean> def;
- // The internal ID of the filter. This value is passed to the
- // setExceptionBreakpoints request.
+ // The internal ID of the filter option. This value is passed to the
+ // 'setExceptionBreakpoints' request.
string filter;
- // The name of the filter. This will be shown in the UI.
+ // The name of the filter option. This will be shown in the UI.
string label;
+ // Controls whether a condition can be specified for this filter option. If
+ // false or missing, a condition can not be set.
+ optional<boolean> supportsCondition;
};
DAP_DECLARE_STRUCT_TYPEINFO(ExceptionBreakpointsFilter);
@@ -290,7 +294,8 @@
// The set of characters that should trigger completion in a REPL. If not
// specified, the UI should assume the '.' character.
optional<array<string>> completionTriggerCharacters;
- // Available filters or options for the setExceptionBreakpoints request.
+ // Available exception filter options for the 'setExceptionBreakpoints'
+ // request.
optional<array<ExceptionBreakpointsFilter>> exceptionBreakpointFilters;
// The debug adapter supports the 'terminateDebuggee' attribute on the
// 'disconnect' request.
@@ -321,6 +326,9 @@
// The debug adapter supports a (side effect free) evaluate request for data
// hovers.
optional<boolean> supportsEvaluateForHovers;
+ // The debug adapter supports 'filterOptions' as an argument on the
+ // 'setExceptionBreakpoints' request.
+ optional<boolean> supportsExceptionFilterOptions;
// The debug adapter supports the 'exceptionInfo' request.
optional<boolean> supportsExceptionInfoRequest;
// The debug adapter supports 'exceptionOptions' on the
@@ -703,7 +711,7 @@
// The number of indexed child variables.
// The client can use this optional information to present the variables in a
// paged UI and fetch them in chunks. The value should be less than or equal
- // to 2147483647 (2^31 - 1).
+ // to 2147483647 (2^31-1).
optional<integer> indexedVariables;
// Optional memory reference to a location appropriate for this result.
// For pointer type eval results, this is generally a reference to the memory
@@ -714,7 +722,7 @@
// The number of named child variables.
// The client can use this optional information to present the variables in a
// paged UI and fetch them in chunks. The value should be less than or equal
- // to 2147483647 (2^31 - 1).
+ // to 2147483647 (2^31-1).
optional<integer> namedVariables;
// Properties of a evaluate result that can be used to determine how to render
// the result in the UI.
@@ -729,7 +737,7 @@
// If variablesReference is > 0, the evaluate result is structured and its
// children can be retrieved by passing variablesReference to the
// VariablesRequest. The value should be less than or equal to 2147483647
- // (2^31 - 1).
+ // (2^31-1).
integer variablesReference;
};
@@ -902,7 +910,8 @@
// The set of characters that should trigger completion in a REPL. If not
// specified, the UI should assume the '.' character.
optional<array<string>> completionTriggerCharacters;
- // Available filters or options for the setExceptionBreakpoints request.
+ // Available exception filter options for the 'setExceptionBreakpoints'
+ // request.
optional<array<ExceptionBreakpointsFilter>> exceptionBreakpointFilters;
// The debug adapter supports the 'terminateDebuggee' attribute on the
// 'disconnect' request.
@@ -933,6 +942,9 @@
// The debug adapter supports a (side effect free) evaluate request for data
// hovers.
optional<boolean> supportsEvaluateForHovers;
+ // The debug adapter supports 'filterOptions' as an argument on the
+ // 'setExceptionBreakpoints' request.
+ optional<boolean> supportsExceptionFilterOptions;
// The debug adapter supports the 'exceptionInfo' request.
optional<boolean> supportsExceptionInfoRequest;
// The debug adapter supports 'exceptionOptions' on the
@@ -1015,6 +1027,8 @@
// May be one of the following enumeration values:
// 'path', 'uri'
optional<string> pathFormat;
+ // Client supports the invalidated event.
+ optional<boolean> supportsInvalidatedEvent;
// Client supports memory references.
optional<boolean> supportsMemoryReferences;
// Client supports progress reporting.
@@ -1049,6 +1063,35 @@
DAP_DECLARE_STRUCT_TYPEINFO(InitializedEvent);
+// Logical areas that can be invalidated by the 'invalidated' event.
+struct InvalidatedAreas {};
+
+DAP_DECLARE_STRUCT_TYPEINFO(InvalidatedAreas);
+
+// This event signals that some state in the debug adapter has changed and
+// requires that the client needs to re-render the data snapshot previously
+// requested. Debug adapters do not have to emit this event for runtime changes
+// like stopped or thread events because in that case the client refetches the
+// new state anyway. But the event can be used for example to refresh the UI
+// after rendering formatting has changed in the debug adapter. This event
+// should only be sent if the debug adapter has received a value true for the
+// 'supportsInvalidatedEvent' capability of the 'initialize' request.
+struct InvalidatedEvent : public Event {
+ // Optional set of logical areas that got invalidated. This property has a
+ // hint characteristic: a client can only be expected to make a 'best effort'
+ // in honouring the areas but there are no guarantees. If this property is
+ // missing, empty, or if values are not understand the client should assume a
+ // single value 'all'.
+ optional<array<InvalidatedAreas>> areas;
+ // If specified, the client only needs to refetch data related to this stack
+ // frame (and the 'threadId' is ignored).
+ optional<integer> stackFrameId;
+ // If specified, the client only needs to refetch data related to this thread.
+ optional<integer> threadId;
+};
+
+DAP_DECLARE_STRUCT_TYPEINFO(InvalidatedEvent);
+
// Response to 'launch' request. This is just an acknowledgement, so no body
// field is required.
struct LaunchResponse : public Response {};
@@ -1241,7 +1284,7 @@
// If an attribute 'variablesReference' exists and its value is > 0, the
// output contains objects which can be retrieved by passing
// 'variablesReference' to the 'variables' request. The value should be less
- // than or equal to 2147483647 (2^31 - 1).
+ // than or equal to 2147483647 (2^31-1).
optional<integer> variablesReference;
};
@@ -1327,7 +1370,7 @@
// request until the request has been either completed or cancelled. If the
// request ID is omitted, the progress report is assumed to be related to some
// general activity of the debug adapter.
- optional<number> requestId;
+ optional<integer> requestId;
// Mandatory (short) title of the progress reporting. Shown in the UI to
// describe the long running operation.
string title;
@@ -1439,11 +1482,11 @@
// Response to 'runInTerminal' request.
struct RunInTerminalResponse : public Response {
- // The process ID. The value should be less than or equal to 2147483647 (2^31
- // - 1).
+ // The process ID. The value should be less than or equal to 2147483647
+ // (2^31-1).
optional<integer> processId;
// The process ID of the terminal shell. The value should be less than or
- // equal to 2147483647 (2^31 - 1).
+ // equal to 2147483647 (2^31-1).
optional<integer> shellProcessId;
};
@@ -1458,7 +1501,8 @@
using Response = RunInTerminalResponse;
// List of arguments. The first argument is the command to run.
array<string> args;
- // Working directory of the command.
+ // Working directory for the command. For non-empty, valid paths this
+ // typically results in execution of a change directory command.
string cwd;
// Environment key-value pairs that are added to or removed from the default
// environment.
@@ -1663,6 +1707,20 @@
DAP_DECLARE_STRUCT_TYPEINFO(ExceptionOptions);
+// An ExceptionFilterOptions is used to specify an exception filter together
+// with a condition for the setExceptionsFilter request.
+struct ExceptionFilterOptions {
+ // An optional expression for conditional exceptions.
+ // The exception will break into the debugger if the result of the condition
+ // is true.
+ optional<string> condition;
+ // ID of an exception filter returned by the 'exceptionBreakpointFilters'
+ // capability.
+ string filterId;
+};
+
+DAP_DECLARE_STRUCT_TYPEINFO(ExceptionFilterOptions);
+
// The request configures the debuggers response to thrown exceptions.
// If an exception is configured to break, a 'stopped' event is fired (with
// reason 'exception'). Clients should only call this request if the capability
@@ -1673,8 +1731,15 @@
// The attribute is only honored by a debug adapter if the capability
// 'supportsExceptionOptions' is true.
optional<array<ExceptionOptions>> exceptionOptions;
- // IDs of checked exception options. The set of IDs is returned via the
- // 'exceptionBreakpointFilters' capability.
+ // Set of exception filters and their options. The set of all possible
+ // exception filters is defined by the 'exceptionBreakpointFilters'
+ // capability. This attribute is only honored by a debug adapter if the
+ // capability 'supportsExceptionFilterOptions' is true. The 'filter' and
+ // 'filterOptions' sets are additive.
+ optional<array<ExceptionFilterOptions>> filterOptions;
+ // Set of exception filters specified by their ID. The set of all possible
+ // exception filters is defined by the 'exceptionBreakpointFilters'
+ // capability. The 'filter' and 'filterOptions' sets are additive.
array<string> filters;
};
@@ -1685,12 +1750,12 @@
// The number of indexed child variables.
// The client can use this optional information to present the variables in a
// paged UI and fetch them in chunks. The value should be less than or equal
- // to 2147483647 (2^31 - 1).
+ // to 2147483647 (2^31-1).
optional<integer> indexedVariables;
// The number of named child variables.
// The client can use this optional information to present the variables in a
// paged UI and fetch them in chunks. The value should be less than or equal
- // to 2147483647 (2^31 - 1).
+ // to 2147483647 (2^31-1).
optional<integer> namedVariables;
// Properties of a value that can be used to determine how to render the
// result in the UI.
@@ -1704,7 +1769,7 @@
string value;
// If variablesReference is > 0, the value is structured and its children can
// be retrieved by passing variablesReference to the VariablesRequest. The
- // value should be less than or equal to 2147483647 (2^31 - 1).
+ // value should be less than or equal to 2147483647 (2^31-1).
optional<integer> variablesReference;
};
@@ -1820,12 +1885,12 @@
// The number of indexed child variables.
// The client can use this optional information to present the variables in a
// paged UI and fetch them in chunks. The value should be less than or equal
- // to 2147483647 (2^31 - 1).
+ // to 2147483647 (2^31-1).
optional<integer> indexedVariables;
// The number of named child variables.
// The client can use this optional information to present the variables in a
// paged UI and fetch them in chunks. The value should be less than or equal
- // to 2147483647 (2^31 - 1).
+ // to 2147483647 (2^31-1).
optional<integer> namedVariables;
// The type of the new value. Typically shown in the UI when hovering over the
// value.
@@ -1834,7 +1899,7 @@
string value;
// If variablesReference is > 0, the new value is structured and its children
// can be retrieved by passing variablesReference to the VariablesRequest. The
- // value should be less than or equal to 2147483647 (2^31 - 1).
+ // value should be less than or equal to 2147483647 (2^31-1).
optional<integer> variablesReference;
};
@@ -1924,7 +1989,12 @@
// stackframes available. This means that there is no location information
// available.
array<StackFrame> stackFrames;
- // The total number of frames available.
+ // The total number of frames available in the stack. If omitted or if
+ // totalFrames is larger than the available frames, a client is expected to
+ // request frames until a request returns less frames than requested (which
+ // indicates the end of the stack). Returning monotonically increasing
+ // totalFrames values for subsequent requests can be used to enforce paging in
+ // the client.
optional<integer> totalFrames;
};
@@ -1951,7 +2021,16 @@
DAP_DECLARE_STRUCT_TYPEINFO(StackFrameFormat);
-// The request returns a stacktrace from the current execution state.
+// The request returns a stacktrace from the current execution state of a given
+// thread. A client can request all stack frames by omitting the startFrame and
+// levels arguments. For performance conscious clients stack frames can be
+// retrieved in a piecemeal way with the startFrame and levels arguments. The
+// response of the stackTrace request may contain a totalFrames property that
+// hints at the total number of frames in the stack. If a client needs this
+// total number upfront, it can issue a request for a single (first) frame and
+// depending on the value of totalFrames decide how to proceed. In any case a
+// client should be prepared to receive less frames than requested, which is an
+// indication that the end of the stack has been reached.
struct StackTraceRequest : public Request {
using Response = StackTraceResponse;
// Specifies details on how to format the stack frames.
diff --git a/include/dap/session.h b/include/dap/session.h
index e06957f..11d5560 100644
--- a/include/dap/session.h
+++ b/include/dap/session.h
@@ -17,6 +17,7 @@
#include "future.h"
#include "io.h"
+#include "traits.h"
#include "typeinfo.h"
#include "typeof.h"
@@ -29,33 +30,6 @@
struct Response;
struct Event;
-// internal functionality
-namespace detail {
-template <typename T>
-struct traits {
- static constexpr bool isRequest = std::is_base_of<dap::Request, T>::value;
- static constexpr bool isResponse = std::is_base_of<dap::Response, T>::value;
- static constexpr bool isEvent = std::is_base_of<dap::Event, T>::value;
-};
-
-// ArgTy<F>::type resolves to the first argument type of the function F.
-// F can be a function, static member function, or lambda.
-template <typename F>
-struct ArgTy {
- using type = typename ArgTy<decltype(&F::operator())>::type;
-};
-
-template <typename R, typename Arg>
-struct ArgTy<R (*)(Arg)> {
- using type = typename std::decay<Arg>::type;
-};
-
-template <typename R, typename C, typename Arg>
-struct ArgTy<R (C::*)(Arg) const> {
- using type = typename std::decay<Arg>::type;
-};
-} // namespace detail
-
////////////////////////////////////////////////////////////////////////////////
// Error
////////////////////////////////////////////////////////////////////////////////
@@ -137,14 +111,24 @@
// (3) Bind the session to the remote endpoint with bind().
// (4) Send requests or events with send().
class Session {
- template <typename T>
- using IsRequest = typename std::enable_if<detail::traits<T>::isRequest>::type;
+ template <typename F, int N>
+ using ParamType = traits::ParameterType<F, N>;
template <typename T>
- using IsEvent = typename std::enable_if<detail::traits<T>::isEvent>::type;
+ using IsRequest = traits::EnableIfIsType<dap::Request, T>;
+
+ template <typename T>
+ using IsEvent = traits::EnableIfIsType<dap::Event, T>;
template <typename F>
- using ArgTy = typename detail::ArgTy<F>::type;
+ using IsRequestHandlerWithoutCallback = traits::EnableIf<
+ traits::CompatibleWith<F, std::function<void(dap::Request)>>::value>;
+
+ template <typename F, typename CallbackType>
+ using IsRequestHandlerWithCallback = traits::EnableIf<traits::CompatibleWith<
+ F,
+ std::function<void(dap::Request, std::function<void(CallbackType)>)>>::
+ value>;
public:
virtual ~Session();
@@ -167,20 +151,47 @@
// ResponseOrError<ResponseType>(const RequestType&)
// ResponseType(const RequestType&)
// Error(const RequestType&)
- template <typename F, typename RequestType = ArgTy<F>>
- inline IsRequest<RequestType> registerHandler(F&& handler);
+ template <typename F, typename RequestType = ParamType<F, 0>>
+ inline IsRequestHandlerWithoutCallback<F> registerHandler(F&& handler);
+
+ // registerHandler() registers a request handler for a specific request type.
+ // The handler has a response callback function for the second argument of the
+ // handler function. This callback may be called after the handler has
+ // returned.
+ // The function F must have the following signature:
+ // void(const RequestType& request,
+ // std::function<void(ResponseType)> response)
+ template <typename F,
+ typename RequestType = ParamType<F, 0>,
+ typename ResponseType = typename RequestType::Response>
+ inline IsRequestHandlerWithCallback<F, ResponseType> registerHandler(
+ F&& handler);
+
+ // registerHandler() registers a request handler for a specific request type.
+ // The handler has a response callback function for the second argument of the
+ // handler function. This callback may be called after the handler has
+ // returned.
+ // The function F must have the following signature:
+ // void(const RequestType& request,
+ // std::function<void(ResponseOrError<ResponseType>)> response)
+ template <typename F,
+ typename RequestType = ParamType<F, 0>,
+ typename ResponseType = typename RequestType::Response>
+ inline IsRequestHandlerWithCallback<F, ResponseOrError<ResponseType>>
+ registerHandler(F&& handler);
// registerHandler() registers a event handler for a specific event type.
// The function F must have the following signature:
// void(const EventType&)
- template <typename F, typename EventType = ArgTy<F>>
+ template <typename F, typename EventType = ParamType<F, 0>>
inline IsEvent<EventType> registerHandler(F&& handler);
// registerSentHandler() registers the function F to be called when a response
// of the specific type has been sent.
// The function F must have the following signature:
// void(const ResponseOrError<ResponseType>&)
- template <typename F, typename ResponseType = typename ArgTy<F>::Request>
+ template <typename F,
+ typename ResponseType = typename ParamType<F, 0>::Request>
inline void registerSentHandler(F&& handler);
// send() sends the request to the connected endpoint and returns a
@@ -251,21 +262,57 @@
virtual bool send(const TypeInfo*, const void* event) = 0;
};
-template <typename F, typename T>
-Session::IsRequest<T> Session::registerHandler(F&& handler) {
- using ResponseType = typename T::Response;
- auto cb = [handler](const void* args, const RequestSuccessCallback& onSuccess,
- const RequestErrorCallback& onError) {
+template <typename F, typename RequestType>
+Session::IsRequestHandlerWithoutCallback<F> Session::registerHandler(
+ F&& handler) {
+ using ResponseType = typename RequestType::Response;
+ const TypeInfo* typeinfo = TypeOf<RequestType>::type();
+ registerHandler(typeinfo, [handler](const void* args,
+ const RequestSuccessCallback& onSuccess,
+ const RequestErrorCallback& onError) {
ResponseOrError<ResponseType> res =
- handler(*reinterpret_cast<const T*>(args));
+ handler(*reinterpret_cast<const RequestType*>(args));
if (res.error) {
onError(TypeOf<ResponseType>::type(), res.error);
} else {
onSuccess(TypeOf<ResponseType>::type(), &res.response);
}
- };
- const TypeInfo* typeinfo = TypeOf<T>::type();
- registerHandler(typeinfo, cb);
+ });
+}
+
+template <typename F, typename RequestType, typename ResponseType>
+Session::IsRequestHandlerWithCallback<F, ResponseType> Session::registerHandler(
+ F&& handler) {
+ using CallbackType = ParamType<F, 1>;
+ registerHandler(
+ TypeOf<RequestType>::type(),
+ [handler](const void* args, const RequestSuccessCallback& onSuccess,
+ const RequestErrorCallback&) {
+ CallbackType responseCallback = [onSuccess](const ResponseType& res) {
+ onSuccess(TypeOf<ResponseType>::type(), &res);
+ };
+ handler(*reinterpret_cast<const RequestType*>(args), responseCallback);
+ });
+}
+
+template <typename F, typename RequestType, typename ResponseType>
+Session::IsRequestHandlerWithCallback<F, ResponseOrError<ResponseType>>
+Session::registerHandler(F&& handler) {
+ using CallbackType = ParamType<F, 1>;
+ registerHandler(
+ TypeOf<RequestType>::type(),
+ [handler](const void* args, const RequestSuccessCallback& onSuccess,
+ const RequestErrorCallback& onError) {
+ CallbackType responseCallback =
+ [onError, onSuccess](const ResponseOrError<ResponseType>& res) {
+ if (res.error) {
+ onError(TypeOf<ResponseType>::type(), res.error);
+ } else {
+ onSuccess(TypeOf<ResponseType>::type(), &res.response);
+ }
+ };
+ handler(*reinterpret_cast<const RequestType*>(args), responseCallback);
+ });
}
template <typename F, typename T>
diff --git a/include/dap/traits.h b/include/dap/traits.h
new file mode 100644
index 0000000..cbc7d39
--- /dev/null
+++ b/include/dap/traits.h
@@ -0,0 +1,159 @@
+// Copyright 2021 Google LLC
+//
+// 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
+//
+// https://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.
+
+#ifndef dap_traits_h
+#define dap_traits_h
+
+#include <tuple>
+#include <type_traits>
+
+namespace dap {
+namespace traits {
+
+// NthTypeOf returns the `N`th type in `Types`
+template <int N, typename... Types>
+using NthTypeOf = typename std::tuple_element<N, std::tuple<Types...>>::type;
+
+// `IsTypeOrDerived<BASE, T>::value` is true iff `T` is of type `BASE`, or
+// derives from `BASE`.
+template <typename BASE, typename T>
+using IsTypeOrDerived = std::integral_constant<
+ bool,
+ std::is_base_of<BASE, typename std::decay<T>::type>::value ||
+ std::is_same<BASE, typename std::decay<T>::type>::value>;
+
+// `EachIsTypeOrDerived<N, BASES, TYPES>::value` is true iff all of the types in
+// the std::tuple `TYPES` is of, or derives from the corresponding indexed type
+// in the std::tuple `BASES`.
+// `N` must be equal to the number of types in both the std::tuple `BASES` and
+// `TYPES`.
+template <int N, typename BASES, typename TYPES>
+struct EachIsTypeOrDerived {
+ using base = typename std::tuple_element<N - 1, BASES>::type;
+ using type = typename std::tuple_element<N - 1, TYPES>::type;
+ using last_matches = IsTypeOrDerived<base, type>;
+ using others_match = EachIsTypeOrDerived<N - 1, BASES, TYPES>;
+ static constexpr bool value = last_matches::value && others_match::value;
+};
+
+// EachIsTypeOrDerived specialization for N = 1
+template <typename BASES, typename TYPES>
+struct EachIsTypeOrDerived<1, BASES, TYPES> {
+ using base = typename std::tuple_element<0, BASES>::type;
+ using type = typename std::tuple_element<0, TYPES>::type;
+ static constexpr bool value = IsTypeOrDerived<base, type>::value;
+};
+
+// EachIsTypeOrDerived specialization for N = 0
+template <typename BASES, typename TYPES>
+struct EachIsTypeOrDerived<0, BASES, TYPES> {
+ static constexpr bool value = true;
+};
+
+// Signature describes the signature of a function.
+template <typename RETURN, typename... PARAMETERS>
+struct Signature {
+ // The return type of the function signature
+ using ret = RETURN;
+ // The parameters of the function signature held in a std::tuple
+ using parameters = std::tuple<PARAMETERS...>;
+ // The type of the Nth parameter of function signature
+ template <std::size_t N>
+ using parameter = NthTypeOf<N, PARAMETERS...>;
+ // The total number of parameters
+ static constexpr std::size_t parameter_count = sizeof...(PARAMETERS);
+};
+
+// SignatureOf is a traits helper that infers the signature of the function,
+// method, static method, lambda, or function-like object `F`.
+template <typename F>
+struct SignatureOf {
+ // The signature of the function-like object `F`
+ using type = typename SignatureOf<decltype(&F::operator())>::type;
+};
+
+// SignatureOf specialization for a regular function or static method.
+template <typename R, typename... ARGS>
+struct SignatureOf<R (*)(ARGS...)> {
+ // The signature of the function-like object `F`
+ using type = Signature<typename std::decay<R>::type,
+ typename std::decay<ARGS>::type...>;
+};
+
+// SignatureOf specialization for a non-static method.
+template <typename R, typename C, typename... ARGS>
+struct SignatureOf<R (C::*)(ARGS...)> {
+ // The signature of the function-like object `F`
+ using type = Signature<typename std::decay<R>::type,
+ typename std::decay<ARGS>::type...>;
+};
+
+// SignatureOf specialization for a non-static, const method.
+template <typename R, typename C, typename... ARGS>
+struct SignatureOf<R (C::*)(ARGS...) const> {
+ // The signature of the function-like object `F`
+ using type = Signature<typename std::decay<R>::type,
+ typename std::decay<ARGS>::type...>;
+};
+
+// SignatureOfT is an alias to `typename SignatureOf<F>::type`.
+template <typename F>
+using SignatureOfT = typename SignatureOf<F>::type;
+
+// ParameterType is an alias to `typename SignatureOf<F>::type::parameter<N>`.
+template <typename F, std::size_t N>
+using ParameterType = typename SignatureOfT<F>::template parameter<N>;
+
+// `HasSignature<F, S>::value` is true iff the function-like `F` has a matching
+// signature to the function-like `S`.
+template <typename F, typename S>
+using HasSignature = std::integral_constant<
+ bool,
+ std::is_same<SignatureOfT<F>, SignatureOfT<S>>::value>;
+
+// `Min<A, B>::value` resolves to the smaller value of A and B.
+template <std::size_t A, std::size_t B>
+using Min = std::integral_constant<std::size_t, (A < B ? A : B)>;
+
+// `CompatibleWith<F, S>::value` is true iff the function-like `F`
+// can be called with the argument types of the function-like `S`. Return type
+// of the two functions are not considered.
+template <typename F, typename S>
+using CompatibleWith = std::integral_constant<
+ bool,
+ (SignatureOfT<S>::parameter_count == SignatureOfT<F>::parameter_count) &&
+ EachIsTypeOrDerived<Min<SignatureOfT<S>::parameter_count,
+ SignatureOfT<F>::parameter_count>::value,
+ typename SignatureOfT<S>::parameters,
+ typename SignatureOfT<F>::parameters>::value>;
+
+// If `CONDITION` is true then EnableIf resolves to type T, otherwise an
+// invalid type.
+template <bool CONDITION, typename T = void>
+using EnableIf = typename std::enable_if<CONDITION, T>::type;
+
+// If `BASE` is a base of `T` then EnableIfIsType resolves to type `TRUE`,
+// otherwise an invalid type.
+template <typename BASE, typename T, typename TRUE = void>
+using EnableIfIsType = EnableIf<IsTypeOrDerived<BASE, T>::value, TRUE>;
+
+// If the function-like `F` has a matching signature to the function-like `S`
+// then EnableIfHasSignature resolves to type `TRUE`, otherwise an invalid type.
+template <typename F, typename S, typename TRUE = void>
+using EnableIfHasSignature = EnableIf<HasSignature<F, S>::value, TRUE>;
+
+} // namespace traits
+} // namespace dap
+
+#endif // dap_traits_h
diff --git a/license-checker.cfg b/license-checker.cfg
index aa86ef2..e28ee40 100644
--- a/license-checker.cfg
+++ b/license-checker.cfg
@@ -1,5 +1,6 @@
{
"licenses": [
+ "Apache-2.0",
"Apache-2.0-Header"
],
"paths": [
@@ -17,7 +18,8 @@
"fuzz/**",
"kokoro/**.cfg",
"third_party/googletest/**",
- "third_party/json/**"
+ "third_party/json/**",
+ "third_party/rapidjson/**"
]
}
]
diff --git a/src/protocol_events.cpp b/src/protocol_events.cpp
index 5be9e9f..3743481 100644
--- a/src/protocol_events.cpp
+++ b/src/protocol_events.cpp
@@ -15,7 +15,7 @@
// Generated with protocol_gen.go -- do not edit this file.
// go run scripts/protocol_gen/protocol_gen.go
//
-// DAP version 1.41.0
+// DAP version 1.43.0
#include "dap/protocol.h"
@@ -42,6 +42,12 @@
DAP_IMPLEMENT_STRUCT_TYPEINFO(InitializedEvent, "initialized");
+DAP_IMPLEMENT_STRUCT_TYPEINFO(InvalidatedEvent,
+ "invalidated",
+ DAP_FIELD(areas, "areas"),
+ DAP_FIELD(stackFrameId, "stackFrameId"),
+ DAP_FIELD(threadId, "threadId"));
+
DAP_IMPLEMENT_STRUCT_TYPEINFO(LoadedSourceEvent,
"loadedSource",
DAP_FIELD(reason, "reason"),
diff --git a/src/protocol_requests.cpp b/src/protocol_requests.cpp
index bdfb7c3..c76b5ff 100644
--- a/src/protocol_requests.cpp
+++ b/src/protocol_requests.cpp
@@ -15,7 +15,7 @@
// Generated with protocol_gen.go -- do not edit this file.
// go run scripts/protocol_gen/protocol_gen.go
//
-// DAP version 1.41.0
+// DAP version 1.43.0
#include "dap/protocol.h"
@@ -103,6 +103,7 @@
DAP_FIELD(linesStartAt1, "linesStartAt1"),
DAP_FIELD(locale, "locale"),
DAP_FIELD(pathFormat, "pathFormat"),
+ DAP_FIELD(supportsInvalidatedEvent, "supportsInvalidatedEvent"),
DAP_FIELD(supportsMemoryReferences, "supportsMemoryReferences"),
DAP_FIELD(supportsProgressReporting, "supportsProgressReporting"),
DAP_FIELD(supportsRunInTerminalRequest, "supportsRunInTerminalRequest"),
@@ -172,6 +173,7 @@
DAP_IMPLEMENT_STRUCT_TYPEINFO(SetExceptionBreakpointsRequest,
"setExceptionBreakpoints",
DAP_FIELD(exceptionOptions, "exceptionOptions"),
+ DAP_FIELD(filterOptions, "filterOptions"),
DAP_FIELD(filters, "filters"));
DAP_IMPLEMENT_STRUCT_TYPEINFO(SetExpressionRequest,
diff --git a/src/protocol_response.cpp b/src/protocol_response.cpp
index 99a278f..f96c3cf 100644
--- a/src/protocol_response.cpp
+++ b/src/protocol_response.cpp
@@ -15,7 +15,7 @@
// Generated with protocol_gen.go -- do not edit this file.
// go run scripts/protocol_gen/protocol_gen.go
//
-// DAP version 1.41.0
+// DAP version 1.43.0
#include "dap/protocol.h"
@@ -100,6 +100,7 @@
"supportsDelayedStackTraceLoading"),
DAP_FIELD(supportsDisassembleRequest, "supportsDisassembleRequest"),
DAP_FIELD(supportsEvaluateForHovers, "supportsEvaluateForHovers"),
+ DAP_FIELD(supportsExceptionFilterOptions, "supportsExceptionFilterOptions"),
DAP_FIELD(supportsExceptionInfoRequest, "supportsExceptionInfoRequest"),
DAP_FIELD(supportsExceptionOptions, "supportsExceptionOptions"),
DAP_FIELD(supportsFunctionBreakpoints, "supportsFunctionBreakpoints"),
diff --git a/src/protocol_types.cpp b/src/protocol_types.cpp
index 61047cd..a9e5355 100644
--- a/src/protocol_types.cpp
+++ b/src/protocol_types.cpp
@@ -15,7 +15,7 @@
// Generated with protocol_gen.go -- do not edit this file.
// go run scripts/protocol_gen/protocol_gen.go
//
-// DAP version 1.41.0
+// DAP version 1.43.0
#include "dap/protocol.h"
@@ -72,7 +72,9 @@
"",
DAP_FIELD(def, "default"),
DAP_FIELD(filter, "filter"),
- DAP_FIELD(label, "label"));
+ DAP_FIELD(label, "label"),
+ DAP_FIELD(supportsCondition,
+ "supportsCondition"));
DAP_IMPLEMENT_STRUCT_TYPEINFO(
Capabilities,
@@ -95,6 +97,7 @@
"supportsDelayedStackTraceLoading"),
DAP_FIELD(supportsDisassembleRequest, "supportsDisassembleRequest"),
DAP_FIELD(supportsEvaluateForHovers, "supportsEvaluateForHovers"),
+ DAP_FIELD(supportsExceptionFilterOptions, "supportsExceptionFilterOptions"),
DAP_FIELD(supportsExceptionInfoRequest, "supportsExceptionInfoRequest"),
DAP_FIELD(supportsExceptionOptions, "supportsExceptionOptions"),
DAP_FIELD(supportsFunctionBreakpoints, "supportsFunctionBreakpoints"),
@@ -186,6 +189,8 @@
DAP_FIELD(label, "label"),
DAP_FIELD(line, "line"));
+DAP_IMPLEMENT_STRUCT_TYPEINFO(InvalidatedAreas, "");
+
DAP_IMPLEMENT_STRUCT_TYPEINFO(Module,
"",
DAP_FIELD(addressRange, "addressRange"),
@@ -241,6 +246,11 @@
DAP_FIELD(breakMode, "breakMode"),
DAP_FIELD(path, "path"));
+DAP_IMPLEMENT_STRUCT_TYPEINFO(ExceptionFilterOptions,
+ "",
+ DAP_FIELD(condition, "condition"),
+ DAP_FIELD(filterId, "filterId"));
+
DAP_IMPLEMENT_STRUCT_TYPEINFO(FunctionBreakpoint,
"",
DAP_FIELD(condition, "condition"),
diff --git a/src/session.cpp b/src/session.cpp
index ad6597c..95b30a0 100644
--- a/src/session.cpp
+++ b/src/session.cpp
@@ -335,7 +335,7 @@
return [=] {
handler(
data,
- [&](const dap::TypeInfo* typeinfo, const void* data) {
+ [=](const dap::TypeInfo* typeinfo, const void* data) {
// onSuccess
dap::json::Serializer s;
s.object([&](dap::FieldSerializer* fs) {
@@ -354,7 +354,7 @@
handler(data, nullptr);
}
},
- [&](const dap::TypeInfo* typeinfo, const dap::Error& error) {
+ [=](const dap::TypeInfo* typeinfo, const dap::Error& error) {
// onError
dap::json::Serializer s;
s.object([&](dap::FieldSerializer* fs) {
diff --git a/src/session_test.cpp b/src/session_test.cpp
index 21b73d6..eeb8fe3 100644
--- a/src/session_test.cpp
+++ b/src/session_test.cpp
@@ -269,6 +269,142 @@
ASSERT_EQ(got.error.message, "Oh noes!");
}
+TEST_F(SessionTest, RequestCallbackResponse) {
+ using ResponseCallback = std::function<void(dap::SetBreakpointsResponse)>;
+
+ server->registerHandler(
+ [&](const dap::SetBreakpointsRequest&, const ResponseCallback& callback) {
+ dap::SetBreakpointsResponse response;
+ dap::Breakpoint bp;
+ bp.line = 2;
+ response.breakpoints.emplace_back(std::move(bp));
+ callback(response);
+ });
+
+ bind();
+
+ auto got = client->send(dap::SetBreakpointsRequest{}).get();
+
+ // Check response was received correctly.
+ ASSERT_EQ(got.error, false);
+ ASSERT_EQ(got.response.breakpoints.size(), 1U);
+}
+
+TEST_F(SessionTest, RequestCallbackResponseOrError) {
+ using ResponseCallback =
+ std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;
+
+ server->registerHandler(
+ [&](const dap::SetBreakpointsRequest&, const ResponseCallback& callback) {
+ dap::SetBreakpointsResponse response;
+ dap::Breakpoint bp;
+ bp.line = 2;
+ response.breakpoints.emplace_back(std::move(bp));
+ callback(response);
+ });
+
+ bind();
+
+ auto got = client->send(dap::SetBreakpointsRequest{}).get();
+
+ // Check response was received correctly.
+ ASSERT_EQ(got.error, false);
+ ASSERT_EQ(got.response.breakpoints.size(), 1U);
+}
+
+TEST_F(SessionTest, RequestCallbackError) {
+ using ResponseCallback =
+ std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;
+
+ server->registerHandler(
+ [&](const dap::SetBreakpointsRequest&, const ResponseCallback& callback) {
+ callback(dap::Error("Oh noes!"));
+ });
+
+ bind();
+
+ auto got = client->send(dap::SetBreakpointsRequest{}).get();
+
+ // Check response was received correctly.
+ ASSERT_EQ(got.error, true);
+ ASSERT_EQ(got.error.message, "Oh noes!");
+}
+
+TEST_F(SessionTest, RequestCallbackSuccessAfterReturn) {
+ using ResponseCallback =
+ std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;
+
+ ResponseCallback callback;
+ std::mutex mutex;
+ std::condition_variable cv;
+
+ server->registerHandler(
+ [&](const dap::SetBreakpointsRequest&, const ResponseCallback& cb) {
+ std::unique_lock<std::mutex> lock(mutex);
+ callback = cb;
+ cv.notify_all();
+ });
+
+ bind();
+
+ auto future = client->send(dap::SetBreakpointsRequest{});
+
+ {
+ dap::SetBreakpointsResponse response;
+ dap::Breakpoint bp;
+ bp.line = 2;
+ response.breakpoints.emplace_back(std::move(bp));
+
+ // Wait for the handler to be called.
+ std::unique_lock<std::mutex> lock(mutex);
+ cv.wait(lock, [&] { return static_cast<bool>(callback); });
+
+ // Issue the callback
+ callback(response);
+ }
+
+ auto got = future.get();
+
+ // Check response was received correctly.
+ ASSERT_EQ(got.error, false);
+ ASSERT_EQ(got.response.breakpoints.size(), 1U);
+}
+
+TEST_F(SessionTest, RequestCallbackErrorAfterReturn) {
+ using ResponseCallback =
+ std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;
+
+ ResponseCallback callback;
+ std::mutex mutex;
+ std::condition_variable cv;
+
+ server->registerHandler(
+ [&](const dap::SetBreakpointsRequest&, const ResponseCallback& cb) {
+ std::unique_lock<std::mutex> lock(mutex);
+ callback = cb;
+ cv.notify_all();
+ });
+
+ bind();
+
+ auto future = client->send(dap::SetBreakpointsRequest{});
+
+ {
+ // Wait for the handler to be called.
+ std::unique_lock<std::mutex> lock(mutex);
+ cv.wait(lock, [&] { return static_cast<bool>(callback); });
+
+ // Issue the callback
+ callback(dap::Error("Oh noes!"));
+ }
+
+ auto got = future.get();
+
+ // Check response was received correctly.
+ ASSERT_EQ(got.error, true);
+ ASSERT_EQ(got.error.message, "Oh noes!");
+}
+
TEST_F(SessionTest, ResponseSentHandlerSuccess) {
const auto response = createResponse();
diff --git a/src/traits_test.cpp b/src/traits_test.cpp
new file mode 100644
index 0000000..aafca04
--- /dev/null
+++ b/src/traits_test.cpp
@@ -0,0 +1,387 @@
+// Copyright 2021 Google LLC
+//
+// 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
+//
+// https://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.
+
+#include "dap/traits.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace dap {
+namespace traits {
+
+namespace {
+struct S {};
+struct E : S {};
+void F1(S) {}
+void F3(int, S, float) {}
+void E1(E) {}
+void E3(int, E, float) {}
+} // namespace
+
+TEST(ParameterType, Function) {
+ F1({}); // Avoid unused method warning
+ F3(0, {}, 0); // Avoid unused method warning
+ static_assert(std::is_same<ParameterType<decltype(&F1), 0>, S>::value, "");
+ static_assert(std::is_same<ParameterType<decltype(&F3), 0>, int>::value, "");
+ static_assert(std::is_same<ParameterType<decltype(&F3), 1>, S>::value, "");
+ static_assert(std::is_same<ParameterType<decltype(&F3), 2>, float>::value,
+ "");
+}
+
+TEST(ParameterType, Method) {
+ class C {
+ public:
+ void F1(S) {}
+ void F3(int, S, float) {}
+ };
+ C().F1({}); // Avoid unused method warning
+ C().F3(0, {}, 0); // Avoid unused method warning
+ static_assert(std::is_same<ParameterType<decltype(&C::F1), 0>, S>::value, "");
+ static_assert(std::is_same<ParameterType<decltype(&C::F3), 0>, int>::value,
+ "");
+ static_assert(std::is_same<ParameterType<decltype(&C::F3), 1>, S>::value, "");
+ static_assert(std::is_same<ParameterType<decltype(&C::F3), 2>, float>::value,
+ "");
+}
+
+TEST(ParameterType, ConstMethod) {
+ class C {
+ public:
+ void F1(S) const {}
+ void F3(int, S, float) const {}
+ };
+ C().F1({}); // Avoid unused method warning
+ C().F3(0, {}, 0); // Avoid unused method warning
+ static_assert(std::is_same<ParameterType<decltype(&C::F1), 0>, S>::value, "");
+ static_assert(std::is_same<ParameterType<decltype(&C::F3), 0>, int>::value,
+ "");
+ static_assert(std::is_same<ParameterType<decltype(&C::F3), 1>, S>::value, "");
+ static_assert(std::is_same<ParameterType<decltype(&C::F3), 2>, float>::value,
+ "");
+}
+
+TEST(ParameterType, StaticMethod) {
+ class C {
+ public:
+ static void F1(S) {}
+ static void F3(int, S, float) {}
+ };
+ C::F1({}); // Avoid unused method warning
+ C::F3(0, {}, 0); // Avoid unused method warning
+ static_assert(std::is_same<ParameterType<decltype(&C::F1), 0>, S>::value, "");
+ static_assert(std::is_same<ParameterType<decltype(&C::F3), 0>, int>::value,
+ "");
+ static_assert(std::is_same<ParameterType<decltype(&C::F3), 1>, S>::value, "");
+ static_assert(std::is_same<ParameterType<decltype(&C::F3), 2>, float>::value,
+ "");
+}
+
+TEST(ParameterType, FunctionLike) {
+ using F1 = std::function<void(S)>;
+ using F3 = std::function<void(int, S, float)>;
+ static_assert(std::is_same<ParameterType<F1, 0>, S>::value, "");
+ static_assert(std::is_same<ParameterType<F3, 0>, int>::value, "");
+ static_assert(std::is_same<ParameterType<F3, 1>, S>::value, "");
+ static_assert(std::is_same<ParameterType<F3, 2>, float>::value, "");
+}
+
+TEST(ParameterType, Lambda) {
+ auto l1 = [](S) {};
+ auto l3 = [](int, S, float) {};
+ static_assert(std::is_same<ParameterType<decltype(l1), 0>, S>::value, "");
+ static_assert(std::is_same<ParameterType<decltype(l3), 0>, int>::value, "");
+ static_assert(std::is_same<ParameterType<decltype(l3), 1>, S>::value, "");
+ static_assert(std::is_same<ParameterType<decltype(l3), 2>, float>::value, "");
+}
+
+TEST(HasSignature, Function) {
+ F1({}); // Avoid unused method warning
+ F3(0, {}, 0); // Avoid unused method warning
+ static_assert(HasSignature<decltype(&F1), decltype(&F1)>::value, "");
+ static_assert(HasSignature<decltype(&F3), decltype(&F3)>::value, "");
+ static_assert(HasSignature<decltype(&F3), decltype(&F3)>::value, "");
+ static_assert(HasSignature<decltype(&F3), decltype(&F3)>::value, "");
+ static_assert(!HasSignature<decltype(&F1), decltype(&F3)>::value, "");
+ static_assert(!HasSignature<decltype(&F3), decltype(&F1)>::value, "");
+ static_assert(!HasSignature<decltype(&F3), decltype(&F1)>::value, "");
+ static_assert(!HasSignature<decltype(&F3), decltype(&F1)>::value, "");
+}
+
+TEST(HasSignature, Method) {
+ class C {
+ public:
+ void F1(S) {}
+ void F3(int, S, float) {}
+ };
+ C().F1({}); // Avoid unused method warning
+ C().F3(0, {}, 0); // Avoid unused method warning
+
+ static_assert(HasSignature<decltype(&C::F1), decltype(&F1)>::value, "");
+ static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+ static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+ static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+ static_assert(!HasSignature<decltype(&C::F1), decltype(&F3)>::value, "");
+ static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+ static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+ static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+}
+
+TEST(HasSignature, ConstMethod) {
+ class C {
+ public:
+ void F1(S) const {}
+ void F3(int, S, float) const {}
+ };
+ C().F1({}); // Avoid unused method warning
+ C().F3(0, {}, 0); // Avoid unused method warning
+
+ static_assert(HasSignature<decltype(&C::F1), decltype(&F1)>::value, "");
+ static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+ static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+ static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+ static_assert(!HasSignature<decltype(&C::F1), decltype(&F3)>::value, "");
+ static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+ static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+ static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+}
+
+TEST(HasSignature, StaticMethod) {
+ class C {
+ public:
+ static void F1(S) {}
+ static void F3(int, S, float) {}
+ };
+ C::F1({}); // Avoid unused method warning
+ C::F3(0, {}, 0); // Avoid unused method warning
+
+ static_assert(HasSignature<decltype(&C::F1), decltype(&F1)>::value, "");
+ static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+ static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+ static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+ static_assert(!HasSignature<decltype(&C::F1), decltype(&F3)>::value, "");
+ static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+ static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+ static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+}
+
+TEST(HasSignature, FunctionLike) {
+ using f1 = std::function<void(S)>;
+ using f3 = std::function<void(int, S, float)>;
+ static_assert(HasSignature<f1, decltype(&F1)>::value, "");
+ static_assert(HasSignature<f3, decltype(&F3)>::value, "");
+ static_assert(HasSignature<f3, decltype(&F3)>::value, "");
+ static_assert(HasSignature<f3, decltype(&F3)>::value, "");
+ static_assert(!HasSignature<f1, decltype(&F3)>::value, "");
+ static_assert(!HasSignature<f3, decltype(&F1)>::value, "");
+ static_assert(!HasSignature<f3, decltype(&F1)>::value, "");
+ static_assert(!HasSignature<f3, decltype(&F1)>::value, "");
+}
+
+TEST(HasSignature, Lambda) {
+ auto l1 = [](S) {};
+ auto l3 = [](int, S, float) {};
+ static_assert(HasSignature<decltype(l1), decltype(&F1)>::value, "");
+ static_assert(HasSignature<decltype(l3), decltype(&F3)>::value, "");
+ static_assert(HasSignature<decltype(l3), decltype(&F3)>::value, "");
+ static_assert(HasSignature<decltype(l3), decltype(&F3)>::value, "");
+ static_assert(!HasSignature<decltype(l1), decltype(&F3)>::value, "");
+ static_assert(!HasSignature<decltype(l3), decltype(&F1)>::value, "");
+ static_assert(!HasSignature<decltype(l3), decltype(&F1)>::value, "");
+ static_assert(!HasSignature<decltype(l3), decltype(&F1)>::value, "");
+}
+
+////
+
+TEST(CompatibleWith, Function) {
+ F1({}); // Avoid unused method warning
+ F3(0, {}, 0); // Avoid unused method warning
+ E1({}); // Avoid unused method warning
+ E3(0, {}, 0); // Avoid unused method warning
+ static_assert(CompatibleWith<decltype(&F1), decltype(&F1)>::value, "");
+ static_assert(CompatibleWith<decltype(&F3), decltype(&F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&F3), decltype(&F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&F3), decltype(&F3)>::value, "");
+
+ static_assert(!CompatibleWith<decltype(&F1), decltype(&F3)>::value, "");
+ static_assert(!CompatibleWith<decltype(&F3), decltype(&F1)>::value, "");
+ static_assert(!CompatibleWith<decltype(&F3), decltype(&F1)>::value, "");
+ static_assert(!CompatibleWith<decltype(&F3), decltype(&F1)>::value, "");
+
+ static_assert(CompatibleWith<decltype(&E1), decltype(&F1)>::value, "");
+ static_assert(CompatibleWith<decltype(&E3), decltype(&F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&E3), decltype(&F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&E3), decltype(&F3)>::value, "");
+
+ static_assert(!CompatibleWith<decltype(&F1), decltype(&E1)>::value, "");
+ static_assert(!CompatibleWith<decltype(&F3), decltype(&E3)>::value, "");
+ static_assert(!CompatibleWith<decltype(&F3), decltype(&E3)>::value, "");
+ static_assert(!CompatibleWith<decltype(&F3), decltype(&E3)>::value, "");
+}
+
+TEST(CompatibleWith, Method) {
+ class C {
+ public:
+ void F1(S) {}
+ void F3(int, S, float) {}
+ void E1(E) {}
+ void E3(int, E, float) {}
+ };
+ C().F1({}); // Avoid unused method warning
+ C().F3(0, {}, 0); // Avoid unused method warning
+ C().E1({}); // Avoid unused method warning
+ C().E3(0, {}, 0); // Avoid unused method warning
+
+ static_assert(CompatibleWith<decltype(&C::F1), decltype(&F1)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+
+ static_assert(!CompatibleWith<decltype(&C::F1), decltype(&F3)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+
+ static_assert(CompatibleWith<decltype(&C::E1), decltype(&C::F1)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+
+ static_assert(!CompatibleWith<decltype(&C::F1), decltype(&C::E1)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+}
+
+TEST(CompatibleWith, ConstMethod) {
+ class C {
+ public:
+ void F1(S) const {}
+ void F3(int, S, float) const {}
+ void E1(E) const {}
+ void E3(int, E, float) const {}
+ };
+ C().F1({}); // Avoid unused method warning
+ C().F3(0, {}, 0); // Avoid unused method warning
+ C().E1({}); // Avoid unused method warning
+ C().E3(0, {}, 0); // Avoid unused method warning
+
+ static_assert(CompatibleWith<decltype(&C::F1), decltype(&F1)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+
+ static_assert(!CompatibleWith<decltype(&C::F1), decltype(&F3)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+
+ static_assert(CompatibleWith<decltype(&C::E1), decltype(&C::F1)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+
+ static_assert(!CompatibleWith<decltype(&C::F1), decltype(&C::E1)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+}
+
+TEST(CompatibleWith, StaticMethod) {
+ class C {
+ public:
+ static void F1(S) {}
+ static void F3(int, S, float) {}
+ static void E1(E) {}
+ static void E3(int, E, float) {}
+ };
+ C::F1({}); // Avoid unused method warning
+ C::F3(0, {}, 0); // Avoid unused method warning
+ C::E1({}); // Avoid unused method warning
+ C::E3(0, {}, 0); // Avoid unused method warning
+
+ static_assert(CompatibleWith<decltype(&C::F1), decltype(&F1)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+
+ static_assert(!CompatibleWith<decltype(&C::F1), decltype(&F3)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+
+ static_assert(CompatibleWith<decltype(&C::E1), decltype(&C::F1)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+ static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+
+ static_assert(!CompatibleWith<decltype(&C::F1), decltype(&C::E1)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+ static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+}
+
+TEST(CompatibleWith, FunctionLike) {
+ using f1 = std::function<void(S)>;
+ using f3 = std::function<void(int, S, float)>;
+ using e1 = std::function<void(E)>;
+ using e3 = std::function<void(int, E, float)>;
+ static_assert(CompatibleWith<f1, decltype(&F1)>::value, "");
+ static_assert(CompatibleWith<f3, decltype(&F3)>::value, "");
+ static_assert(CompatibleWith<f3, decltype(&F3)>::value, "");
+ static_assert(CompatibleWith<f3, decltype(&F3)>::value, "");
+
+ static_assert(!CompatibleWith<f1, decltype(&F3)>::value, "");
+ static_assert(!CompatibleWith<f3, decltype(&F1)>::value, "");
+ static_assert(!CompatibleWith<f3, decltype(&F1)>::value, "");
+ static_assert(!CompatibleWith<f3, decltype(&F1)>::value, "");
+
+ static_assert(CompatibleWith<e1, f1>::value, "");
+ static_assert(CompatibleWith<e3, f3>::value, "");
+ static_assert(CompatibleWith<e3, f3>::value, "");
+ static_assert(CompatibleWith<e3, f3>::value, "");
+
+ static_assert(!CompatibleWith<f1, e1>::value, "");
+ static_assert(!CompatibleWith<f3, e3>::value, "");
+ static_assert(!CompatibleWith<f3, e3>::value, "");
+ static_assert(!CompatibleWith<f3, e3>::value, "");
+}
+
+TEST(CompatibleWith, Lambda) {
+ auto f1 = [](S) {};
+ auto f3 = [](int, S, float) {};
+ auto e1 = [](E) {};
+ auto e3 = [](int, E, float) {};
+ static_assert(CompatibleWith<decltype(f1), decltype(&F1)>::value, "");
+ static_assert(CompatibleWith<decltype(f3), decltype(&F3)>::value, "");
+ static_assert(CompatibleWith<decltype(f3), decltype(&F3)>::value, "");
+ static_assert(CompatibleWith<decltype(f3), decltype(&F3)>::value, "");
+
+ static_assert(!CompatibleWith<decltype(f1), decltype(&F3)>::value, "");
+ static_assert(!CompatibleWith<decltype(f3), decltype(&F1)>::value, "");
+ static_assert(!CompatibleWith<decltype(f3), decltype(&F1)>::value, "");
+ static_assert(!CompatibleWith<decltype(f3), decltype(&F1)>::value, "");
+
+ static_assert(CompatibleWith<decltype(e1), decltype(f1)>::value, "");
+ static_assert(CompatibleWith<decltype(e3), decltype(f3)>::value, "");
+ static_assert(CompatibleWith<decltype(e3), decltype(f3)>::value, "");
+ static_assert(CompatibleWith<decltype(e3), decltype(f3)>::value, "");
+
+ static_assert(!CompatibleWith<decltype(f1), decltype(e1)>::value, "");
+ static_assert(!CompatibleWith<decltype(f3), decltype(e3)>::value, "");
+ static_assert(!CompatibleWith<decltype(f3), decltype(e3)>::value, "");
+ static_assert(!CompatibleWith<decltype(f3), decltype(e3)>::value, "");
+}
+
+} // namespace traits
+} // namespace dap