File: Utils.cs
Web Access
Project: src\tools-local\Microsoft.ML.InternalCodeAnalyzer\Microsoft.ML.InternalCodeAnalyzer.csproj (Microsoft.ML.InternalCodeAnalyzer)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
namespace Microsoft.ML.InternalCodeAnalyzer
{
    internal static class Utils
    {
        /// <summary>
        /// Checks whether a name is properly <c>camelCased</c> or <c>PascalCased</c>.
        /// Also disallows things like <c>HTMLStream<c> while preferring <c>IOStream</c>.
        /// </summary>
        /// <param name="name">The symbol name to analyze</param>
        /// <param name="min">The position in the name to start</param>
        /// <param name="upper">Whether it should be <c>PascalCased</c></param>
        /// <returns>Whether this name is good</returns>
        public static bool NameIsGood(string name, int min, bool upper)
        {
            // C# naming guidelines say, any initialism greater than two characters should not
            // be all upper cased. So: _readIOStream is good, and _readHttpStream is good. You
            // could imagine having two two-letter initialisms, like: _readIOUI, where you use
            // two two character initialism, but I'm going to suppose that never happens since
            // if someone is doing that, that's pretty odd. The upshot is: 
            const int maxConsecutive = 3;
            // Force the first after the _ to be lower case.
            int consecutive = upper ? 0 : maxConsecutive;
            // Specific to numbers. You could imagine counterexamples, like, say, d3js. Should
            // we be even more strict, and say that the numbers should only appear potentially
            // in suffixes?
            for (int i = min; i < name.Length; ++i)
            {
                char c = name[i];
                // Only letters and digits.
                if (!char.IsLetterOrDigit(c))
                    return false;
                if (char.IsDigit(c))
                {
                    // Consider digits as being effectively upper case letters, where they appear.
                    upper = false;
                    consecutive = 0;
                    continue;
                }
                if (char.IsUpper(c))
                {
                    upper = false;
                    if (++consecutive > maxConsecutive)
                        return false;
                    continue;
                }
                if (upper)
                    return false;
                consecutive = 0;
            }
            // Don't allow maxConsecutive on the end. So: IOStream is fine, but IOS is not.
            return consecutive < maxConsecutive;
        }
    }
}