// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include <vector>
namespace autofill {
struct FormFieldData {
FormFieldData();
FormFieldData(const FormFieldData&);
FormFieldData& operator=(const FormFieldData&);
std::u16string value;
int something_else;
};
// References in compiler-generated code must not be rewritten.
FormFieldData::FormFieldData() = default;
FormFieldData::FormFieldData(const FormFieldData&) = default;
FormFieldData& FormFieldData::operator=(const FormFieldData&) = default;
class AutofillField : public FormFieldData {};
} // namespace autofill
namespace testing {
template <typename Class, typename FieldType>
void Field(FieldType Class::*field, int matcher) {}
template <typename Class, typename FieldType>
void Property(FieldType Class::*field(), int matcher) {}
} // namespace testing
namespace base {
std::u16string ASCIIToUTF16(std::string x) {
return u"arbitrary string";
}
} // namespace base
namespace not_autofill {
struct FormFieldData {
std::u16string value;
int something_else;
};
} // namespace not_autofill
// Tests that a read reference `f.value` is replaced with `r.value()`.
std::u16string FunRead() {
autofill::FormFieldData f;
return f.value;
}
// Tests that `f.value` at the left of an assignment is replaced with
// `f.set_value(rhs)`.
void FunWrite() {
::autofill::FormFieldData f;
f.value = u"foo";
}
// Tests that a read reference `f->value` is replaced with `r->value()`.
std::u16string FunReadPointer() {
autofill::FormFieldData f;
autofill::FormFieldData* g = &f;
return g->value;
}
// Tests that `f->value` at the left of an assignment is replaced with
// `f->set_value(rhs)`.
void FunWritePointer() {
autofill::FormFieldData f;
autofill::FormFieldData* g = &f;
g->value = u"foo";
}
// Tests that a read reference `f.value()` in a member function is replaced with
// `f.value()`.
class Class {
static const std::u16string& value(const autofill::FormFieldData& f) {
return f.value;
}
};
// Tests that a references at the left and right hand side of an assignment aer
// replaced appropriately.
void FunReadAndWrite() {
::autofill::FormFieldData f;
::autofill::FormFieldData g;
f.value = g.value;
}
// Like FunReadAndWrite() but additionally tests that a constness doesn't affect
// the rewriting.
void FunReadConstAndWrite() {
::autofill::FormFieldData f;
const ::autofill::FormFieldData g;
f.value = g.value;
}
// Like FunReadConstAndWrite() but additionally tests that redundant
// parentheses doesn't affect the rewriting.
void FunReadConstAndWriteWithParentheses() {
::autofill::FormFieldData f;
const ::autofill::FormFieldData g;
((f).value) = ((g).value);
}
// Like FunReadConstAndWrite() but additionally tests that additional whitespace
// doesn't affect the rewriting of a read reference and that the comments
// survive the rewriting.
void FunReadWithWhitespace() {
autofill::FormFieldData f;
std::u16string s = f // comment 1
. // comment 2
value; // comment 3
}
// Like FunReadConstAndWrite() but additionally tests that additional
// whitespace doesn't affect the rewriting of a write reference and that the
// comments survive the rewriting.
void FunWriteWithWhitespace() {
autofill::FormFieldData f;
f // comment 1
. // comment 2
value // comment 3
= // comment 4
u"foo";
}
// Tests whether explicit `operator=()` is rewritten. This is desirable but
// currently not implemented.
void FunWriteExplicitOperator() {
::autofill::FormFieldData f;
f.value.operator=(u"foo"); // Currently not properly rewritten.
}
namespace autofill {
// Tests that references are rewritten even if the object's type isn't fully
// qualified.
std::u16string FunReadImplicitNamespace() {
FormFieldData f;
return f.value;
}
// Tests that a reference at the left of an assignment is replaced with
// set_value(), and that a more complex right-hand side experission is
// preserved.
void FunWriteCallExpr() {
std::string value;
FormFieldData field;
field.value = base::ASCIIToUTF16(value);
}
} // namespace autofill
// Like FunWriteCallExpr() but with a more complex expression at the right-hand
// side. It involves UTF-16 string literals to test that the rewriter uses the
// correct clang::LangOptions (and not the default argument).
void FunWriteComplexCallExpr() {
auto g = [](const std::u16string& s) { return s; };
autofill::FormFieldData f;
f.value = u"bar" + g(std::u16string(u"foo") + u"qux");
}
// Tests that the replacement does not touch classes from other namespaces.
std::u16string FunReadNotAutofill() {
::not_autofill::FormFieldData f;
return f.value;
}
// Tests that write references on members of a derived class are rewritten.
void FunWriteDerived() {
autofill::AutofillField f;
f.value = u"bar";
}
// Tests that read references on vector elements are rewritten.
std::u16string FunReadVector() {
std::vector<autofill::FormFieldData> fields;
fields.emplace_back();
return fields[0].value;
}
// Tests that write references on vector elements are rewritten.
void FunWriteVector() {
std::vector<autofill::FormFieldData> fields;
fields.emplace_back();
fields[0].value = u"foo";
}
// Tests that pointers to members are not rewritten.
std::u16string FunFieldPointer() {
using autofill::FormFieldData;
FormFieldData f;
std::u16string FormFieldData::*ptr = &FormFieldData::value;
return f.*ptr;
}
// Tests that Field(&Class::member, ...) is replaced with
// Property(&Class::member, ...).
void FunMatcher() {
::testing::Field(&autofill::FormFieldData::value, {});
::testing::Field(&autofill::FormFieldData::something_else, {});
::testing::Field(¬_autofill::FormFieldData::value, {});
::testing::Field(¬_autofill::FormFieldData::something_else, {});
using ::testing::Field;
using ::testing::Property;
Field(&autofill::FormFieldData::value, {});
Field(&autofill::FormFieldData::something_else, {});
Field(¬_autofill::FormFieldData::value, {});
Field(¬_autofill::FormFieldData::something_else, {});
}