internal static ImmutableArray <Words> GetBaseNames(ITypeSymbol type, bool pluralize)
            {
                var baseName = TryRemoveInterfacePrefix(type);
                var parts    = StringBreaker.GetWordParts(baseName);
                var result   = GetInterleavedPatterns(parts, baseName, pluralize);

                parts.Free();
                return(result);
            }
예제 #2
0
        public static IdentifierNameParts CreateIdentifierNameParts(ISymbol symbol, ImmutableArray <NamingRule> rules)
        {
            var baseName = RemovePrefixesAndSuffixes(symbol, rules, symbol.Name);

            var parts = StringBreaker.GetWordParts(baseName);
            var words = CreateWords(parts, baseName);

            return(new IdentifierNameParts(baseName, words));
        }
            internal static ImmutableArray <Words> GetBaseNames(IAliasSymbol alias)
            {
                var name = alias.Name;

                if (alias.Target.IsType && (((INamedTypeSymbol)alias.Target).IsInterfaceType() &&
                                            CanRemoveInterfacePrefix(name)))
                {
                    name = name.Substring(1);
                }

                var breaks = StringBreaker.GetWordParts(name);
                var result = GetInterleavedPatterns(breaks, name, pluralize: false);

                breaks.Free();
                return(result);
            }
예제 #4
0
        private PatternMatch?NonFuzzyMatchPatternChunk(
            string candidate,
            TextChunk patternChunk,
            bool punctuationStripped)
        {
            var candidateLength = candidate.Length;

            var caseInsensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.IgnoreCase);

            if (caseInsensitiveIndex == 0)
            {
                // We found the pattern at the start of the candidate.  This is either an exact or
                // prefix match.

                if (patternChunk.Text.Length == candidateLength)
                {
                    // Lengths were the same, this is either a case insensitive or sensitive exact match.
                    return(new PatternMatch(
                               PatternMatchKind.Exact, punctuationStripped, isCaseSensitive: candidate == patternChunk.Text,
                               matchedSpan: GetMatchedSpan(0, candidateLength)));
                }
                else
                {
                    // Lengths were the same, this is either a case insensitive or sensitive prefix match.
                    return(new PatternMatch(
                               PatternMatchKind.Prefix, punctuationStripped, isCaseSensitive: _compareInfo.IsPrefix(candidate, patternChunk.Text),
                               matchedSpan: GetMatchedSpan(0, patternChunk.Text.Length)));
                }
            }

            ArrayBuilder <TextSpan> candidateHumpsOpt = null;

            try
            {
                var patternIsLowercase = patternChunk.IsLowercase;
                if (caseInsensitiveIndex > 0)
                {
                    // We found the pattern somewhere in the candidate.  This could be a substring match.
                    // However, we don't want to be overaggressive in returning just any substring results.
                    // So do a few more checks to make sure this is a good result.

                    if (!patternIsLowercase)
                    {
                        // Pattern contained uppercase letters.  This is a strong indication from the
                        // user that they expect the same letters to be uppercase in the result.  As
                        // such, only return this if we can find this pattern exactly in the candidate.

                        var caseSensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.None);
                        if (caseSensitiveIndex > 0)
                        {
                            return(new PatternMatch(
                                       PatternMatchKind.Substring, punctuationStripped, isCaseSensitive: true,
                                       matchedSpan: GetMatchedSpan(caseSensitiveIndex, patternChunk.Text.Length)));
                        }
                    }
                    else
                    {
                        // Pattern was all lowercase.  This can lead to lots of false positives.  For
                        // example, we don't want "bin" to match "CombineUnits".  Instead, we want it
                        // to match "BinaryOperator".  As such, make sure our match looks like it's
                        // starting an actual word in the candidate.

                        // Do a quick check to avoid the expensive work of having to go get the candidate
                        // humps.
                        if (char.IsUpper(candidate[caseInsensitiveIndex]))
                        {
                            return(new PatternMatch(PatternMatchKind.Substring, punctuationStripped,
                                                    isCaseSensitive: false,
                                                    matchedSpan: GetMatchedSpan(caseInsensitiveIndex, patternChunk.Text.Length)));
                        }

                        candidateHumpsOpt = StringBreaker.GetWordParts(candidate);
                        for (int i = 0, n = candidateHumpsOpt.Count; i < n; i++)
                        {
                            var hump = TextSpan.FromBounds(candidateHumpsOpt[i].Start, candidateLength);
                            if (PartStartsWith(candidate, hump, patternChunk.Text, CompareOptions.IgnoreCase))
                            {
                                return(new PatternMatch(PatternMatchKind.Substring, punctuationStripped,
                                                        isCaseSensitive: PartStartsWith(candidate, hump, patternChunk.Text, CompareOptions.None),
                                                        matchedSpan: GetMatchedSpan(hump.Start, patternChunk.Text.Length)));
                            }
                        }
                    }
                }

                // Didn't have an exact/prefix match, or a high enough quality substring match.
                // See if we can find a camel case match.
                if (candidateHumpsOpt == null)
                {
                    candidateHumpsOpt = StringBreaker.GetWordParts(candidate);
                }

                // Didn't have an exact/prefix match, or a high enough quality substring match.
                // See if we can find a camel case match.
                return(TryCamelCaseMatch(
                           candidate, patternChunk, punctuationStripped, patternIsLowercase, candidateHumpsOpt));
            }
            finally
            {
                candidateHumpsOpt?.Free();
            }
        }
예제 #5
0
 private static ImmutableArray <string> BreakIntoWordParts(string identifier)
 => PartListToSubstrings(identifier, StringBreaker.GetWordParts(identifier));
예제 #6
0
        private PatternMatch?NonFuzzyMatchPatternChunk(
            string candidate,
            TextChunk patternChunk,
            bool punctuationStripped)
        {
            var candidateLength = candidate.Length;

            var caseInsensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.IgnoreCase);

            if (caseInsensitiveIndex == 0)
            {
                // We found the pattern at the start of the candidate.  This is either an exact or
                // prefix match.

                if (patternChunk.Text.Length == candidateLength)
                {
                    // Lengths were the same, this is either a case insensitive or sensitive exact match.
                    return(new PatternMatch(
                               PatternMatchKind.Exact, punctuationStripped, isCaseSensitive: candidate == patternChunk.Text,
                               matchedSpan: GetMatchedSpan(0, candidateLength)));
                }
                else
                {
                    // Lengths were the same, this is either a case insensitive or sensitive prefix match.
                    return(new PatternMatch(
                               PatternMatchKind.Prefix, punctuationStripped, isCaseSensitive: _compareInfo.IsPrefix(candidate, patternChunk.Text),
                               matchedSpan: GetMatchedSpan(0, patternChunk.Text.Length)));
                }
            }

            ArrayBuilder <TextSpan> candidateHumpsOpt = null;

            try
            {
                var patternIsLowercase = patternChunk.IsLowercase;
                if (caseInsensitiveIndex > 0)
                {
                    // We found the pattern somewhere in the candidate.  This could be a substring match.
                    // However, we don't want to be overaggressive in returning just any substring results.
                    // So do a few more checks to make sure this is a good result.

                    if (!patternIsLowercase)
                    {
                        // Pattern contained uppercase letters.  This is a strong indication from the
                        // user that they expect the same letters to be uppercase in the result.  As
                        // such, only return this if we can find this pattern exactly in the candidate.

                        var caseSensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.None);
                        if (caseSensitiveIndex > 0)
                        {
                            if (char.IsUpper(candidate[caseInsensitiveIndex]))
                            {
                                return(new PatternMatch(
                                           PatternMatchKind.StartOfWordSubstring, punctuationStripped, isCaseSensitive: true,
                                           matchedSpan: GetMatchedSpan(caseInsensitiveIndex, patternChunk.Text.Length)));
                            }
                            else
                            {
                                return(new PatternMatch(
                                           PatternMatchKind.NonLowercaseSubstring, punctuationStripped, isCaseSensitive: true,
                                           matchedSpan: GetMatchedSpan(caseSensitiveIndex, patternChunk.Text.Length)));
                            }
                        }
                    }
                    else
                    {
                        // Pattern was all lowercase.  This can lead to lots of hits.  For example, "bin" in
                        // "CombineUnits".  Instead, we want it to match "Operator[|Bin|]ary" first rather than
                        // Com[|bin|]eUnits

                        // If the lowercase search string matched what looks to be the start of a word then that's a
                        // reasonable hit. This is equivalent to 'bin' matching 'Operator[|Bin|]ary'
                        if (char.IsUpper(candidate[caseInsensitiveIndex]))
                        {
                            return(new PatternMatch(PatternMatchKind.StartOfWordSubstring, punctuationStripped,
                                                    isCaseSensitive: false,
                                                    matchedSpan: GetMatchedSpan(caseInsensitiveIndex, patternChunk.Text.Length)));
                        }

                        // Now do the more expensive check to see if we're at the start of a word.  This is to catch
                        // word matches like CombineBinary.  We want to find the hit against '[|Bin|]ary' not
                        // 'Com[|bin|]e'
                        candidateHumpsOpt = StringBreaker.GetWordParts(candidate);
                        for (int i = 0, n = candidateHumpsOpt.Count; i < n; i++)
                        {
                            var hump = TextSpan.FromBounds(candidateHumpsOpt[i].Start, candidateLength);
                            if (PartStartsWith(candidate, hump, patternChunk.Text, CompareOptions.IgnoreCase))
                            {
                                return(new PatternMatch(PatternMatchKind.StartOfWordSubstring, punctuationStripped,
                                                        isCaseSensitive: PartStartsWith(candidate, hump, patternChunk.Text, CompareOptions.None),
                                                        matchedSpan: GetMatchedSpan(hump.Start, patternChunk.Text.Length)));
                            }
                        }
                    }
                }

                // Didn't have an exact/prefix match, or a high enough quality substring match.
                // See if we can find a camel case match.
                if (candidateHumpsOpt == null)
                {
                    candidateHumpsOpt = StringBreaker.GetWordParts(candidate);
                }

                // Didn't have an exact/prefix match, or a high enough quality substring match.
                // See if we can find a camel case match.
                var match = TryCamelCaseMatch(candidate, patternChunk, punctuationStripped, patternIsLowercase, candidateHumpsOpt);
                if (match != null)
                {
                    return(match);
                }

                // If pattern was all lowercase, we allow it to match an all lowercase section of the candidate.  But
                // only after we've tried all other forms first.  This is the weakest of all matches.  For example, if
                // user types 'bin' we want to match 'OperatorBinary' (start of word) or 'BinaryInformationNode' (camel
                // humps) before matching 'Combine'.
                //
                // We only do this for strings longer than three characters to avoid too many false positives when the
                // user has only barely started writing a word.
                if (patternIsLowercase && caseInsensitiveIndex > 0 && patternChunk.Text.Length >= 3)
                {
                    var caseSensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.None);
                    if (caseSensitiveIndex > 0)
                    {
                        return(new PatternMatch(
                                   PatternMatchKind.LowercaseSubstring, punctuationStripped, isCaseSensitive: true,
                                   matchedSpan: GetMatchedSpan(caseSensitiveIndex, patternChunk.Text.Length)));
                    }
                }

                return(null);
            }
            finally
            {
                candidateHumpsOpt?.Free();
            }
        }