aboutsummaryrefslogtreecommitdiff
path: root/lib/Driver/OptTable.cpp
diff options
context:
space:
mode:
authorDaniel Dunbar <daniel@zuster.org>2009-03-23 18:41:45 +0000
committerDaniel Dunbar <daniel@zuster.org>2009-03-23 18:41:45 +0000
commitb355692a7f9349e9af747b6b444ce56e9228a696 (patch)
tree298d5263bacef745a415074bd7d9f8f02a2a73d6 /lib/Driver/OptTable.cpp
parent7fd0995e993438a3a1f5408d8549b3af0009ff30 (diff)
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
Diffstat (limited to 'lib/Driver/OptTable.cpp')
-rw-r--r--lib/Driver/OptTable.cpp80
1 files changed, 75 insertions, 5 deletions
diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp
index 07e3511719..283ebf927b 100644
--- a/lib/Driver/OptTable.cpp
+++ b/lib/Driver/OptTable.cpp
@@ -27,6 +27,48 @@ struct Info {
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[] = {
// The InputOption info
{ "<input>", "d", Option::InputClass, OPT_INVALID, OPT_INVALID, 0 },
@@ -44,11 +86,40 @@ static Info &getInfo(unsigned id) {
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() {
- for (unsigned i=0; i<numOptions; ++i)
+ for (unsigned i = 0; i < numOptions; ++i)
delete Options[i];
delete[] Options;
}
@@ -136,9 +207,8 @@ Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const {
if (Str[0] != '-' || Str[1] == '\0')
return new PositionalArg(getOption(OPT_INPUT), Index++);
- // FIXME: Make this fast, and avoid looking through option
- // groups. Maybe we should declare them separately?
- for (unsigned j = OPT_UNKNOWN + 1; j < LastOption; ++j) {
+ // FIXME: Make this fast.
+ for (unsigned j = FirstSearchableOption; j < LastOption; ++j) {
const char *OptName = getOptionName((options::ID) j);
// Arguments are only accepted by options which prefix them.