/// <summary>
        /// Adds all members of a class to a dictionary, taking into account partial classes.
        /// </summary>
        /// <param name="parentClass">
        /// The class to collect. 
        /// </param>
        /// <returns>
        /// Returns the dictionary of class members. 
        /// </returns>
        public static Dictionary<string, List<CsElement>> CollectClassMembers(ClassBase parentClass)
        {
            Param.AssertNotNull(parentClass, "parentClass");

            Dictionary<string, List<CsElement>> members = new Dictionary<string, List<CsElement>>();

            if (parentClass.Declaration.ContainsModifier(CsTokenType.Partial))
            {
                foreach (ClassBase @class in parentClass.PartialElementList)
                {
                    CollectClassMembersAux(@class, members);
                }
            }
            else
            {
                CollectClassMembersAux(parentClass, members);
            }

            return members;
        }
Example #2
0
        /// <summary>
        /// Finds the given class member in the given class.
        /// </summary>
        /// <param name="word">
        /// The word to check.
        /// </param>
        /// <param name="parentClass">
        /// The class the word appears in.
        /// </param>
        /// <param name="members">
        /// The collection of members of the parent class.
        /// </param>
        /// <param name="interfaces">
        /// True if interface implementations should be included.
        /// </param>
        /// <returns>
        /// Returns the class members that match against the given name.
        /// </returns>
        public static ICollection <CsElement> FindClassMember(string word, ClassBase parentClass, Dictionary <string, List <CsElement> > members, bool interfaces)
        {
            Param.AssertNotNull(word, "word");
            Param.AssertNotNull(parentClass, "parentClass");
            Param.AssertNotNull(members, "members");
            Param.Ignore(interfaces);

            // If the word is the same as the class name, then this is a constructor and we
            // don't want to match against it.
            if (word != parentClass.Declaration.Name)
            {
                ICollection <CsElement> matches = MatchClassMember(word, members, interfaces);
                if (matches != null && matches.Count > 0)
                {
                    return(matches);
                }
            }

            return(null);
        }
Example #3
0
        /// <summary>
        /// Adds all members of a class to a dictionary, taking into account partial classes.
        /// </summary>
        /// <param name="parentClass">
        /// The class to collect.
        /// </param>
        /// <returns>
        /// Returns the dictionary of class members.
        /// </returns>
        public static Dictionary <string, List <CsElement> > CollectClassMembers(ClassBase parentClass)
        {
            Param.AssertNotNull(parentClass, "parentClass");

            Dictionary <string, List <CsElement> > members = new Dictionary <string, List <CsElement> >();

            if (parentClass.Declaration.ContainsModifier(CsTokenType.Partial))
            {
                foreach (ClassBase @class in parentClass.PartialElementList)
                {
                    CollectClassMembersAux(@class, members);
                }
            }
            else
            {
                CollectClassMembersAux(parentClass, members);
            }

            return(members);
        }
        /// <summary>
        /// Parses the given statement list.
        /// </summary>
        /// <param name="statements">
        /// The list of statements to parse.
        /// </param>
        /// <param name="parentElement">
        /// The element that contains the statements.
        /// </param>
        /// <param name="parentClass">
        /// The class that the element belongs to.
        /// </param>
        /// <param name="members">
        /// The collection of members of the parent class.
        /// </param>
        private void CheckClassMemberRulesForStatements(
            ICollection <Statement> statements, CsElement parentElement, ClassBase parentClass, Dictionary <string, List <CsElement> > members)
        {
            Param.AssertNotNull(statements, "statements");
            Param.AssertNotNull(parentElement, "parentElement");
            Param.Ignore(parentClass);
            Param.Ignore(members);

            // Loop through each of the statements.
            foreach (Statement statement in statements)
            {
                if (statement.ChildStatements.Count > 0)
                {
                    // Parse the sub-statements.
                    this.CheckClassMemberRulesForStatements(statement.ChildStatements, parentElement, parentClass, members);
                }

                // Parse the expressions in the statement.
                this.CheckClassMemberRulesForExpressions(statement.ChildExpressions, null, parentElement, parentClass, members);
            }
        }
        /// <summary>
        /// Checks the items within the given element.
        /// </summary>
        /// <param name="element">
        /// The element to check. 
        /// </param>
        /// <param name="parentClass">
        /// The class that the element belongs to. 
        /// </param>
        /// <param name="members">
        /// The collection of members of the parent class. 
        /// </param>
        /// <returns>
        /// Returns false if the analyzer should quit. 
        /// </returns>
        private bool CheckClassMemberRulesForElements(CsElement element, ClassBase parentClass, Dictionary<string, List<CsElement>> members)
        {
            Param.AssertNotNull(element, "element");
            Param.Ignore(parentClass);
            Param.Ignore(members);

            // Check whether processing has been cancelled by the user.
            if (this.Cancel)
            {
                return false;
            }

            if (element.ElementType == ElementType.Class || element.ElementType == ElementType.Struct || element.ElementType == ElementType.Interface)
            {
                parentClass = element as ClassBase;
                members = Utils.CollectClassMembers(parentClass);
            }

            foreach (CsElement child in element.ChildElements)
            {
                if (!child.Generated)
                {
                    if (child.ElementType == ElementType.Method || child.ElementType == ElementType.Constructor || child.ElementType == ElementType.Destructor
                        || child.ElementType == ElementType.Accessor || !child.HasBody)
                    {
                        // If the parent class is null, then this element is sitting outside of a class.
                        // This is illegal in C# so the code will not compile, but we still attempt to
                        // parse it. In this case there is no use of this prefixes since there is no class.
                        if (parentClass != null)
                        {
                            this.CheckClassMemberRulesForStatements(child.ChildStatements, child, parentClass, members);
                        }
                    }
                    else
                    {
                        if (child.ElementType == ElementType.Class || child.ElementType == ElementType.Struct)
                        {
                            ClassBase elementContainer = child as ClassBase;
                            Debug.Assert(elementContainer != null, "The element is not a class.");

                            this.CheckClassMemberRulesForElements(child, elementContainer, members);
                        }
                        else if (!this.CheckClassMemberRulesForElements(child, parentClass, members))
                        {
                            return false;
                        }
                    }
                }
            }

            return true;
        }
        /// <summary>
        /// Checks a token to see if it should be prefixed (with this. or maybe another prefix).
        /// </summary>
        /// <param name="expression">
        /// The expression the word appears within.
        /// </param>
        /// <param name="parentClass">
        /// The parent class that this element belongs to.
        /// </param>
        /// <param name="matchesForPassedMethod">
        /// Matches for the passed-in version of the member name.
        /// </param>
        /// <param name="matchesForGenericMethod">
        /// The matches for the generic version of the member name.
        /// </param>
        /// <param name="memberName">
        /// The name of the member to check.
        /// </param>
        /// <returns>
        /// True if the prefix is required otherwise false.
        /// </returns>
        private static bool IsThisRequiredFromMemberList(
            Expression expression, ClassBase parentClass, IEnumerable<CsElement> matchesForPassedMethod, IEnumerable<CsElement> matchesForGenericMethod, string memberName)
        {
            if (matchesForPassedMethod != null)
            {
                return IsThisRequiredFromMemberList(matchesForPassedMethod);
            }

            if (matchesForGenericMethod != null)
            {
                return IsThisRequiredFromMemberList(matchesForGenericMethod);
            }

            if (parentClass.BaseClass != string.Empty)
            {
                if (Utils.IsExpressionInsideContainer(
                    expression,
                    typeof(NullConditionExpression),
                    typeof(TypeofExpression),
                    typeof(IsExpression),
                    typeof(CastExpression),
                    typeof(AsExpression),
                    typeof(NewExpression),
                    typeof(NewArrayExpression),
                    typeof(MemberAccessExpression),
                    typeof(DefaultValueExpression),
                    typeof(VariableDeclarationExpression)))
                {
                    return false;
                }

                if (expression.Parent is CatchStatement || expression.Parent is LabelStatement || expression.Parent is GotoStatement)
                {
                    return false;
                }

                return true;
            }

            if (parentClass.BaseClass == string.Empty && memberName == "Equals")
            {
                return true;
            }

            return false;
        }
Example #7
0
 /// <summary>
 /// Returns True if this class or any of its Partial Classes has a BaseClass specified.
 /// </summary>
 /// <param name="classBase">
 /// The class to check.
 /// </param>
 /// <returns>
 /// True if it finds a BaseClass.
 /// </returns>
 public static bool HasABaseClassSpecified(ClassBase classBase)
 {
     return(!string.IsNullOrEmpty(classBase.BaseClass) ||
            (classBase.PartialElementList != null && classBase.PartialElementList.OfType <Class>().Any(d => !string.IsNullOrEmpty(d.BaseClass))));
 }
        /// <summary>
        /// Parses the given expression.
        /// </summary>
        /// <param name="expression">
        /// The expression.
        /// </param>
        /// <param name="parentExpression">
        /// The parent expression, if there is one.
        /// </param>
        /// <param name="parentElement">
        /// The element that contains the expressions.
        /// </param>
        /// <param name="parentClass">
        /// The class that the element belongs to.
        /// </param>
        /// <param name="members">
        /// The collection of members of the parent class.
        /// </param>
        private void CheckClassMemberRulesForExpression(
            Expression expression, Expression parentExpression, CsElement parentElement, ClassBase parentClass, Dictionary <string, List <CsElement> > members)
        {
            Param.AssertNotNull(expression, "expression");
            Param.Ignore(parentExpression);
            Param.AssertNotNull(parentElement, "parentElement");
            Param.AssertNotNull(parentClass, "parentClass");
            Param.AssertNotNull(members, "members");

            if (expression.ExpressionType == ExpressionType.Literal)
            {
                LiteralExpression literalExpression = (LiteralExpression)expression;

                // Check to see whether this literal is preceded by a member access symbol. If not
                // then we want to check whether this is a reference to one of our class members.
                if (!IsLiteralTokenPrecededByMemberAccessSymbol(literalExpression.TokenNode, expression.Tokens.MasterList))
                {
                    // Process the literal.
                    this.CheckClassMemberRulesForLiteralToken(literalExpression.TokenNode, expression, parentExpression, parentElement, parentClass, members);
                }
            }
            else
            {
                if (expression.ExpressionType == ExpressionType.Assignment && parentExpression != null &&
                    parentExpression.ExpressionType == ExpressionType.CollectionInitializer)
                {
                    // When we encounter assignment expressions within collection initializer expressions, we ignore the expression
                    // on the left-hand side of the assignment. This is because we know that the left-hand side refers to a property on
                    // the type being initialized, not a property on the local class. Thus, it does not ever need to be prefixed by this.
                    // Without this check we can get name collisions, such as:
                    // public sealed class Person
                    //// {
                    ////     public string FirstName { get; }
                    ////     public void CreateAnonymousType()
                    ////     {
                    ////         var anonymousType = new { FirstName = this.FirstName };
                    ////     }
                    //// }
                    this.CheckClassMemberRulesForExpression(((AssignmentExpression)expression).RightHandSide, expression, parentElement, parentClass, members);
                }
                else if (expression.ChildExpressions.Count > 0)
                {
                    // Check each child expression within this expression.
                    this.CheckClassMemberRulesForExpressions(expression.ChildExpressions, expression, parentElement, parentClass, members);
                }

                // Check if this is an anonymous method expression, which contains a child statement list.
                if (expression.ExpressionType == ExpressionType.AnonymousMethod)
                {
                    // Check the statements under this anonymous method.
                    this.CheckClassMemberRulesForStatements(expression.ChildStatements, parentElement, parentClass, members);
                }
                else if (expression.ExpressionType == ExpressionType.MethodInvocation)
                {
                    // Check each of the arguments passed into the method call.
                    MethodInvocationExpression methodInvocation = (MethodInvocationExpression)expression;
                    foreach (Argument argument in methodInvocation.Arguments)
                    {
                        // Check each expression within this child expression.
                        if (argument.Expression.ExpressionType != ExpressionType.MethodInvocation)
                        {
                            this.CheckClassMemberRulesForExpression(argument.Expression, null, parentElement, parentClass, members);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Calculates whether the base prefix is required.
        /// </summary>
        /// <param name="memberName">
        /// The text of the method call to check. 
        /// </param>
        /// <param name="parentClass">
        /// The class this this member belongs to. 
        /// </param>
        /// <param name="members">
        /// All the members of this class. 
        /// </param>
        /// <returns>
        /// True if base is required otherwise false. 
        /// </returns>
        private bool IsBaseRequired(string memberName, ClassBase parentClass, Dictionary<string, List<CsElement>> members)
        {
            // An item is only allowed to start with base if there is an implementation of the
            // item in the local class and the caller is trying to explicitly call the base
            // class implementation instead of the local class implementation.
            bool memberNameHasGeneric = memberName.IndexOf('<') > -1;

            bool overrideOnTrimmedMethod = false;
            bool overrideOnGenericMethod = false;
            bool overrideOnPassedMethod = false;

            bool newOnPassedMethod = false;
            bool newOnGenericMethod = false;

            ICollection<CsElement> matchesForTrimmedMethod = null;
            ICollection<CsElement> matchesForGenericMethod = null;
            ICollection<CsElement> matchesForPassedMethod = Utils.FindClassMember(memberName, parentClass, members, true);

            if (memberNameHasGeneric)
            {
                string trimmedName = memberName.Substring(0, memberName.IndexOf('<'));

                matchesForTrimmedMethod = Utils.FindClassMember(trimmedName, parentClass, members, true);

                if (matchesForTrimmedMethod != null)
                {
                    foreach (CsElement match in matchesForTrimmedMethod)
                    {
                        if (match.Declaration.ContainsModifier(CsTokenType.Override))
                        {
                            overrideOnTrimmedMethod = true;
                            break;
                        }
                    }
                }
            }
            else
            {
                matchesForGenericMethod = Utils.FindClassMember(memberName + "<T>", parentClass, members, true);

                if (matchesForGenericMethod != null)
                {
                    foreach (CsElement match in matchesForGenericMethod)
                    {
                        if (match.Declaration.ContainsModifier(CsTokenType.Override))
                        {
                            overrideOnGenericMethod = true;
                        }

                        if (match.Declaration.ContainsModifier(CsTokenType.New))
                        {
                            newOnGenericMethod = true;
                        }
                    }
                }
            }

            // We check for a method marked override and a method marked new
            if (matchesForPassedMethod != null)
            {
                foreach (CsElement match in matchesForPassedMethod)
                {
                    if (match.Declaration.ContainsModifier(CsTokenType.Override))
                    {
                        overrideOnPassedMethod = true;
                    }

                    if (match.Declaration.ContainsModifier(CsTokenType.New))
                    {
                        newOnPassedMethod = true;
                        break;
                    }
                }
            }

            bool baseIsRequired = memberNameHasGeneric && (overrideOnTrimmedMethod || newOnPassedMethod || overrideOnPassedMethod);

            if (!memberNameHasGeneric && (overrideOnPassedMethod || newOnGenericMethod || overrideOnGenericMethod || matchesForPassedMethod != null))
            {
                baseIsRequired = true;
            }

            if (memberNameHasGeneric && (overrideOnTrimmedMethod || matchesForTrimmedMethod != null))
            {
                baseIsRequired = true;
            }

            return baseIsRequired;
        }
        /// <summary>
        /// Parses the given literal token.
        /// </summary>
        /// <param name="tokenNode">
        /// The literal token node. 
        /// </param>
        /// <param name="expression">
        /// The expression that contains the token. 
        /// </param>
        /// <param name="parentExpression">
        /// The parent of the expression that contains the token. 
        /// </param>
        /// <param name="parentElement">
        /// The element that contains the expression. 
        /// </param>
        /// <param name="parentClass">
        /// The class that the element belongs to. 
        /// </param>
        /// <param name="members">
        /// The collection of members of the parent class. 
        /// </param>
        private void CheckClassMemberRulesForLiteralToken(
            Node<CsToken> tokenNode,
            Expression expression,
            Expression parentExpression,
            CsElement parentElement,
            ClassBase parentClass,
            Dictionary<string, List<CsElement>> members)
        {
            Param.AssertNotNull(tokenNode, "token");
            Param.AssertNotNull(expression, "expression");
            Param.Ignore(parentExpression);
            Param.AssertNotNull(parentElement, "parentElement");
            Param.Ignore(parentClass);
            Param.Ignore(members);

            // Skip types. We only care about named members.
            if (!(tokenNode.Value is TypeToken) || tokenNode.Value.CsTokenClass == CsTokenClass.GenericType)
            {
                // If the name starts with a dot, ignore it.
                if (!tokenNode.Value.Text.StartsWith(".", StringComparison.Ordinal))
                {
                    if (tokenNode.Value.Text == "base" && parentExpression != null)
                    {
                        CsToken name = Utils.ExtractBaseClassMemberName(parentExpression, tokenNode);
                        if (name != null)
                        {
                            if (!this.IsBaseRequired(name.Text, parentClass, members))
                            {
                                this.AddViolation(parentElement, name.Location, Rules.DoNotPrefixCallsWithBaseUnlessLocalImplementationExists, name);
                            }
                        }
                    }
                    else if (tokenNode.Value.Text != "this")
                    {
                        if (this.IsThisRequired(tokenNode, expression, parentClass, members))
                        {
                            if ((parentClass.BaseClass != string.Empty) || (tokenNode.Value.Text == "Equals" || tokenNode.Value.Text == "ReferenceEquals"))
                            {
                                string className = parentClass.FullyQualifiedName.SubstringAfterLast('.');

                                if (parentClass.BaseClass != string.Empty)
                                {
                                    className = className + ".' or '" + parentClass.BaseClass;
                                }

                                this.AddViolation(parentElement, tokenNode.Value.Location, Rules.PrefixCallsCorrectly, tokenNode.Value.Text, className);
                            }
                            else
                            {
                                this.AddViolation(parentElement, tokenNode.Value.Location, Rules.PrefixLocalCallsWithThis, tokenNode.Value.Text);
                            }
                        }
                    }
                }
            }
        }
Example #11
0
        /// <summary>
        /// Gets the actual qualified namespace of the class. For nested types where A.B.C.D exists and C.D is the type it returns A.B rather than A.B.C.
        /// </summary>
        /// <param name="type">
        /// The type to get the namespace for.
        /// </param>
        /// <returns>
        /// A string of the actual namespace.
        /// </returns>
        private static string GetActualQualifiedNamespace(ClassBase type)
        {
            Param.AssertNotNull(type, "type");

            CsElement localType = type;
            while (localType.Parent is ClassBase)
            {
                localType = (CsElement)localType.Parent;
            }

            string fullyQualifiedNameOfParentClass = localType.FullyQualifiedName;
            int lastIndexOfDot = fullyQualifiedNameOfParentClass.LastIndexOf('.');

            return lastIndexOfDot == -1 ? string.Empty : fullyQualifiedNameOfParentClass.Substring(0, lastIndexOfDot + 1);
        }
Example #12
0
        /// <summary>
        /// For a type Foo.Bar in namespace A.B this returns (A.B.Foo.Bar | B.Foo.Bar | Foo.Bar | Bar) and (A.B.Foo{E,F}.Bar | B.Foo{E,F}.Bar | Foo{E,F}.Bar | Bar)
        /// </summary>
        /// <param name="type">
        /// The type to build the <see cref="Regex"/> for.
        /// </param>
        /// <param name="regexWithGenerics">
        /// The <see cref="Regex"/> with generics.
        /// </param>
        /// <param name="regexWithoutGenerics">
        /// The <see cref="Regex"/> without generics.
        /// </param>
        private static void BuildRegExForAllTypeOptions(ClassBase type, out string regexWithGenerics, out string regexWithoutGenerics)
        {
            Param.AssertNotNull(type, "type");

            string[] typeNameParts = type.FullyQualifiedName.Split('.');

            StringBuilder actualTypeNameWithoutGenerics = new StringBuilder();
            StringBuilder typeNameWithGenerics = new StringBuilder();

            for (int i = 0; i < typeNameParts.Length; ++i)
            {
                typeNameWithGenerics.Append(BuildTypeNameStringWithGenerics(typeNameParts[i]));
                actualTypeNameWithoutGenerics.Append(RemoveGenericsFromTypeName(typeNameParts[i]));

                if (i < typeNameParts.Length - 1)
                {
                    typeNameWithGenerics.Append(".");
                    actualTypeNameWithoutGenerics.Append(".");
                }
            }

            regexWithGenerics = BuildRegExStringFromTypeName(typeNameWithGenerics.ToString());
            regexWithoutGenerics = BuildRegExStringFromTypeName(actualTypeNameWithoutGenerics.ToString());
        }
Example #13
0
        /// <summary>
        /// Builds a regular expression that can be used to validate the name of the given type when 
        /// used within a documentation <c>cref</c> attribute.
        /// </summary>
        /// <param name="type">
        /// The type to match against.
        /// </param>
        /// <returns>
        /// Returns the regular expression object.
        /// </returns>
        private static string BuildCrefValidationStringForType(ClassBase type)
        {
            Param.AssertNotNull(type, "type");

            StringBuilder typeNameWithParamsNumber = new StringBuilder();

            string[] typeNameParts = type.FullyQualifiedName.Split('.');

            // Start at index 1 to skip the 'Root'
            for (int i = 1; i < typeNameParts.Length; i++)
            {
                typeNameWithParamsNumber.Append(BuildTypeNameStringWithParamsNumber(typeNameParts[i]));

                if (i < typeNameParts.Length - 1)
                {
                    typeNameWithParamsNumber.Append(@"\.");
                }
            }

            string regexWithGenerics;
            string regexWithoutGenerics;

            BuildRegExForAllTypeOptions(type, out regexWithGenerics, out regexWithoutGenerics);

            // Build the regex string to match all possible formats for the type name.
            return string.Format(CultureInfo.InvariantCulture, CrefRegex, typeNameWithParamsNumber, regexWithoutGenerics, regexWithGenerics);
        }
Example #14
0
        /// <summary>
        /// Checks the Xml header block of the given class for consistency with the class.
        /// </summary>
        /// <param name="classElement">
        /// The element to parse.
        /// </param>
        /// <param name="settings">
        /// The analyzer settings.
        /// </param>
        private void CheckClassElementHeader(ClassBase classElement, AnalyzerSettings settings)
        {
            Param.AssertNotNull(classElement, "classElement");
            Param.Ignore(settings);

            AnalyzerSettings adjustedSettings = settings;
            adjustedSettings.RequireFields = false;

            this.CheckHeader(classElement, adjustedSettings, classElement.Declaration.ContainsModifier(CsTokenType.Partial));
        }
        /// <summary>
        /// The save.
        /// </summary>
        /// <param name="class">
        /// The class.
        /// </param>
        private void Save(ClassBase @class)
        {
            // this is template
            this.IsCPPInHeader = @class.Declaration.Name.Contains('<');

            // save attributes
            foreach (var attr in @class.Attributes)
            {
                this.Save(attr, this.headerWriter);
            }

            var nakedClassName = this.GetNameBase(@class.Declaration.Name);

            this.ClassContext = new ClassContext(@class, this.FullyQualifiedNames);

            if (@class.AccessModifier != AccessModifierType.Internal)
            {
                this.Save(@class.AccessModifier);
                this.headerWriter.Write(" ");
            }

            this.headerWriter.Write("ref ");

            this.headerWriter.Write(this.BuildDeclaretionTemplatePart(@class.Declaration.Name));

            this.currentClassNamespace = nakedClassName;

            var typeKeyword = SharpToCppConverterHelper.GetTypeKeyword(@class);

            this.headerWriter.Write("{1} {0}", nakedClassName, typeKeyword);

            if (@class.HasToken(CsTokenType.Sealed))
            {
                this.headerWriter.Write(" sealed");
            }

            var baseClass = this.GetNameBase(@class.BaseClass, false);

            var hasColon = false;
            if (!string.IsNullOrEmpty(baseClass) && !baseClass.Equals(typeKeyword))
            {
                this.headerWriter.Write(": public ");

                this.currentBaseClass = baseClass;

                this.Save(
                    baseClass, this.headerWriter, SavingOptions.UseFullyQualifiedNames | SavingOptions.RemovePointer);

                hasColon = true;
            }

            // writer interfaces
            if (!hasColon && @class.ImplementedInterfaces != null && @class.ImplementedInterfaces.Count > 0)
            {
                this.headerWriter.Write(": ");
            }

            var first = !hasColon;
            foreach (var interfaceOfClass in @class.ImplementedInterfaces)
            {
                if (!first)
                {
                    this.headerWriter.Write(", ");
                }

                this.Save(
                    interfaceOfClass,
                    this.headerWriter,
                    SavingOptions.UseFullyQualifiedNames | SavingOptions.RemovePointer);

                first = false;
            }

            this.headerWriter.WriteLine();
            this.headerWriter.WriteLine('{');
            this.headerWriter.Indent++;

            // before save all static initializers
            this.SaveFieldInitializersIntoDefaultConstructor(false);

            this.@switch(@class.ChildElements);

            this.headerWriter.Indent--;

            this.headerWriter.WriteLine("};");

            this.ClassContext = null;
        }
Example #16
0
 /// <summary>
 /// Returns True if this class or any of its Partial Classes has a BaseClass specified.
 /// </summary>
 /// <param name="classBase">
 /// The class to check.
 /// </param>
 /// <returns>
 /// True if it finds a BaseClass.
 /// </returns>
 public static bool HasImplementedInterfaces(ClassBase classBase)
 {
     return(classBase.ImplementedInterfaces.Count > 0 ||
            (classBase.PartialElementList != null && classBase.PartialElementList.OfType <Class>().Any(d => d.ImplementedInterfaces.Count > 0)));
 }
        /// <summary>
        /// Parses the given expression.
        /// </summary>
        /// <param name="expression">
        /// The expression. 
        /// </param>
        /// <param name="parentExpression">
        /// The parent expression, if there is one. 
        /// </param>
        /// <param name="parentElement">
        /// The element that contains the expressions. 
        /// </param>
        /// <param name="parentClass">
        /// The class that the element belongs to. 
        /// </param>
        /// <param name="members">
        /// The collection of members of the parent class. 
        /// </param>
        private void CheckClassMemberRulesForExpression(
            Expression expression, Expression parentExpression, CsElement parentElement, ClassBase parentClass, Dictionary<string, List<CsElement>> members)
        {
            Param.AssertNotNull(expression, "expression");
            Param.Ignore(parentExpression);
            Param.AssertNotNull(parentElement, "parentElement");
            Param.AssertNotNull(parentClass, "parentClass");
            Param.AssertNotNull(members, "members");

            if (expression.ExpressionType == ExpressionType.Literal)
            {
                LiteralExpression literalExpression = (LiteralExpression)expression;

                // Check to see whether this literal is preceded by a member access symbol. If not
                // then we want to check whether this is a reference to one of our class members.
                if (!IsLiteralTokenPrecededByMemberAccessSymbol(literalExpression.TokenNode, expression.Tokens.MasterList))
                {
                    // Process the literal.
                    this.CheckClassMemberRulesForLiteralToken(literalExpression.TokenNode, expression, parentExpression, parentElement, parentClass, members);
                }
            }
            else
            {
                if (expression.ExpressionType == ExpressionType.Assignment && parentExpression != null
                    && parentExpression.ExpressionType == ExpressionType.CollectionInitializer)
                {
                    // When we encounter assignment expressions within collection initializer expressions, we ignore the expression
                    // on the left-hand side of the assignment. This is because we know that the left-hand side refers to a property on
                    // the type being initialized, not a property on the local class. Thus, it does not ever need to be prefixed by this.
                    // Without this check we can get name collisions, such as:
                    // public sealed class Person
                    //// {
                    ////     public string FirstName { get; }
                    ////     public void CreateAnonymousType()
                    ////     {
                    ////         var anonymousType = new { FirstName = this.FirstName };
                    ////     }
                    //// }
                    this.CheckClassMemberRulesForExpression(((AssignmentExpression)expression).RightHandSide, expression, parentElement, parentClass, members);
                }
                else if (expression.ChildExpressions.Count > 0)
                {
                    // Check each child expression within this expression.
                    this.CheckClassMemberRulesForExpressions(expression.ChildExpressions, expression, parentElement, parentClass, members);
                }

                // Check if this is an anonymous method expression, which contains a child statement list.
                if (expression.ExpressionType == ExpressionType.AnonymousMethod)
                {
                    // Check the statements under this anonymous method.
                    this.CheckClassMemberRulesForStatements(expression.ChildStatements, parentElement, parentClass, members);
                }
                else if (expression.ExpressionType == ExpressionType.MethodInvocation)
                {
                    // Check each of the arguments passed into the method call.
                    MethodInvocationExpression methodInvocation = (MethodInvocationExpression)expression;
                    foreach (Argument argument in methodInvocation.Arguments)
                    {
                        // Check each expression within this child expression.
                        if (argument.Expression.ExpressionType != ExpressionType.MethodInvocation)
                        {
                            this.CheckClassMemberRulesForExpression(argument.Expression, null, parentElement, parentClass, members);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Parses the list of expressions.
        /// </summary>
        /// <param name="expressions">
        /// The list of expressions. 
        /// </param>
        /// <param name="parentExpression">
        /// The parent expression, if there is one. 
        /// </param>
        /// <param name="parentElement">
        /// The element that contains the expressions. 
        /// </param>
        /// <param name="parentClass">
        /// The class that the element belongs to. 
        /// </param>
        /// <param name="members">
        /// The collection of members of the parent class. 
        /// </param>
        private void CheckClassMemberRulesForExpressions(
            IEnumerable<Expression> expressions, Expression parentExpression, CsElement parentElement, ClassBase parentClass, Dictionary<string, List<CsElement>> members)
        {
            Param.AssertNotNull(expressions, "expressions");
            Param.AssertNotNull(parentElement, "parentElement");
            Param.Ignore(parentExpression);
            Param.Ignore(parentClass);
            Param.Ignore(members);

            // Loop through each of the expressions in the list.
            foreach (Expression expression in expressions)
            {
                // If the expression is a variable declarator expression, we don't want to match against the identifier tokens.
                if (expression.ExpressionType == ExpressionType.VariableDeclarator)
                {
                    VariableDeclaratorExpression declarator = expression as VariableDeclaratorExpression;
                    if (declarator.Initializer != null)
                    {
                        this.CheckClassMemberRulesForExpression(declarator.Initializer, parentExpression, parentElement, parentClass, members);
                    }
                }
                else
                {
                    this.CheckClassMemberRulesForExpression(expression, parentExpression, parentElement, parentClass, members);
                }
            }
        }
        /// <summary>
        /// Finds the given class member in the given class.
        /// </summary>
        /// <param name="word">
        /// The word to check. 
        /// </param>
        /// <param name="parentClass">
        /// The class the word appears in. 
        /// </param>
        /// <param name="members">
        /// The collection of members of the parent class. 
        /// </param>
        /// <param name="interfaces">
        /// True if interface implementations should be included. 
        /// </param>
        /// <returns>
        /// Returns the class members that match against the given name. 
        /// </returns>
        public static ICollection<CsElement> FindClassMember(string word, ClassBase parentClass, Dictionary<string, List<CsElement>> members, bool interfaces)
        {
            Param.AssertNotNull(word, "word");
            Param.AssertNotNull(parentClass, "parentClass");
            Param.AssertNotNull(members, "members");
            Param.Ignore(interfaces);

            // If the word is the same as the class name, then this is a constructor and we
            // don't want to match against it.
            if (word != parentClass.Declaration.Name)
            {
                ICollection<CsElement> matches = MatchClassMember(word, members, interfaces);
                if (matches != null && matches.Count > 0)
                {
                    return matches;
                }
            }

            return null;
        }
        /// <summary>
        /// Parses the given statement list.
        /// </summary>
        /// <param name="statements">
        /// The list of statements to parse. 
        /// </param>
        /// <param name="parentElement">
        /// The element that contains the statements. 
        /// </param>
        /// <param name="parentClass">
        /// The class that the element belongs to. 
        /// </param>
        /// <param name="members">
        /// The collection of members of the parent class. 
        /// </param>
        private void CheckClassMemberRulesForStatements(
            ICollection<Statement> statements, CsElement parentElement, ClassBase parentClass, Dictionary<string, List<CsElement>> members)
        {
            Param.AssertNotNull(statements, "statements");
            Param.AssertNotNull(parentElement, "parentElement");
            Param.Ignore(parentClass);
            Param.Ignore(members);

            // Loop through each of the statements.
            foreach (Statement statement in statements)
            {
                if (statement.ChildStatements.Count > 0)
                {
                    // Parse the sub-statements.
                    this.CheckClassMemberRulesForStatements(statement.ChildStatements, parentElement, parentClass, members);
                }

                // Parse the expressions in the statement.
                this.CheckClassMemberRulesForExpressions(statement.ChildExpressions, null, parentElement, parentClass, members);
            }
        }
 /// <summary>
 /// Returns True if this class or any of its Partial Classes has a BaseClass specified.
 /// </summary>
 /// <param name="classBase">
 /// The class to check.
 /// </param>
 /// <returns>
 /// True if it finds a BaseClass.
 /// </returns>
 public static bool HasABaseClassSpecified(ClassBase classBase)
 {
     return !string.IsNullOrEmpty(classBase.BaseClass)
            || (classBase.PartialElementList != null && classBase.PartialElementList.OfType<Class>().Any(d => !string.IsNullOrEmpty(d.BaseClass)));
 }
        /// <summary>
        /// Checks a token to see if it should be prefixed (with this. or maybe another prefix).
        /// </summary>
        /// <param name="tokenNode">
        /// The TokenNode to check. 
        /// </param>
        /// <param name="expression">
        /// The expression the word appears within. 
        /// </param>
        /// <param name="parentClass">
        /// The parent class that this element belongs to. 
        /// </param>
        /// <param name="members">
        /// The collection of members of the parent class. 
        /// </param>
        /// <returns>
        /// True if the prefix is required otherwise false. 
        /// </returns>
        private bool IsThisRequired(Node<CsToken> tokenNode, Expression expression, ClassBase parentClass, Dictionary<string, List<CsElement>> members)
        {
            string memberName = tokenNode.Value.Text;

            if (IsLocalMember(memberName, tokenNode.Value, expression) || IsObjectInitializerLeftHandSideExpression(expression) || memberName == "object"
                || tokenNode.Value.CsTokenType != CsTokenType.Other)
            {
                return false;
            }

            ICollection<CsElement> matchesForGenericMethod;
            ICollection<CsElement> matchesForPassedMethod = Utils.FindClassMember(memberName, parentClass, members, true);

            bool memberNameHasGeneric = memberName.IndexOf('<') > -1;

            if (memberNameHasGeneric)
            {
                matchesForGenericMethod = Utils.FindClassMember(memberName.Substring(0, memberName.IndexOf('<')) + "<T>", parentClass, members, true);
                return IsThisRequiredFromMemberList(expression, parentClass, matchesForPassedMethod, matchesForGenericMethod, memberName);
            }

            matchesForGenericMethod = Utils.FindClassMember(memberName + "<T>", parentClass, members, true);

            return IsThisRequiredFromMemberList(expression, parentClass, matchesForPassedMethod, matchesForGenericMethod, memberName);
        }
 /// <summary>
 /// Returns True if this class or any of its Partial Classes has a BaseClass specified.
 /// </summary>
 /// <param name="classBase">
 /// The class to check.
 /// </param>
 /// <returns>
 /// True if it finds a BaseClass.
 /// </returns>
 public static bool HasImplementedInterfaces(ClassBase classBase)
 {
     return classBase.ImplementedInterfaces.Count > 0
            || (classBase.PartialElementList != null && classBase.PartialElementList.OfType<Class>().Any(d => d.ImplementedInterfaces.Count > 0));
 }
        /// <summary>
        /// Parses the list of expressions.
        /// </summary>
        /// <param name="expressions">
        /// The list of expressions.
        /// </param>
        /// <param name="parentExpression">
        /// The parent expression, if there is one.
        /// </param>
        /// <param name="parentElement">
        /// The element that contains the expressions.
        /// </param>
        /// <param name="parentClass">
        /// The class that the element belongs to.
        /// </param>
        /// <param name="members">
        /// The collection of members of the parent class.
        /// </param>
        private void CheckClassMemberRulesForExpressions(
            IEnumerable <Expression> expressions, Expression parentExpression, CsElement parentElement, ClassBase parentClass, Dictionary <string, List <CsElement> > members)
        {
            Param.AssertNotNull(expressions, "expressions");
            Param.AssertNotNull(parentElement, "parentElement");
            Param.Ignore(parentExpression);
            Param.Ignore(parentClass);
            Param.Ignore(members);

            // Loop through each of the expressions in the list.
            foreach (Expression expression in expressions)
            {
                // If the expression is a variable declarator expression, we don't want to match against the identifier tokens.
                if (expression.ExpressionType == ExpressionType.VariableDeclarator)
                {
                    VariableDeclaratorExpression declarator = expression as VariableDeclaratorExpression;
                    if (declarator.Initializer != null)
                    {
                        this.CheckClassMemberRulesForExpression(declarator.Initializer, parentExpression, parentElement, parentClass, members);
                    }
                }
                else
                {
                    this.CheckClassMemberRulesForExpression(expression, parentExpression, parentElement, parentClass, members);
                }
            }
        }
        /// <summary>
        /// Adds all members of a class to a dictionary.
        /// </summary>
        /// <param name="class">
        /// The class to collect. 
        /// </param>
        /// <param name="members">
        /// Adds all members of the class to the given dictionary. 
        /// </param>
        private static void CollectClassMembersAux(ClassBase @class, Dictionary<string, List<CsElement>> members)
        {
            Param.AssertNotNull(@class, "class");
            Param.AssertNotNull(members, "members");

            foreach (CsElement child in @class.ChildElements)
            {
                if (child.ElementType == ElementType.Field)
                {
                    // Look through each of the declarators in the field.
                    foreach (VariableDeclaratorExpression declarator in ((Field)child).VariableDeclarationStatement.Declarators)
                    {
                        AddClassMember(members, child, declarator.Identifier.Text);
                    }
                }
                else if (child.ElementType == ElementType.Event)
                {
                    // Look through each of the declarators in the event.
                    foreach (EventDeclaratorExpression declarator in ((Event)child).Declarators)
                    {
                        AddClassMember(members, child, declarator.Identifier.Text);
                    }
                }
                else if (child.ElementType != ElementType.EmptyElement)
                {
                    AddClassMember(members, child, child.Declaration.Name);
                }
            }
        }
        /// <summary>
        /// Calculates whether the base prefix is required.
        /// </summary>
        /// <param name="memberName">
        /// The text of the method call to check.
        /// </param>
        /// <param name="parentClass">
        /// The class this this member belongs to.
        /// </param>
        /// <param name="members">
        /// All the members of this class.
        /// </param>
        /// <returns>
        /// True if base is required otherwise false.
        /// </returns>
        private bool IsBaseRequired(string memberName, ClassBase parentClass, Dictionary <string, List <CsElement> > members)
        {
            // An item is only allowed to start with base if there is an implementation of the
            // item in the local class and the caller is trying to explicitly call the base
            // class implementation instead of the local class implementation.
            bool memberNameHasGeneric = memberName.IndexOf('<') > -1;

            bool overrideOnTrimmedMethod = false;
            bool overrideOnGenericMethod = false;
            bool overrideOnPassedMethod  = false;

            bool newOnPassedMethod  = false;
            bool newOnGenericMethod = false;

            ICollection <CsElement> matchesForTrimmedMethod = null;
            ICollection <CsElement> matchesForGenericMethod = null;
            ICollection <CsElement> matchesForPassedMethod  = Utils.FindClassMember(memberName, parentClass, members, true);

            if (memberNameHasGeneric)
            {
                string trimmedName = memberName.Substring(0, memberName.IndexOf('<'));

                matchesForTrimmedMethod = Utils.FindClassMember(trimmedName, parentClass, members, true);

                if (matchesForTrimmedMethod != null)
                {
                    foreach (CsElement match in matchesForTrimmedMethod)
                    {
                        if (match.Declaration.ContainsModifier(CsTokenType.Override))
                        {
                            overrideOnTrimmedMethod = true;
                            break;
                        }
                    }
                }
            }
            else
            {
                matchesForGenericMethod = Utils.FindClassMember(memberName + "<T>", parentClass, members, true);

                if (matchesForGenericMethod != null)
                {
                    foreach (CsElement match in matchesForGenericMethod)
                    {
                        if (match.Declaration.ContainsModifier(CsTokenType.Override))
                        {
                            overrideOnGenericMethod = true;
                        }

                        if (match.Declaration.ContainsModifier(CsTokenType.New))
                        {
                            newOnGenericMethod = true;
                        }
                    }
                }
            }

            // We check for a method marked override and a method marked new
            if (matchesForPassedMethod != null)
            {
                foreach (CsElement match in matchesForPassedMethod)
                {
                    if (match.Declaration.ContainsModifier(CsTokenType.Override))
                    {
                        overrideOnPassedMethod = true;
                    }

                    if (match.Declaration.ContainsModifier(CsTokenType.New))
                    {
                        newOnPassedMethod = true;
                        break;
                    }
                }
            }

            bool baseIsRequired = memberNameHasGeneric && (overrideOnTrimmedMethod || newOnPassedMethod || overrideOnPassedMethod);

            if (!memberNameHasGeneric && (overrideOnPassedMethod || newOnGenericMethod || overrideOnGenericMethod || matchesForPassedMethod != null))
            {
                baseIsRequired = true;
            }

            if (memberNameHasGeneric && (overrideOnTrimmedMethod || matchesForTrimmedMethod != null))
            {
                baseIsRequired = true;
            }

            return(baseIsRequired);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ClassContext"/> class.
 /// </summary>
 /// <param name="class">
 /// The class.
 /// </param>
 /// <param name="fullyQualifiedNameCache">
 /// The fully qualified name cache.
 /// </param>
 public ClassContext(ClassBase @class, FullyQualifiedNamesCache fullyQualifiedNameCache)
 {
     this.@class = @class;
     this.namespaceNode = fullyQualifiedNameCache.FindNamespaceNodeFromRoot(this.Class.FullyQualifiedName);
     //Debug.Assert(this.namespaceNode != null);
 }