Skip to content

Commit

Permalink
Add ChecksumAlgorithm to project snapshot (#62840)
Browse files Browse the repository at this point in the history
* Revert "Revert "Deprecate usage of Workspace in TextLoader (breaking change) (#63616)" (#64228)"

This reverts commit 9d2a58e.

* Implement override detection

* Add ChecksumAlgorithm to DocumentAttributes and ProjectAttributes

* Ban more overloads of SyntaxTree.Create

* LoadChecksum

* LoadTextOptions


* Better banned symbols comment


* Remove checksum alg from TreeAndVersion


* More feedback


* Remove DocumentInfo.LoadTextOptions


* Make CanReloadText internal


* EnC: use the document snapshot when validating PDB checksum

* Fix style

* Make new TextLoader APIs internal

* Feedback


* PdbMatchingSourceTextProvider

* Move GetSyntaxTreeFilePath to DocumentAttributes
  • Loading branch information
tmat authored Oct 10, 2022
1 parent 1382bbf commit 157d34a
Show file tree
Hide file tree
Showing 219 changed files with 3,653 additions and 1,504 deletions.
7 changes: 7 additions & 0 deletions docs/Breaking API Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,10 @@ Roslyn does not support implementing completion for arbitrary languages.
### `Microsoft.CodeAnalysis.CodeStyle.NotificationOption` is now immutable

All property setters now throw an exception.

# Version 4.4.0

`Workspace.OnWorkspaceFailed` is no longer called when an error occurs while reading source file content from disk.

The `Workspace` and `DocumentId` parameters of `TextLoader.LoadTextAndVersionAsync(Workspace, DocumentId, CancellationToken)` are deprecated.
The method now receives `null` `Workspace` and `DocumentId`.
16 changes: 15 additions & 1 deletion eng/config/BannedSymbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,18 @@ M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAna
M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAnalysis.Document,Microsoft.CodeAnalysis.SyntaxAnnotation,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload that takes SimplifierOptions
M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAnalysis.Document,Microsoft.CodeAnalysis.Text.TextSpan,Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload that takes SimplifierOptions
M:Microsoft.CodeAnalysis.Simplification.Simplifier.ReduceAsync(Microsoft.CodeAnalysis.Document,System.Collections.Generic.IEnumerable{Microsoft.CodeAnalysis.Text.TextSpan},Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use overload that takes SimplifierOptions
M:Microsoft.CodeAnalysis.Editing.SyntaxEditor.#ctor(Microsoft.CodeAnalysis.SyntaxNode,Microsoft.CodeAnalysis.Host.HostWorkspaceServices); Use overload that takes HostSolutionServices instead
M:Microsoft.CodeAnalysis.Editing.SyntaxEditor.#ctor(Microsoft.CodeAnalysis.SyntaxNode,Microsoft.CodeAnalysis.Host.HostWorkspaceServices); Use overload that takes HostSolutionServices instead
M:Microsoft.CodeAnalysis.FileTextLoader.#ctor(System.String,System.Text.Encoding); use WorkspaceFileTextLoader that calls on ITextFactoryService to create SourceText
M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SyntaxTree(Microsoft.CodeAnalysis.SyntaxNode,Microsoft.CodeAnalysis.ParseOptions,System.String,System.Text.Encoding); Use CSharpSyntaxTree sublass that takes checksum algorithm
M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseSyntaxTree(System.String,Microsoft.CodeAnalysis.ParseOptions,System.String,System.Text.Encoding,System.Threading.CancellationToken); Use CSharpSyntaxTree sublass that takes checksum algorithm
M:Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.CreateWithoutClone(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode); Use CSharpSyntaxTree sublass that takes checksum algorithm
M:Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.Create(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions options, System.String path, System.Text.Encoding encoding); Use CSharpSyntaxTree sublass that takes checksum algorithm
M:Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(System.String,Microsoft.CodeAnalysis.CSharp.CSharpParseOptions,System.String,System.Text.Encoding,System.Threading.CancellationToken); Use API that takes SourceText
M:Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(System.String,Microsoft.CodeAnalysis.CSharp.CSharpParseOptions,System.String,System.Text.Encoding,System.Collections.Immutable.ImmutableDictionary{System.String,Microsoft.CodeAnalysis.ReportDiagnostic},System.Nullable{System.Boolean},System.Threading.CancellationToken); Use API that takes SourceText
M:Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.SyntaxTree(Microsoft.CodeAnalysis.SyntaxNode,Microsoft.CodeAnalysis.ParseOptions,System.String,System.Text.Encoding); Use VisualBasicSyntaxTree sublass that takes checksum algorithm
M:Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.ParseSyntaxTree(System.String,Microsoft.CodeAnalysis.ParseOptions,System.String,System.Text.Encoding,System.Threading.CancellationToken); Use overload with SourceText
M:Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.ParseSyntaxTree(System.String,Microsoft.CodeAnalysis.ParseOptions,System.String,System.Text.Encoding,System.Collections.Immutable.ImmutableDictionary{System.String,Microsoft.CodeAnalysis.ReportDiagnostic},System.Threading.CancellationToken); Use overload with SourceText
M:Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.CreateWithoutClone(Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxNode); Use VisualBasicSyntaxTree sublass that takes checksum algorithm
M:Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.Create(Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxNode,Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions,System.String,System.Text.Encoding,System.Collections.Immutable.ImmutableDictionary{System.String,Microsoft.CodeAnalysis.ReportDiagnostic}); Use VisualBasicSyntaxTree sublass that takes checksum algorithm
M:Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.Create(Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxNode,Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions,System.String,System.Text.Encoding); Use VisualBasicSyntaxTree sublass that takes checksum algorithm
M:Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.ParseText(System.String,Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions,System.String,System.Text.Encoding,System.Collections.Immutable.ImmutableDictionary{System.String,Microsoft.CodeAnalysis.ReportDiagnostic},System.Threading.CancellationToken); Use overload with SourceText
4 changes: 2 additions & 2 deletions eng/targets/Imports.targets
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@
</ItemGroup>

<ItemGroup>
<!-- Include BannedSymbols covering all projects -->
<AdditionalFiles Include="$(MSBuildThisFileDirectory)..\config\BannedSymbols.txt" />
<!-- Include BannedSymbols covering all product projects -->
<AdditionalFiles Include="$(MSBuildThisFileDirectory)..\config\BannedSymbols.txt" Condition="'$(IsTestProject)' == 'false'" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable<string> ar
bool embedAllSourceFiles = false;
bool resourcesOrModulesSpecified = false;
Encoding? codepage = null;
var checksumAlgorithm = SourceHashAlgorithmUtils.DefaultContentHashAlgorithm;
var checksumAlgorithm = SourceHashAlgorithms.Default;
var defines = ArrayBuilder<string>.GetInstance();
List<CommandLineReference> metadataReferences = new List<CommandLineReference>();
List<CommandLineAnalyzerReference> analyzers = new List<CommandLineAnalyzerReference>();
Expand Down
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ private static SyntaxTree ComputeSyntaxTree(CSharpSyntaxNode node)
if (parent == null)
{
// set the tree on the root node atomically
#pragma warning disable RS0030 // Do not use banned APIs (CreateWithoutClone is intended to be used from this call site only)
Interlocked.CompareExchange(ref node._syntaxTree, CSharpSyntaxTree.CreateWithoutClone(node), null);
#pragma warning restore
tree = node._syntaxTree;
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ namespace Microsoft.CodeAnalysis.CSharp
{
public partial class CSharpSyntaxTree
{
private class DebuggerSyntaxTree : ParsedSyntaxTree
/// <summary>
/// Use by Expression Evaluator.
/// </summary>
private sealed class DebuggerSyntaxTree : ParsedSyntaxTree
{
public DebuggerSyntaxTree(CSharpSyntaxNode root, SourceText text, CSharpParseOptions options)
: base(
Expand Down
14 changes: 6 additions & 8 deletions src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxTree.Dummy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public partial class CSharpSyntaxTree
{
internal sealed class DummySyntaxTree : CSharpSyntaxTree
{
private const SourceHashAlgorithm ChecksumAlgorithm = SourceHashAlgorithm.Sha1;

private readonly CompilationUnitSyntax _node;

public DummySyntaxTree()
Expand All @@ -30,12 +32,12 @@ public override string ToString()

public override SourceText GetText(CancellationToken cancellationToken)
{
return SourceText.From(string.Empty, Encoding.UTF8);
return SourceText.From(string.Empty, Encoding, ChecksumAlgorithm);
}

public override bool TryGetText(out SourceText text)
{
text = SourceText.From(string.Empty, Encoding.UTF8);
text = SourceText.From(string.Empty, Encoding, ChecksumAlgorithm);
return true;
}

Expand Down Expand Up @@ -90,14 +92,10 @@ public override bool HasCompilationUnitRoot
}

public override SyntaxTree WithRootAndOptions(SyntaxNode root, ParseOptions options)
{
return SyntaxFactory.SyntaxTree(root, options: options, path: FilePath, encoding: null);
}
=> Create((CSharpSyntaxNode)root, (CSharpParseOptions)options, FilePath, Encoding, ChecksumAlgorithm);

public override SyntaxTree WithFilePath(string path)
{
return SyntaxFactory.SyntaxTree(_node, options: this.Options, path: path, encoding: null);
}
=> Create(_node, Options, path, Encoding, ChecksumAlgorithm);
}
}
}
23 changes: 21 additions & 2 deletions src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,25 @@ public static SyntaxTree Create(
cloneRoot: true);
}

internal static SyntaxTree Create(
CSharpSyntaxNode root,
CSharpParseOptions options,
string? path,
Encoding? encoding,
SourceHashAlgorithm checksumAlgorithm)
{
return new ParsedSyntaxTree(
textOpt: null,
encodingOpt: encoding,
checksumAlgorithm: checksumAlgorithm,
path: path,
options: options,
root: root,
directives: default,
diagnosticOptions: null,
cloneRoot: true);
}

/// <summary>
/// Creates a new syntax tree from a syntax node with text that should correspond to the syntax node.
/// </summary>
Expand Down Expand Up @@ -438,7 +457,7 @@ public static SyntaxTree ParseText(
bool? isGeneratedCode,
CancellationToken cancellationToken)
{
return ParseText(SourceText.From(text, encoding), options, path, diagnosticOptions, isGeneratedCode, cancellationToken);
return ParseText(SourceText.From(text, encoding, SourceHashAlgorithm.Sha1), options, path, diagnosticOptions, isGeneratedCode, cancellationToken);
}

// The overload that has more parameters is itself obsolete, as an intentional break to allow future
Expand Down Expand Up @@ -915,7 +934,7 @@ public static SyntaxTree ParseText(
Encoding? encoding,
ImmutableDictionary<string, ReportDiagnostic>? diagnosticOptions,
CancellationToken cancellationToken)
=> ParseText(text, options, path, encoding, diagnosticOptions, isGeneratedCode: null, cancellationToken);
=> ParseText(SourceText.From(text, encoding, SourceHashAlgorithm.Sha1), options, path, diagnosticOptions, isGeneratedCode: null, cancellationToken);

// 3.3 BACK COMPAT OVERLOAD -- DO NOT MODIFY
[EditorBrowsable(EditorBrowsableState.Never)]
Expand Down
10 changes: 5 additions & 5 deletions src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1544,13 +1544,12 @@ public static IdentifierNameSyntax IdentifierName(string name)
/// Create a new syntax tree from a syntax node.
/// </summary>
public static SyntaxTree SyntaxTree(SyntaxNode root, ParseOptions? options = null, string path = "", Encoding? encoding = null)
{
return CSharpSyntaxTree.Create((CSharpSyntaxNode)root, (CSharpParseOptions?)options, path, encoding);
}
=> CSharpSyntaxTree.Create((CSharpSyntaxNode)root, (CSharpParseOptions?)options ?? CSharpParseOptions.Default, path, encoding, SourceHashAlgorithm.Sha1);

#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters
#pragma warning disable RS0027 // Public API with optional parameter(s) should have the most parameters amongst its public overloads.

#pragma warning disable RS0030 // Do not used banned APIs
#pragma warning disable CS0618 // Type or member is obsolete
/// <inheritdoc cref="CSharpSyntaxTree.ParseText(string, CSharpParseOptions?, string, Encoding?, CancellationToken)"/>
public static SyntaxTree ParseSyntaxTree(
string text,
Expand All @@ -1559,8 +1558,9 @@ public static SyntaxTree ParseSyntaxTree(
Encoding? encoding = null,
CancellationToken cancellationToken = default)
{
return CSharpSyntaxTree.ParseText(text, (CSharpParseOptions?)options, path, encoding, cancellationToken);
return CSharpSyntaxTree.ParseText(SourceText.From(text, encoding, SourceHashAlgorithm.Sha1), (CSharpParseOptions?)options, path, diagnosticOptions: null, isGeneratedCode: null, cancellationToken);
}
#pragma warning restore

/// <inheritdoc cref="CSharpSyntaxTree.ParseText(SourceText, CSharpParseOptions?, string, CancellationToken)"/>
public static SyntaxTree ParseSyntaxTree(
Expand Down
26 changes: 26 additions & 0 deletions src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,32 @@ public void SourceGeneratedFiles()
</symbols>", options: PdbValidationOptions.ExcludeMethods);
}

[Fact]
public void EmitDebugInfoForSynthesizedSyntaxTree()
{
var tree1 = SyntaxFactory.ParseCompilationUnit(@"
#line 1 ""test.cs""
class C { void M() {} }
").SyntaxTree;
var tree2 = SyntaxFactory.ParseCompilationUnit(@"
class D { void M() {} }
").SyntaxTree;

var comp = CSharpCompilation.Create("test", new[] { tree1, tree2 }, TargetFrameworkUtil.StandardReferences, TestOptions.DebugDll);

var result = comp.Emit(new MemoryStream(), pdbStream: new MemoryStream());
result.Diagnostics.Verify();

comp.VerifyPdb(@"
<symbols>
<files>
<file id=""1"" name="""" language=""C#"" />
<file id=""2"" name=""test.cs"" language=""C#"" />
</files>
</symbols>
", format: DebugInformationFormat.PortablePdb, options: PdbValidationOptions.ExcludeMethods);
}

[WorkItem(846584, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/846584")]
[ConditionalFact(typeof(WindowsOnly))]
public void RelativePathForExternalSource_Sha1_Windows()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
Expand All @@ -16,6 +17,7 @@
using Microsoft.CodeAnalysis.FlowAnalysis;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Xunit;

Expand Down Expand Up @@ -8673,13 +8675,13 @@ Task On01234567890123456()
Task.WhenAll(this.c01234567890123456789.Select(v01234567 => v01234567.U0123456789012345678901234())));
";

var newText = Microsoft.CodeAnalysis.Text.StringText.From(text2, System.Text.Encoding.UTF8);
using var lexer = new Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.Lexer(newText, TestOptions.RegularDefault);
using var parser = new Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.LanguageParser(lexer,
(CSharpSyntaxNode)oldTree.GetRoot(), new[] { new Microsoft.CodeAnalysis.Text.TextChangeRange(new Microsoft.CodeAnalysis.Text.TextSpan(282, 0), 1) });
var newText = SourceText.From(text2, Encoding.UTF8, SourceHashAlgorithms.Default);
using var lexer = new Syntax.InternalSyntax.Lexer(newText, TestOptions.RegularDefault);
using var parser = new Syntax.InternalSyntax.LanguageParser(lexer,
(CSharpSyntaxNode)oldTree.GetRoot(), new[] { new TextChangeRange(new TextSpan(282, 0), 1) });

var compilationUnit = (CompilationUnitSyntax)parser.ParseCompilationUnit().CreateRed();
var tree = CSharpSyntaxTree.Create(compilationUnit, TestOptions.RegularDefault, encoding: System.Text.Encoding.UTF8);
var tree = CSharpSyntaxTree.Create(compilationUnit, TestOptions.RegularDefault, path: "", Encoding.UTF8, SourceHashAlgorithms.Default);
Assert.Equal(text2, tree.GetText().ToString());
tree.VerifySource();

Expand Down
28 changes: 18 additions & 10 deletions src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxTreeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#nullable disable

using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
Expand Down Expand Up @@ -112,18 +113,25 @@ static SyntaxTree WithInitializedDirectives(SyntaxTree tree)
}
}

[Fact]
public void Create()
{
var root = SyntaxFactory.ParseCompilationUnit("");

var tree = CSharpSyntaxTree.Create(root);
Assert.Equal(SourceHashAlgorithm.Sha1, tree.GetText().ChecksumAlgorithm);
}

// Diagnostic options on syntax trees are now obsolete
#pragma warning disable CS0618
[Fact]
public void Create_WithDiagnosticOptions()
{
var options = CreateImmutableDictionary(("CS0078", ReportDiagnostic.Suppress));
var tree = CSharpSyntaxTree.Create(SyntaxFactory.ParseCompilationUnit(""),
options: null,
path: "",
encoding: null,
diagnosticOptions: options);
var tree = CSharpSyntaxTree.Create(SyntaxFactory.ParseCompilationUnit(""), options: null, path: null, encoding: null, diagnosticOptions: options);

Assert.Same(options, tree.DiagnosticOptions);
Assert.Equal(SourceHashAlgorithm.Sha1, tree.GetText().ChecksumAlgorithm);
}

[Fact]
Expand Down Expand Up @@ -248,7 +256,7 @@ public void WithRootAndOptions_ParsedTree()
[Fact]
public void WithRootAndOptions_ParsedTreeWithText()
{
var oldText = SourceText.From("class B {}", Encoding.Unicode, SourceHashAlgorithm.Sha256);
var oldText = SourceText.From("class B {}", Encoding.Unicode, SourceHashAlgorithms.Default);
var oldTree = SyntaxFactory.ParseSyntaxTree(oldText);

var newRoot = SyntaxFactory.ParseCompilationUnit("class C {}");
Expand All @@ -259,7 +267,7 @@ public void WithRootAndOptions_ParsedTreeWithText()
Assert.Equal(newRoot.ToString(), newTree.GetRoot().ToString());
Assert.Same(newOptions, newTree.Options);
Assert.Same(Encoding.Unicode, newText.Encoding);
Assert.Equal(SourceHashAlgorithm.Sha256, newText.ChecksumAlgorithm);
Assert.Equal(SourceHashAlgorithms.Default, newText.ChecksumAlgorithm);
}

[Fact]
Expand Down Expand Up @@ -290,7 +298,7 @@ public void WithFilePath_ParsedTree()
[Fact]
public void WithFilePath_ParsedTreeWithText()
{
var oldText = SourceText.From("class B {}", Encoding.Unicode, SourceHashAlgorithm.Sha256);
var oldText = SourceText.From("class B {}", Encoding.Unicode, SourceHashAlgorithms.Default);
var oldTree = SyntaxFactory.ParseSyntaxTree(oldText, path: "old.cs");

var newTree = oldTree.WithFilePath("new.cs");
Expand All @@ -300,7 +308,7 @@ public void WithFilePath_ParsedTreeWithText()
Assert.Equal(oldTree.ToString(), newTree.ToString());

Assert.Same(Encoding.Unicode, newText.Encoding);
Assert.Equal(SourceHashAlgorithm.Sha256, newText.ChecksumAlgorithm);
Assert.Equal(SourceHashAlgorithms.Default, newText.ChecksumAlgorithm);
}

[Fact]
Expand All @@ -321,7 +329,7 @@ public void WithFilePath_Null()
oldTree = SyntaxFactory.ParseSyntaxTree("", path: "old.cs");
Assert.Equal(string.Empty, oldTree.WithFilePath(null).FilePath);
Assert.Equal(string.Empty, SyntaxFactory.ParseSyntaxTree("", path: null).FilePath);
Assert.Equal(string.Empty, CSharpSyntaxTree.Create((CSharpSyntaxNode)oldTree.GetRoot(), path: null).FilePath);
Assert.Equal(string.Empty, CSharpSyntaxTree.Create((CSharpSyntaxNode)oldTree.GetRoot()).FilePath);
}

[Fact]
Expand Down
Loading

0 comments on commit 157d34a

Please sign in to comment.