Ejemplo n.º 1
0
        public static (bool uidExists, string uidValue) GetOrGenerateUid(this XamlElementProcessor source, string xamlElement, string attributeName)
        {
            var uidExists = source.TryGetAttribute(xamlElement, Attributes.Uid, AttributeType.Inline, out AttributeType _, out int _, out int _, out string uid);

            if (!uidExists)
            {
                // reuse `Name` or `x:Name` if exist
                if (source.TryGetAttribute(xamlElement, Attributes.Name, AttributeType.InlineOrElement, out AttributeType _, out int _, out int _, out string name))
                {
                    uid = name;
                }
                else
                {
                    var elementName = XamlElementProcessor.GetElementName(xamlElement.AsSpan());

                    if (source.TryGetAttribute(xamlElement, attributeName, AttributeType.InlineOrElement, out _, out _, out _, out string value))
                    {
                        uid = $"{CultureInfo.InvariantCulture.TextInfo.ToTitleCase(value)}{elementName}";

                        uid = uid.RemoveAllWhitespace().RemoveNonAlphaNumerics();
                    }
                    else
                    {
                        // This is just a large random number created to hopefully avoid collisions
                        uid = $"{elementName}{new Random().Next(1001, 8999)}";
                    }
                }
            }
Ejemplo n.º 2
0
        public static void CheckForHardCodedAttribute(this XamlElementProcessor source, string fileName, string elementName, string attributeName, AttributeType types, string descriptionFormat, string xamlElement, ITextSnapshot snapshot, int offset, string guidFallbackAttributeName, Guid elementIdentifier, TagList tags, List <TagSuppression> suppressions, ProjectType projType)
        {
            if (source.TryGetAttribute(xamlElement, attributeName, types, out AttributeType foundAttributeType, out int tbIndex, out int length, out string value))
            {
                if (!string.IsNullOrWhiteSpace(value) && char.IsLetterOrDigit(value[0]))
                {
                    var tagDeps = source.CreateBaseTagDependencies(
                        new Span(offset + tbIndex, length),
                        snapshot,
                        fileName);

                    var(uidExists, uidValue) = source.GetOrGenerateUid(xamlElement, guidFallbackAttributeName);

                    var tag = new HardCodedStringTag(tagDeps, elementName, attributeName, projType)
                    {
                        AttributeType = foundAttributeType,
                        Value         = value,
                        Description   = descriptionFormat.WithParams(value),
                        UidExists     = uidExists,
                        UidValue      = uidValue,
                        ElementGuid   = elementIdentifier,
                    };

                    tags.TryAdd(tag, xamlElement, suppressions);
                }
            }
        }
Ejemplo n.º 3
0
        public static Dictionary <int, int> GetExclusions(string xaml, string elementName)
        {
            string elementOpen         = $"<{elementName}";
            string elementOpenSpace    = $"<{elementName} ";
            string elementOpenComplete = $"<{elementName}>";
            string elementClose        = $"</{elementName}>";

            var exclusions = new Dictionary <int, int>();

            // This is the opening position of the next opening (here) or closing (when set subsequently) tag
            var tagOfInterestPos = xaml.Substring(elementOpen.Length).AsSpan().FirstIndexOf(elementOpenComplete, elementOpenSpace) + elementOpen.Length;

            // track the number of open tags seen so know when get to the corresponding closing one.
            var openings = 0;

            // Track this outside the loop as may have nesting.
            int startClosePos = 0;

            while (tagOfInterestPos > elementOpen.Length && tagOfInterestPos < xaml.Length)
            {
                // closing tags
                if (xaml.Substring(tagOfInterestPos, 2) == "</")
                {
                    // Allow for having seen multiple openings before the closing
                    if (openings == 1)
                    {
                        exclusions.Add(startClosePos + 1, tagOfInterestPos + elementClose.Length);
                        openings = 0;
                    }
                    else
                    {
                        openings -= 1;
                    }
                }
                else
                {
                    // ignore self closing tags as nothing to exclude
                    if (!XamlElementProcessor.IsSelfClosing(xaml.AsSpan(), tagOfInterestPos))
                    {
                        // opening tag s
                        if (openings <= 0)
                        {
                            startClosePos = xaml.IndexOf(">", tagOfInterestPos, StringComparison.Ordinal);
                            openings      = 1;
                        }
                        else
                        {
                            openings += 1;
                        }
                    }
                }

                // Find next opening or closing tag
                var nextOpening = xaml.Substring(tagOfInterestPos + elementOpen.Length).AsSpan().FirstIndexOf(elementOpenComplete, elementOpenSpace);

                if (nextOpening > -1)
                {
                    nextOpening += tagOfInterestPos + elementOpen.Length;
                }

                var nextClosing = xaml.IndexOf(elementClose, tagOfInterestPos + elementOpen.Length, StringComparison.Ordinal);

                tagOfInterestPos = nextOpening > -1 && nextOpening < nextClosing ? nextOpening : nextClosing;
            }

            return(exclusions);
        }
Ejemplo n.º 4
0
        public override void Process(string fileName, int offset, string xamlElement, string linePadding, ITextSnapshot snapshot, TagList tags, List <TagSuppression> suppressions = null)
        {
            const string gridOpenSpace    = "<Grid ";
            const string gridOpenComplete = "<Grid>";

            var endOfOpening    = xamlElement.IndexOf(">", StringComparison.Ordinal) + 1;
            var firstNestedGrid = xamlElement.FirstIndexOf(gridOpenSpace, gridOpenComplete);

            var rowDefPos = xamlElement.IndexOf("<Grid.RowDefinitions", StringComparison.Ordinal);
            var colDefPos = xamlElement.IndexOf("<Grid.ColumnDefinitions", StringComparison.Ordinal);

            var gridIsSelfClosing = XamlElementProcessor.IsSelfClosing(xamlElement);

            var hasRowDef = false;

            if (rowDefPos > 0)
            {
                hasRowDef = firstNestedGrid <= 0 || rowDefPos < firstNestedGrid;
            }

            var hasColDef = false;

            if (colDefPos > 0)
            {
                hasColDef = firstNestedGrid <= 0 || colDefPos < firstNestedGrid;
            }

            var leftPad = linePadding.Contains("\t") ? linePadding + "\t" : linePadding + "    ";

            var rowDefsClosingPos = -1;

            if (!hasRowDef)
            {
                var tag = new AddRowDefinitionsTag(new Span(offset, endOfOpening), snapshot, fileName, this.Logger)
                {
                    InsertPosition     = offset + endOfOpening,
                    LeftPad            = leftPad,
                    GridNeedsExpanding = gridIsSelfClosing,
                };
                tags.TryAdd(tag, xamlElement, suppressions);

                rowDefsClosingPos = xamlElement.IndexOf(">", StringComparison.Ordinal);
            }
            else
            {
                rowDefsClosingPos = xamlElement.IndexOf("</Grid.RowDefinitions", StringComparison.Ordinal);
            }

            var colDefsClosingPos = -1;

            if (!hasColDef)
            {
                var tag = new AddColumnDefinitionsTag(new Span(offset, endOfOpening), snapshot, fileName, this.Logger)
                {
                    InsertPosition     = offset + endOfOpening,
                    LeftPad            = leftPad,
                    GridNeedsExpanding = gridIsSelfClosing,
                };
                tags.TryAdd(tag, xamlElement, suppressions);

                colDefsClosingPos = xamlElement.IndexOf(">", StringComparison.Ordinal);
            }
            else
            {
                colDefsClosingPos = xamlElement.IndexOf("</Grid.ColumnDefinitions", StringComparison.Ordinal);
            }

            if (!hasRowDef && !hasColDef)
            {
                var tag = new AddRowAndColumnDefinitionsTag(new Span(offset, endOfOpening), snapshot, fileName, this.Logger)
                {
                    InsertPosition     = offset + endOfOpening,
                    LeftPad            = leftPad,
                    GridNeedsExpanding = gridIsSelfClosing,
                };
                tags.TryAdd(tag, xamlElement, suppressions);
            }

            const string rowDefStart = "<RowDefinition";

            var rowDefsCount = 0;

            var toAdd = new List <InsertRowDefinitionTag>();

            var rowDefIndex = xamlElement.IndexOf(rowDefStart, StringComparison.Ordinal);

            while (rowDefIndex >= 0)
            {
                var endPos = xamlElement.IndexOf('>', rowDefIndex);

                var tag = new InsertRowDefinitionTag(new Span(offset + rowDefIndex, endPos - rowDefIndex + 1), snapshot, fileName, this.Logger)
                {
                    RowId        = rowDefsCount,
                    GridStartPos = offset,
                    GridLength   = xamlElement.Length,
                    XamlTag      = xamlElement.Substring(rowDefIndex, endPos - rowDefIndex + 1),
                    InsertPoint  = offset + rowDefIndex,
                };

                rowDefsCount += 1;

                toAdd.Add(tag);

                rowDefIndex = xamlElement.IndexOf(rowDefStart, endPos, StringComparison.Ordinal);
            }

            foreach (var tag in toAdd)
            {
                tag.RowCount = rowDefsCount;
                tags.TryAdd(tag, xamlElement, suppressions);
            }

            const string colDef = "<ColumnDefinition";

            var colDefsCount = 0;

            var colDefIndex = xamlElement.IndexOf(colDef, StringComparison.Ordinal);

            while (colDefIndex > -1)
            {
                colDefsCount += 1;

                colDefIndex = xamlElement.IndexOf(colDef, colDefIndex + 1, StringComparison.Ordinal);
            }

            const string rowDefUse = "Grid.Row=\"";
            const string colDefUse = "Grid.Column=\"";

            int highestAssignedRow = -1;
            int highestAssignedCol = -1;

            var undefinedTags = new List <MissingDefinitionTag>();

            var nextDefUseIndex = xamlElement.FirstIndexOf(rowDefUse, colDefUse);
            var defUseOffset    = 0;

            while (nextDefUseIndex > 0)
            {
                defUseOffset += nextDefUseIndex;

                if (nextDefUseIndex > endOfOpening)
                {
                    if (!xamlElement.InComment(defUseOffset))
                    {
                        // Get assigned value
                        if (xamlElement.Substring(defUseOffset).StartsWith(rowDefUse))
                        {
                            var valueStartPos = defUseOffset + rowDefUse.Length;
                            var closePos      = xamlElement.IndexOf("\"", valueStartPos, StringComparison.Ordinal);

                            var assignedStr = xamlElement.Substring(valueStartPos, closePos - valueStartPos);

                            if (int.TryParse(assignedStr, out int assignedInt))
                            {
                                if (assignedInt > 0 && assignedInt >= rowDefsCount)
                                {
                                    undefinedTags.Add(new MissingRowDefinitionTag(
                                                          new Span(offset + defUseOffset, closePos - defUseOffset + 1),
                                                          snapshot,
                                                          fileName,
                                                          this.Logger)
                                    {
                                        AssignedInt        = assignedInt,
                                        Description        = StringRes.UI_XamlAnalysisMissingRowDefinitionDescription.WithParams(assignedInt),
                                        ExistingDefsCount  = rowDefsCount,
                                        HasSomeDefinitions = hasRowDef,
                                        InsertPosition     = offset + rowDefsClosingPos,
                                        LeftPad            = leftPad,
                                    });
                                }

                                if (assignedInt > highestAssignedRow)
                                {
                                    highestAssignedRow = assignedInt;
                                }
                            }
                        }
                        else if (xamlElement.Substring(defUseOffset).StartsWith(colDefUse))
                        {
                            var valueStartPos = defUseOffset + colDefUse.Length;
                            var closePos      = xamlElement.IndexOf("\"", valueStartPos, StringComparison.Ordinal);

                            var assignedStr = xamlElement.Substring(valueStartPos, closePos - valueStartPos);

                            if (int.TryParse(assignedStr, out int assignedInt))
                            {
                                if (assignedInt > 0 && assignedInt >= colDefsCount)
                                {
                                    undefinedTags.Add(new MissingColumnDefinitionTag(
                                                          new Span(offset + defUseOffset, closePos - defUseOffset + 1),
                                                          snapshot,
                                                          fileName,
                                                          this.Logger)
                                    {
                                        AssignedInt        = assignedInt,
                                        Description        = StringRes.UI_XamlAnalysisMissingColumnDefinitionDescription.WithParams(assignedInt),
                                        ExistingDefsCount  = colDefsCount,
                                        HasSomeDefinitions = hasColDef,
                                        InsertPosition     = offset + colDefsClosingPos,
                                        LeftPad            = leftPad,
                                    });
                                }

                                if (assignedInt > highestAssignedCol)
                                {
                                    highestAssignedCol = assignedInt;
                                }
                            }
                        }
                    }
                }

                nextDefUseIndex = xamlElement.Substring(defUseOffset + 1).FirstIndexOf(colDefUse, rowDefUse) + 1;
            }

            foreach (var undefinedTag in undefinedTags)
            {
                undefinedTag.TotalDefsRequired = undefinedTag is MissingRowDefinitionTag ? highestAssignedRow
                                                                                         : highestAssignedCol;
                tags.TryAdd(undefinedTag, xamlElement, suppressions);
            }

            const string rowSpanUse = "Grid.RowSpan=\"";
            const string colSpanUse = "Grid.ColumnSpan=\"";

            var nextSpanUseIndex = xamlElement.FirstIndexOf(rowSpanUse, colSpanUse);
            var spanUseOffset    = 0;

            while (nextSpanUseIndex > 0)
            {
                spanUseOffset += nextSpanUseIndex;

                if (nextSpanUseIndex > endOfOpening)
                {
                    if (!xamlElement.InComment(spanUseOffset))
                    {
                        if (xamlElement.Substring(spanUseOffset).StartsWith(rowSpanUse))
                        {
                            var valueStartPos = spanUseOffset + rowSpanUse.Length;
                            var closePos      = xamlElement.IndexOf("\"", valueStartPos, StringComparison.Ordinal);

                            var assignedStr = xamlElement.Substring(valueStartPos, closePos - valueStartPos);

                            if (int.TryParse(assignedStr, out int assignedInt))
                            {
                                var element = XamlElementProcessor.GetSubElementAtPosition(this.ProjectType, fileName, snapshot, xamlElement, spanUseOffset, this.Logger);

                                var row = 0;
                                if (this.TryGetAttribute(element, "Grid.Row", AttributeType.InlineOrElement, out _, out _, out _, out string rowStr))
                                {
                                    row = int.Parse(rowStr);
                                }

                                if (assignedInt > 1 && assignedInt - 1 + row >= rowDefsCount)
                                {
                                    var rowTag = new RowSpanOverflowTag(
                                        new Span(offset + spanUseOffset, closePos - spanUseOffset + 1),
                                        snapshot,
                                        fileName,
                                        this.Logger)
                                    {
                                        TotalDefsRequired  = assignedInt + row - 1,
                                        Description        = StringRes.UI_XamlAnalysisRowSpanOverflowDescription,
                                        ExistingDefsCount  = rowDefsCount,
                                        HasSomeDefinitions = hasRowDef,
                                        InsertPosition     = offset + rowDefsClosingPos,
                                        LeftPad            = leftPad,
                                    };

                                    tags.TryAdd(rowTag, xamlElement, suppressions);
                                }
                            }
                        }
                        else if (xamlElement.Substring(spanUseOffset).StartsWith(colSpanUse))
                        {
                            var valueStartPos = spanUseOffset + colSpanUse.Length;
                            var closePos      = xamlElement.IndexOf("\"", valueStartPos, StringComparison.Ordinal);

                            var assignedStr = xamlElement.Substring(valueStartPos, closePos - valueStartPos);

                            if (int.TryParse(assignedStr, out int assignedInt))
                            {
                                var element = XamlElementProcessor.GetSubElementAtPosition(this.ProjectType, fileName, snapshot, xamlElement, spanUseOffset, this.Logger);

                                var gridCol = 0;
                                if (this.TryGetAttribute(element, "Grid.Column", AttributeType.InlineOrElement, out _, out _, out _, out string colStr))
                                {
                                    gridCol = int.Parse(colStr);
                                }

                                if (assignedInt > 1 && assignedInt - 1 + gridCol >= colDefsCount)
                                {
                                    var colTag = new ColumnSpanOverflowTag(
                                        new Span(offset + spanUseOffset, closePos - spanUseOffset + 1),
                                        snapshot,
                                        fileName,
                                        this.Logger)
                                    {
                                        TotalDefsRequired  = assignedInt - 1 + gridCol,
                                        Description        = StringRes.UI_XamlAnalysisColumnSpanOverflowDescription,
                                        ExistingDefsCount  = colDefsCount,
                                        HasSomeDefinitions = hasColDef,
                                        InsertPosition     = offset + colDefsClosingPos,
                                        LeftPad            = leftPad,
                                    };

                                    tags.TryAdd(colTag, xamlElement, suppressions);
                                }
                            }
                        }
                    }
                }

                nextSpanUseIndex = xamlElement.Substring(spanUseOffset + 1).FirstIndexOf(colSpanUse, rowSpanUse) + 1;
            }
        }