зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
7fd0995e99
Коммит
b355692a7f
|
@ -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.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче