Re-push "[Option] Fix PR37006 prefix choice in findNearest"

Summary:
Original changeset (https://reviews.llvm.org/D46776) by @modocache. It was
reverted after the PS4 bot failed.

The issue has been determined to be with the way the PS4 SDK handles this
particular option. https://reviews.llvm.org/D50410 removes this test, so we
can push this again.

Patch by Arnaud Coomans!

Reviewers: cfe-commits, modocache

Reviewed By: modocache

Differential Revision: https://reviews.llvm.org/D50515

llvm-svn: 341329
This commit is contained in:
Brian Gesiak 2018-09-03 17:30:57 +00:00
parent 96c13488ab
commit f534485387
3 changed files with 29 additions and 24 deletions

View File

@ -252,38 +252,33 @@ unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,
unsigned MinimumLength) const { unsigned MinimumLength) const {
assert(!Option.empty()); assert(!Option.empty());
// Consider each option as a candidate, finding the closest match. // Consider each [option prefix + option name] pair as a candidate, finding
// the closest match.
unsigned BestDistance = UINT_MAX; unsigned BestDistance = UINT_MAX;
for (const Info &CandidateInfo : for (const Info &CandidateInfo :
ArrayRef<Info>(OptionInfos).drop_front(FirstSearchableIndex)) { ArrayRef<Info>(OptionInfos).drop_front(FirstSearchableIndex)) {
StringRef CandidateName = CandidateInfo.Name; StringRef CandidateName = CandidateInfo.Name;
// Ignore option candidates with empty names, such as "--", or names // We can eliminate some option prefix/name pairs as candidates right away:
// that do not meet the minimum length. // * Ignore option candidates with empty names, such as "--", or names
// that do not meet the minimum length.
if (CandidateName.empty() || CandidateName.size() < MinimumLength) if (CandidateName.empty() || CandidateName.size() < MinimumLength)
continue; continue;
// If FlagsToInclude were specified, ignore options that don't include // * If FlagsToInclude were specified, ignore options that don't include
// those flags. // those flags.
if (FlagsToInclude && !(CandidateInfo.Flags & FlagsToInclude)) if (FlagsToInclude && !(CandidateInfo.Flags & FlagsToInclude))
continue; continue;
// Ignore options that contain the FlagsToExclude. // * Ignore options that contain the FlagsToExclude.
if (CandidateInfo.Flags & FlagsToExclude) if (CandidateInfo.Flags & FlagsToExclude)
continue; continue;
// Ignore positional argument option candidates (which do not // * Ignore positional argument option candidates (which do not
// have prefixes). // have prefixes).
if (!CandidateInfo.Prefixes) if (!CandidateInfo.Prefixes)
continue; continue;
// Find the most appropriate prefix. For example, if a user asks for
// "--helm", suggest "--help" over "-help".
StringRef Prefix = CandidateInfo.Prefixes[0];
for (int P = 1; CandidateInfo.Prefixes[P]; P++) {
if (Option.startswith(CandidateInfo.Prefixes[P]))
Prefix = CandidateInfo.Prefixes[P];
}
// Check if the candidate ends with a character commonly used when // Now check if the candidate ends with a character commonly used when
// delimiting an option from its value, such as '=' or ':'. If it does, // delimiting an option from its value, such as '=' or ':'. If it does,
// attempt to split the given option based on that delimiter. // attempt to split the given option based on that delimiter.
std::string Delimiter = ""; std::string Delimiter = "";
@ -297,14 +292,19 @@ unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,
else else
std::tie(LHS, RHS) = Option.split(Last); std::tie(LHS, RHS) = Option.split(Last);
std::string NormalizedName = // Consider each possible prefix for each candidate to find the most
(LHS.drop_front(Prefix.size()) + Delimiter).str(); // appropriate one. For example, if a user asks for "--helm", suggest
unsigned Distance = // "--help" over "-help".
CandidateName.edit_distance(NormalizedName, /*AllowReplacements=*/true, for (int P = 0; const char *const CandidatePrefix = CandidateInfo.Prefixes[P]; P++) {
/*MaxEditDistance=*/BestDistance); std::string NormalizedName = (LHS + Delimiter).str();
if (Distance < BestDistance) { StringRef Candidate = (CandidatePrefix + CandidateName).str();
BestDistance = Distance; unsigned Distance =
NearestString = (Prefix + CandidateName + RHS).str(); Candidate.edit_distance(NormalizedName, /*AllowReplacements=*/true,
/*MaxEditDistance=*/BestDistance);
if (Distance < BestDistance) {
BestDistance = Distance;
NearestString = (Candidate + RHS).str();
}
} }
} }
return BestDistance; return BestDistance;

View File

@ -283,6 +283,10 @@ TEST(Option, FindNearest) {
EXPECT_EQ(Nearest, "-blorp"); EXPECT_EQ(Nearest, "-blorp");
EXPECT_EQ(1U, T.findNearest("--blorm", Nearest)); EXPECT_EQ(1U, T.findNearest("--blorm", Nearest));
EXPECT_EQ(Nearest, "--blorp"); EXPECT_EQ(Nearest, "--blorp");
EXPECT_EQ(1U, T.findNearest("-blarg", Nearest));
EXPECT_EQ(Nearest, "-blarn");
EXPECT_EQ(1U, T.findNearest("--blarm", Nearest));
EXPECT_EQ(Nearest, "--blarn");
EXPECT_EQ(1U, T.findNearest("-fjormp", Nearest)); EXPECT_EQ(1U, T.findNearest("-fjormp", Nearest));
EXPECT_EQ(Nearest, "--fjormp"); EXPECT_EQ(Nearest, "--fjormp");

View File

@ -30,6 +30,7 @@ def Slurp : Option<["-"], "slurp", KIND_REMAINING_ARGS>;
def SlurpJoined : Option<["-"], "slurpjoined", KIND_REMAINING_ARGS_JOINED>; def SlurpJoined : Option<["-"], "slurpjoined", KIND_REMAINING_ARGS_JOINED>;
def Blorp : Flag<["-", "--"], "blorp">, HelpText<"The blorp option">, Flags<[OptFlag1]>; def Blorp : Flag<["-", "--"], "blorp">, HelpText<"The blorp option">, Flags<[OptFlag1]>;
def Blarn : Flag<["--", "-"], "blarn">, HelpText<"The blarn option">, Flags<[OptFlag1]>;
def Cramb : Joined<["/"], "cramb:">, HelpText<"The cramb option">, MetaVarName<"CRAMB">, Flags<[OptFlag1]>; def Cramb : Joined<["/"], "cramb:">, HelpText<"The cramb option">, MetaVarName<"CRAMB">, Flags<[OptFlag1]>;
def Doopf1 : Flag<["-"], "doopf1">, HelpText<"The doopf1 option">, Flags<[OptFlag1]>; def Doopf1 : Flag<["-"], "doopf1">, HelpText<"The doopf1 option">, Flags<[OptFlag1]>;
def Doopf2 : Flag<["-"], "doopf2">, HelpText<"The doopf2 option">, Flags<[OptFlag2]>; def Doopf2 : Flag<["-"], "doopf2">, HelpText<"The doopf2 option">, Flags<[OptFlag2]>;