diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index c9cab350f9f12..7c2f4b20f4956 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -94,6 +94,28 @@ json::Value toJSON(const ExceptionBreakpointsFilter &EBF) { return result; } +bool fromJSON(const json::Value &Params, ColumnType &CT, json::Path P) { + auto rawColumnType = Params.getAsString(); + if (!rawColumnType) { + P.report("expected a string"); + return false; + } + std::optional columnType = + StringSwitch>(*rawColumnType) + .Case("string", eColumnTypeString) + .Case("number", eColumnTypeNumber) + .Case("boolean", eColumnTypeBoolean) + .Case("unixTimestampUTC ", eColumnTypeTimestamp) + .Default(std::nullopt); + if (!columnType) { + P.report("unexpected value, expected 'string', 'number', 'boolean', or " + "'unixTimestampUTC'"); + return false; + } + CT = *columnType; + return true; +} + json::Value toJSON(const ColumnType &T) { switch (T) { case eColumnTypeString: @@ -108,6 +130,14 @@ json::Value toJSON(const ColumnType &T) { llvm_unreachable("unhandled column type."); } +bool fromJSON(const llvm::json::Value &Params, ColumnDescriptor &CD, + llvm::json::Path P) { + llvm::json::ObjectMapper O(Params, P); + return O && O.map("attributeName", CD.attributeName) && + O.map("label", CD.label) && O.mapOptional("format", CD.format) && + O.mapOptional("type", CD.type) && O.mapOptional("width", CD.width); +} + json::Value toJSON(const ColumnDescriptor &CD) { json::Object result{{"attributeName", CD.attributeName}, {"label", CD.label}}; @@ -149,6 +179,30 @@ json::Value toJSON(const BreakpointModeApplicability &BMA) { llvm_unreachable("unhandled breakpoint mode applicability."); } +bool fromJSON(const llvm::json::Value &Params, BreakpointModeApplicability &BMA, + llvm::json::Path P) { + auto rawApplicability = Params.getAsString(); + if (!rawApplicability) { + P.report("expected a string"); + return false; + } + std::optional applicability = + llvm::StringSwitch>( + *rawApplicability) + .Case("source", eBreakpointModeApplicabilitySource) + .Case("exception", eBreakpointModeApplicabilityException) + .Case("data", eBreakpointModeApplicabilityData) + .Case("instruction", eBreakpointModeApplicabilityInstruction) + .Default(std::nullopt); + if (!applicability) { + P.report("unexpected value, expected 'source', 'exception', 'data', or " + "'instruction'"); + return false; + } + BMA = *applicability; + return true; +} + json::Value toJSON(const BreakpointMode &BM) { json::Object result{ {"mode", BM.mode}, @@ -162,6 +216,14 @@ json::Value toJSON(const BreakpointMode &BM) { return result; } +bool fromJSON(const llvm::json::Value &Params, BreakpointMode &BM, + llvm::json::Path P) { + llvm::json::ObjectMapper O(Params, P); + return O && O.map("mode", BM.mode) && O.map("label", BM.label) && + O.mapOptional("description", BM.description) && + O.map("appliesTo", BM.appliesTo); +} + static llvm::StringLiteral ToString(AdapterFeature feature) { switch (feature) { case eAdapterFeatureANSIStyling: @@ -320,6 +382,26 @@ llvm::json::Value toJSON(const BreakpointReason &BR) { llvm_unreachable("unhandled breakpoint reason."); } +bool fromJSON(const llvm::json::Value &Params, BreakpointReason &BR, + llvm::json::Path P) { + auto rawReason = Params.getAsString(); + if (!rawReason) { + P.report("expected a string"); + return false; + } + std::optional reason = + llvm::StringSwitch>(*rawReason) + .Case("pending", BreakpointReason::eBreakpointReasonPending) + .Case("failed", BreakpointReason::eBreakpointReasonFailed) + .Default(std::nullopt); + if (!reason) { + P.report("unexpected value, expected 'pending' or 'failed'"); + return false; + } + BR = *reason; + return true; +} + json::Value toJSON(const Breakpoint &BP) { json::Object result{{"verified", BP.verified}}; @@ -348,6 +430,20 @@ json::Value toJSON(const Breakpoint &BP) { return result; } +bool fromJSON(const llvm::json::Value &Params, Breakpoint &BP, + llvm::json::Path P) { + llvm::json::ObjectMapper O(Params, P); + return O && O.mapOptional("id", BP.id) && O.map("verified", BP.verified) && + O.mapOptional("message", BP.message) && + O.mapOptional("source", BP.source) && O.mapOptional("line", BP.line) && + O.mapOptional("column", BP.column) && + O.mapOptional("endLine", BP.endLine) && + O.mapOptional("endColumn", BP.endColumn) && + O.mapOptional("instructionReference", BP.instructionReference) && + O.mapOptional("offset", BP.offset) && + O.mapOptional("reason", BP.reason); +} + bool fromJSON(const llvm::json::Value &Params, SourceBreakpoint &SB, llvm::json::Path P) { json::ObjectMapper O(Params, P); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index d1e86b0897675..cab188637acd5 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -65,6 +65,8 @@ enum ColumnType : unsigned { eColumnTypeBoolean, eColumnTypeTimestamp }; +bool fromJSON(const llvm::json::Value &, ColumnType &, llvm::json::Path); +llvm::json::Value toJSON(const ColumnType &); /// A ColumnDescriptor specifies what module attribute to show in a column of /// the modules view, how to format it, and what the column’s label should be. @@ -89,6 +91,7 @@ struct ColumnDescriptor { /// Width of this column in characters (hint only). std::optional width; }; +bool fromJSON(const llvm::json::Value &, ColumnDescriptor &, llvm::json::Path); llvm::json::Value toJSON(const ColumnDescriptor &); /// Names of checksum algorithms that may be supported by a debug adapter. @@ -114,6 +117,8 @@ enum BreakpointModeApplicability : unsigned { /// In `InstructionBreakpoint`'s. eBreakpointModeApplicabilityInstruction }; +bool fromJSON(const llvm::json::Value &, BreakpointModeApplicability &, + llvm::json::Path); llvm::json::Value toJSON(const BreakpointModeApplicability &); /// A `BreakpointMode` is provided as a option when setting breakpoints on @@ -133,6 +138,7 @@ struct BreakpointMode { /// Describes one or more type of breakpoint this mode applies to. std::vector appliesTo; }; +bool fromJSON(const llvm::json::Value &, BreakpointMode &, llvm::json::Path); llvm::json::Value toJSON(const BreakpointMode &); /// Debug Adapter Features flags supported by lldb-dap. @@ -364,6 +370,7 @@ enum class BreakpointReason : unsigned { /// adapter does not believe it can be verified without intervention. eBreakpointReasonFailed, }; +bool fromJSON(const llvm::json::Value &, BreakpointReason &, llvm::json::Path); llvm::json::Value toJSON(const BreakpointReason &); /// Information about a breakpoint created in `setBreakpoints`, @@ -415,6 +422,7 @@ struct Breakpoint { /// should omit this property. std::optional reason; }; +bool fromJSON(const llvm::json::Value &, Breakpoint &, llvm::json::Path); llvm::json::Value toJSON(const Breakpoint &); /// Properties of a breakpoint or logpoint passed to the `setBreakpoints` diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index fa46816ca4a10..56b21f18fa7cd 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -60,3 +60,75 @@ TEST(ProtocolTypesTest, Source) { EXPECT_EQ(source.sourceReference, deserialized_source->sourceReference); EXPECT_EQ(source.presentationHint, deserialized_source->presentationHint); } + +TEST(ProtocolTypesTest, ColumnDescriptor) { + ColumnDescriptor column; + column.attributeName = "moduleName"; + column.label = "Module Name"; + column.format = "uppercase"; + column.type = eColumnTypeString; + column.width = 20; + + llvm::Expected deserialized_column = roundtrip(column); + ASSERT_THAT_EXPECTED(deserialized_column, llvm::Succeeded()); + + EXPECT_EQ(column.attributeName, deserialized_column->attributeName); + EXPECT_EQ(column.label, deserialized_column->label); + EXPECT_EQ(column.format, deserialized_column->format); + EXPECT_EQ(column.type, deserialized_column->type); + EXPECT_EQ(column.width, deserialized_column->width); +} + +TEST(ProtocolTypesTest, BreakpointMode) { + BreakpointMode mode; + mode.mode = "testMode"; + mode.label = "Test Mode"; + mode.description = "This is a test mode"; + mode.appliesTo = {eBreakpointModeApplicabilitySource, + eBreakpointModeApplicabilityException}; + + llvm::Expected deserialized_mode = roundtrip(mode); + ASSERT_THAT_EXPECTED(deserialized_mode, llvm::Succeeded()); + + EXPECT_EQ(mode.mode, deserialized_mode->mode); + EXPECT_EQ(mode.label, deserialized_mode->label); + EXPECT_EQ(mode.description, deserialized_mode->description); + EXPECT_EQ(mode.appliesTo, deserialized_mode->appliesTo); +} + +TEST(ProtocolTypesTest, Breakpoint) { + Breakpoint breakpoint; + breakpoint.id = 42; + breakpoint.verified = true; + breakpoint.message = "Breakpoint set successfully"; + breakpoint.source = + Source{"test.cpp", "/path/to/test.cpp", 123, ePresentationHintNormal}; + breakpoint.line = 10; + breakpoint.column = 5; + breakpoint.endLine = 15; + breakpoint.endColumn = 10; + breakpoint.instructionReference = "0x12345678"; + breakpoint.offset = 4; + breakpoint.reason = BreakpointReason::eBreakpointReasonPending; + + llvm::Expected deserialized_breakpoint = roundtrip(breakpoint); + ASSERT_THAT_EXPECTED(deserialized_breakpoint, llvm::Succeeded()); + + EXPECT_EQ(breakpoint.id, deserialized_breakpoint->id); + EXPECT_EQ(breakpoint.verified, deserialized_breakpoint->verified); + EXPECT_EQ(breakpoint.message, deserialized_breakpoint->message); + EXPECT_EQ(breakpoint.source->name, deserialized_breakpoint->source->name); + EXPECT_EQ(breakpoint.source->path, deserialized_breakpoint->source->path); + EXPECT_EQ(breakpoint.source->sourceReference, + deserialized_breakpoint->source->sourceReference); + EXPECT_EQ(breakpoint.source->presentationHint, + deserialized_breakpoint->source->presentationHint); + EXPECT_EQ(breakpoint.line, deserialized_breakpoint->line); + EXPECT_EQ(breakpoint.column, deserialized_breakpoint->column); + EXPECT_EQ(breakpoint.endLine, deserialized_breakpoint->endLine); + EXPECT_EQ(breakpoint.endColumn, deserialized_breakpoint->endColumn); + EXPECT_EQ(breakpoint.instructionReference, + deserialized_breakpoint->instructionReference); + EXPECT_EQ(breakpoint.offset, deserialized_breakpoint->offset); + EXPECT_EQ(breakpoint.reason, deserialized_breakpoint->reason); +}