public void IncrementalParsingIsSameAsFullParsing_MiddleEdits() { var lines = Xml.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); var middle = string.Join(Environment.NewLine, lines.Skip(2).Take(lines.Length - 3)); var delta = lines[0].Length + lines[1].Length + 2 * Environment.NewLine.Length; XmlDocumentSyntax previousDocument = null; for (int i = 1; i <= middle.Length; i++) { var currentText = lines[0] + Environment.NewLine + lines[1] + Environment.NewLine + middle.Substring(0, i) + Environment.NewLine + lines.Last(); var full = Parser.ParseText(currentText); var incremental = Parser.ParseIncremental( currentText, new[] { new TextChangeRange(new TextSpan(delta + i - 1, 0), 1) }, previousDocument ); AssertSameNodes(full, incremental); previousDocument = incremental; } }
protected virtual void AnnotateFile( AnalysisServices services, RepoFile file, XmlSourceFileBuilder binder, XmlDocumentSyntax document) { }
public void CanCompleteAttribute(string testFileName, int line, int column, string expectedElementName, PaddingType expectedPadding) { Position testPosition = new Position(line, column); string testXml = LoadTestFile("TestFiles", testFileName + ".xml"); TextPositions positions = new TextPositions(testXml); XmlDocumentSyntax document = Parser.ParseText(testXml); XmlLocator locator = new XmlLocator(document, positions); XmlLocation location = locator.Inspect(testPosition); Assert.NotNull(location); XSPath elementPath = XSPath.Parse(expectedElementName); XSElement element; XSAttribute replaceAttribute; PaddingType needsPadding; Assert.True( location.CanCompleteAttribute(out element, out replaceAttribute, out needsPadding, onElementWithPath: elementPath), "CanCompleteAttribute" ); Assert.NotNull(element); Assert.Null(replaceAttribute); Assert.Equal(expectedPadding, needsPadding); }
public void InEmptyElementName(string testFileName, int line, int column, string expectedElementName) { Position testPosition = new Position(line, column); string testXml = LoadTestFile("TestFiles", testFileName + ".xml"); TextPositions positions = new TextPositions(testXml); XmlDocumentSyntax document = Parser.ParseText(testXml); XmlLocator locator = new XmlLocator(document, positions); XmlLocation result = locator.Inspect(testPosition); Assert.NotNull(result); Assert.Equal(XSNodeKind.Element, result.Node.Kind); Assert.True(result.IsElement(), "IsElement"); XSElement element = (XSElement)result.Node; Assert.Equal(expectedElementName, element.Name); Assert.True(result.IsEmptyElement(), "IsEmptyElement"); Assert.True(result.IsName(), "IsName"); Assert.False(result.IsElementContent(), "IsElementContent"); // TODO: Verify Parent, PreviousSibling, and NextSibling. }
void NodeRange(string testFileName, int index, int startLine, int startColumn, int endLine, int endColumn) { string testXml = LoadTestFile("TestFiles", testFileName + ".xml"); TextPositions xmlPositions = new TextPositions(testXml); XmlDocumentSyntax xmlDocument = Parser.ParseText(testXml); List <XSNode> nodes = xmlDocument.GetSemanticModel(xmlPositions); Assert.NotNull(nodes); Assert.InRange(index, 0, nodes.Count - 1); XSNode node = nodes[index]; Assert.NotNull(node); TestOutput.WriteLine("Node {0} at {1} is {2}.", index, node.Range, node.Kind ); Range expectedRange = new Range( start: new Position(startLine, startColumn), end: new Position(endLine, endColumn) ); Assert.Equal(expectedRange, node.Range); }
public void InsideElement1(string testFileName, int line, int column) { // TODO: Change this test to use XmlLocator. Position testPosition = new Position(line, column); string testXml = LoadTestFile("TestFiles", testFileName + ".xml"); TextPositions positions = new TextPositions(testXml); XmlDocumentSyntax xmlDocument = Parser.ParseText(testXml); int absolutePosition = positions.GetAbsolutePosition(testPosition) - 1; // To find out if we can insert an element, make sure we find the node at the position ONE BEFORE the insertion point! SyntaxNode foundNode = xmlDocument.FindNode(absolutePosition, descendIntoChildren: node => true ); Assert.NotNull(foundNode); Assert.IsAssignableFrom <SyntaxList>(foundNode); SyntaxList list = (SyntaxList)foundNode; Range listSpan = list.Span.ToNative(positions); Assert.True( listSpan.Contains(testPosition), "List's span must contain the test position." ); }
public void InvalidElementRange(string testFileName, int nodeIndex, string elementName, int startLine, int startColumn, int endLine, int endColumn) { string testXml = LoadTestFile("TestFiles", testFileName + ".xml"); TextPositions xmlPositions = new TextPositions(testXml); XmlDocumentSyntax xmlDocument = Parser.ParseText(testXml); List <XSNode> nodes = xmlDocument.GetSemanticModel(xmlPositions); Assert.NotNull(nodes); XSNode targetNode = nodes[nodeIndex]; Assert.NotNull(targetNode); Assert.IsAssignableFrom <XSElement>(targetNode); XSElement targetElement = (XSElement)targetNode; Assert.Equal(elementName, targetElement.Name); Assert.False(targetElement.IsValid, "IsValid"); Range expectedRange = new Range( start: new Position(startLine, startColumn), end: new Position(endLine, endColumn) ); Assert.Equal(expectedRange, targetElement.Range); }
public static XmlDocumentSyntax Analyze(BoundSourceFileBuilder binder) { var text = binder.SourceFile.Content; XmlDocumentSyntax parsedXml = Parser.ParseText(text); Classify(binder, parsedXml); return(parsedXml); }
protected override void AnnotateFile( AnalysisServices services, RepoFile file, XmlSourceFileBuilder binder, XmlDocumentSyntax document) { Analyze(services, file, binder, document); }
void NodeCount(string testFileName, int expectedNodeCount) { string testXml = LoadTestFile("TestFiles", testFileName + ".xml"); TextPositions xmlPositions = new TextPositions(testXml); XmlDocumentSyntax xmlDocument = Parser.ParseText(testXml); List <XSNode> nodes = xmlDocument.GetSemanticModel(xmlPositions); Assert.NotNull(nodes); Assert.Equal(expectedNodeCount, nodes.Count); }
private static void Classify(BoundSourceFileBuilder binder, XmlDocumentSyntax parsedXml) { ClassifierVisitor.Visit(parsedXml, 0, parsedXml.FullWidth, (start, length, node, classification) => { var leadingTriviaWidth = node.GetLeadingTriviaWidth(); var trailingTriviaWidth = node.GetTrailingTriviaWidth(); start += leadingTriviaWidth; length -= (leadingTriviaWidth + trailingTriviaWidth); binder.AnnotateClassification(start, length, ClassificationTypeNamesLookup[(int)classification]); }); }
public void IncrementalParsingIsSameAsFullParsing() { XmlDocumentSyntax previousDocument = null; for (int i = 1; i <= Xml.Length; i++) { var currentText = Xml.Substring(0, i); var full = Parser.ParseText(currentText); var incremental = Parser.ParseIncremental( currentText, new[] { new TextChangeRange(new TextSpan(currentText.Length - 1, 0), 1) }, previousDocument ); AssertSameNodes(full, incremental); previousDocument = incremental; } }
public void IncrementalParsingIsSameAsFullParsing_MultipleConcurrentEdits() { int[] FindAllIndexes(string str, string needle) { var result = new List <int>(); var foundIndex = 0; var startSearchAt = 0; while ((foundIndex = str.IndexOf(needle, startSearchAt)) != -1) { result.Add(foundIndex); startSearchAt = foundIndex + needle.Length; } return(result.ToArray()); } const string AttributeName = "sameLengthAttributeName"; var attrIndexes = FindAllIndexes(Xml2, AttributeName); XmlDocumentSyntax previousDocument = null; for (int i = 1; i <= AttributeName.Length; i++) { var currentText = Xml2; var changes = new List <TextChangeRange>(); // Reconstruct the intermediary attributes for (int j = attrIndexes.Length - 1; j >= 0; j--) { currentText = currentText.Remove(attrIndexes[j], AttributeName.Length); currentText = currentText.Insert(attrIndexes[j], AttributeName.Substring(0, i)); changes.Add(new TextChangeRange(new TextSpan(attrIndexes[j] + i - 1 - j * (AttributeName.Length - i), 0), 1)); } changes.Reverse(); // All changes should map to the same letter Assert.All(changes, c => Assert.Equal(currentText[c.Span.Start], currentText[changes[0].Span.Start])); var full = Parser.ParseText(currentText); var incremental = Parser.ParseIncremental( currentText, changes.ToArray(), previousDocument ); AssertSameNodes(full, incremental); previousDocument = incremental; } }
void NodeKind(string testFileName, int index, XSNodeKind nodeKind) { string testXml = LoadTestFile("TestFiles", testFileName + ".xml"); TextPositions xmlPositions = new TextPositions(testXml); XmlDocumentSyntax xmlDocument = Parser.ParseText(testXml); List <XSNode> nodes = xmlDocument.GetSemanticModel(xmlPositions); Assert.NotNull(nodes); Assert.InRange(index, 0, nodes.Count - 1); XSNode node = nodes[index]; Assert.NotNull(node); Assert.Equal(nodeKind, node.Kind); }
public void CanCompleteElement(string testFileName, int line, int column) { Position testPosition = new Position(line, column); string testXml = LoadTestFile("TestFiles", testFileName + ".xml"); TextPositions positions = new TextPositions(testXml); XmlDocumentSyntax document = Parser.ParseText(testXml); XmlLocator locator = new XmlLocator(document, positions); XmlLocation location = locator.Inspect(testPosition); Assert.NotNull(location); XSElement replacingElement; Assert.True(location.CanCompleteElement(out replacingElement), "CanCompleteElement"); Assert.NotNull(replacingElement); }
private IEnumerable <Diagnostic> ValidateTemplatedValues(XmlDocumentSyntax syntaxTree, TextPositions textPositions) { foreach (var node in syntaxTree.DescendantNodesAndSelf().OfType <XmlTextSyntax>()) { if (!TemplatedValues.Any(x => node.Value.Contains(x, StringComparison.OrdinalIgnoreCase))) { continue; } var range = textPositions.GetRange(node.Start, node.End); yield return(new Diagnostic { Message = "Templated value which should be removed", Severity = DiagnosticSeverity.Error, Range = range }); } }
internal static string ParseChallenge(string xml) { XmlDocumentSyntax root = Parser.ParseText(xml); string base64Info = string.Empty; foreach (IXmlElement node in root.Elements) { if (node.Name == "challenge") { base64Info = node.Value; } } byte[] uniqDataB = new byte[1024]; uniqDataB = Convert.FromBase64String(base64Info); return(Encoding.Default.GetString(uniqDataB)); }
/// <summary> /// Parse the syntax model to derive a semantic model. /// </summary> /// <param name="document"> /// The <see cref="XmlDocumentSyntax"/> to parse. /// </param> /// <param name="xmlPositions"> /// The lookup for document positions. /// </param> /// <returns> /// A list of <see cref="XSNode"/>s, sorted by <see cref="XSNode.Range"/>. /// </returns> public static List <XSNode> GetSemanticModel(this XmlDocumentSyntax document, TextPositions xmlPositions) { if (document == null) { throw new ArgumentNullException(nameof(document)); } if (xmlPositions == null) { throw new ArgumentNullException(nameof(xmlPositions)); } XSParserVisitor parserVisitor = new XSParserVisitor(xmlPositions); parserVisitor.Visit(document); parserVisitor.FinaliseModel(); return(parserVisitor.DiscoveredNodes); }
/// <summary> /// Visit an <see cref="XmlDocumentSyntax"/>. /// </summary> /// <param name="document"> /// The <see cref="XmlDocumentSyntax"/>. /// </param> /// <returns> /// The <see cref="XmlDocumentSyntax"/> (unchanged). /// </returns> public override SyntaxNode VisitXmlDocument(XmlDocumentSyntax document) { XmlElementSyntaxBase root = document.Root as XmlElementSyntaxBase; if (root == null) { return(document); } if (root is XmlElementSyntax rootElement && rootElement.StartTag == null) { root = rootElement.Elements.FirstOrDefault() as XmlElementSyntaxBase; } if (root != null) { Visit(root); } return(document); }
public void InAttributeValue(string testFileName, int line, int column, string expectedAttributeName) { Position testPosition = new Position(line, column); string testXml = LoadTestFile("TestFiles", testFileName + ".xml"); TextPositions positions = new TextPositions(testXml); XmlDocumentSyntax document = Parser.ParseText(testXml); XmlLocator locator = new XmlLocator(document, positions); XmlLocation result = locator.Inspect(testPosition); Assert.NotNull(result); XSAttribute attribute; Assert.True(result.IsAttribute(out attribute), "IsAttribute"); Assert.True(result.IsAttributeValue(), "IsAttributeValue"); Assert.Equal(expectedAttributeName, attribute.Name); // TODO: Verify Parent, PreviousSibling, and NextSibling. }
void ElementAttributesRange(string testFileName, string elementName, int startLine, int startColumn, int endLine, int endColumn) { string testXml = LoadTestFile("TestFiles", testFileName + ".xml"); TextPositions xmlPositions = new TextPositions(testXml); XmlDocumentSyntax xmlDocument = Parser.ParseText(testXml); List <XSNode> nodes = xmlDocument.GetSemanticModel(xmlPositions); Assert.NotNull(nodes); XSNode targetNode = nodes.Find(node => node.Name == elementName); Assert.NotNull(targetNode); Assert.IsAssignableFrom <XSElement>(targetNode); XSElement targetElement = (XSElement)targetNode; Range expectedRange = new Range( start: new Position(startLine, startColumn), end: new Position(endLine, endColumn) ); Assert.Equal(expectedRange, targetElement.AttributesRange); }
public void IsExpression_Success(string testFileName, int line, int column, ExpressionKind expectedExpressionKind) { Position testPosition = new Position(line, column); string testXml = LoadTestFile("TestFiles", testFileName + ".xml"); TextPositions positions = new TextPositions(testXml); XmlDocumentSyntax document = Parser.ParseText(testXml); XmlLocator locator = new XmlLocator(document, positions); XmlLocation location = locator.Inspect(testPosition); Assert.NotNull(location); ExpressionNode actualExpression; Range actualExpressionRange; Assert.True( location.IsExpression(out actualExpression, out actualExpressionRange), "IsExpression" ); Assert.NotNull(actualExpression); Assert.Equal(expectedExpressionKind, actualExpression.Kind); }
public void CanCompleteElementInParentWithRelativePath(string testFileName, int line, int column, string expectedParent) { Position testPosition = new Position(line, column); string testXml = LoadTestFile("TestFiles", testFileName + ".xml"); TextPositions positions = new TextPositions(testXml); XmlDocumentSyntax document = Parser.ParseText(testXml); XmlLocator locator = new XmlLocator(document, positions); XmlLocation location = locator.Inspect(testPosition); Assert.NotNull(location); XSPath expectedParentPath = XSPath.Parse(expectedParent); XSElement replaceElement; Assert.True( location.CanCompleteElement(out replaceElement, parentPath: expectedParentPath), "CanCompleteElement" ); Assert.NotNull(replaceElement); Assert.Equal(expectedParent, replaceElement.ParentElement?.Name); }
/// <summary> /// Create a new <see cref="XmlLocator"/>. /// </summary> /// <param name="document"> /// The underlying XML document. /// </param> /// <param name="documentPositions"> /// The position-lookup for the underlying XML document text. /// </param> public XmlLocator(XmlDocumentSyntax document, TextPositions documentPositions) { if (document == null) { throw new ArgumentNullException(nameof(document)); } if (documentPositions == null) { throw new ArgumentNullException(nameof(documentPositions)); } _documentPositions = documentPositions; List <XSNode> allNodes = document.GetSemanticModel(_documentPositions); foreach (XSNode node in allNodes) { _nodeRanges.Add(node.Range); _nodesByStartPosition.Add(node.Range.Start, node); } _nodeRanges.Sort(); }
private void AnalyzeEvaluation( AnalysisServices services, RepoFile file, XmlSourceFileBuilder binder, XmlDocumentSyntax document) { var repo = file.PrimaryProject.Repo; using (var scope = GetProjectCollectionScope()) { try { Project project = new Project(file.FilePath, null, "Current", scope.Collection, ProjectLoadSettings.IgnoreMissingImports | ProjectLoadSettings.RecordDuplicateButNotCircularImports); foreach (var item in project.ItemsIgnoringCondition) { if (item.IsImported || item.Xml?.IncludeLocation == null) { continue; } RepoFile otherRepoFile = null; try { var fullPath = item.GetMetadataValue("FullPath"); otherRepoFile = repo.TryGetFile(fullPath); } catch { } if (otherRepoFile == null) { continue; } var location = item.Xml.IncludeLocation; var itemIncludeAttribute = binder .TryGetElement(location.Line - 1, location.Column - 1)? .Attribute("Include"); binder.AddAttributeNameReferences(itemIncludeAttribute, BoundSourceFileBuilder.CreateFileReferenceSymbol( otherRepoFile.LogicalPath, otherRepoFile.PrimaryProject.ProjectId)); } foreach (var import in project.ImportsIncludingDuplicates) { if (import.IsImported || import.ImportingElement == null) { continue; } var fullPath = import.ImportedProject.FullPath; RepoFile otherRepoFile = repo.TryGetFile(fullPath); if (otherRepoFile == null && fullPath != null) { if (!AddImports) { continue; } lock (MSBuildSharedProject) { otherRepoFile = MSBuildSharedProject.AddFile(fullPath); // The file is marked with explicit in this lock so we can // use that to know whether another thread has added the file already // and we can skip redundant analysis here if (otherRepoFile.HasExplicitAnalyzer) { continue; } otherRepoFile.Analyzer = this; otherRepoFile.HasExplicitAnalyzer = true; Placeholder.NotImplemented("Normalize imports to remove any references to repo specific files. Check if project is MSBuildSharedProject in order to determine if normalization is needed"); } otherRepoFile.Analyze(); } var location = import.ImportingElement.ProjectLocation; var importProjectAttribute = binder .TryGetElement(location.Line - 1, location.Column - 1)? .Attribute("Project"); binder.AddAttributeNameReferences(importProjectAttribute, BoundSourceFileBuilder.CreateFileReferenceSymbol( otherRepoFile.LogicalPath, otherRepoFile.PrimaryProject.ProjectId)); } } catch (Exception ex) { services.Logger.LogExceptionError($"Analyzing MSBuild file evaluation: {file.FilePath}", ex); } } }
private void AnalyzeEvaluation( AnalysisServices services, RepoFile file, XmlSourceFileBuilder binder, XmlDocumentSyntax document) { var repo = file.PrimaryProject.Repo; using (var scope = GetProjectCollectionScope()) { try { Project project = new Project(file.FilePath, null, null, scope.Collection, ProjectLoadSettings.IgnoreMissingImports | ProjectLoadSettings.RecordDuplicateButNotCircularImports); foreach (var item in project.ItemsIgnoringCondition) { if (item.IsImported || item.Xml?.IncludeLocation == null) { continue; } RepoFile otherRepoFile = null; try { var fullPath = item.GetMetadataValue("FullPath"); otherRepoFile = repo.TryGetFile(fullPath); } catch { } if (otherRepoFile == null) { continue; } var location = item.Xml.IncludeLocation; var itemIncludeAttribute = binder .TryGetElement(location.Line - 1, location.Column - 1)? .Attribute("Include"); binder.AddAttributeNameReferences(itemIncludeAttribute, BoundSourceFileBuilder.CreateFileReferenceSymbol( otherRepoFile.LogicalPath, otherRepoFile.PrimaryProject.ProjectId)); } foreach (var import in project.ImportsIncludingDuplicates) { if (import.IsImported || import.ImportingElement == null) { continue; } var fullPath = import.ImportedProject.FullPath; RepoFile otherRepoFile = repo.TryGetFile(fullPath); if (otherRepoFile == null && fullPath != null) { if (!AddImports) { continue; } lock (MSBuildSharedProject) { otherRepoFile = MSBuildSharedProject.AddFile(fullPath); } otherRepoFile.IsSingleton = true; otherRepoFile.Analyze(); } var location = import.ImportingElement.ProjectLocation; var importProjectAttribute = binder .TryGetElement(location.Line - 1, location.Column - 1)? .Attribute("Project"); binder.AddAttributeNameReferences(importProjectAttribute, BoundSourceFileBuilder.CreateFileReferenceSymbol( otherRepoFile.LogicalPath, otherRepoFile.PrimaryProject.ProjectId)); } } catch (Exception ex) { services.Logger.LogExceptionError($"Analyzing MSBuild file evaluation: {file.FilePath}", ex); } } }
public void Analyze( AnalysisServices services, RepoFile file, XmlSourceFileBuilder binder, XmlDocumentSyntax document) { IXmlElement root = document.Root; // corrupt or invalid or empty XML if (root == null) { return; } if (root.Name == null && root.Elements.Count() == 1) { root = root.Elements.First(); } if (root.Name != "Project") { return; } ExpressionProcessor targetListProcessor = ProcessSemicolonSeparatedTargetList; AnalyzeEvaluation(services, file, binder, document); AnalyzePropertiesAndItems(binder, root); AnalyzeChoose(binder, root); foreach (var element in root.Elements("UsingTask")) { binder.AddReferences(element.Attribute("Condition").GetAttributeValueExpressionSpans()); var taskName = element["TaskName"]; if (taskName != null) { string shortName = taskName; string containerName = null; int lastDot = taskName.LastIndexOf("."); if (lastDot > -1) { containerName = taskName.Substring(0, lastDot); shortName = taskName.Substring(lastDot + 1); } binder.AddAttributeValueDefinition(element.Attribute("TaskName"), new DefinitionSymbol() { DisplayName = taskName, ShortName = shortName, ContainerQualifiedName = containerName, Id = GetTaskSymbolId(shortName), Kind = nameof(SymbolKinds.MSBuildTask), ProjectId = MSBuildExtensions.MSBuildProjectId, ReferenceKind = nameof(ReferenceKind.Definition), }); } foreach (var outputElement in element.Elements("Output")) { foreach (var attribute in outputElement.AsSyntaxElement.Attributes) { if (attribute.Name == "ItemName") { binder.AddAttributeValueReferences(attribute, CreateItemReference(attribute.Value)); } else if (attribute.Name == "PropertyName") { binder.AddAttributeValueReferences(attribute, CreatePropertyReference(attribute.Value)); } } } } foreach (var import in root.Elements("Import")) { AnalyzeImport(binder, import); } foreach (var importGroup in root.Elements("ImportGroup")) { binder.AddReferences(importGroup.Attribute("Condition").GetAttributeValueExpressionSpans()); foreach (var import in importGroup.Elements("Import")) { AnalyzeImport(binder, import); } } foreach (var target in root.Elements("Target")) { var targetName = target["Name"]; binder.AddAttributeValueDefinition(target.Attribute("Name"), CreateTargetDefinition(targetName)); binder.AddReferences(target.Attribute("Condition").GetAttributeValueExpressionSpans()); binder.AddReferences(target.Attribute("DependsOnTargets").GetAttributeValueExpressionSpans(targetListProcessor)); binder.AddReferences(target.Attribute("Inputs").GetAttributeValueExpressionSpans()); binder.AddReferences(target.Attribute("Outputs").GetAttributeValueExpressionSpans()); binder.AddReferences(target.Attribute("BeforeTargets").GetAttributeValueExpressionSpans(targetListProcessor)); binder.AddReferences(target.Attribute("AfterTargets").GetAttributeValueExpressionSpans(targetListProcessor)); foreach (var taskElement in target.Elements.Where(el => el.Name != "PropertyGroup" && el.Name != "ItemGroup")) { binder.AddElementNameReferences(taskElement, new ReferenceSymbol() { Id = GetTaskSymbolId(taskElement.Name), Kind = nameof(SymbolKinds.MSBuildTask), ProjectId = MSBuildExtensions.MSBuildProjectId, ReferenceKind = nameof(ReferenceKind.Reference), }); // NOTE: Also parses condition attribute foreach (var taskParameterAttribute in taskElement.AsSyntaxElement.Attributes) { binder.AddReferences(taskParameterAttribute.GetAttributeValueExpressionSpans()); } foreach (var output in taskElement.Elements("Output")) { binder.AddReferences(output.Attribute("Condition").GetAttributeValueExpressionSpans()); var propertyNameAttribute = output.Attribute("PropertyName"); if (propertyNameAttribute != null) { binder.AddAttributeValueReferences(propertyNameAttribute, CreatePropertyReference(propertyNameAttribute.Value)); } var itemNameAttribute = output.Attribute("ItemName"); if (itemNameAttribute != null) { binder.AddAttributeValueReferences(itemNameAttribute, CreateItemReference(itemNameAttribute.Value)); } } } AnalyzePropertiesAndItems(binder, target); } }
/// <summary> /// Returns the URL of the file that contains the definition of the item at the current position /// </summary> /// <param name="filePath">Current file</param> /// <param name="sourceText">Text in the current file</param> /// <param name="position">Position of item that is to be resolved</param> /// <returns></returns> public List <Definition> ResolveDefinition(string filePath, string sourceText, int position) { Verify.NotDisposed(this); List <Definition> definitions = new List <Definition>(); if (_project != null) { XmlDocumentSyntax root = Parser.ParseText(sourceText); SyntaxNode syntaxNode = SyntaxLocator.FindNode(root, position); // Resolves Definition for properties e.g. $(foo) if (syntaxNode.Kind == SyntaxKind.XmlTextLiteralToken && Utilities.IsProperty(sourceText.Substring(syntaxNode.Span.Start, syntaxNode.FullWidth), position - syntaxNode.Span.Start, out string propertyName)) { foreach (ProjectProperty property in _project.Properties) { if (property.Name == propertyName) { ProjectProperty currentProperty = property; while (currentProperty.Predecessor != null) { if (currentProperty.Xml?.Location != null) { ElementLocation location = currentProperty.Xml.Location; definitions.Add(new Definition(location.File, Path.GetFileNameWithoutExtension(_project.Xml.Location.File), currentProperty.Name + " Definitions", currentProperty.EvaluatedValue, location.Line, location.Column)); } currentProperty = currentProperty.Predecessor; } if (currentProperty.Xml?.Location != null) { ElementLocation lastLocation = currentProperty.Xml.Location; definitions.Add(new Definition(lastLocation.File, Path.GetFileNameWithoutExtension(_project.Xml.Location.File), currentProperty.Name + " Definitions", currentProperty.EvaluatedValue, lastLocation.Line, lastLocation.Column)); } break; } } } // Resolves Definition for regular imports else if (syntaxNode.ParentElement != null && syntaxNode.ParentElement.Name.Equals(SyntaxNames.Import)) { while (syntaxNode.Parent.ParentElement == syntaxNode.ParentElement) { syntaxNode = syntaxNode.Parent; } int nodeStart = syntaxNode.Parent.Span.Start; int col = nodeStart - Utilities.GetStartOfLine(sourceText, nodeStart) + 1; int line = Utilities.GetLine(sourceText, nodeStart) + 1; foreach (ResolvedImport import in _project.Imports) { ElementLocation location = import.ImportingElement.Location; if (location.File == filePath && col == location.Column && line == location.Line) { definitions.Add(new Definition(import.ImportedProject.FullPath, Path.GetFileNameWithoutExtension(_project.Xml.Location.File), "Imported Files", Path.GetFileName(import.ImportedProject.FullPath))); } } } // Resolves Definition for the project's sdk else if (syntaxNode.ParentElement != null && syntaxNode.ParentElement.Name.Equals(SyntaxNames.Project)) { bool foundSdk = false; for (int i = 0; i < 3; i++) { if (sourceText.Substring(syntaxNode.Start, 3).Equals(SyntaxNames.Sdk)) { foundSdk = true; break; } syntaxNode = syntaxNode.Parent; } if (foundSdk) { foreach (ResolvedImport import in _project.Imports) { ElementLocation location = import.ImportingElement.Location; if (location.File == filePath && 0 == location.Column && 0 == location.Line) { definitions.Add(new Definition(import.ImportedProject.FullPath, Path.GetFileNameWithoutExtension(_project.Xml.Location.File), "Sdk Imports", Path.GetFileName(import.ImportedProject.FullPath))); } } } } } return(definitions); }