diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -313,8 +313,8 @@ std::string Nearest; if (getOpts().findNearest(ArgString, Nearest, IncludedFlagsBitmask, ExcludedFlagsBitmask) > 1) { - if (getOpts().findNearest(ArgString, Nearest, options::CC1Option) == 0 && - !IsCLMode()) { + if (!IsCLMode() && + getOpts().findExact(ArgString, Nearest, options::CC1Option)) { DiagID = diag::err_drv_unknown_argument_with_suggestion; Diags.Report(DiagID) << ArgString << "-Xclang " + Nearest; } else { @@ -339,8 +339,8 @@ // Warn on joined arguments that are similar to a long argument. std::string ArgString = ArgStrings[A->getIndex()]; std::string Nearest; - if (getOpts().findNearest("-" + ArgString, Nearest, IncludedFlagsBitmask, - ExcludedFlagsBitmask) == 0) + if (getOpts().findExact("-" + ArgString, Nearest, IncludedFlagsBitmask, + ExcludedFlagsBitmask)) Diags.Report(diag::warn_drv_potentially_misspelled_joined_argument) << A->getAsString(Args) << Nearest; } @@ -2472,7 +2472,7 @@ getIncludeExcludeOptionFlagMasks(IsCLMode()); std::string Nearest; if (getOpts().findNearest(Value, Nearest, IncludedFlagsBitmask, - ExcludedFlagsBitmask) <= 1) { + ExcludedFlagsBitmask, 0, 1) <= 1) { Diag(clang::diag::err_drv_no_such_file_with_suggestion) << Value << Nearest; return false; diff --git a/llvm/include/llvm/Option/OptTable.h b/llvm/include/llvm/Option/OptTable.h --- a/llvm/include/llvm/Option/OptTable.h +++ b/llvm/include/llvm/Option/OptTable.h @@ -175,11 +175,21 @@ /// \param [in] MinimumLength - Don't find options shorter than this length. /// For example, a minimum length of 3 prevents "-x" from being considered /// near to "-S". + /// \param [in] MinimumDistance - Don't find options whose distance is greater + /// than this value. /// /// \return The edit distance of the nearest string found. unsigned findNearest(StringRef Option, std::string &NearestString, unsigned FlagsToInclude = 0, unsigned FlagsToExclude = 0, - unsigned MinimumLength = 4) const; + unsigned MinimumLength = 4, + unsigned MinimumDistance = UINT_MAX - 1) const; + + bool findExact(StringRef Option, std::string &ExactString, + unsigned FlagsToInclude = 0, + unsigned FlagsToExclude = 0) const { + return findNearest(Option, ExactString, FlagsToInclude, FlagsToExclude, + Option.size(), 0) == 0; + } /// Parse a single argument; returning the new argument and /// updating Index. diff --git a/llvm/lib/Option/OptTable.cpp b/llvm/lib/Option/OptTable.cpp --- a/llvm/lib/Option/OptTable.cpp +++ b/llvm/lib/Option/OptTable.cpp @@ -227,12 +227,13 @@ unsigned OptTable::findNearest(StringRef Option, std::string &NearestString, unsigned FlagsToInclude, unsigned FlagsToExclude, - unsigned MinimumLength) const { + unsigned MinimumLength, + unsigned MinimumDistance) const { assert(!Option.empty()); // Consider each [option prefix + option name] pair as a candidate, finding // the closest match. - unsigned BestDistance = UINT_MAX; + unsigned BestDistance = MinimumDistance + 1; SmallString<16> Candidate; SmallString<16> NormalizedName; @@ -276,6 +277,14 @@ // appropriate one. For example, if a user asks for "--helm", suggest // "--help" over "-help". for (auto CandidatePrefix : CandidateInfo.Prefixes) { + // If Candidate and NormalizedName have more than 'BestDistance' + // characters of difference, no need to compute the edit distance, it's + // going to be greater than BestDistance. Don't bother computing Candidate + // at all. + if (std::abs((signed)(CandidatePrefix.size() + CandidateName.size()) - + (signed)NormalizedName.size()) > (signed)BestDistance) { + continue; + } Candidate = CandidatePrefix; Candidate += CandidateName; unsigned Distance = StringRef(Candidate).edit_distance(