Skip to content

Commit 3e9e372

Browse files
author
Fcitx Bot
committed
Merge remote-tracking branch 'origin/master' into fcitx
2 parents 7e82aab + 88f812a commit 3e9e372

27 files changed

+1188
-629
lines changed

src/base/win32/BUILD.bazel

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,9 @@ mozc_cc_library(
295295
tags = MOZC_TAGS.WIN_ONLY,
296296
target_compatible_with = ["@platforms//os:windows"],
297297
deps = [
298+
":hresult",
298299
":hresultor",
299-
"@com_google_absl//absl/meta:type_traits",
300+
"@com_google_absl//absl/base:nullability",
300301
"@com_microsoft_wil//:wil",
301302
],
302303
)

src/base/win32/com.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include <type_traits>
4343
#include <utility>
4444

45+
#include "absl/base/nullability.h"
4546
#include "base/win32/hresult.h"
4647
#include "base/win32/hresultor.h"
4748

@@ -134,6 +135,71 @@ inline wil::unique_bstr MakeUniqueBSTR(const wchar_t *source) {
134135
return wil::unique_bstr(SysAllocString(source));
135136
}
136137

138+
// Saves the value to the out parameter of a COM method.
139+
//
140+
// Return values:
141+
// - S_OK: success.
142+
// - E_INVALIDARG: the out parameter is null.
143+
// - E_OUTOFMEMORY: the value is a null pointer.
144+
//
145+
// Note: this behavior is different from IUnknown methods. Check COM interface
146+
// documentation to make sure the returned error codes are correct.
147+
template <typename T, typename U>
148+
requires std::integral<T> && std::integral<U>
149+
HResult SaveToOutParam(T value, U *absl_nullable out);
150+
template <typename T, typename U>
151+
HResult SaveToOutParam(T *absl_nullable value, U **absl_nullable out);
152+
template <typename T, typename U>
153+
HResult SaveToOutParam(wil::com_ptr_nothrow<T> value, U **absl_nullable out) {
154+
return SaveToOutParam<T, U>(value.detach(), out);
155+
}
156+
template <typename T>
157+
HResult SaveToOutParam(
158+
wil::unique_any_t<T> value,
159+
typename wil::unique_any_t<T>::pointer *absl_nullable out) {
160+
return SaveToOutParam(value.release(), out);
161+
}
162+
163+
// Saves the value to the out parameter of a COM method. It's a noop if the
164+
// out parameter is nullptr.
165+
template <typename T, typename U>
166+
requires std::integral<T> && std::integral<U>
167+
void SaveToOptionalOutParam(T value, U *absl_nullable out);
168+
169+
// Implementations.
170+
171+
template <typename T, typename U>
172+
requires std::integral<T> && std::integral<U>
173+
HResult SaveToOutParam(T value, U *absl_nullable out) {
174+
static_assert(std::convertible_to<T, U>);
175+
if (out == nullptr) {
176+
return HResultInvalidArg();
177+
}
178+
*out = value;
179+
return HResultOk();
180+
}
181+
182+
template <typename T, typename U>
183+
HResult SaveToOutParam(T *absl_nullable value, U **absl_nullable out) {
184+
if (out == nullptr) {
185+
return HResultInvalidArg();
186+
}
187+
if (value == nullptr) {
188+
return HResultOutOfMemory();
189+
}
190+
*out = value;
191+
return HResultOk();
192+
}
193+
194+
template <typename T, typename U>
195+
requires std::integral<T> && std::integral<U>
196+
void SaveToOptionalOutParam(T value, U *absl_nullable out) {
197+
static_assert(std::convertible_to<T, U>);
198+
if (out != nullptr) {
199+
*out = value;
200+
}
201+
}
202+
137203
} // namespace mozc::win32
138204

139205
#endif // MOZC_BASE_WIN32_COM_H_

src/base/win32/com_test.cc

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
namespace mozc::win32 {
4949
namespace {
5050

51+
using ::testing::IsNull;
52+
using ::testing::NotNull;
5153
using ::testing::StrEq;
5254

5355
// Mock interfaces for testing.
@@ -113,38 +115,38 @@ class ComTest : public ::testing::Test {
113115
TEST_F(ComTest, ComCreateInstance) {
114116
wil::com_ptr_nothrow<IShellLink> shellink =
115117
ComCreateInstance<IShellLink, ShellLink>();
116-
EXPECT_TRUE(shellink);
117-
EXPECT_TRUE(ComCreateInstance<IShellLink>(CLSID_ShellLink));
118-
EXPECT_FALSE(ComCreateInstance<IShellFolder>(CLSID_ShellLink));
118+
EXPECT_THAT(shellink, NotNull());
119+
EXPECT_THAT(ComCreateInstance<IShellLink>(CLSID_ShellLink), NotNull());
120+
EXPECT_THAT(ComCreateInstance<IShellFolder>(CLSID_ShellLink), IsNull());
119121
}
120122

121123
TEST_F(ComTest, MakeComPtr) {
122124
auto ptr = MakeComPtr<Mock>();
123-
EXPECT_TRUE(ptr);
125+
ASSERT_THAT(ptr, NotNull());
124126
EXPECT_EQ(object_count, 1);
125127
EXPECT_EQ(ptr->GetQICountAndReset(), 0);
126128
}
127129

128130
TEST_F(ComTest, ComQuery) {
129131
wil::com_ptr_nothrow<IMock1> mock1(MakeComPtr<Mock>());
130-
EXPECT_TRUE(mock1);
132+
ASSERT_THAT(mock1, NotNull());
131133
EXPECT_EQ(mock1->Test1(), S_OK);
132134

133135
wil::com_ptr_nothrow<IDerived> derived = ComQuery<IDerived>(mock1);
134-
EXPECT_TRUE(derived);
136+
ASSERT_THAT(derived, NotNull());
135137
EXPECT_EQ(derived->Derived(), 2);
136138
EXPECT_EQ(derived->GetQICountAndReset(), 1);
137139

138-
EXPECT_TRUE(ComQuery<IMock1>(derived));
140+
EXPECT_THAT(ComQuery<IMock1>(derived), NotNull());
139141
EXPECT_EQ(derived->GetQICountAndReset(), 0);
140142

141143
wil::com_ptr_nothrow<IMock2> mock2 = ComQuery<IMock2>(mock1);
142-
EXPECT_TRUE(mock2);
144+
ASSERT_THAT(mock2, NotNull());
143145
EXPECT_EQ(mock2->Test2(), S_FALSE);
144146
EXPECT_EQ(mock1->GetQICountAndReset(), 1);
145147

146148
mock2 = ComQuery<IMock2>(mock1);
147-
EXPECT_TRUE(mock2);
149+
ASSERT_THAT(mock2, NotNull());
148150
EXPECT_EQ(mock2->Test2(), S_FALSE);
149151
EXPECT_EQ(mock1->GetQICountAndReset(), 1);
150152

@@ -154,18 +156,18 @@ TEST_F(ComTest, ComQuery) {
154156

155157
TEST_F(ComTest, ComCopy) {
156158
wil::com_ptr_nothrow<IMock1> mock1(MakeComPtr<Mock>());
157-
EXPECT_TRUE(mock1);
159+
ASSERT_THAT(mock1, NotNull());
158160
EXPECT_EQ(mock1->Test1(), S_OK);
159161

160162
wil::com_ptr_nothrow<IUnknown> unknown = ComCopy<IUnknown>(mock1);
161-
EXPECT_TRUE(unknown);
163+
EXPECT_THAT(unknown, NotNull());
162164
EXPECT_EQ(mock1->GetQICountAndReset(), 0);
163165

164-
EXPECT_FALSE(ComCopy<IShellLink>(unknown));
166+
EXPECT_THAT(ComCopy<IShellLink>(unknown), IsNull());
165167
EXPECT_EQ(mock1->GetQICountAndReset(), 1);
166168

167169
IUnknown *null = nullptr;
168-
EXPECT_FALSE(ComCopy<IUnknown>(null));
170+
EXPECT_THAT(ComCopy<IUnknown>(null), IsNull());
169171
}
170172

171173
TEST(ComBSTRTest, MakeUniqueBSTR) {
@@ -177,5 +179,50 @@ TEST(ComBSTRTest, MakeUniqueBSTR) {
177179
EXPECT_EQ(result.get(), kSource);
178180
}
179181

182+
TEST(SaveToOutParam, Nullptr) {
183+
EXPECT_EQ(SaveToOutParam(0, static_cast<int *>(nullptr)), E_INVALIDARG);
184+
EXPECT_EQ(SaveToOutParam(wil::unique_bstr(), static_cast<BSTR *>(nullptr)),
185+
E_INVALIDARG);
186+
EXPECT_EQ(
187+
SaveToOutParam(static_cast<BSTR>(nullptr), static_cast<BSTR *>(nullptr)),
188+
E_INVALIDARG);
189+
EXPECT_EQ(SaveToOutParam(wil::com_ptr_nothrow<IMock1>(),
190+
static_cast<IMock1 **>(nullptr)),
191+
E_INVALIDARG);
192+
}
193+
194+
TEST(SaveToOutParam, OutOfMemory) {
195+
BSTR out = nullptr;
196+
EXPECT_EQ(SaveToOutParam(static_cast<BSTR>(nullptr), &out), E_OUTOFMEMORY);
197+
}
198+
199+
TEST(SaveToOutParam, BSTR) {
200+
wil::unique_bstr output;
201+
EXPECT_EQ(SaveToOutParam(MakeUniqueBSTR(L"Hello"), output.put()), S_OK);
202+
EXPECT_THAT(output.get(), StrEq(L"Hello"));
203+
}
204+
205+
TEST(SaveToOutParam, ComPtr) {
206+
wil::com_ptr_nothrow<IMock1> output;
207+
EXPECT_EQ(SaveToOutParam(MakeComPtr<Mock>(), output.put()), S_OK);
208+
EXPECT_THAT(output, NotNull());
209+
}
210+
211+
TEST(SaveToOutParam, Int) {
212+
int output = 1;
213+
EXPECT_EQ(SaveToOutParam(0, &output), S_OK);
214+
EXPECT_EQ(output, 0);
215+
}
216+
217+
TEST(SaveToOptionalOutParam, Nullptr) {
218+
SaveToOptionalOutParam(1, static_cast<int *>(nullptr));
219+
}
220+
221+
TEST(SaveToOptionalOutParam, Int) {
222+
int output = 1;
223+
SaveToOptionalOutParam(0, &output);
224+
EXPECT_EQ(output, 0);
225+
}
226+
180227
} // namespace
181228
} // namespace mozc::win32

src/converter/candidate.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class Candidate {
6666
// Allows to refer Attribute via Candidate::XXX
6767
// TODO(taku): Remove this alias after full migration.
6868
using Attribute = converter::Attribute::Attribute_;
69-
using enum Attribute;
69+
using enum converter::Attribute::Attribute_;
7070

7171
enum Command {
7272
DEFAULT_COMMAND = 0,

src/converter/inner_segment.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,33 @@ class InnerSegments {
310310
return std::make_pair(key, value);
311311
}
312312

313+
// Returns the concatenated suffix key and value of segments size `size`, used
314+
// in history result. When size is -1, returns all key/value.
315+
std::pair<absl::string_view, absl::string_view> GetSuffixKeyAndValue(
316+
int size = -1) const {
317+
absl::string_view key = begin_.data_.key_;
318+
absl::string_view value = begin_.data_.value_;
319+
320+
if (size == 0) {
321+
// Returns last empty string so to allow pointer diff.
322+
return std::make_pair(key.substr(key.size()), value.substr(value.size()));
323+
}
324+
325+
int index = this->size() - size - 1;
326+
327+
if (size < 0 || index < 0) {
328+
return std::make_pair(key, value);
329+
} else {
330+
for (const auto& iter : *this) {
331+
key.remove_prefix(iter.GetKey().size());
332+
value.remove_prefix(iter.GetValue().size());
333+
if (index-- == 0) return std::make_pair(key, value);
334+
}
335+
}
336+
337+
return std::make_pair(key, value);
338+
}
339+
313340
// Constructor for the structure only with key/value.
314341
InnerSegments(absl::string_view key, absl::string_view value,
315342
InnerSegmentBoundarySpan inner_segment_boundary)

src/converter/inner_segment_test.cc

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <vector>
3535

3636
#include "absl/log/log.h"
37+
#include "absl/strings/str_cat.h"
3738
#include "absl/strings/string_view.h"
3839
#include "testing/gunit.h"
3940

@@ -241,5 +242,94 @@ TEST(InnerSegment, InnerSegmentIteratorInvalid) {
241242
}
242243
}
243244

245+
TEST(InnerSegments, GetSuffixKeyAndValue) {
246+
auto suffix_key_default = [](const InnerSegments &inner_segments) {
247+
return inner_segments.GetSuffixKeyAndValue().first;
248+
};
249+
250+
auto suffix_value_default = [](const InnerSegments &inner_segments) {
251+
return inner_segments.GetSuffixKeyAndValue().second;
252+
};
253+
254+
auto suffix_key = [](const InnerSegments &inner_segments, int size) {
255+
return inner_segments.GetSuffixKeyAndValue(size).first;
256+
};
257+
258+
auto suffix_value = [](const InnerSegments &inner_segments, int size) {
259+
return inner_segments.GetSuffixKeyAndValue(size).second;
260+
};
261+
262+
{
263+
std::string all_key, all_value;
264+
265+
converter::InnerSegmentBoundaryBuilder builder;
266+
267+
auto add_segment = [&](absl::string_view key, absl::string_view value) {
268+
builder.Add(key.size(), value.size(), key.size(), value.size());
269+
absl::StrAppend(&all_key, key);
270+
absl::StrAppend(&all_value, value);
271+
};
272+
273+
for (int i = 0; i < 3; ++i) {
274+
add_segment(absl::StrCat("k", i), absl::StrCat("v", i));
275+
}
276+
277+
InnerSegmentBoundary inner_segment_boundary =
278+
builder.Build(all_key, all_value);
279+
280+
const InnerSegments inner_segments(all_key, all_value,
281+
inner_segment_boundary);
282+
283+
EXPECT_EQ(inner_segments.size(), 3);
284+
EXPECT_EQ(suffix_key_default(inner_segments), "k0k1k2");
285+
EXPECT_EQ(suffix_value_default(inner_segments), "v0v1v2");
286+
EXPECT_EQ(suffix_key(inner_segments, -1), "k0k1k2");
287+
EXPECT_EQ(suffix_value(inner_segments, -1), "v0v1v2");
288+
EXPECT_EQ(suffix_key(inner_segments, 10), "k0k1k2");
289+
EXPECT_EQ(suffix_value(inner_segments, 10), "v0v1v2");
290+
EXPECT_EQ(suffix_key(inner_segments, 0), "");
291+
EXPECT_EQ(suffix_value(inner_segments, 0), "");
292+
EXPECT_EQ(suffix_key(inner_segments, 1), "k2");
293+
EXPECT_EQ(suffix_value(inner_segments, 1), "v2");
294+
EXPECT_EQ(suffix_key(inner_segments, 2), "k1k2");
295+
EXPECT_EQ(suffix_value(inner_segments, 2), "v1v2");
296+
EXPECT_EQ(suffix_key(inner_segments, 3), "k0k1k2");
297+
EXPECT_EQ(suffix_value(inner_segments, 3), "v0v1v2");
298+
EXPECT_EQ(suffix_key(inner_segments, 4), "k0k1k2");
299+
EXPECT_EQ(suffix_value(inner_segments, 4), "v0v1v2");
300+
}
301+
302+
{
303+
const InnerSegments inner_segments("", "", {});
304+
305+
EXPECT_EQ(inner_segments.size(), 0);
306+
EXPECT_EQ(suffix_key_default(inner_segments), "");
307+
EXPECT_EQ(suffix_value_default(inner_segments), "");
308+
EXPECT_EQ(suffix_key(inner_segments, -1), "");
309+
EXPECT_EQ(suffix_value(inner_segments, -1), "");
310+
EXPECT_EQ(suffix_key(inner_segments, 10), "");
311+
EXPECT_EQ(suffix_value(inner_segments, 10), "");
312+
EXPECT_EQ(suffix_key(inner_segments, 0), "");
313+
EXPECT_EQ(suffix_value(inner_segments, 0), "");
314+
EXPECT_EQ(suffix_key(inner_segments, 2), "");
315+
EXPECT_EQ(suffix_value(inner_segments, 2), "");
316+
EXPECT_EQ(suffix_key(inner_segments, 1), "");
317+
EXPECT_EQ(suffix_value(inner_segments, 1), "");
318+
}
319+
320+
{
321+
const InnerSegments inner_segments("key", "value", {});
322+
EXPECT_EQ(inner_segments.size(), 1);
323+
EXPECT_EQ(suffix_key_default(inner_segments), "key");
324+
EXPECT_EQ(suffix_value_default(inner_segments), "value");
325+
EXPECT_EQ(suffix_key(inner_segments, -1), "key");
326+
EXPECT_EQ(suffix_value(inner_segments, -1), "value");
327+
EXPECT_EQ(suffix_key(inner_segments, 1), "key");
328+
EXPECT_EQ(suffix_value(inner_segments, 1), "value");
329+
EXPECT_EQ(suffix_key(inner_segments, 2), "key");
330+
EXPECT_EQ(suffix_value(inner_segments, 2), "value");
331+
}
332+
}
333+
244334
} // namespace converter
245335
} // namespace mozc

0 commit comments

Comments
 (0)