static CompilationResult CheckSemanticModel(Microsoft.CodeAnalysis.SyntaxTree syntaxTree, CompilationResult compilationResult) { SemanticModel semanticModel = GetSemanticModel(syntaxTree); // run all the semantic code analyzers var diagnostics = new List <CompilerError>(); Profiler.BeginSample("GetDiagnostics"); ImmutableArray <Diagnostic> rawDiagnostics = semanticModel.GetDiagnostics(); Profiler.EndSample(); Profiler.BeginSample("ProcessDiagnostics"); ProcessDiagnostics(rawDiagnostics, diagnostics); Profiler.EndSample(); Profiler.BeginSample("Format"); var codeText = syntaxTree.GetText().ToString(); compilationResult.sourceCode[(int)SourceCodePhases.Final] = codeText; Profiler.EndSample(); if (diagnostics.Any()) { compilationResult.errors = diagnostics; } return(compilationResult); }
protected override IEnumerable<string> ReportAllErrors(SyntaxTree userSolution) { var text = userSolution.GetText(); var longLines = text.Lines.Where(line => line.End - line.Start > maxLineLen).ToList(); if (longLines.Count == 0) yield break; var position = userSolution.GetLineSpan(longLines[0].Span); yield return Report( position, "Слишком длинная строка. Не заставляйте людей использовать горизонтальный скролл"); }
protected LineDirectiveMap(SyntaxTree syntaxTree) { // Accumulate all the directives, in source code order var syntaxRoot = (SyntaxNodeOrToken)syntaxTree.GetRoot(); IEnumerable <TDirective> directives = syntaxRoot.GetDirectives <TDirective>(filter: ShouldAddDirective); Debug.Assert(directives != null); // Create the entry map. this.Entries = CreateEntryMap(syntaxTree.GetText(), directives); }
public virtual Microsoft.CodeAnalysis.SyntaxTree OnTranslate(VSGraphModel graphModel, AssemblyType assemblyType, CompilationOptions compilationOptions, ref CompilationResult compilationResult) { const string windowsLineEndings = "\r\n"; const string unixLineEndings = "\n"; Microsoft.CodeAnalysis.SyntaxTree syntaxTree = Translate(graphModel, compilationOptions); // we will measure plugins time later string preferredLineEndings; LineEndingsMode lineEndingsForNewScripts = EditorSettings.lineEndingsForNewScripts; switch (lineEndingsForNewScripts) { case LineEndingsMode.OSNative: preferredLineEndings = Application.platform == RuntimePlatform.WindowsEditor ? windowsLineEndings : unixLineEndings; break; case LineEndingsMode.Unix: preferredLineEndings = unixLineEndings; break; case LineEndingsMode.Windows: preferredLineEndings = windowsLineEndings; break; default: preferredLineEndings = unixLineEndings; break; } var adHocWorkspace = new AdhocWorkspace(); var options = adHocWorkspace.Options .WithChangedOption(CSharpFormattingOptions.NewLineForMembersInObjectInit, true) .WithChangedOption(CSharpFormattingOptions.WrappingPreserveSingleLine, false) .WithChangedOption(CSharpFormattingOptions.WrappingKeepStatementsOnSingleLine, false) .WithChangedOption(CSharpFormattingOptions.NewLinesForBracesInObjectCollectionArrayInitializers, true) .WithChangedOption(FormattingOptions.NewLine, LanguageNames.CSharp, preferredLineEndings); compilationResult.sourceCode[(int)SourceCodePhases.Initial] = syntaxTree.GetText().ToString(); var formattedTree = Formatter.Format(syntaxTree.GetCompilationUnitRoot(), adHocWorkspace, options); formattedTree = new VisualScriptingCSharpFormatter().Visit(formattedTree); string codeText = formattedTree.GetText().ToString(); compilationResult.sourceCode[(int)SourceCodePhases.Final] = codeText; return(syntaxTree); }
private static SyntaxTree ToResult(Compilation compilation, string name, SyntaxTree tree, string path, bool writeToDisk) { var ext = (compilation.Language == LanguageNames.VisualBasic) ? ".vb" : ".cs"; var fileName = $"{FixUpName(name)}{ext}"; path = PathUtilities.CombinePossiblyRelativeAndRelativePaths(path, fileName); if (writeToDisk) { var sourceText = tree.GetText(); var encoding = sourceText.Encoding ?? Encoding.UTF8; PortableShim.File.WriteAllText(path, sourceText.ToString(), encoding); } return tree.WithFilePath(path); }
private static SyntaxTree ToResult(Compilation compilation, string name, SyntaxTree tree, string path, bool writeToDisk) { var ext = (compilation.Language == LanguageNames.VisualBasic) ? ".vb" : ".cs"; var fileName = $"{FixUpName(name)}{ext}"; path = PathUtilities.CombinePossiblyRelativeAndRelativePaths(path, fileName); if (writeToDisk) { var sourceText = tree.GetText(); var encoding = sourceText.Encoding ?? Encoding.UTF8; PortableShim.File.WriteAllText(path, sourceText.ToString(), encoding); } return(tree.WithFilePath(path)); }
// use static method so we don't capture references to this private static Tuple <ValueSource <TextAndVersion>, TreeAndVersion> CreateRecoverableTextAndTree( SyntaxNode newRoot, string filePath, VersionStamp textVersion, VersionStamp treeVersion, Encoding encoding, DocumentInfo.DocumentAttributes attributes, ParseOptions options, ImmutableDictionary <string, ReportDiagnostic> treeDiagnosticReportingOptionsOpt, ISyntaxTreeFactoryService factory, PreservationMode mode) { SyntaxTree tree = null; ValueSource <TextAndVersion> lazyTextAndVersion = null; if ((mode == PreservationMode.PreserveIdentity) || !factory.CanCreateRecoverableTree(newRoot)) { // its okay to use a strong cached AsyncLazy here because the compiler layer SyntaxTree will also keep the text alive once its built. lazyTextAndVersion = new TreeTextSource( new AsyncLazy <SourceText>( c => tree.GetTextAsync(c), c => tree.GetText(c), cacheResult: true), textVersion, filePath); tree = factory.CreateSyntaxTree(filePath, options, encoding, newRoot, treeDiagnosticReportingOptionsOpt); } else { // uses CachedWeakValueSource so the document and tree will return the same SourceText instance across multiple accesses as long // as the text is referenced elsewhere. lazyTextAndVersion = new TreeTextSource( new CachedWeakValueSource <SourceText>( new AsyncLazy <SourceText>( c => BuildRecoverableTreeTextAsync(tree, encoding, c), c => BuildRecoverableTreeText(tree, encoding, c), cacheResult: false)), textVersion, filePath); tree = factory.CreateRecoverableTree(attributes.Id.ProjectId, filePath, options, lazyTextAndVersion, encoding, newRoot, treeDiagnosticReportingOptionsOpt); } return(Tuple.Create(lazyTextAndVersion, TreeAndVersion.Create(tree, treeVersion))); }
static void ApplyPluginsToAst(ref Microsoft.CodeAnalysis.SyntaxTree syntaxTree, CompilationOptions options, Stencil stencil, ref CompilationResult result) { Profiler.BeginSample("Code Analysis"); // run all the syntactic code analyzers CompilationStatus status = CompilationStatus.Succeeded; result.pluginSourceCode = new Dictionary <Type, string>(); foreach (IRoslynPluginHandler handler in stencil.GetCompilationPluginHandlers(options).OfType <IRoslynPluginHandler>()) { handler.Apply(ref syntaxTree, options); result.pluginSourceCode[handler.GetType()] = syntaxTree.GetText().ToString(); } result.status = status; Profiler.EndSample(); }
// return a set of text changes that when applied to the old document produces the new document internal static IList<TextChange> GetTextChanges(SyntaxTree before, SyntaxTree after) { if (before == after) { return SpecializedCollections.EmptyList<TextChange>(); } else if (before == null) { return new[] { new TextChange(new TextSpan(0, 0), after.GetText().ToString()) }; } else if (after == null) { throw new ArgumentNullException("after"); } else { return GetTextChanges(before.GetRoot(), after.GetRoot()); } }
protected override bool IsPartialMethodCompletionContext(SyntaxTree tree, int position, CancellationToken cancellationToken, out DeclarationModifiers modifiers, out SyntaxToken token) { var touchingToken = tree.FindTokenOnLeftOfPosition(position, cancellationToken); var targetToken = touchingToken.GetPreviousTokenIfTouchingWord(position); var text = tree.GetText(cancellationToken); token = targetToken; modifiers = default(DeclarationModifiers); if (targetToken.IsKind(SyntaxKind.VoidKeyword, SyntaxKind.PartialKeyword) || (targetToken.Kind() == SyntaxKind.IdentifierToken && targetToken.HasMatchingText(SyntaxKind.PartialKeyword))) { return !IsOnSameLine(touchingToken.GetNextToken(), touchingToken, text) && VerifyModifiers(tree, position, cancellationToken, out modifiers); } return false; }
// return a set of text changes that when applied to the old document produces the new document internal static IList <TextChange> GetTextChanges(SyntaxTree before, SyntaxTree after) { if (before == after) { return(SpecializedCollections.EmptyList <TextChange>()); } else if (before == null) { return(new[] { new TextChange(new TextSpan(0, 0), after.GetText().ToString()) }); } else if (after == null) { throw new ArgumentNullException(nameof(after)); } else { return(GetTextChanges(before.GetRoot(), after.GetRoot())); } }
internal static IList <TextSpan> GetPossiblyDifferentTextSpans(SyntaxTree before, SyntaxTree after) { if (before == after) { // They're the same, so nothing changed. return(SpecializedCollections.EmptyList <TextSpan>()); } else if (before == null) { // The tree is completely new, everything has changed. return(new[] { new TextSpan(0, after.GetText().Length) }); } else if (after == null) { throw new ArgumentNullException(nameof(after)); } else { return(GetPossiblyDifferentTextSpans(before.GetRoot(), after.GetRoot())); } }
internal static IList<TextSpan> GetPossiblyDifferentTextSpans(SyntaxTree before, SyntaxTree after) { if (before == after) { // They're the same, so nothing changed. return SpecializedCollections.EmptyList<TextSpan>(); } else if (before == null) { // The tree is completely new, everything has changed. return new[] { new TextSpan(0, after.GetText().Length) }; } else if (after == null) { throw new ArgumentNullException("after"); } else { return GetPossiblyDifferentTextSpans(before.GetRoot(), after.GetRoot()); } }
internal static bool TryGetBreakpointSpan(SyntaxTree tree, int position, CancellationToken cancellationToken, out TextSpan breakpointSpan) { var source = tree.GetText(cancellationToken); // If the line is entirely whitespace, then don't set any breakpoint there. var line = source.Lines.GetLineFromPosition(position); if (IsBlank(line)) { breakpointSpan = default(TextSpan); return false; } // If the user is asking for breakpoint in an inactive region, then just create a line // breakpoint there. if (tree.IsInInactiveRegion(position, cancellationToken)) { breakpointSpan = default(TextSpan); return true; } var root = tree.GetRoot(cancellationToken); return root.TryGetClosestBreakpointSpan(position, out breakpointSpan); }
/// <summary> /// Writes the DbContext to disk using the given Roslyn SyntaxTree. /// The method expects that SyntaxTree has a file path associated with it. /// Handles both writing a new file and editing an existing file. /// </summary> /// <param name="newTree"></param> private void PersistSyntaxTree(SyntaxTree newTree) { Debug.Assert(newTree != null); Debug.Assert(!String.IsNullOrEmpty(newTree.FilePath)); Directory.CreateDirectory(Path.GetDirectoryName(newTree.FilePath)); using (var fileStream = new FileStream(newTree.FilePath, FileMode.OpenOrCreate, FileAccess.Write)) { using (var streamWriter = new StreamWriter(stream: fileStream, encoding: Encoding.UTF8)) { newTree.GetText().Write(streamWriter); } } }
private static TextLine GetLineOfToken(SyntaxToken token, SyntaxTree tree) { return tree.GetText().Lines[token.GetLocation().GetLineSpan().StartLinePosition.Line]; }
/// <summary> /// Get a string that represents the differences in the file in a way that is readable /// </summary> /// <param name="ancestor">SyntaxTree that changed was modified from</param> /// <param name="diffs">all the changes to the ancestor</param> /// <returns>a string that can be inspected to see the changes</returns> public static string VisualDiff(IEnumerable<Diff> diffs, SyntaxTree ancestor) { var builder = new StringBuilder(); var currentAncestorPos = 0; foreach (var d in diffs) { var dStart = d.Ancestor.Span.Start; if (dStart > currentAncestorPos) { builder.Append(ancestor .GetText() .ToString(TextSpan.FromBounds(currentAncestorPos, dStart))); } builder.Append(d); currentAncestorPos = d.Ancestor.Span.End; } builder.Append(ancestor .GetText() .ToString(TextSpan.FromBounds(currentAncestorPos, ancestor.Length))); return builder.ToString(); }
/// <summary> /// Gets the location representing the position of the given element in the source file. /// </summary> /// <param name="syntaxTree">The syntax tree to use for generating the location.</param> /// <param name="element">The XML element to get the location of.</param> /// <returns>The location representing the position of the given element in the source file.</returns> internal Location GetElementLocation(SyntaxTree syntaxTree, XElement element) { var headerSourceText = syntaxTree.GetText().GetSubText(TextSpan.FromBounds(this.fileHeaderStart, this.fileHeaderEnd)).ToString(); var tagStart = "<" + element.Name.LocalName; var index = headerSourceText.IndexOf(tagStart); var textSpan = TextSpan.FromBounds(this.fileHeaderStart + index, this.fileHeaderStart + index + tagStart.Length); return Location.Create(syntaxTree, textSpan); }
private static Dictionary<int, string> ExpectedIssues(SyntaxTree syntaxTree) { var expectedIssueMessage = new Dictionary<int, string>(); foreach (var line in syntaxTree.GetText().Lines) { var lineText = line.ToString(); if (!lineText.Contains(NONCOMPLIANT_START)) { continue; } var lineNumber = GetNonCompliantLineNumber(line); expectedIssueMessage.Add(lineNumber, null); var match = Regex.Match(lineText, NONCOMPLIANT_MESSAGE_PATTERN); if (!match.Success) { continue; } var message = match.Groups[1].ToString(); expectedIssueMessage[lineNumber] = message.Substring(2, message.Length - 4); } return expectedIssueMessage; }
private static IEnumerable<int> ExpectedIssues(SyntaxTree syntaxTree) { return syntaxTree.GetText().Lines .Where(l => l.ToString().Contains(NONCOMPLIANT_START)) .Select(l => GetNoncompliantLineNumber(l)); }
static bool VerifyModifiers(SyntaxTree tree, int position, CancellationToken cancellationToken/*, out DeclarationModifiers modifiers*/) { var touchingToken = tree.FindTokenOnLeftOfPosition(position, cancellationToken); var token = touchingToken.GetPreviousToken(); bool foundPartial = touchingToken.IsKindOrHasMatchingText(SyntaxKind.PartialKeyword); bool foundAsync = false; while (IsOnSameLine(token, touchingToken, tree.GetText(cancellationToken))) { if (token.IsKind(SyntaxKind.ExternKeyword, SyntaxKind.PublicKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.InternalKeyword)) { //modifiers = default(DeclarationModifiers); return false; } if (token.IsKindOrHasMatchingText(SyntaxKind.AsyncKeyword)) { foundAsync = true; } foundPartial = foundPartial || token.IsKindOrHasMatchingText(SyntaxKind.PartialKeyword); token = token.GetPreviousToken(); } /*modifiers = new DeclarationModifiers() .WithPartial(true) .WithAsync (foundAsync);*/ return foundPartial; }
private static string getSnippet(SyntaxTree tree, int startPos, int endPos) { var rawSnippet = tree.GetText().GetSubText(new Microsoft.CodeAnalysis.Text.TextSpan(startPos, endPos - startPos)).ToString(); return removeWhitespace(rawSnippet); }
private static Dictionary<int, ExactIssueLocation> ExpectedIssueLocations(SyntaxTree syntaxTree, string language) { var exactLocations = new Dictionary<int, ExactIssueLocation>(); var locationPattern = language == LanguageNames.CSharp ? EXPECTED_ISSUE_LOCATION_PATTERN_CSHARP : EXPECTED_ISSUE_LOCATION_PATTERN_VBNET; foreach (var line in syntaxTree.GetText().Lines) { var lineText = line.ToString(); var match = Regex.Match(lineText, locationPattern); if (!match.Success) { var commentStart = language == LanguageNames.CSharp ? COMMENT_START_CSHARP : COMMENT_START_VBNET; if (Regex.IsMatch(lineText, commentStart + EXPECTED_ISSUE_LOCATION_PATTERN + "$")) { Assert.Fail("Line matches expected location pattern, but doesn't start at the beginning of the line."); } continue; } var position = match.Groups[1]; exactLocations.Add(line.LineNumber, new ExactIssueLocation { Line = line.LineNumber, StartPosition = position.Index, Length = position.Length, }); } return exactLocations; }
internal static void VerifySource(this SyntaxTree tree, IEnumerable <TextChangeRange> changes = null) { var root = tree.GetRoot(); var text = tree.GetText(); var fullSpan = new TextSpan(0, text.Length); SyntaxNode node = null; // If only a subset of the document has changed, // just check that subset to reduce verification cost. if (changes != null) { var change = TextChangeRange.Collapse(changes).Span; if (change != fullSpan) { // Find the lowest node in the tree that contains the changed region. node = root.DescendantNodes(n => n.FullSpan.Contains(change)).LastOrDefault(); } } if (node == null) { node = root; } var span = node.FullSpan; var textSpanOpt = span.Intersection(fullSpan); int index; if (textSpanOpt == null) { index = 0; } else { var fromText = text.ToString(textSpanOpt.Value); var fromNode = node.ToFullString(); index = FindFirstDifference(fromText, fromNode); } if (index >= 0) { index += span.Start; string message; if (index < text.Length) { var position = text.Lines.GetLinePosition(index); var line = text.Lines[position.Line]; var allText = text.ToString(); // Entire document as string to allow inspecting the text in the debugger. message = string.Format("Unexpected difference at offset {0}: Line {1}, Column {2} \"{3}\"", index, position.Line + 1, position.Character + 1, line.ToString()); } else { message = "Unexpected difference past end of the file"; } Debug.Assert(false, message); } }
public override SourceText GetText(CancellationToken cancellationToken = default) => _tree.GetText(cancellationToken);
private SyntaxTree AnalyzeSyntax(SyntaxTree tree, string code) { var root = tree.GetRoot(); var codeErrors = root.GetDiagnostics().Where(error => error.Id == "CS1022"). OrderBy(error => error.Location.SourceSpan.Start).GetEnumerator(); Diagnostic currError = null; int currErrorPos = 0; if (codeErrors != null && codeErrors.MoveNext()) currError = codeErrors.Current; List<StatementSyntax> statements = new List<StatementSyntax>(); List<MemberDeclarationSyntax> members = new List<MemberDeclarationSyntax>(); List<MemberDeclarationSyntax> types = new List<MemberDeclarationSyntax>(); foreach (var child in root.ChildNodes()) { if (child is IncompleteMemberSyntax) continue; if (child is FieldDeclarationSyntax) { //case: code variable? FieldDeclarationSyntax field = (FieldDeclarationSyntax)child; //td: !!! variable initialization continue; } if (child is MethodDeclarationSyntax) { //case: bad method? MethodDeclarationSyntax method = (MethodDeclarationSyntax)child; if (method.Body == null) continue; } if (child is MemberDeclarationSyntax) { bool foundError = false; if (currError != null) { if (child.SpanStart > currError.Location.SourceSpan.Start) { SourceText errorSource = tree.GetText().GetSubText(new TextSpan(currErrorPos, child.SpanStart - currErrorPos)); parseStatements(errorSource.ToString(), currErrorPos, statements); foundError = true; currError = null; while (codeErrors.MoveNext()) { var nextError = codeErrors.Current; if (nextError.Location.SourceSpan.Start > child.Span.End) { currError = nextError; break; } } } } currErrorPos = child.Span.End; var toAdd = child as MemberDeclarationSyntax; if (foundError) { toAdd = toAdd.ReplaceTrivia(child.GetLeadingTrivia(), (oldTrivia, newTrivia) => { return SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, string.Empty); }); } if (toAdd is TypeDeclarationSyntax || toAdd is EnumDeclarationSyntax) types.Add(toAdd); else if (!(toAdd is NamespaceDeclarationSyntax)) members.Add(toAdd); } else { //any other top level construct indicates completeness return tree; } } if (currError != null) { SourceText errorSource = tree.GetText().GetSubText(new TextSpan(currErrorPos, tree.GetRoot().FullSpan.End - currErrorPos)); parseStatements(errorSource.ToString(), currErrorPos, statements); } bool hasCode = statements.Count > 0; bool hasMembers = members.Count > 0; if (!hasCode && !hasMembers) { return tree; //nothing to se here } var complete = ctx_.Complete(statements, members, types); return complete != null? complete : tree; //var container = SyntaxFactory.ClassDeclaration("application"); //if (hasCode) //{ // hasMembers = true; // members.Add(SyntaxFactory.MethodDeclaration(Void, "main"). // WithBody(SyntaxFactory.Block(). // WithStatements(SyntaxFactory.List(statements)))); //} //if (hasMembers) // container = container.WithMembers(SyntaxFactory.List(members)); //if (types.Count > 0) //{ // types.Insert(0, container); // return SyntaxFactory.CompilationUnit(). // WithMembers(SyntaxFactory.List(types)).SyntaxTree; //} //return container.SyntaxTree; }
private static IEnumerable<int> ExpectedIssues(SyntaxTree syntaxTree) { return from l in syntaxTree.GetText().Lines where l.ToString().Contains("Noncompliant") select l.LineNumber + 1; }
/// <summary> /// Gets the absolute position in the synatxtree from the line and character offset /// </summary> private static int GetAbsolutePosition(SyntaxTree syntaxTree, int line, int lineCharOffset) => syntaxTree.GetText().Lines[line - 1].Start + lineCharOffset;