Fix ranking bug with ALL_CAPS variables

GetWordBoundaryChars would return "allcaps" for "ALL_CAPS" instead of "ac". This
would manifest as ranking (for instance) "STDIN_FILENO" ahead of "stdin" for
query "std", which is terrible.

This bug has been present in YCM for many months, but no one noticed the issue.

Fixes #272.
This commit is contained in:
Strahinja Val Markovic 2013-04-28 13:21:13 -07:00
parent a80739ad6f
commit 387102a99f
4 changed files with 106 additions and 15 deletions

View File

@ -28,21 +28,6 @@ namespace YouCompleteMe {
namespace {
std::string GetWordBoundaryChars( const std::string &text ) {
std::string result;
for ( uint i = 0; i < text.size(); ++i ) {
if ( i == 0 ||
IsUppercase( text[ i ] ) ||
( i > 0 && text[ i - 1 ] == '_' && isalpha( text[ i ] ) )
) {
result.push_back( tolower( text[ i ] ) );
}
}
return result;
}
LetterNode *FirstUppercaseNode( const std::list< LetterNode *> &list ) {
LetterNode *node = NULL;
foreach( LetterNode * current_node, list ) {
@ -67,6 +52,28 @@ LetterNode *FirstLowercaseNode( const std::list< LetterNode *> &list ) {
} // unnamed namespace
std::string GetWordBoundaryChars( const std::string &text ) {
std::string result;
for ( uint i = 0; i < text.size(); ++i ) {
bool is_first_char_but_not_underscore = i == 0 && text[ i ] != '_';
bool is_good_uppercase = i > 0 &&
IsUppercase( text[ i ] ) &&
!IsUppercase( text[ i - 1 ] );
bool is_alpha_after_underscore = i > 0 &&
text[ i - 1 ] == '_' &&
isalpha( text[ i ] );
if ( is_first_char_but_not_underscore ||
is_good_uppercase ||
is_alpha_after_underscore ) {
result.push_back( tolower( text[ i ] ) );
}
}
return result;
}
Bitset LetterBitsetFromString( const std::string &text ) {
Bitset letter_bitset;

View File

@ -34,6 +34,9 @@ typedef std::bitset< NUM_LETTERS > Bitset;
Bitset LetterBitsetFromString( const std::string &text );
// Public for tests
std::string GetWordBoundaryChars( const std::string &text );
class Candidate : boost::noncopyable {
public:

View File

@ -21,6 +21,78 @@
namespace YouCompleteMe {
TEST( GetWordBoundaryCharsTest, SimpleOneWord ) {
EXPECT_EQ( "s", GetWordBoundaryChars( "simple" ) );
}
TEST( GetWordBoundaryCharsTest, UnderscoreInMiddle ) {
EXPECT_EQ( "sf", GetWordBoundaryChars( "simple_foo" ) );
}
TEST( GetWordBoundaryCharsTest, UnderscoreStart ) {
EXPECT_EQ( "s", GetWordBoundaryChars( "_simple" ) );
}
TEST( GetWordBoundaryCharsTest, ManyUnderscoreStart ) {
EXPECT_EQ( "s", GetWordBoundaryChars( "___simple" ) );
}
TEST( GetWordBoundaryCharsTest, UnderscoreStartAndInMiddle ) {
EXPECT_EQ( "sf", GetWordBoundaryChars( "_simple_foo" ) );
}
TEST( GetWordBoundaryCharsTest, ManyUnderscoreStartAndInMiddle ) {
EXPECT_EQ( "sf", GetWordBoundaryChars( "___simple__foo" ) );
}
TEST( GetWordBoundaryCharsTest, SimpleCapitalStart ) {
EXPECT_EQ( "s", GetWordBoundaryChars( "Simple" ) );
}
TEST( GetWordBoundaryCharsTest, SimpleCapitalTwoWord ) {
EXPECT_EQ( "ss", GetWordBoundaryChars( "SimpleStuff" ) );
}
TEST( GetWordBoundaryCharsTest, SimpleCapitalTwoWordUnderscoreMiddle ) {
EXPECT_EQ( "ss", GetWordBoundaryChars( "Simple_Stuff" ) );
}
TEST( GetWordBoundaryCharsTest, JavaCase ) {
EXPECT_EQ( "ssf", GetWordBoundaryChars( "simpleStuffFoo" ) );
}
TEST( GetWordBoundaryCharsTest, UppercaseSequence ) {
EXPECT_EQ( "ss", GetWordBoundaryChars( "simpleSTUFF" ) );
}
TEST( GetWordBoundaryCharsTest, UppercaseSequenceInMiddle ) {
EXPECT_EQ( "ss", GetWordBoundaryChars( "simpleSTUFFfoo" ) );
}
TEST( GetWordBoundaryCharsTest, UppercaseSequenceInMiddleUnderscore ) {
EXPECT_EQ( "ssf", GetWordBoundaryChars( "simpleSTUFF_Foo" ) );
}
TEST( GetWordBoundaryCharsTest, UppercaseSequenceInMiddleUnderscoreLowercase ) {
EXPECT_EQ( "ssf", GetWordBoundaryChars( "simpleSTUFF_foo" ) );
}
TEST( GetWordBoundaryCharsTest, AllCapsSimple ) {
EXPECT_EQ( "s", GetWordBoundaryChars( "SIMPLE" ) );
}
TEST( GetWordBoundaryCharsTest, AllCapsUnderscoreStart ) {
EXPECT_EQ( "s", GetWordBoundaryChars( "_SIMPLE" ) );
}
TEST( GetWordBoundaryCharsTest, AllCapsUnderscoreMiddle ) {
EXPECT_EQ( "ss", GetWordBoundaryChars( "SIMPLE_STUFF" ) );
}
TEST( GetWordBoundaryCharsTest, AllCapsUnderscoreMiddleAndStart ) {
EXPECT_EQ( "ss", GetWordBoundaryChars( "_SIMPLE_STUFF" ) );
}
TEST( CandidateTest, TextValid ) {
std::string text = "foo";
Candidate candidate( text );

View File

@ -207,6 +207,15 @@ TEST( IdentifierCompleterTest, SameLowercaseCandidateWins ) {
"Foobar" ) );
}
TEST( IdentifierCompleterTest, ShorterAndLowercaseWins ) {
EXPECT_THAT( IdentifierCompleter(
StringVector(
"STDIN_FILENO",
"stdin" ) ).CandidatesForQuery( "std" ),
ElementsAre( "stdin",
"STDIN_FILENO" ) );
}
// TODO: tests for filepath and filetype candidate storing
} // namespace YouCompleteMe