[yaml2obj] - Add a support for "<none>" value for all optional fields.

It implements an approach suggested in the D84398 thread.

With it the following:

```
Sections:
  - Name:   .bar
    Type:   SHT_PROGBITS
    Offset: [[MACRO=<none>]]
```

works just like the `Offset` key was not specified.
It is useful for tests that want to have a default value for a field and to
have a way to override it at the same time.

Differential revision: https://reviews.llvm.org/D84526
This commit is contained in:
Georgii Rymar 2020-07-23 15:26:23 +03:00
parent 6d47431d7e
commit d919ae9df8
2 changed files with 80 additions and 18 deletions

View file

@ -902,24 +902,7 @@ private:
template <typename T, typename Context>
void processKeyWithDefault(const char *Key, Optional<T> &Val,
const Optional<T> &DefaultValue, bool Required,
Context &Ctx) {
assert(DefaultValue.hasValue() == false &&
"Optional<T> shouldn't have a value!");
void *SaveInfo;
bool UseDefault = true;
const bool sameAsDefault = outputting() && !Val.hasValue();
if (!outputting() && !Val.hasValue())
Val = T();
if (Val.hasValue() &&
this->preflightKey(Key, Required, sameAsDefault, UseDefault,
SaveInfo)) {
yamlize(*this, Val.getValue(), Required, Ctx);
this->postflightKey(SaveInfo);
} else {
if (UseDefault)
Val = DefaultValue;
}
}
Context &Ctx);
template <typename T, typename Context>
void processKeyWithDefault(const char *Key, T &Val, const T &DefaultValue,
@ -1625,6 +1608,40 @@ private:
StringRef PaddingBeforeContainer;
};
template <typename T, typename Context>
void IO::processKeyWithDefault(const char *Key, Optional<T> &Val,
const Optional<T> &DefaultValue, bool Required,
Context &Ctx) {
assert(DefaultValue.hasValue() == false &&
"Optional<T> shouldn't have a value!");
void *SaveInfo;
bool UseDefault = true;
const bool sameAsDefault = outputting() && !Val.hasValue();
if (!outputting() && !Val.hasValue())
Val = T();
if (Val.hasValue() &&
this->preflightKey(Key, Required, sameAsDefault, UseDefault, SaveInfo)) {
// When reading an Optional<X> key from a YAML description, we allow the
// special "<none>" value, which can be used to specify that no value was
// requested, i.e. the DefaultValue will be assigned. The DefaultValue is
// usually None.
bool IsNone = false;
if (!outputting())
if (auto *Node = dyn_cast<ScalarNode>(((Input *)this)->getCurrentNode()))
IsNone = Node->getRawValue() == "<none>";
if (IsNone)
Val = DefaultValue;
else
yamlize(*this, Val.getValue(), Required, Ctx);
this->postflightKey(SaveInfo);
} else {
if (UseDefault)
Val = DefaultValue;
}
}
/// YAML I/O does conversion based on types. But often native data types
/// are just a typedef of built in intergral types (e.g. int). But the C++
/// type matching system sees through the typedef and all the typedefed types

View file

@ -0,0 +1,45 @@
## We have a special "<none>" value for all keys that are implemented
## as Optional<> in the code. Setting a key to "<none>" means no-op and
## works in the same way as when a field was not specified at all.
## Test a few keys for which the "<none>" value is supported.
## We do not test all possible keys, because it would be too verbose.
## It reasonable to test all keys for a section, because normally many
## of them would conflict or intersect when specified together.
# RUN: yaml2obj %s --docnum=1 -o %t-none
# RUN: yaml2obj %s --docnum=2 -o %t-base
# RUN: cmp %t-none %t-base
## We do not use the TEST macro. It exists to
## demonstrate the expected use case for the <none> word.
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_X86_64
Sections:
- Name: .bar
Type: SHT_PROGBITS
Offset: [[TEST=<none>]]
Address: [[TEST=<none>]]
Content: [[TEST=<none>]]
Size: [[TEST=<none>]]
ContentArray: [[TEST=<none>]]
Info: [[TEST=<none>]]
EntSize: [[TEST=<none>]]
ShName: [[TEST=<none>]]
ShOffset: [[TEST=<none>]]
ShSize: [[TEST=<none>]]
ShFlags: [[TEST=<none>]]
## The same document, but all fields that were set to <none> are removed.
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_X86_64
Sections:
- Name: .bar
Type: SHT_PROGBITS