2017-12-02 01:08:02 +08:00
|
|
|
//===-- FuzzyMatchTests.cpp - String fuzzy matcher tests --------*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2017-12-02 01:08:02 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "FuzzyMatch.h"
|
|
|
|
|
|
|
|
#include "llvm/ADT/StringExtras.h"
|
|
|
|
#include "gmock/gmock.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
namespace {
|
2019-05-06 18:08:47 +08:00
|
|
|
using ::testing::Not;
|
2017-12-02 01:08:02 +08:00
|
|
|
|
|
|
|
struct ExpectedMatch {
|
2018-03-06 01:34:33 +08:00
|
|
|
// Annotations are optional, and will not be asserted if absent.
|
2019-01-07 23:45:19 +08:00
|
|
|
ExpectedMatch(llvm::StringRef Match) : Word(Match), Annotated(Match) {
|
2017-12-02 01:08:02 +08:00
|
|
|
for (char C : "[]")
|
|
|
|
Word.erase(std::remove(Word.begin(), Word.end(), C), Word.end());
|
2018-03-06 01:34:33 +08:00
|
|
|
if (Word.size() == Annotated->size())
|
2019-01-07 23:45:19 +08:00
|
|
|
Annotated = llvm::None;
|
2018-03-06 01:34:33 +08:00
|
|
|
}
|
2019-01-07 23:45:19 +08:00
|
|
|
bool accepts(llvm::StringRef ActualAnnotated) const {
|
2018-03-06 01:34:33 +08:00
|
|
|
return !Annotated || ActualAnnotated == *Annotated;
|
2017-12-02 01:08:02 +08:00
|
|
|
}
|
2018-03-06 01:34:33 +08:00
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
|
|
|
|
const ExpectedMatch &M) {
|
2018-03-06 22:30:07 +08:00
|
|
|
OS << "'" << M.Word;
|
2018-03-06 01:34:33 +08:00
|
|
|
if (M.Annotated)
|
|
|
|
OS << "' as " << *M.Annotated;
|
2018-03-06 22:30:07 +08:00
|
|
|
return OS;
|
2018-03-06 01:34:33 +08:00
|
|
|
}
|
|
|
|
|
2018-03-06 22:30:07 +08:00
|
|
|
std::string Word;
|
|
|
|
|
2018-03-06 01:34:33 +08:00
|
|
|
private:
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::Optional<llvm::StringRef> Annotated;
|
2017-12-02 01:08:02 +08:00
|
|
|
};
|
|
|
|
|
2019-05-06 18:08:47 +08:00
|
|
|
struct MatchesMatcher : public ::testing::MatcherInterface<llvm::StringRef> {
|
2017-12-02 01:08:02 +08:00
|
|
|
ExpectedMatch Candidate;
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::Optional<float> Score;
|
|
|
|
MatchesMatcher(ExpectedMatch Candidate, llvm::Optional<float> Score)
|
2018-06-06 20:38:37 +08:00
|
|
|
: Candidate(std::move(Candidate)), Score(Score) {}
|
2017-12-02 01:08:02 +08:00
|
|
|
|
|
|
|
void DescribeTo(::std::ostream *OS) const override {
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::raw_os_ostream(*OS) << "Matches " << Candidate;
|
2018-06-06 20:38:37 +08:00
|
|
|
if (Score)
|
|
|
|
*OS << " with score " << *Score;
|
2017-12-02 01:08:02 +08:00
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
bool MatchAndExplain(llvm::StringRef Pattern,
|
2019-05-06 18:08:47 +08:00
|
|
|
::testing::MatchResultListener *L) const override {
|
2019-01-07 23:45:19 +08:00
|
|
|
std::unique_ptr<llvm::raw_ostream> OS(
|
|
|
|
L->stream()
|
|
|
|
? (llvm::raw_ostream *)(new llvm::raw_os_ostream(*L->stream()))
|
|
|
|
: new llvm::raw_null_ostream());
|
2017-12-02 01:08:02 +08:00
|
|
|
FuzzyMatcher Matcher(Pattern);
|
|
|
|
auto Result = Matcher.match(Candidate.Word);
|
|
|
|
auto AnnotatedMatch = Matcher.dumpLast(*OS << "\n");
|
2018-06-06 20:38:37 +08:00
|
|
|
return Result && Candidate.accepts(AnnotatedMatch) &&
|
2019-05-06 18:08:47 +08:00
|
|
|
(!Score || ::testing::Value(*Result, ::testing::FloatEq(*Score)));
|
2017-12-02 01:08:02 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-06-06 20:38:37 +08:00
|
|
|
// Accepts patterns that match a given word, optionally requiring a score.
|
2017-12-02 01:08:02 +08:00
|
|
|
// Dumps the debug tables on match failure.
|
2019-05-06 18:08:47 +08:00
|
|
|
::testing::Matcher<llvm::StringRef> matches(llvm::StringRef M,
|
|
|
|
llvm::Optional<float> Score = {}) {
|
|
|
|
return ::testing::MakeMatcher<llvm::StringRef>(new MatchesMatcher(M, Score));
|
2017-12-02 01:08:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FuzzyMatch, Matches) {
|
2018-01-14 00:46:26 +08:00
|
|
|
EXPECT_THAT("", matches("unique_ptr"));
|
2017-12-02 01:08:02 +08:00
|
|
|
EXPECT_THAT("u_p", matches("[u]nique[_p]tr"));
|
|
|
|
EXPECT_THAT("up", matches("[u]nique_[p]tr"));
|
2018-06-14 21:50:30 +08:00
|
|
|
EXPECT_THAT("uq", Not(matches("unique_ptr")));
|
2017-12-02 01:08:02 +08:00
|
|
|
EXPECT_THAT("qp", Not(matches("unique_ptr")));
|
|
|
|
EXPECT_THAT("log", Not(matches("SVGFEMorphologyElement")));
|
|
|
|
|
|
|
|
EXPECT_THAT("tit", matches("win.[tit]"));
|
|
|
|
EXPECT_THAT("title", matches("win.[title]"));
|
|
|
|
EXPECT_THAT("WordCla", matches("[Word]Character[Cla]ssifier"));
|
|
|
|
EXPECT_THAT("WordCCla", matches("[WordC]haracter[Cla]ssifier"));
|
|
|
|
|
|
|
|
EXPECT_THAT("dete", Not(matches("editor.quickSuggestionsDelay")));
|
|
|
|
|
|
|
|
EXPECT_THAT("highlight", matches("editorHover[Highlight]"));
|
|
|
|
EXPECT_THAT("hhighlight", matches("editor[H]over[Highlight]"));
|
|
|
|
EXPECT_THAT("dhhighlight", Not(matches("editorHoverHighlight")));
|
|
|
|
|
|
|
|
EXPECT_THAT("-moz", matches("[-moz]-foo"));
|
|
|
|
EXPECT_THAT("moz", matches("-[moz]-foo"));
|
|
|
|
EXPECT_THAT("moza", matches("-[moz]-[a]nimation"));
|
|
|
|
|
|
|
|
EXPECT_THAT("ab", matches("[ab]A"));
|
2018-06-14 21:50:30 +08:00
|
|
|
EXPECT_THAT("ccm", Not(matches("cacmelCase")));
|
2017-12-02 01:08:02 +08:00
|
|
|
EXPECT_THAT("bti", Not(matches("the_black_knight")));
|
|
|
|
EXPECT_THAT("ccm", Not(matches("camelCase")));
|
|
|
|
EXPECT_THAT("cmcm", Not(matches("camelCase")));
|
|
|
|
EXPECT_THAT("BK", matches("the_[b]lack_[k]night"));
|
|
|
|
EXPECT_THAT("KeyboardLayout=", Not(matches("KeyboardLayout")));
|
|
|
|
EXPECT_THAT("LLL", matches("SVisual[L]ogger[L]ogs[L]ist"));
|
|
|
|
EXPECT_THAT("LLLL", Not(matches("SVilLoLosLi")));
|
|
|
|
EXPECT_THAT("LLLL", Not(matches("SVisualLoggerLogsList")));
|
|
|
|
EXPECT_THAT("TEdit", matches("[T]ext[Edit]"));
|
|
|
|
EXPECT_THAT("TEdit", matches("[T]ext[Edit]or"));
|
2018-06-14 21:50:30 +08:00
|
|
|
EXPECT_THAT("TEdit", Not(matches("[T]ext[edit]")));
|
2017-12-02 01:08:02 +08:00
|
|
|
EXPECT_THAT("TEdit", matches("[t]ext_[edit]"));
|
2018-06-14 21:50:30 +08:00
|
|
|
EXPECT_THAT("TEditDt", matches("[T]ext[Edit]or[D]ecoration[T]ype"));
|
2017-12-02 01:08:02 +08:00
|
|
|
EXPECT_THAT("TEdit", matches("[T]ext[Edit]orDecorationType"));
|
|
|
|
EXPECT_THAT("Tedit", matches("[T]ext[Edit]"));
|
|
|
|
EXPECT_THAT("ba", Not(matches("?AB?")));
|
|
|
|
EXPECT_THAT("bkn", matches("the_[b]lack_[kn]ight"));
|
2018-06-14 21:50:30 +08:00
|
|
|
EXPECT_THAT("bt", Not(matches("the_[b]lack_knigh[t]")));
|
|
|
|
EXPECT_THAT("ccm", Not(matches("[c]amelCase[cm]")));
|
|
|
|
EXPECT_THAT("fdm", Not(matches("[f]in[dM]odel")));
|
|
|
|
EXPECT_THAT("fob", Not(matches("[fo]o[b]ar")));
|
2017-12-02 01:08:02 +08:00
|
|
|
EXPECT_THAT("fobz", Not(matches("foobar")));
|
|
|
|
EXPECT_THAT("foobar", matches("[foobar]"));
|
|
|
|
EXPECT_THAT("form", matches("editor.[form]atOnSave"));
|
|
|
|
EXPECT_THAT("g p", matches("[G]it:[ P]ull"));
|
|
|
|
EXPECT_THAT("g p", matches("[G]it:[ P]ull"));
|
|
|
|
EXPECT_THAT("gip", matches("[Gi]t: [P]ull"));
|
|
|
|
EXPECT_THAT("gip", matches("[Gi]t: [P]ull"));
|
|
|
|
EXPECT_THAT("gp", matches("[G]it: [P]ull"));
|
|
|
|
EXPECT_THAT("gp", matches("[G]it_Git_[P]ull"));
|
|
|
|
EXPECT_THAT("is", matches("[I]mport[S]tatement"));
|
|
|
|
EXPECT_THAT("is", matches("[is]Valid"));
|
2018-06-14 21:50:30 +08:00
|
|
|
EXPECT_THAT("lowrd", Not(matches("[low]Wo[rd]")));
|
|
|
|
EXPECT_THAT("myvable", Not(matches("[myva]ria[ble]")));
|
2017-12-02 01:08:02 +08:00
|
|
|
EXPECT_THAT("no", Not(matches("")));
|
|
|
|
EXPECT_THAT("no", Not(matches("match")));
|
|
|
|
EXPECT_THAT("ob", Not(matches("foobar")));
|
|
|
|
EXPECT_THAT("sl", matches("[S]Visual[L]oggerLogsList"));
|
2018-06-14 21:50:30 +08:00
|
|
|
EXPECT_THAT("sllll", matches("[S]Visua[L]ogger[Ll]ama[L]ist"));
|
|
|
|
EXPECT_THAT("THRE", matches("H[T]ML[HRE]lement"));
|
2018-03-06 01:34:33 +08:00
|
|
|
EXPECT_THAT("b", Not(matches("NDEBUG")));
|
2017-12-02 01:08:02 +08:00
|
|
|
EXPECT_THAT("Three", matches("[Three]"));
|
|
|
|
EXPECT_THAT("fo", Not(matches("barfoo")));
|
|
|
|
EXPECT_THAT("fo", matches("bar_[fo]o"));
|
|
|
|
EXPECT_THAT("fo", matches("bar_[Fo]o"));
|
|
|
|
EXPECT_THAT("fo", matches("bar [fo]o"));
|
|
|
|
EXPECT_THAT("fo", matches("bar.[fo]o"));
|
|
|
|
EXPECT_THAT("fo", matches("bar/[fo]o"));
|
|
|
|
EXPECT_THAT("fo", matches("bar\\[fo]o"));
|
|
|
|
|
|
|
|
EXPECT_THAT(
|
|
|
|
"aaaaaa",
|
|
|
|
matches("[aaaaaa]aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
|
|
|
|
EXPECT_THAT("baba", Not(matches("ababababab")));
|
|
|
|
EXPECT_THAT("fsfsfs", Not(matches("dsafdsafdsafdsafdsafdsafdsafasdfdsa")));
|
|
|
|
EXPECT_THAT("fsfsfsfsfsfsfsf",
|
|
|
|
Not(matches("dsafdsafdsafdsafdsafdsafdsafasdfdsafdsafdsafdsafdsfd"
|
|
|
|
"safdsfdfdfasdnfdsajfndsjnafjndsajlknfdsa")));
|
|
|
|
|
|
|
|
EXPECT_THAT(" g", matches("[ g]roup"));
|
|
|
|
EXPECT_THAT("g", matches(" [g]roup"));
|
|
|
|
EXPECT_THAT("g g", Not(matches(" groupGroup")));
|
|
|
|
EXPECT_THAT("g g", matches(" [g]roup[ G]roup"));
|
|
|
|
EXPECT_THAT(" g g", matches("[ ] [g]roup[ G]roup"));
|
|
|
|
EXPECT_THAT("zz", matches("[zz]Group"));
|
|
|
|
EXPECT_THAT("zzg", matches("[zzG]roup"));
|
|
|
|
EXPECT_THAT("g", matches("zz[G]roup"));
|
|
|
|
|
|
|
|
EXPECT_THAT("aaaa", matches("_a_[aaaa]")); // Prefer consecutive.
|
2018-03-06 01:34:33 +08:00
|
|
|
// These would ideally match, but would need special segmentation rules.
|
|
|
|
EXPECT_THAT("printf", Not(matches("s[printf]")));
|
|
|
|
EXPECT_THAT("str", Not(matches("o[str]eam")));
|
2018-06-14 21:50:30 +08:00
|
|
|
EXPECT_THAT("strcpy", Not(matches("strncpy")));
|
|
|
|
EXPECT_THAT("std", Not(matches("PTHREAD_MUTEX_STALLED")));
|
|
|
|
EXPECT_THAT("std", Not(matches("pthread_condattr_setpshared")));
|
2017-12-02 01:08:02 +08:00
|
|
|
}
|
|
|
|
|
2019-05-06 18:08:47 +08:00
|
|
|
struct RankMatcher : public ::testing::MatcherInterface<llvm::StringRef> {
|
2017-12-02 01:08:02 +08:00
|
|
|
std::vector<ExpectedMatch> RankedStrings;
|
|
|
|
RankMatcher(std::initializer_list<ExpectedMatch> RankedStrings)
|
|
|
|
: RankedStrings(RankedStrings) {}
|
|
|
|
|
|
|
|
void DescribeTo(::std::ostream *OS) const override {
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::raw_os_ostream O(*OS);
|
2017-12-02 01:08:02 +08:00
|
|
|
O << "Ranks strings in order: [";
|
|
|
|
for (const auto &Str : RankedStrings)
|
|
|
|
O << "\n\t" << Str;
|
|
|
|
O << "\n]";
|
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
bool MatchAndExplain(llvm::StringRef Pattern,
|
2019-05-06 18:08:47 +08:00
|
|
|
::testing::MatchResultListener *L) const override {
|
2019-01-07 23:45:19 +08:00
|
|
|
std::unique_ptr<llvm::raw_ostream> OS(
|
|
|
|
L->stream()
|
|
|
|
? (llvm::raw_ostream *)(new llvm::raw_os_ostream(*L->stream()))
|
|
|
|
: new llvm::raw_null_ostream());
|
2017-12-02 01:08:02 +08:00
|
|
|
FuzzyMatcher Matcher(Pattern);
|
|
|
|
const ExpectedMatch *LastMatch;
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::Optional<float> LastScore;
|
2017-12-02 01:08:02 +08:00
|
|
|
bool Ok = true;
|
|
|
|
for (const auto &Str : RankedStrings) {
|
|
|
|
auto Score = Matcher.match(Str.Word);
|
|
|
|
if (!Score) {
|
|
|
|
*OS << "\nDoesn't match '" << Str.Word << "'";
|
|
|
|
Matcher.dumpLast(*OS << "\n");
|
|
|
|
Ok = false;
|
|
|
|
} else {
|
|
|
|
std::string Buf;
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::raw_string_ostream Info(Buf);
|
2017-12-02 01:08:02 +08:00
|
|
|
auto AnnotatedMatch = Matcher.dumpLast(Info);
|
|
|
|
|
2018-03-06 01:34:33 +08:00
|
|
|
if (!Str.accepts(AnnotatedMatch)) {
|
|
|
|
*OS << "\nDoesn't match " << Str << ", but " << AnnotatedMatch << "\n"
|
2017-12-02 01:08:02 +08:00
|
|
|
<< Info.str();
|
|
|
|
Ok = false;
|
|
|
|
} else if (LastScore && *LastScore < *Score) {
|
|
|
|
*OS << "\nRanks '" << Str.Word << "'=" << *Score << " above '"
|
|
|
|
<< LastMatch->Word << "'=" << *LastScore << "\n"
|
|
|
|
<< Info.str();
|
|
|
|
Matcher.match(LastMatch->Word);
|
|
|
|
Matcher.dumpLast(*OS << "\n");
|
|
|
|
Ok = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LastMatch = &Str;
|
|
|
|
LastScore = Score;
|
|
|
|
}
|
|
|
|
return Ok;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Accepts patterns that match all the strings and rank them in the given order.
|
|
|
|
// Dumps the debug tables on match failure.
|
2019-01-07 23:45:19 +08:00
|
|
|
template <typename... T>
|
2019-05-06 18:08:47 +08:00
|
|
|
::testing::Matcher<llvm::StringRef> ranks(T... RankedStrings) {
|
|
|
|
return ::testing::MakeMatcher<llvm::StringRef>(
|
2017-12-02 01:08:02 +08:00
|
|
|
new RankMatcher{ExpectedMatch(RankedStrings)...});
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FuzzyMatch, Ranking) {
|
|
|
|
EXPECT_THAT("cons",
|
|
|
|
ranks("[cons]ole", "[Cons]ole", "ArrayBuffer[Cons]tructor"));
|
|
|
|
EXPECT_THAT("foo", ranks("[foo]", "[Foo]"));
|
2018-06-14 21:50:30 +08:00
|
|
|
EXPECT_THAT("onMes",
|
|
|
|
ranks("[onMes]sage", "[onmes]sage", "[on]This[M]ega[Es]capes"));
|
[clangd] Tune the fuzzy-matching algorithm
Summary:
To reduce the gap between prefix and initialism matches.
The motivation is producing better scoring in one particular example,
but the change does not seem to cause large regressions in other cases.
The examples is matching 'up' against 'unique_ptr' and 'upper_bound'.
Before the change, we had:
- "[u]nique_[p]tr" with a score of 0.3,
- "[up]per_bound" with a score of 1.0.
A 3x difference meant that symbol quality signals were almost always ignored
and 'upper_bound' was always ranked higher.
However, intuitively, the match scores should be very close for the two.
After the change we have the following scores:
- "[u]nique_[p]tr" with a score of 0.75,
- "[up]per_bound" with a score of 1.0.
Reviewers: ioeric
Reviewed By: ioeric
Subscribers: MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D59300
llvm-svn: 356261
2019-03-15 22:00:49 +08:00
|
|
|
EXPECT_THAT("onmes",
|
|
|
|
ranks("[onmes]sage", "[onMes]sage", "[on]This[M]ega[Es]capes"));
|
2017-12-02 01:08:02 +08:00
|
|
|
EXPECT_THAT("CC", ranks("[C]amel[C]ase", "[c]amel[C]ase"));
|
|
|
|
EXPECT_THAT("cC", ranks("[c]amel[C]ase", "[C]amel[C]ase"));
|
2018-06-06 20:38:37 +08:00
|
|
|
EXPECT_THAT("p", ranks("[p]", "[p]arse", "[p]osix", "[p]afdsa", "[p]ath"));
|
2017-12-02 01:08:02 +08:00
|
|
|
EXPECT_THAT("pa", ranks("[pa]rse", "[pa]th", "[pa]fdsa"));
|
|
|
|
EXPECT_THAT("log", ranks("[log]", "Scroll[Log]icalPosition"));
|
|
|
|
EXPECT_THAT("e", ranks("[e]lse", "Abstract[E]lement"));
|
|
|
|
EXPECT_THAT("workbench.sideb",
|
|
|
|
ranks("[workbench.sideB]ar.location",
|
|
|
|
"[workbench.]editor.default[SideB]ySideLayout"));
|
|
|
|
EXPECT_THAT("editor.r", ranks("[editor.r]enderControlCharacter",
|
|
|
|
"[editor.]overview[R]ulerlanes",
|
|
|
|
"diff[Editor.r]enderSideBySide"));
|
|
|
|
EXPECT_THAT("-mo", ranks("[-mo]z-columns", "[-]ms-ime-[mo]de"));
|
|
|
|
EXPECT_THAT("convertModelPosition",
|
|
|
|
ranks("[convertModelPosition]ToViewPosition",
|
|
|
|
"[convert]ViewTo[ModelPosition]"));
|
|
|
|
EXPECT_THAT("is", ranks("[is]ValidViewletId", "[i]mport [s]tatement"));
|
2018-06-14 21:50:30 +08:00
|
|
|
EXPECT_THAT("strcpy", ranks("[strcpy]", "[strcpy]_s"));
|
2017-12-02 01:08:02 +08:00
|
|
|
}
|
|
|
|
|
2018-06-06 20:38:37 +08:00
|
|
|
// Verify some bounds so we know scores fall in the right range.
|
|
|
|
// Testing exact scores is fragile, so we prefer Ranking tests.
|
|
|
|
TEST(FuzzyMatch, Scoring) {
|
[clangd] Tune the fuzzy-matching algorithm
Summary:
To reduce the gap between prefix and initialism matches.
The motivation is producing better scoring in one particular example,
but the change does not seem to cause large regressions in other cases.
The examples is matching 'up' against 'unique_ptr' and 'upper_bound'.
Before the change, we had:
- "[u]nique_[p]tr" with a score of 0.3,
- "[up]per_bound" with a score of 1.0.
A 3x difference meant that symbol quality signals were almost always ignored
and 'upper_bound' was always ranked higher.
However, intuitively, the match scores should be very close for the two.
After the change we have the following scores:
- "[u]nique_[p]tr" with a score of 0.75,
- "[up]per_bound" with a score of 1.0.
Reviewers: ioeric
Reviewed By: ioeric
Subscribers: MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D59300
llvm-svn: 356261
2019-03-15 22:00:49 +08:00
|
|
|
EXPECT_THAT("abs", matches("[a]w[B]xYz[S]", 7.f / 12.f));
|
2018-06-06 20:38:37 +08:00
|
|
|
EXPECT_THAT("abs", matches("[abs]l", 1.f));
|
|
|
|
EXPECT_THAT("abs", matches("[abs]", 2.f));
|
|
|
|
EXPECT_THAT("Abs", matches("[abs]", 2.f));
|
|
|
|
}
|
|
|
|
|
[clangd] Tune the fuzzy-matching algorithm
Summary:
To reduce the gap between prefix and initialism matches.
The motivation is producing better scoring in one particular example,
but the change does not seem to cause large regressions in other cases.
The examples is matching 'up' against 'unique_ptr' and 'upper_bound'.
Before the change, we had:
- "[u]nique_[p]tr" with a score of 0.3,
- "[up]per_bound" with a score of 1.0.
A 3x difference meant that symbol quality signals were almost always ignored
and 'upper_bound' was always ranked higher.
However, intuitively, the match scores should be very close for the two.
After the change we have the following scores:
- "[u]nique_[p]tr" with a score of 0.75,
- "[up]per_bound" with a score of 1.0.
Reviewers: ioeric
Reviewed By: ioeric
Subscribers: MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D59300
llvm-svn: 356261
2019-03-15 22:00:49 +08:00
|
|
|
TEST(FuzzyMatch, InitialismAndPrefix) {
|
|
|
|
// We want these scores to be roughly the same.
|
|
|
|
EXPECT_THAT("up", matches("[u]nique_[p]tr", 3.f / 4.f));
|
|
|
|
EXPECT_THAT("up", matches("[up]per_bound", 1.f));
|
|
|
|
}
|
|
|
|
|
2018-07-20 16:01:37 +08:00
|
|
|
// Returns pretty-printed segmentation of Text.
|
|
|
|
// e.g. std::basic_string --> +-- +---- +-----
|
2019-01-07 23:45:19 +08:00
|
|
|
std::string segment(llvm::StringRef Text) {
|
2018-07-20 16:01:37 +08:00
|
|
|
std::vector<CharRole> Roles(Text.size());
|
|
|
|
calculateRoles(Text, Roles);
|
|
|
|
std::string Printed;
|
|
|
|
for (unsigned I = 0; I < Text.size(); ++I)
|
|
|
|
Printed.push_back("?-+ "[static_cast<unsigned>(Roles[I])]);
|
|
|
|
return Printed;
|
|
|
|
}
|
|
|
|
|
|
|
|
// this is a no-op hack so clang-format will vertically align our testcases.
|
2020-01-29 06:30:02 +08:00
|
|
|
std::string returns(llvm::StringRef Text) { return std::string(Text); }
|
2018-07-20 16:01:37 +08:00
|
|
|
|
|
|
|
TEST(FuzzyMatch, Segmentation) {
|
|
|
|
EXPECT_THAT(segment("std::basic_string"), //
|
|
|
|
returns("+-- +---- +-----"));
|
|
|
|
EXPECT_THAT(segment("XMLHttpRequest"), //
|
|
|
|
returns("+--+---+------"));
|
|
|
|
EXPECT_THAT(segment("t3h PeNgU1N oF d00m!!!!!!!!"), //
|
|
|
|
returns("+-- +-+-+-+ ++ +--- "));
|
|
|
|
}
|
|
|
|
|
2017-12-02 01:08:02 +08:00
|
|
|
} // namespace
|
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|