@@ -320,7 +320,8 @@ class TextFormat::Parser::ParserImpl {
320
320
bool allow_case_insensitive_field, bool allow_unknown_field,
321
321
bool allow_unknown_extension, bool allow_unknown_enum,
322
322
bool allow_field_number, bool allow_relaxed_whitespace,
323
- bool allow_partial, int recursion_limit)
323
+ bool allow_partial, int recursion_limit,
324
+ bool error_on_no_op_fields)
324
325
: error_collector_(error_collector),
325
326
finder_ (finder),
326
327
parse_info_tree_(parse_info_tree),
@@ -337,7 +338,8 @@ class TextFormat::Parser::ParserImpl {
337
338
initial_recursion_limit_(recursion_limit),
338
339
recursion_limit_(recursion_limit),
339
340
had_silent_marker_(false ),
340
- had_errors_(false ) {
341
+ had_errors_(false ),
342
+ error_on_no_op_fields_(error_on_no_op_fields) {
341
343
// For backwards-compatibility with proto1, we need to allow the 'f' suffix
342
344
// for floats.
343
345
tokenizer_.set_allow_f_after_float (true );
@@ -817,75 +819,86 @@ class TextFormat::Parser::ParserImpl {
817
819
// Define an easy to use macro for setting fields. This macro checks
818
820
// to see if the field is repeated (in which case we need to use the Add
819
821
// methods or not (in which case we need to use the Set methods).
820
- #define SET_FIELD (CPPTYPE, VALUE ) \
821
- if (field->is_repeated ()) { \
822
- reflection->Add ##CPPTYPE (message, field, VALUE); \
823
- } else { \
824
- reflection->Set ##CPPTYPE (message, field, VALUE); \
822
+ // When checking for no-op operations, We verify that both the existing value in
823
+ // the message and the new value are the default. If the existing field value is
824
+ // not the default, setting it to the default should not be treated as a no-op.
825
+ #define SET_FIELD (CPPTYPE, CPPTYPELCASE, VALUE ) \
826
+ if (field->is_repeated ()) { \
827
+ reflection->Add ##CPPTYPE (message, field, VALUE); \
828
+ } else { \
829
+ if (error_on_no_op_fields_ && !field->has_presence () && \
830
+ field->default_value_ ##CPPTYPELCASE () == \
831
+ reflection->Get ##CPPTYPE (*message, field) && \
832
+ field->default_value_ ##CPPTYPELCASE () == VALUE) { \
833
+ ReportError (" Input field " + field->full_name () + \
834
+ " did not change resulting proto." ); \
835
+ } else { \
836
+ reflection->Set ##CPPTYPE (message, field, std::move (VALUE)); \
837
+ } \
825
838
}
826
839
827
840
switch (field->cpp_type ()) {
828
841
case FieldDescriptor::CPPTYPE_INT32: {
829
842
int64_t value;
830
843
DO (ConsumeSignedInteger (&value, kint32max));
831
- SET_FIELD (Int32, static_cast <int32_t >(value));
844
+ SET_FIELD (Int32, int32, static_cast <int32_t >(value));
832
845
break ;
833
846
}
834
847
835
848
case FieldDescriptor::CPPTYPE_UINT32: {
836
849
uint64_t value;
837
850
DO (ConsumeUnsignedInteger (&value, kuint32max));
838
- SET_FIELD (UInt32, static_cast <uint32_t >(value));
851
+ SET_FIELD (UInt32, uint32, static_cast <uint32_t >(value));
839
852
break ;
840
853
}
841
854
842
855
case FieldDescriptor::CPPTYPE_INT64: {
843
856
int64_t value;
844
857
DO (ConsumeSignedInteger (&value, kint64max));
845
- SET_FIELD (Int64, value);
858
+ SET_FIELD (Int64, int64, value);
846
859
break ;
847
860
}
848
861
849
862
case FieldDescriptor::CPPTYPE_UINT64: {
850
863
uint64_t value;
851
864
DO (ConsumeUnsignedInteger (&value, kuint64max));
852
- SET_FIELD (UInt64, value);
865
+ SET_FIELD (UInt64, uint64, value);
853
866
break ;
854
867
}
855
868
856
869
case FieldDescriptor::CPPTYPE_FLOAT: {
857
870
double value;
858
871
DO (ConsumeDouble (&value));
859
- SET_FIELD (Float, io::SafeDoubleToFloat (value));
872
+ SET_FIELD (Float, float , io::SafeDoubleToFloat (value));
860
873
break ;
861
874
}
862
875
863
876
case FieldDescriptor::CPPTYPE_DOUBLE: {
864
877
double value;
865
878
DO (ConsumeDouble (&value));
866
- SET_FIELD (Double, value);
879
+ SET_FIELD (Double, double , value);
867
880
break ;
868
881
}
869
882
870
883
case FieldDescriptor::CPPTYPE_STRING: {
871
884
std::string value;
872
885
DO (ConsumeString (&value));
873
- SET_FIELD (String, std::move ( value) );
886
+ SET_FIELD (String, string, value);
874
887
break ;
875
888
}
876
889
877
890
case FieldDescriptor::CPPTYPE_BOOL: {
878
891
if (LookingAtType (io::Tokenizer::TYPE_INTEGER)) {
879
892
uint64_t value;
880
893
DO (ConsumeUnsignedInteger (&value, 1 ));
881
- SET_FIELD (Bool, value);
894
+ SET_FIELD (Bool, bool , value);
882
895
} else {
883
896
std::string value;
884
897
DO (ConsumeIdentifier (&value));
885
898
if (value == " true" || value == " True" || value == " t" ) {
886
- SET_FIELD (Bool, true );
899
+ SET_FIELD (Bool, bool , true );
887
900
} else if (value == " false" || value == " False" || value == " f" ) {
888
- SET_FIELD (Bool, false );
901
+ SET_FIELD (Bool, bool , false );
889
902
} else {
890
903
ReportError (absl::StrCat (" Invalid value for boolean field \" " ,
891
904
field->name (), " \" . Value: \" " , value,
@@ -921,7 +934,7 @@ class TextFormat::Parser::ParserImpl {
921
934
if (enum_value == nullptr ) {
922
935
if (int_value != kint64max &&
923
936
!field->legacy_enum_field_treated_as_closed ()) {
924
- SET_FIELD (EnumValue, int_value);
937
+ SET_FIELD (EnumValue, int64, int_value);
925
938
return true ;
926
939
} else if (!allow_unknown_enum_) {
927
940
ReportError (absl::StrCat (" Unknown enumeration value of \" " , value,
@@ -935,7 +948,7 @@ class TextFormat::Parser::ParserImpl {
935
948
}
936
949
}
937
950
938
- SET_FIELD (Enum, enum_value);
951
+ SET_FIELD (Enum, enum , enum_value);
939
952
break ;
940
953
}
941
954
@@ -1404,6 +1417,8 @@ class TextFormat::Parser::ParserImpl {
1404
1417
int recursion_limit_;
1405
1418
bool had_silent_marker_;
1406
1419
bool had_errors_;
1420
+ bool error_on_no_op_fields_;
1421
+
1407
1422
};
1408
1423
1409
1424
// ===========================================================================
@@ -1700,7 +1715,7 @@ bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input,
1700
1715
allow_case_insensitive_field_, allow_unknown_field_,
1701
1716
allow_unknown_extension_, allow_unknown_enum_,
1702
1717
allow_field_number_, allow_relaxed_whitespace_,
1703
- allow_partial_, recursion_limit_);
1718
+ allow_partial_, recursion_limit_, error_on_no_op_fields_ );
1704
1719
return MergeUsingImpl (input, output, &parser);
1705
1720
}
1706
1721
@@ -1725,7 +1740,7 @@ bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input,
1725
1740
allow_case_insensitive_field_, allow_unknown_field_,
1726
1741
allow_unknown_extension_, allow_unknown_enum_,
1727
1742
allow_field_number_, allow_relaxed_whitespace_,
1728
- allow_partial_, recursion_limit_);
1743
+ allow_partial_, recursion_limit_, error_on_no_op_fields_ );
1729
1744
return MergeUsingImpl (input, output, &parser);
1730
1745
}
1731
1746
@@ -1755,12 +1770,13 @@ bool TextFormat::Parser::ParseFieldValueFromString(const std::string& input,
1755
1770
const FieldDescriptor* field,
1756
1771
Message* output) {
1757
1772
io::ArrayInputStream input_stream (input.data (), input.size ());
1758
- ParserImpl parser (
1759
- output->GetDescriptor (), &input_stream, error_collector_, finder_,
1760
- parse_info_tree_, ParserImpl::ALLOW_SINGULAR_OVERWRITES,
1761
- allow_case_insensitive_field_, allow_unknown_field_,
1762
- allow_unknown_extension_, allow_unknown_enum_, allow_field_number_,
1763
- allow_relaxed_whitespace_, allow_partial_, recursion_limit_);
1773
+ ParserImpl parser (output->GetDescriptor (), &input_stream, error_collector_,
1774
+ finder_, parse_info_tree_,
1775
+ ParserImpl::ALLOW_SINGULAR_OVERWRITES,
1776
+ allow_case_insensitive_field_, allow_unknown_field_,
1777
+ allow_unknown_extension_, allow_unknown_enum_,
1778
+ allow_field_number_, allow_relaxed_whitespace_,
1779
+ allow_partial_, recursion_limit_, error_on_no_op_fields_);
1764
1780
return parser.ParseField (field, output);
1765
1781
}
1766
1782
0 commit comments