Driver: Check that options are ordered properly (outside of

Release-Asserts mode).

Also, avoid searching through option groups (which will never match).


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67548 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Daniel Dunbar 2009-03-23 18:41:45 +00:00
Родитель 7fd0995e99
Коммит b355692a7f
2 изменённых файлов: 82 добавлений и 5 удалений

Просмотреть файл

@ -37,8 +37,15 @@ namespace options {
/// instantiating Options, while letting other parts of the driver /// instantiating Options, while letting other parts of the driver
/// still use Option instances where convient. /// still use Option instances where convient.
class OptTable { class OptTable {
/// The table of options which have been constructed, indexed by
/// option::ID - 1.
mutable Option **Options; mutable Option **Options;
/// The index of the first option which can be parsed (i.e., is
/// not a special option like 'input' or 'unknown', and is not an
/// option group).
unsigned FirstSearchableOption;
Option *constructOption(options::ID id) const; Option *constructOption(options::ID id) const;
public: public:

Просмотреть файл

@ -27,6 +27,48 @@ struct Info {
unsigned Param; unsigned Param;
}; };
// Ordering on Info. The ordering is *almost* lexicographic, with two
// exceptions. First, '\0' comes at the end of the alphabet instead of
// the beginning (thus options preceed any other options which prefix
// them). Second, for options with the same name, the less permissive
// version should come first; a Flag option should preceed a Joined
// option, for example.
static int StrCmpOptionName(const char *A, const char *B) {
char a = *A, b = *B;
while (a == b) {
if (a == '\0')
return 0;
a = *++A;
b = *++B;
}
if (a == '\0') // A is a prefix of B.
return 1;
if (b == '\0') // B is a prefix of A.
return -1;
// Otherwise lexicographic.
return (a < b) ? -1 : 1;
}
static inline bool operator<(const Info &A, const Info &B) {
if (&A == &B)
return false;
if (int N = StrCmpOptionName(A.Name, B.Name))
return N == -1;
// Names are the same, check that classes are in order; exactly one
// should be joined, and it should succeed the other.
assert((A.Kind == Option::JoinedClass ^ B.Kind == Option::JoinedClass) &&
"Unexpected classes for options with same name.");
return B.Kind == Option::JoinedClass;
}
//
static Info OptionInfos[] = { static Info OptionInfos[] = {
// The InputOption info // The InputOption info
{ "<input>", "d", Option::InputClass, OPT_INVALID, OPT_INVALID, 0 }, { "<input>", "d", Option::InputClass, OPT_INVALID, OPT_INVALID, 0 },
@ -44,11 +86,40 @@ static Info &getInfo(unsigned id) {
return OptionInfos[id - 1]; return OptionInfos[id - 1];
} }
OptTable::OptTable() : Options(new Option*[numOptions]()) { OptTable::OptTable() : Options(new Option*[numOptions]()) {
// Find start of normal options.
FirstSearchableOption = 0;
for (unsigned i = OPT_UNKNOWN + 1; i < LastOption; ++i) {
if (getInfo(i).Kind != Option::GroupClass) {
FirstSearchableOption = i + 1;
break;
}
}
assert(FirstSearchableOption != 0 && "No searchable options?");
#ifndef NDEBUG
// Check that everything after the first searchable option is a
// regular option class.
for (unsigned i = FirstSearchableOption; i < LastOption; ++i) {
Option::OptionClass Kind = getInfo(i).Kind;
assert((Kind != Option::InputClass && Kind != Option::UnknownClass &&
Kind != Option::GroupClass) &&
"Special options should be defined first!");
}
// Check that options are in order.
for (unsigned i = FirstSearchableOption + 1; i < LastOption; ++i) {
if (!(getInfo(i - 1) < getInfo(i))) {
getOption((options::ID) (i - 1))->dump();
getOption((options::ID) i)->dump();
assert(0 && "Options are not in order!");
}
}
#endif
} }
OptTable::~OptTable() { OptTable::~OptTable() {
for (unsigned i=0; i<numOptions; ++i) for (unsigned i = 0; i < numOptions; ++i)
delete Options[i]; delete Options[i];
delete[] Options; delete[] Options;
} }
@ -136,9 +207,8 @@ Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const {
if (Str[0] != '-' || Str[1] == '\0') if (Str[0] != '-' || Str[1] == '\0')
return new PositionalArg(getOption(OPT_INPUT), Index++); return new PositionalArg(getOption(OPT_INPUT), Index++);
// FIXME: Make this fast, and avoid looking through option // FIXME: Make this fast.
// groups. Maybe we should declare them separately? for (unsigned j = FirstSearchableOption; j < LastOption; ++j) {
for (unsigned j = OPT_UNKNOWN + 1; j < LastOption; ++j) {
const char *OptName = getOptionName((options::ID) j); const char *OptName = getOptionName((options::ID) j);
// Arguments are only accepted by options which prefix them. // Arguments are only accepted by options which prefix them.