From 43f2f3d8b0d6e713307b7e80cbf18355164f90f8 Mon Sep 17 00:00:00 2001 From: Cory Smith Date: Tue, 5 Jan 2021 18:45:06 -0600 Subject: [PATCH 01/65] Add SourceGenerators (VB) examples. --- .../SourceGenerators/GeneratedDemo/Cars.csv | 4 + .../GeneratedDemo/GeneratedDemo.vbproj | 23 ++ .../GeneratedDemo/MainSettings.xmlsettings | 6 + .../SourceGenerators/GeneratedDemo/People.csv | 3 + .../SourceGenerators/GeneratedDemo/Program.vb | 39 ++++ .../GeneratedDemo/UseAutoNotifyGenerator.vb | 42 ++++ .../GeneratedDemo/UseCsvGenerator.vb | 18 ++ .../GeneratedDemo/UseHelloWorldGenerator.vb | 8 + .../GeneratedDemo/UseMustacheGenerator.vb | 94 ++++++++ .../GeneratedDemo/UseXmlSettingsGenerator.vb | 25 +++ .../VisualBasic/SourceGenerators/README.md | 35 +++ .../AutoNotifyGenerator.vb | 201 +++++++++++++++++ .../SourceGeneratorSamples/CsvGenerator.props | 7 + .../SourceGeneratorSamples/CsvGenerator.vb | 208 ++++++++++++++++++ .../HelloWorldGenerator.vb | 66 ++++++ .../MustacheGenerator.vb | 146 ++++++++++++ .../SettingsXmlGenerator.vb | 102 +++++++++ .../SourceGeneratorSamples.vbproj | 31 +++ .../SourceGenerators/SourceGenerators.sln | 31 +++ 19 files changed, 1089 insertions(+) create mode 100644 samples/VisualBasic/SourceGenerators/GeneratedDemo/Cars.csv create mode 100644 samples/VisualBasic/SourceGenerators/GeneratedDemo/GeneratedDemo.vbproj create mode 100644 samples/VisualBasic/SourceGenerators/GeneratedDemo/MainSettings.xmlsettings create mode 100644 samples/VisualBasic/SourceGenerators/GeneratedDemo/People.csv create mode 100644 samples/VisualBasic/SourceGenerators/GeneratedDemo/Program.vb create mode 100644 samples/VisualBasic/SourceGenerators/GeneratedDemo/UseAutoNotifyGenerator.vb create mode 100644 samples/VisualBasic/SourceGenerators/GeneratedDemo/UseCsvGenerator.vb create mode 100644 samples/VisualBasic/SourceGenerators/GeneratedDemo/UseHelloWorldGenerator.vb create mode 100644 samples/VisualBasic/SourceGenerators/GeneratedDemo/UseMustacheGenerator.vb create mode 100644 samples/VisualBasic/SourceGenerators/GeneratedDemo/UseXmlSettingsGenerator.vb create mode 100644 samples/VisualBasic/SourceGenerators/README.md create mode 100644 samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb create mode 100644 samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.props create mode 100644 samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.vb create mode 100644 samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/HelloWorldGenerator.vb create mode 100644 samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb create mode 100644 samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SettingsXmlGenerator.vb create mode 100644 samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SourceGeneratorSamples.vbproj create mode 100644 samples/VisualBasic/SourceGenerators/SourceGenerators.sln diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/Cars.csv b/samples/VisualBasic/SourceGenerators/GeneratedDemo/Cars.csv new file mode 100644 index 0000000000..26a5d2051e --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/Cars.csv @@ -0,0 +1,4 @@ +Brand, Model, Year, cc, Favorite +Fiat, Punto, 2008, 12.3, No +Ford, Wagon, 1956, 20.3, No +BMW, "335", 2014, 20.3, Yes \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/GeneratedDemo.vbproj b/samples/VisualBasic/SourceGenerators/GeneratedDemo/GeneratedDemo.vbproj new file mode 100644 index 0000000000..08120ed6f7 --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/GeneratedDemo.vbproj @@ -0,0 +1,23 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/MainSettings.xmlsettings b/samples/VisualBasic/SourceGenerators/GeneratedDemo/MainSettings.xmlsettings new file mode 100644 index 0000000000..96b96f5e54 --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/MainSettings.xmlsettings @@ -0,0 +1,6 @@ + + + False + 1234 + Hello World! + \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/People.csv b/samples/VisualBasic/SourceGenerators/GeneratedDemo/People.csv new file mode 100644 index 0000000000..5179c3539f --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/People.csv @@ -0,0 +1,3 @@ +Name, address, 11Age +"Luca Bol", "23 Bell Street", 90 +"john doe", "32 Carl street", 45 \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/Program.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/Program.vb new file mode 100644 index 0000000000..154f716e0e --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/Program.vb @@ -0,0 +1,39 @@ +Option Explicit On +Option Strict On +Option Infer On + +Module Program + + Public Sub Main() + + Console.WriteLine("Running HelloWorld: +") + UseHelloWorldGenerator.Run() + + Console.WriteLine(" + +Running AutoNotify: +") + UseAutoNotifyGenerator.Run() + + Console.WriteLine(" + +Running XmlSettings: +") + UseXmlSettingsGenerator.Run() + + Console.WriteLine(" + +Running CsvGenerator: +") + UseCsvGenerator.Run() + + Console.WriteLine(" + +Running MustacheGenerator: +") + UseMustacheGenerator.Run() + + End Sub + +End Module \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseAutoNotifyGenerator.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseAutoNotifyGenerator.vb new file mode 100644 index 0000000000..ea1a1a3d83 --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseAutoNotifyGenerator.vb @@ -0,0 +1,42 @@ +Option Explicit On +Option Strict On +Option Infer On + +Imports AutoNotify + +' The view model we'd like to augment +Partial Public Class ExampleViewModel + + + Private _text As String = "private field text" + + + Private _amount As Integer = 5 + +End Class + +Public Module UseAutoNotifyGenerator + + Public Sub Run() + + Dim vm As New ExampleViewModel() + + ' we didn't explicitly create the 'Text' property, it was generated for us + Dim text = vm.Text + Console.WriteLine($"Text = {text}") + + ' Properties can have differnt names generated based on the PropertyName argument of the attribute + Dim count = vm.Count + Console.WriteLine($"Count = {count}") + + ' the viewmodel will automatically implement INotifyPropertyChanged + AddHandler vm.PropertyChanged, Sub(o, e) Console.WriteLine($"Property {e.PropertyName} was changed") + vm.Text = "abc" + vm.Count = 123 + + ' Try adding fields to the ExampleViewModel class above and tagging them with the attribute + ' You'll see the matching generated properties visibile in IntelliSense in realtime + + End Sub + +End Module \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseCsvGenerator.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseCsvGenerator.vb new file mode 100644 index 0000000000..78c1993265 --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseCsvGenerator.vb @@ -0,0 +1,18 @@ +Option Explicit On +Option Strict On +Option Infer On + +Imports CSV + +Friend Class UseCsvGenerator + + Public Shared Sub Run() + + Console.WriteLine("## CARS") + Cars.All.ToList().ForEach(Sub(c) Console.WriteLine(c.Brand & vbTab & c.Model & vbTab & c.Year & vbTab & c.Cc & vbTab & c.Favorite)) + Console.WriteLine(vbCr & "## PEOPLE") + People.All.ToList().ForEach(Sub(p) Console.WriteLine(p.Name & vbTab & p.Address & vbTab & p._11Age)) + + End Sub + +End Class \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseHelloWorldGenerator.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseHelloWorldGenerator.vb new file mode 100644 index 0000000000..78a173ca73 --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseHelloWorldGenerator.vb @@ -0,0 +1,8 @@ +Public Module UseHelloWorldGenerator + + Public Sub Run() + ' The static call below is generated at build time, and will list the syntax trees used in the compilation + HelloWorldGenerated.HelloWorld.SayHello() + End Sub + +End Module diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseMustacheGenerator.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseMustacheGenerator.vb new file mode 100644 index 0000000000..3c9a97c414 --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseMustacheGenerator.vb @@ -0,0 +1,94 @@ +Option Explicit On +Option Strict On +Option Infer On + +Imports GeneratedDemo.UseMustacheGenerator + + + + + + + +Friend Class UseMustacheGenerator + + Public Shared Sub Run() + Console.WriteLine(Mustache.Constants.Lottery) + Console.WriteLine(Mustache.Constants.HR) + Console.WriteLine(Mustache.Constants.HTML) + Console.WriteLine(Mustache.Constants.Section) + Console.WriteLine(Mustache.Constants.NestedSection) + End Sub + + ' Mustache templates and hashes from the manual at https://mustache.github.io/mustache.1.html... + Public Const t1 As String = " +Hello {{name}} +You have just won {{value}} dollars! +{{#in_ca}} +Well, {{taxed_value}} dollars, after taxes. +{{/in_ca}} +" + Public Const h1 As String = " +{ + ""name"": ""Chris"", + ""value"": 10000, + ""taxed_value"": 5000, + ""in_ca"": true +} +" + Public Const t2 As String = " +* {{name}} +* {{age}} +* {{company}} +* {{{company}}} +" + Public Const h2 As String = " +{ + ""name"": ""Chris"", + ""company"": ""GitHub"" +} +" + Public Const t3 As String = " + Shown + {{#person}} + Never shown! + {{/person}} + " + Public Const h3 As String = " +{ + ""person"": false +} +" + Public Const t4 As String = " +{{#repo}} + {{name}} +{{/repo}} +" + Public Const h4 As String = " +{ + ""repo"": [ + { ""name"": ""resque"" }, + { ""name"": ""hub"" }, + { ""name"": ""rip"" } + ] +} +" + Public Const t5 As String = " +{{#repo}} + {{name}} + {{#nested}} + NestedName: {{name}} + {{/nested}} +{{/repo}} +" + Public Const h5 As String = " +{ + ""repo"": [ + { ""name"": ""resque"", ""nested"":[{""name"":""nestedResque""}] }, + { ""name"": ""hub"" }, + { ""name"": ""rip"" } + ] +} +" + +End Class \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseXmlSettingsGenerator.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseXmlSettingsGenerator.vb new file mode 100644 index 0000000000..0ace59e747 --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseXmlSettingsGenerator.vb @@ -0,0 +1,25 @@ +Imports AutoSettings + +Public Module UseXmlSettingsGenerator + + Public Sub Run() + + ' This XmlSettings generator makes a static property in the XmlSettings class for each .xmlsettings file + + ' here we have the 'Main' settings file from MainSettings.xmlsettings + ' the name is determined by the 'name' attribute of the root settings element + Dim main As XmlSettings.MainSettings = XmlSettings.Main + Console.WriteLine($"Reading settings from {main.GetLocation()}") + + ' settings are strongly typed and can be read directly from the static instance + Dim firstRun As Boolean = XmlSettings.Main.FirstRun + Console.WriteLine($"Setting firstRun = {firstRun}") + + Dim cacheSize As Integer = XmlSettings.Main.CacheSize + Console.WriteLine($"Setting cacheSize = {cacheSize}") + + ' Try adding some keys to the settings file and see the settings become available to read from + + End Sub + +End Module \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/README.md b/samples/VisualBasic/SourceGenerators/README.md new file mode 100644 index 0000000000..63d0029eb5 --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/README.md @@ -0,0 +1,35 @@ +🚧 Work In Progress +======== + +These samples are for an in-progress feature of Roslyn. As such they may change or break as the feature is developed, and no level of support is implied. + +For more information on the Source Generators feature, see the [design document](https://github.com/dotnet/roslyn/blob/master/docs/features/source-generators.md). + +Prerequisites +----- + +These samples require **Visual Studio 16.9.0 Preview 2.0** or higher. + +Building the samples +----- +Open `SourceGenerators.sln` in Visual Studio or run `dotnet build` from the `\SourceGenerators` directory. + +Running the samples +----- + +The generators must be run as part of another build, as they inject source into the project being built. This repo contains a sample project `GeneratorDemo` that relies of the sample generators to add code to it's compilation. + +Run `GeneratedDemo` in Visual studio or run `dotnet run` from the `GeneratorDemo` directory. + +Using the samples in your project +----- + +You can add the sample generators to your own project by adding an item group containing an analyzer reference: + +```xml + + + +``` + +You will most likely need to close and reopen the solution in Visual Studio for any changes made to the generators to take effect. diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb new file mode 100644 index 0000000000..981ae965de --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb @@ -0,0 +1,201 @@ +Option Explicit On +Option Infer On +Option Strict On + +Imports System.Text + +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax + +Namespace SourceGeneratorSamples + + + Public Class AutoNotifyGenerator + Implements ISourceGenerator + + Private Const ATTRIBUTE_TEXT As String = " +Imports System + +Namespace Global.AutoNotify + + Friend NotInheritable Class AutoNotifyAttribute + Inherits Attribute + + Public Sub New() + End Sub + + Public Property PropertyName As String + End Class +End Namespace +" + + Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize + ' Register a syntax receiver that will be created for each generation pass + context.RegisterForSyntaxNotifications(Function() As ISyntaxReceiver + Return New SyntaxReceiver + End Function) + End Sub + + Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute + + ' add the attribute text + context.AddSource("AutoNotifyAttribute", SourceText.From(ATTRIBUTE_TEXT, Encoding.UTF8)) + + ' retreive the populated receiver + Dim tempVar = TypeOf context.SyntaxReceiver Is SyntaxReceiver + Dim receiver = TryCast(context.SyntaxReceiver, SyntaxReceiver) + If Not tempVar Then + Return + End If + + ' we're going to create a new compilation that contains the attribute. + ' TODO: we should allow source generators to provide source during initialize, so that this step isn't required. + Dim options1 = context.Compilation.SyntaxTrees.First().Options + Dim compilation1 = context.Compilation.AddSyntaxTrees(VisualBasicSyntaxTree.ParseText(SourceText.From(ATTRIBUTE_TEXT, Encoding.UTF8), CType(options1, VisualBasicParseOptions))) + + ' get the newly bound attribute, and INotifyPropertyChanged + Dim attributeSymbol = compilation1.GetTypeByMetadataName("AutoNotify.AutoNotifyAttribute") + Dim notifySymbol = compilation1.GetTypeByMetadataName("System.ComponentModel.INotifyPropertyChanged") + + ' loop over the candidate fields, and keep the ones that are actually annotated + Dim fieldSymbols As New List(Of IFieldSymbol) + + For Each field In receiver.CandidateFields + Dim model = compilation1.GetSemanticModel(field.SyntaxTree) + For Each variable In field.Declarators + For Each name In variable.Names + ' Get the symbol being decleared by the field, and keep it if its annotated + Dim fieldSymbol = TryCast(model.GetDeclaredSymbol(name), IFieldSymbol) + If fieldSymbol.GetAttributes().Any(Function(ad) ad.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.[Default])) Then + fieldSymbols.Add(fieldSymbol) + End If + Next + Next + Next + + ' group the fields by class, and generate the source + For Each group In fieldSymbols.GroupBy(Function(f) f.ContainingType) + Dim classSource = ProcessClass(group.Key, group.ToList(), attributeSymbol, notifySymbol) + context.AddSource($"{group.Key.Name}_AutoNotify.vb", SourceText.From(classSource, Encoding.UTF8)) + Next + + End Sub + + Private Function ProcessClass(classSymbol As INamedTypeSymbol, fields As List(Of IFieldSymbol), attributeSymbol As ISymbol, notifySymbol As ISymbol) As String + + If Not classSymbol.ContainingSymbol.Equals(classSymbol.ContainingNamespace, SymbolEqualityComparer.[Default]) Then + Return Nothing 'TODO: issue a diagnostic that it must be top level + End If + + Dim namespaceName = classSymbol.ContainingNamespace.ToDisplayString() + + ' begin building the generated source + Dim source = New StringBuilder($"Option Explicit On +Option Strict On +Option Infer On + +Namespace Global.{namespaceName} + + Partial Public Class {classSymbol.Name} + Implements {notifySymbol.ToDisplayString()} + +") + + ' if the class doesn't implement INotifyPropertyChanged already, add it + If Not classSymbol.Interfaces.Contains(CType(notifySymbol, INamedTypeSymbol)) Then + source.Append(" Public Event PropertyChanged As System.ComponentModel.PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged +") + End If + + ' create properties for each field + For Each fieldSymbol In fields + ProcessField(source, fieldSymbol, attributeSymbol) + Next + + source.Append(" + End Class + +End Namespace") + + Return source.ToString() + + End Function + + Private Sub ProcessField(source As StringBuilder, fieldSymbol As IFieldSymbol, attributeSymbol As ISymbol) + + Dim chooseName As Func(Of String, TypedConstant, String) = + Function(fieldName1 As String, overridenNameOpt1 As TypedConstant) As String + + If Not overridenNameOpt1.IsNull Then + Return overridenNameOpt1.Value.ToString() + End If + + fieldName1 = fieldName1.TrimStart("_"c) + If fieldName1.Length = 0 Then + Return String.Empty + End If + + If fieldName1.Length = 1 Then + Return fieldName1.ToUpper() + End If + + Return fieldName1.Substring(0, 1).ToUpper() & fieldName1.Substring(1) + + End Function + + ' get the name and type of the field + Dim fieldName = fieldSymbol.Name + Dim fieldType = fieldSymbol.Type + + ' get the AutoNotify attribute from the field, and any associated data + Dim attributeData = fieldSymbol.GetAttributes().[Single](Function(ad) ad.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.[Default])) + Dim overridenNameOpt = attributeData.NamedArguments.SingleOrDefault(Function(kvp) kvp.Key = "PropertyName").Value + + Dim propertyName = chooseName(fieldName, overridenNameOpt) + If propertyName.Length = 0 OrElse propertyName = fieldName Then + 'TODO: issue a diagnostic that we can't process this field + Return + End If + + source.Append($" + Public Property {propertyName} As {fieldType} + Get + Return Me.{fieldName} + End Get + Set(value As {fieldType}) + Me.{fieldName} = value + RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs(NameOf({propertyName}))) + End Set + End Property +") + + End Sub + + ''' + ''' Created on demand before each generation pass + ''' + Class SyntaxReceiver + Implements ISyntaxReceiver + + Public ReadOnly Property CandidateFields As List(Of FieldDeclarationSyntax) = New List(Of FieldDeclarationSyntax) + + ''' + ''' Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation + ''' + Public Sub OnVisitSyntaxNode(syntaxNode As SyntaxNode) Implements ISyntaxReceiver.OnVisitSyntaxNode + ' any field with at least one attribute is a candidate for property generation + If TypeOf syntaxNode Is FieldDeclarationSyntax Then + Dim fieldDeclarationSyntax = TryCast(syntaxNode, FieldDeclarationSyntax) + If fieldDeclarationSyntax.AttributeLists.Count > 0 Then + CandidateFields.Add(fieldDeclarationSyntax) + End If + End If + End Sub + + End Class + + End Class + +End Namespace \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.props b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.props new file mode 100644 index 0000000000..0741032bb3 --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.props @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.vb new file mode 100644 index 0000000000..d474fdca29 --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.vb @@ -0,0 +1,208 @@ +Option Explicit On +Option Infer On +Option Strict On + +Imports System.IO +Imports System.Text + +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Text + +Imports NotVisualBasic.FileIO + +' CsvTextFileParser from https://github.com/22222/CsvTextFieldParser adding suppression rules for default VS config + +Namespace SourceGeneratorSamples + + + Public Class CsvGenerator + Implements ISourceGenerator + + Public Enum CsvLoadType + Startup + OnDemand + End Enum + + Public Sub Initialize(context As GeneratorInitializationContext) Implements Microsoft.CodeAnalysis.ISourceGenerator.Initialize + + End Sub + + Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute + Dim options As IEnumerable(Of (CsvLoadType, Boolean, AdditionalText)) = GetLoadOptions(context) + Dim nameCodeSequence As IEnumerable(Of (Name As String, Code As String)) = SourceFilesFromAdditionalFiles(options) + For Each entry In nameCodeSequence + context.AddSource($"Csv_{entry.Name}", SourceText.From(entry.Code, Encoding.UTF8)) + Next + End Sub + + ' Guesses type of property for the object from the value of a csv field + Public Shared Function GetCsvFieldType(exemplar As String) As String + Dim garbageBoolean As Boolean + Dim garbageInteger As Integer + Dim garbageDouble As Double + Select Case True + Case Boolean.TryParse(exemplar, garbageBoolean) : Return "Boolean" + Case Integer.TryParse(exemplar, garbageInteger) : Return "Integer" + Case Double.TryParse(exemplar, garbageDouble) : Return "Double" + Case Else : Return "String" + End Select + End Function + + ' Examines the header row and the first row in the csv file to gather all header types and names + ' Also it returns the first row of data, because it must be read to figure out the types, + ' As the CsvTextFieldParser cannot 'Peek' ahead of one line. If there is no first line, + ' it consider all properties as strings. The generator returns an empty list of properly + ' typed objects in such case. If the file is completely empty, an error is generated. + Public Shared Function ExtractProperties(parser As CsvTextFieldParser) As (Types As String(), Names As String(), Fields As String()) + + Dim headerFields = parser.ReadFields() + If headerFields Is Nothing Then + Throw New Exception("Empty csv file!") + End If + + Dim firstLineFields = parser.ReadFields() + If firstLineFields Is Nothing Then + Return (Enumerable.Repeat("String", headerFields.Length).ToArray(), headerFields, firstLineFields) + Else + Return (firstLineFields.[Select](Function(field) GetCsvFieldType(field)).ToArray(), headerFields.[Select](New Func(Of String, String)(AddressOf StringToValidPropertyName)).ToArray(), firstLineFields) + End If + + End Function + + ' Adds a class to the `CSV` namespace for each `csv` file passed in. The class has a static property + ' named `All` that returns the list of strongly typed objects generated on demand at first access. + ' There is the slight chance of a race condition in a multi-thread program, but the result is relatively benign + ' , loading the collection multiple times instead of once. Measures could be taken to avoid that. + Public Shared Function GenerateClassFile(className As String, csvText As String, loadTime As CsvLoadType, cacheObjects As Boolean) As String + + Dim sb As New StringBuilder + Dim parser As New CsvTextFieldParser(New StringReader(csvText)) + + ''' Imports + sb.Append("Option Explicit On +Option Strict On +Option Infer On + +Imports System.Collections.Generic + +Namespace Global.CSV +") + + ''' Class Definition + sb.Append($" + Public Class {className} + +") + + If loadTime = CsvLoadType.Startup Then + sb.Append($" Shared Sub New() + Dim x = All + End Sub + +") + End If + + Dim tupleTemp = ExtractProperties(parser) : Dim types = tupleTemp.Types, names = tupleTemp.Names, fields = tupleTemp.Fields + Dim minLen = Math.Min(types.Length, names.Length) + + For i = 0 To minLen - 1 + sb.AppendLine($" Public Property {StringToValidPropertyName(names(i))} As {types(i)}") + Next + + ''' Loading data + sb.Append($" + Private Shared m_all As IEnumerable(Of {className}) + + Public Shared ReadOnly Property All As IEnumerable(Of {className}) + Get +") + + If cacheObjects Then + sb.Append(" If m_all IsNot Nothing Then + Return m_all + End If +") + End If + + sb.Append($" Dim l As New List(Of {className})() + Dim c As {className} +") + + Do + + If fields Is Nothing Then + Continue Do + End If + If fields.Length < minLen Then + Throw New Exception("Not enough fields in CSV file.") + End If + + sb.AppendLine($" c = New {className}()") + + Dim value As String '= "" + For i As Integer = 0 To minLen - 1 + ' Wrap strings in quotes. + value = If(GetCsvFieldType(fields(i)) = "String", $"""{fields(i).Trim().Trim(New Char() {""""c})}""", fields(i)) + sb.AppendLine($" c.{names(i)} = {value}") + Next + + sb.AppendLine(" l.Add(c)") + + fields = parser.ReadFields() + + Loop While fields IsNot Nothing + + sb.Append($" m_all = l + Return l +") + + ' Close things (property, class, namespace) + sb.Append(" End Get + End Property + + End Class + +End Namespace") + + Return sb.ToString() + + End Function + + Private Shared Function StringToValidPropertyName(s As String) As String + s = s.Trim() + s = If(Char.IsLetter(s(0)), Char.ToUpper(s(0)) & s.Substring(1), s) + s = If(Char.IsDigit(s.Trim()(0)), "_" & s, s) + s = New String(s.[Select](Function(ch) If(Char.IsDigit(ch) OrElse Char.IsLetter(ch), ch, "_"c)).ToArray()) + Return s + End Function + + Private Shared Function SourceFilesFromAdditionalFile(loadType As CsvLoadType, cacheObjects As Boolean, file As AdditionalText) As IEnumerable(Of (Name As String, Code As String)) + Dim className = Path.GetFileNameWithoutExtension(file.Path) + Dim csvText = file.GetText().ToString() + Return New(String, String)() {(className, GenerateClassFile(className, csvText, loadType, cacheObjects))} + End Function + + Private Shared Function SourceFilesFromAdditionalFiles(pathsData As IEnumerable(Of (LoadType As CsvLoadType, CacheObjects As Boolean, File As AdditionalText))) As IEnumerable(Of (Name As String, Code As String)) + Return pathsData.SelectMany(Function(d) SourceFilesFromAdditionalFile(d.LoadType, d.CacheObjects, d.File)) + End Function + + Private Shared Iterator Function GetLoadOptions(context As GeneratorExecutionContext) As IEnumerable(Of (LoadType As CsvLoadType, CacheObjects As Boolean, File As AdditionalText)) + For Each file In context.AdditionalFiles + If Path.GetExtension(file.Path).Equals(".csv", StringComparison.OrdinalIgnoreCase) Then + ' are there any options for it? + Dim loadTimeString As String = Nothing + context.AnalyzerConfigOptions.GetOptions(file).TryGetValue("build_metadata.additionalfiles.CsvLoadType", loadTimeString) + Dim loadType As CsvLoadType = Nothing + [Enum].TryParse(loadTimeString, ignoreCase:=True, loadType) + Dim cacheObjectsString As String = Nothing + context.AnalyzerConfigOptions.GetOptions(file).TryGetValue("build_metadata.additionalfiles.CacheObjects", cacheObjectsString) + Dim cacheObjects As Boolean = Nothing + Boolean.TryParse(cacheObjectsString, cacheObjects) + Yield (loadType, cacheObjects, file) + End If + Next + End Function + + End Class + +End Namespace \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/HelloWorldGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/HelloWorldGenerator.vb new file mode 100644 index 0000000000..792c3b62ae --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/HelloWorldGenerator.vb @@ -0,0 +1,66 @@ +Option Explicit On +Option Infer On +Option Strict On + +Imports System.Text + +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Text + +Namespace SourceGeneratorSamples + + + Public Class HelloWorldGenerator + Implements ISourceGenerator + + Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize + ' No initialization required + End Sub + + Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute + + ' begin creating the source we'll inject into the users compilation + + Dim sourceBuilder = New StringBuilder("Option Explicit On +Option Strict On +Option Infer On + +Namespace Global.HelloWorldGenerated + + Public Module HelloWorld + + Public Sub SayHello() + + Console.WriteLine(""Hello from generated code!"") + Console.WriteLine(""The following syntax trees existed in the compilation that created this program:"") +") + + ' for testing... let's include a comment with the current date/time. + sourceBuilder.AppendLine($" ' Generated at {DateTime.Now}") + + ' using the context, get a list of syntax trees in the users compilation + ' add the filepath of each tree to the class we're building + + For Each tree In context.Compilation.SyntaxTrees + sourceBuilder.AppendLine($" Console.WriteLine("" - {tree.FilePath}"")") + Next + + ' finish creating the source to inject + + sourceBuilder.Append(" + + End Sub + + End Module + +End Namespace") + + ' inject the created source into the users compilation + + context.AddSource("HelloWorldGenerated", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8)) + + End Sub + + End Class + +End Namespace \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb new file mode 100644 index 0000000000..38004dbe7a --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb @@ -0,0 +1,146 @@ +Option Explicit On +Option Infer On +Option Strict On + +Imports System.Collections.Immutable +Imports System.Text + +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Text + +Imports Microsoft.CodeAnalysis.VisualBasic +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax + +Namespace SourceGeneratorSamples + + + Public Class MustacheGenerator + Implements ISourceGenerator + + Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize + ' No initialization required + End Sub + + Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute + + Dim attributeSource = "Option Explicit On +Option Strict On +Option Infer On + +Namespace Global + + + Friend NotInheritable Class MustacheAttribute + Inherits System.Attribute + + Public ReadOnly Property Name As String + Public ReadOnly Property Template As String + Public ReadOnly Property Hash As String + + Public Sub New(name As String, template As String, hash As String) + Me.Name = name + Me.Template = template + Me.Hash = hash + End Sub + + End Class + +End Namespace +" + + context.AddSource("Mustache_MainAttributes__", SourceText.From(attributeSource, Encoding.UTF8)) + + Dim compilation = context.Compilation + + Dim options = GetMustacheOptions(compilation) + Dim namesSources = SourceFilesFromMustachePaths(options) + + For Each entry In namesSources + context.AddSource($"Mustache{entry.Item1}", SourceText.From(entry.Item2, Encoding.UTF8)) + Next + + End Sub + + Private Shared Iterator Function GetMustacheOptions(compilation As Compilation) As IEnumerable(Of (String, String, String)) + + ' Get all Mustache attributes + + Dim allNodes = compilation.SyntaxTrees.SelectMany(Function(s) s.GetRoot().DescendantNodes()) + + + Dim allAttributes = allNodes.Where(Function(d) d.IsKind(SyntaxKind.Attribute)).OfType(Of AttributeSyntax)() + Dim attributes = allAttributes.Where(Function(d) d.Name.ToString() = "Mustache").ToImmutableArray() + + Dim models = compilation.SyntaxTrees.[Select](Function(st) compilation.GetSemanticModel(st)) + For Each att In attributes + + Dim mustacheName = "" + Dim template = "" + Dim hash = "" + Dim index = 0 + + If att.ArgumentList Is Nothing Then + Throw New Exception("Can't be null here") + End If + + Dim m = compilation.GetSemanticModel(att.SyntaxTree) + + For Each arg In att.ArgumentList.Arguments + + Dim expr As ExpressionSyntax = Nothing + If TypeOf arg Is SimpleArgumentSyntax Then + expr = TryCast(arg, SimpleArgumentSyntax).Expression + End If + If expr Is Nothing Then + Continue For + End If + + Dim t = m.GetTypeInfo(expr) + Dim v = m.GetConstantValue(expr) + If index = 0 Then + mustacheName = v.ToString() + ElseIf index = 1 Then + template = v.ToString() + Else + hash = v.ToString() + End If + index += 1 + + Next + + Yield (mustacheName, template, hash) + + Next + + End Function + + Private Shared Function SourceFileFromMustachePath(name As String, template As String, hash As String) As String + Dim tree = HandlebarsDotNet.Handlebars.Compile(template) + Dim o = Newtonsoft.Json.JsonConvert.DeserializeObject(hash) + Dim mustacheText = tree(o) + Return GenerateMustacheClass(name, mustacheText) + End Function + + Private Shared Iterator Function SourceFilesFromMustachePaths(pathsData As IEnumerable(Of (Name As String, Template As String, Hash As String))) As IEnumerable(Of (Name As String, Code As String)) + For Each entry In pathsData + Yield (entry.Name, SourceFileFromMustachePath(entry.Name, entry.Template, entry.Hash)) + Next + End Function + + Private Shared Function GenerateMustacheClass(className As String, mustacheText As String) As String + Return $" + +Namespace Global.Mustache + + Partial Public Module Constants + + Public Const {className} As String = ""{mustacheText.Replace("""", """""")}"" + + End Module + +End Namespace" + End Function + + End Class + +End Namespace \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SettingsXmlGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SettingsXmlGenerator.vb new file mode 100644 index 0000000000..1754315d85 --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SettingsXmlGenerator.vb @@ -0,0 +1,102 @@ +Option Explicit On +Option Infer On +Option Strict On + +Imports System.IO +Imports System.Text +Imports System.Xml + +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Text + +Namespace SourceGeneratorSamples + + + Public Class SettingsXmlGenerator + Implements ISourceGenerator + + Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize + + End Sub + + Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute + ' Using the context, get any additional files that end in .xmlsettings + For Each settingsFile In context.AdditionalFiles.Where(Function(at) at.Path.EndsWith(".xmlsettings")) + ProcessSettingsFile(settingsFile, context) + Next + End Sub + + Private Sub ProcessSettingsFile(xmlFile As AdditionalText, context As GeneratorExecutionContext) + + ' try and load the settings file + Dim xmlDoc As New XmlDocument + Dim text = xmlFile.GetText(context.CancellationToken).ToString() + Try + xmlDoc.LoadXml(text) + Catch + 'TODO: issue a diagnostic that says we couldn't parse it + Return + End Try + + ' create a class in the XmlSetting class that represnts this entry, and a static field that contains a singleton instance. + Dim fileName = Path.GetFileName(xmlFile.Path) + Dim name = xmlDoc.DocumentElement.GetAttribute("name") + + Dim sb = New StringBuilder($"Option Explicit On +Option Strict On +Option Infer On + +Imports System.Xml + +Namespace Global.AutoSettings + + Partial Public Class XmlSettings + + Public Shared ReadOnly Property {name} As {name}Settings = New {name}Settings(""{fileName}"") + + Public Class {name}Settings + + Private m_xmlDoc As New XmlDocument() + + Private m_fileName As String + + Friend Sub New(fileName As String) + m_fileName = fileName + m_xmlDoc.Load(m_fileName) + End Sub + + Public Function GetLocation() As String + Return m_fileName + End Function") + + For i = 0 To xmlDoc.DocumentElement.ChildNodes.Count - 1 + + Dim setting = CType(xmlDoc.DocumentElement.ChildNodes(i), XmlElement) + Dim settingName = setting.GetAttribute("name") + Dim settingType = setting.GetAttribute("type") + + sb.Append($" + + Public ReadOnly Property {settingName} As {settingType} + Get + Return DirectCast(Convert.ChangeType(DirectCast(m_xmlDoc.DocumentElement.ChildNodes({i}), XmlElement).InnerText, GetType({settingType})), {settingType}) + End Get + End Property") + + Next + + sb.Append(" + + End Class + + End Class + +End Namespace") + + context.AddSource($"Settings_{name}", SourceText.From(sb.ToString(), Encoding.UTF8)) + + End Sub + + End Class + +End Namespace \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SourceGeneratorSamples.vbproj b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SourceGeneratorSamples.vbproj new file mode 100644 index 0000000000..f719a9496d --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SourceGeneratorSamples.vbproj @@ -0,0 +1,31 @@ + + + + netstandard2.0 + + + + + + + + + + + + + + + + $(GetTargetPathDependsOn);GetDependencyTargetPaths + + + + + + + + + + + \ No newline at end of file diff --git a/samples/VisualBasic/SourceGenerators/SourceGenerators.sln b/samples/VisualBasic/SourceGenerators/SourceGenerators.sln new file mode 100644 index 0000000000..6b79479857 --- /dev/null +++ b/samples/VisualBasic/SourceGenerators/SourceGenerators.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30022.13 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "GeneratedDemo", "GeneratedDemo\GeneratedDemo.vbproj", "{08612C19-D039-44D1-9030-D192CEAF05BB}" +EndProject +Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "SourceGeneratorSamples", "SourceGeneratorSamples\SourceGeneratorSamples.vbproj", "{90BDB1C3-E353-448C-8A29-E5B2EF10670B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {08612C19-D039-44D1-9030-D192CEAF05BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {08612C19-D039-44D1-9030-D192CEAF05BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {08612C19-D039-44D1-9030-D192CEAF05BB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {08612C19-D039-44D1-9030-D192CEAF05BB}.Release|Any CPU.Build.0 = Release|Any CPU + {90BDB1C3-E353-448C-8A29-E5B2EF10670B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {90BDB1C3-E353-448C-8A29-E5B2EF10670B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90BDB1C3-E353-448C-8A29-E5B2EF10670B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {90BDB1C3-E353-448C-8A29-E5B2EF10670B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {623C84B6-B8A4-4F29-8E68-4ED37D4529D5} + EndGlobalSection +EndGlobal From 2095c557a634e46dcd31e5ef15cb6613328ec4b5 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 15 Apr 2021 12:39:39 +0000 Subject: [PATCH 02/65] Update dependencies from https://github.com/dotnet/arcade build 20210414.5 (#786) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- eng/common/templates/job/onelocbuild.yml | 3 +++ global.json | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 52d5f57f6c..48e96f28f8 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - db49d790a4bfa977a9ed7436bf2aa242cefae45e + 93a6389f406e5e900da46ab643c608578f143851 diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml index 928a70cda2..d2b271ec1a 100644 --- a/eng/common/templates/job/onelocbuild.yml +++ b/eng/common/templates/job/onelocbuild.yml @@ -11,6 +11,7 @@ parameters: SourcesDirectory: $(Build.SourcesDirectory) CreatePr: true + AutoCompletePr: false UseCheckedInLocProjectJson: false LanguageSet: VS_Main_Languages LclSource: lclFilesInRepo @@ -54,6 +55,8 @@ jobs: lclSource: ${{ parameters.LclSource }} lclPackageId: ${{ parameters.LclPackageId }} isCreatePrSelected: ${{ parameters.CreatePr }} + ${{ if eq(parameters.CreatePr, true) }}: + isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }} packageSourceAuth: patAuth patVariable: ${{ parameters.CeapexPat }} ${{ if eq(parameters.RepoType, 'gitHub') }}: diff --git a/global.json b/global.json index 7b55f21860..e0c9ed58f0 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21212.6" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21214.5" } } From b85f5638271fa6a79f9bdb039d10bedb1cf21205 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 16 Apr 2021 12:55:51 +0000 Subject: [PATCH 03/65] Update dependencies from https://github.com/dotnet/arcade build 20210415.5 (#788) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 48e96f28f8..d3d920c1d0 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 93a6389f406e5e900da46ab643c608578f143851 + e76fe48d5eb894e58fe7841f3a2c0bcfa654ee80 diff --git a/global.json b/global.json index e0c9ed58f0..449f02bbc5 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21214.5" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21215.5" } } From 8835cb7ef3de5d76b43874f091346e56c37ce912 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 17 Apr 2021 12:39:23 +0000 Subject: [PATCH 04/65] Update dependencies from https://github.com/dotnet/arcade build 20210416.2 (#792) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d3d920c1d0..edf23bb13a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - e76fe48d5eb894e58fe7841f3a2c0bcfa654ee80 + 53fe29e220fc0db05eafd5c6bc6c8fb9ee7cec7c diff --git a/global.json b/global.json index 449f02bbc5..01bd3b397e 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21215.5" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21216.2" } } From 38459e5c095f071f0fd22cbc5b66fc8e1104ca06 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 20 Apr 2021 12:55:21 +0000 Subject: [PATCH 05/65] Update dependencies from https://github.com/dotnet/arcade build 20210419.2 (#795) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- eng/common/generate-locproject.ps1 | 17 +++++++++++++---- global.json | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index edf23bb13a..5600780994 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 53fe29e220fc0db05eafd5c6bc6c8fb9ee7cec7c + 1d951297eb7bdd29a31dff3149606152717ed6b4 diff --git a/eng/common/generate-locproject.ps1 b/eng/common/generate-locproject.ps1 index 7225ddc666..24c00b5be9 100644 --- a/eng/common/generate-locproject.ps1 +++ b/eng/common/generate-locproject.ps1 @@ -66,10 +66,19 @@ $locJson = @{ } if ($continue) { - return @{ - SourceFile = $sourceFile - CopyOption = "LangIDOnName" - OutputPath = $outputPath + if ($_.Directory.Name -eq 'en' -and $_.Extension -eq '.json') { + return @{ + SourceFile = $sourceFile + CopyOption = "LangIDOnPath" + OutputPath = "$($_.Directory.Parent.FullName | Resolve-Path -Relative)\" + } + } + else { + return @{ + SourceFile = $sourceFile + CopyOption = "LangIDOnName" + OutputPath = $outputPath + } } } } diff --git a/global.json b/global.json index 01bd3b397e..7f16c3bf4d 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21216.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21219.2" } } From dc0e9830bbdb138c82c07ba4f01d05a1972a99cd Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 21 Apr 2021 12:49:25 +0000 Subject: [PATCH 06/65] Update dependencies from https://github.com/dotnet/arcade build 20210420.2 (#798) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 5600780994..4b10cde236 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 1d951297eb7bdd29a31dff3149606152717ed6b4 + 2803c841d5e5f5cdc3d3ea42d532d51ec96fcadb diff --git a/global.json b/global.json index 7f16c3bf4d..009781b75a 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21219.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21220.2" } } From 34274ee29ea79ff55e0d1c067faf04d840b5ef8e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 22 Apr 2021 12:50:05 +0000 Subject: [PATCH 07/65] Update dependencies from https://github.com/dotnet/arcade build 20210421.1 (#799) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 4b10cde236..bb05057ff2 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 2803c841d5e5f5cdc3d3ea42d532d51ec96fcadb + f7e58cfb0f6c93980cbb664cc9e62d9ef2df0c2f diff --git a/global.json b/global.json index 009781b75a..7a3994ba0d 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21220.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21221.1" } } From 8a1306bc833da2bd02555c100ffc26fd7a8d7e87 Mon Sep 17 00:00:00 2001 From: Jon Fortescue Date: Fri, 23 Apr 2021 14:40:33 -0700 Subject: [PATCH 08/65] Add OneLocBuild --- .vsts-ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.vsts-ci.yml b/.vsts-ci.yml index 23eac359ef..52edabcdf2 100644 --- a/.vsts-ci.yml +++ b/.vsts-ci.yml @@ -18,6 +18,11 @@ stages: displayName: Build and Test jobs: + - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - template: /eng/common/templates/job/onelocbuild.yml + parameters: + CreatePr: false + - job: OfficialBuild displayName: Official Build pool: From 4b2714110986e476b3b1c56ac1eb4e274cca6004 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 24 Apr 2021 12:45:29 +0000 Subject: [PATCH 09/65] Update dependencies from https://github.com/dotnet/arcade build 20210422.1 (#800) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- eng/common/templates/job/source-index-stage1.yml | 2 +- global.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index bb05057ff2..3d7cf82775 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - f7e58cfb0f6c93980cbb664cc9e62d9ef2df0c2f + b7279bb45342c948ab46fea2d08ec17ae2f2a1bf diff --git a/eng/common/templates/job/source-index-stage1.yml b/eng/common/templates/job/source-index-stage1.yml index c002a2b1b0..a649d2b599 100644 --- a/eng/common/templates/job/source-index-stage1.yml +++ b/eng/common/templates/job/source-index-stage1.yml @@ -1,6 +1,6 @@ parameters: runAsPublic: false - sourceIndexPackageVersion: 1.0.1-20210225.1 + sourceIndexPackageVersion: 1.0.1-20210421.1 sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci" preSteps: [] diff --git a/global.json b/global.json index 7a3994ba0d..ea6efb8059 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21221.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21222.1" } } From abe4a2be221922b909c6101c578c2d23b13dad02 Mon Sep 17 00:00:00 2001 From: Jon Fortescue Date: Mon, 26 Apr 2021 14:11:09 -0700 Subject: [PATCH 10/65] Change to reflect CI --- .vsts-ci.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.vsts-ci.yml b/.vsts-ci.yml index 52edabcdf2..a90bb8df4a 100644 --- a/.vsts-ci.yml +++ b/.vsts-ci.yml @@ -18,10 +18,9 @@ stages: displayName: Build and Test jobs: - - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - template: /eng/common/templates/job/onelocbuild.yml - parameters: - CreatePr: false + - template: /eng/common/templates/job/onelocbuild.yml + parameters: + CreatePr: false - job: OfficialBuild displayName: Official Build From ff639f7f3bb566b570081656130de2a63f624ff2 Mon Sep 17 00:00:00 2001 From: Jon Fortescue Date: Tue, 27 Apr 2021 13:41:36 -0700 Subject: [PATCH 11/65] Add package --- .vsts-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.vsts-ci.yml b/.vsts-ci.yml index a90bb8df4a..6799a999dc 100644 --- a/.vsts-ci.yml +++ b/.vsts-ci.yml @@ -21,6 +21,8 @@ stages: - template: /eng/common/templates/job/onelocbuild.yml parameters: CreatePr: false + LclSource: lclFilesfromPackage + LclPackageId: 'LCL-JUNO-PROD-ROSLYNSDK' - job: OfficialBuild displayName: Official Build From e5e13246465018945e92dfd32ad3c80757fec80f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 29 Apr 2021 12:43:02 +0000 Subject: [PATCH 12/65] Update dependencies from https://github.com/dotnet/arcade build 20210428.3 (#804) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- eng/common/templates/job/onelocbuild.yml | 8 +++++--- global.json | 6 +++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3d7cf82775..d8ec37c47b 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - b7279bb45342c948ab46fea2d08ec17ae2f2a1bf + e1044f09e18638a98a9f0448086a7295f3d16834 diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml index d2b271ec1a..b27d6faf30 100644 --- a/eng/common/templates/job/onelocbuild.yml +++ b/eng/common/templates/job/onelocbuild.yml @@ -17,6 +17,7 @@ parameters: LclSource: lclFilesInRepo LclPackageId: '' RepoType: gitHub + condition: '' jobs: - job: OneLocBuild @@ -44,6 +45,7 @@ jobs: filePath: $(Build.SourcesDirectory)/eng/common/generate-locproject.ps1 arguments: $(_GenerateLocProjectArguments) displayName: Generate LocProject.json + condition: ${{ parameters.condition }} - task: OneLocBuild@2 displayName: OneLocBuild @@ -62,7 +64,7 @@ jobs: ${{ if eq(parameters.RepoType, 'gitHub') }}: repoType: ${{ parameters.RepoType }} gitHubPatVariable: "${{ parameters.GithubPat }}" - condition: always() + condition: ${{ parameters.condition }} - task: PublishBuildArtifacts@1 displayName: Publish Localization Files @@ -70,7 +72,7 @@ jobs: PathtoPublish: '$(Build.ArtifactStagingDirectory)/loc' PublishLocation: Container ArtifactName: Loc - condition: always() + condition: ${{ parameters.condition }} - task: PublishBuildArtifacts@1 displayName: Publish LocProject.json @@ -78,4 +80,4 @@ jobs: PathtoPublish: '$(Build.SourcesDirectory)/Localize/' PublishLocation: Container ArtifactName: Loc - condition: always() \ No newline at end of file + condition: ${{ parameters.condition }} \ No newline at end of file diff --git a/global.json b/global.json index ea6efb8059..31e7ed350f 100644 --- a/global.json +++ b/global.json @@ -1,11 +1,11 @@ { "sdk": { - "version": "6.0.100-preview.2.21155.3", + "version": "6.0.100-preview.3.21202.5", "allowPrerelease": true, "rollForward": "major" }, "tools": { - "dotnet": "6.0.100-preview.2.21155.3", + "dotnet": "6.0.100-preview.3.21202.5", "runtimes": { "dotnet": [ "3.1.0" @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21222.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21228.3" } } From 53ba88da727b09cb7ed01b9243016d847a69e9d0 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 30 Apr 2021 12:44:53 +0000 Subject: [PATCH 13/65] Update dependencies from https://github.com/dotnet/arcade build 20210429.1 (#807) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 +- eng/common/post-build/symbols-validation.ps1 | 94 +++++++++++--------- global.json | 2 +- 3 files changed, 54 insertions(+), 46 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d8ec37c47b..7cfbadda3c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - e1044f09e18638a98a9f0448086a7295f3d16834 + 67f4230b38092d53d8f8d3a37301feb997adf26c diff --git a/eng/common/post-build/symbols-validation.ps1 b/eng/common/post-build/symbols-validation.ps1 index 99bf28cd5c..e6d5d2fd05 100644 --- a/eng/common/post-build/symbols-validation.ps1 +++ b/eng/common/post-build/symbols-validation.ps1 @@ -1,9 +1,10 @@ param( - [Parameter(Mandatory=$true)][string] $InputPath, # Full path to directory where NuGet packages to be checked are stored - [Parameter(Mandatory=$true)][string] $ExtractPath, # Full path to directory where the packages will be extracted during validation - [Parameter(Mandatory=$true)][string] $DotnetSymbolVersion, # Version of dotnet symbol to use - [Parameter(Mandatory=$false)][switch] $ContinueOnError, # If we should keep checking symbols after an error - [Parameter(Mandatory=$false)][switch] $Clean # Clean extracted symbols directory after checking symbols + [Parameter(Mandatory = $true)][string] $InputPath, # Full path to directory where NuGet packages to be checked are stored + [Parameter(Mandatory = $true)][string] $ExtractPath, # Full path to directory where the packages will be extracted during validation + [Parameter(Mandatory = $true)][string] $DotnetSymbolVersion, # Version of dotnet symbol to use + [Parameter(Mandatory = $false)][switch] $CheckForWindowsPdbs, # If we should check for the existence of windows pdbs in addition to portable PDBs + [Parameter(Mandatory = $false)][switch] $ContinueOnError, # If we should keep checking symbols after an error + [Parameter(Mandatory = $false)][switch] $Clean # Clean extracted symbols directory after checking symbols ) # Maximum number of jobs to run in parallel @@ -19,9 +20,15 @@ $SecondsBetweenLoadChecks = 10 Set-Variable -Name "ERROR_BADEXTRACT" -Option Constant -Value -1 Set-Variable -Name "ERROR_FILEDOESNOTEXIST" -Option Constant -Value -2 +$WindowsPdbVerificationParam = "" +if ($CheckForWindowsPdbs) { + $WindowsPdbVerificationParam = "--windows-pdbs" +} + $CountMissingSymbols = { param( - [string] $PackagePath # Path to a NuGet package + [string] $PackagePath, # Path to a NuGet package + [string] $WindowsPdbVerificationParam # If we should check for the existence of windows pdbs in addition to portable PDBs ) . $using:PSScriptRoot\..\tools.ps1 @@ -34,7 +41,7 @@ $CountMissingSymbols = { if (!(Test-Path $PackagePath)) { Write-PipelineTaskError "Input file does not exist: $PackagePath" return [pscustomobject]@{ - result = $using:ERROR_FILEDOESNOTEXIST + result = $using:ERROR_FILEDOESNOTEXIST packagePath = $PackagePath } } @@ -57,24 +64,25 @@ $CountMissingSymbols = { Write-Host "Something went wrong extracting $PackagePath" Write-Host $_ return [pscustomobject]@{ - result = $using:ERROR_BADEXTRACT + result = $using:ERROR_BADEXTRACT packagePath = $PackagePath } } Get-ChildItem -Recurse $ExtractPath | - Where-Object {$RelevantExtensions -contains $_.Extension} | - ForEach-Object { - $FileName = $_.FullName - if ($FileName -Match '\\ref\\') { - Write-Host "`t Ignoring reference assembly file " $FileName - return - } + Where-Object { $RelevantExtensions -contains $_.Extension } | + ForEach-Object { + $FileName = $_.FullName + if ($FileName -Match '\\ref\\') { + Write-Host "`t Ignoring reference assembly file " $FileName + return + } - $FirstMatchingSymbolDescriptionOrDefault = { + $FirstMatchingSymbolDescriptionOrDefault = { param( - [string] $FullPath, # Full path to the module that has to be checked - [string] $TargetServerParam, # Parameter to pass to `Symbol Tool` indicating the server to lookup for symbols + [string] $FullPath, # Full path to the module that has to be checked + [string] $TargetServerParam, # Parameter to pass to `Symbol Tool` indicating the server to lookup for symbols + [string] $WindowsPdbVerificationParam, # Parameter to pass to potential check for windows-pdbs. [string] $SymbolsPath ) @@ -99,7 +107,7 @@ $CountMissingSymbols = { # DWARF file for a .dylib $DylibDwarf = $SymbolPath.Replace($Extension, '.dylib.dwarf') - + $dotnetSymbolExe = "$env:USERPROFILE\.dotnet\tools" $dotnetSymbolExe = Resolve-Path "$dotnetSymbolExe\dotnet-symbol.exe" @@ -107,7 +115,7 @@ $CountMissingSymbols = { while ($totalRetries -lt $using:MaxRetry) { # Save the output and get diagnostic output - $output = & $dotnetSymbolExe --symbols --modules --windows-pdbs $TargetServerParam $FullPath -o $SymbolsPath --diagnostics | Out-String + $output = & $dotnetSymbolExe --symbols --modules $WindowsPdbVerificationParam $TargetServerParam $FullPath -o $SymbolsPath --diagnostics | Out-String if (Test-Path $PdbPath) { return 'PDB' @@ -136,30 +144,30 @@ $CountMissingSymbols = { return $null } - $SymbolsOnMSDL = & $FirstMatchingSymbolDescriptionOrDefault $FileName '--microsoft-symbol-server' $SymbolsPath - $SymbolsOnSymWeb = & $FirstMatchingSymbolDescriptionOrDefault $FileName '--internal-server' $SymbolsPath + $SymbolsOnMSDL = & $FirstMatchingSymbolDescriptionOrDefault $FileName '--microsoft-symbol-server' $SymbolsPath $WindowsPdbVerificationParam + $SymbolsOnSymWeb = & $FirstMatchingSymbolDescriptionOrDefault $FileName '--internal-server' $SymbolsPath $WindowsPdbVerificationParam - Write-Host -NoNewLine "`t Checking file " $FileName "... " + Write-Host -NoNewLine "`t Checking file " $FileName "... " - if ($SymbolsOnMSDL -ne $null -and $SymbolsOnSymWeb -ne $null) { - Write-Host "Symbols found on MSDL ($SymbolsOnMSDL) and SymWeb ($SymbolsOnSymWeb)" + if ($SymbolsOnMSDL -ne $null -and $SymbolsOnSymWeb -ne $null) { + Write-Host "Symbols found on MSDL ($SymbolsOnMSDL) and SymWeb ($SymbolsOnSymWeb)" + } + else { + $MissingSymbols++ + + if ($SymbolsOnMSDL -eq $null -and $SymbolsOnSymWeb -eq $null) { + Write-Host 'No symbols found on MSDL or SymWeb!' } else { - $MissingSymbols++ - - if ($SymbolsOnMSDL -eq $null -and $SymbolsOnSymWeb -eq $null) { - Write-Host 'No symbols found on MSDL or SymWeb!' + if ($SymbolsOnMSDL -eq $null) { + Write-Host 'No symbols found on MSDL!' } else { - if ($SymbolsOnMSDL -eq $null) { - Write-Host 'No symbols found on MSDL!' - } - else { - Write-Host 'No symbols found on SymWeb!' - } + Write-Host 'No symbols found on SymWeb!' } } } + } if ($using:Clean) { Remove-Item $ExtractPath -Recurse -Force @@ -168,16 +176,16 @@ $CountMissingSymbols = { Pop-Location return [pscustomobject]@{ - result = $MissingSymbols - packagePath = $PackagePath - } + result = $MissingSymbols + packagePath = $PackagePath + } } function CheckJobResult( - $result, - $packagePath, - [ref]$DupedSymbols, - [ref]$TotalFailures) { + $result, + $packagePath, + [ref]$DupedSymbols, + [ref]$TotalFailures) { if ($result -eq $ERROR_BADEXTRACT) { Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "$packagePath has duplicated symbol files" $DupedSymbols.Value++ @@ -222,7 +230,7 @@ function CheckSymbolsAvailable { return } - Start-Job -ScriptBlock $CountMissingSymbols -ArgumentList $FullName | Out-Null + Start-Job -ScriptBlock $CountMissingSymbols -ArgumentList @($FullName,$WindowsPdbVerificationParam) | Out-Null $NumJobs = @(Get-Job -State 'Running').Count diff --git a/global.json b/global.json index 31e7ed350f..fc54a010e1 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21228.3" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21229.1" } } From 15974e41e2bcff3b172f89df6feb24b421a4bb8e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 1 May 2021 12:39:14 +0000 Subject: [PATCH 14/65] Update dependencies from https://github.com/dotnet/arcade build 20210430.2 (#808) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 7cfbadda3c..28cea99be1 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 67f4230b38092d53d8f8d3a37301feb997adf26c + 46ad27d3cc557f2b84ce30b2c4e27438526dc91d diff --git a/global.json b/global.json index fc54a010e1..c9ebb3b028 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21229.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21230.2" } } From fefb0595b6b340af1c6317a5081b1098e96458c5 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 3 May 2021 12:14:51 -0700 Subject: [PATCH 15/65] Dispose workspaces at the end of RunAsync Fixes #805 --- .../AnalyzerTest`1.cs | 34 +++++++++++++++++-- .../PublicAPI.Unshipped.txt | 6 ++-- .../CodeFixTest`1.cs | 2 +- .../PublicAPI.Unshipped.txt | 2 +- .../CodeRefactoringTest`1.cs | 2 +- .../PublicAPI.Unshipped.txt | 2 +- .../PublicAPI.Unshipped.txt | 2 +- .../SourceGeneratorTest`1.cs | 2 +- 8 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs index 770326c4f9..e17ac7b5db 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -165,12 +166,34 @@ public string TestCode /// protected TimeSpan MatchDiagnosticsTimeout { get; set; } = TimeSpan.FromSeconds(2); + private readonly ConcurrentBag _workspaces = new ConcurrentBag(); + /// /// Runs the test. /// /// The that the operation will observe. /// A representing the asynchronous operation. - public virtual async Task RunAsync(CancellationToken cancellationToken = default) + public async Task RunAsync(CancellationToken cancellationToken = default) + { + try + { + await RunImplAsync(cancellationToken); + } + finally + { + while (_workspaces.TryTake(out var workspace)) + { + workspace.Dispose(); + } + } + } + + /// + /// Runs the test. + /// + /// The that the operation will observe. + /// A representing the asynchronous operation. + protected virtual async Task RunImplAsync(CancellationToken cancellationToken) { Verify.NotEmpty($"{nameof(TestState)}.{nameof(SolutionState.Sources)}", TestState.Sources); @@ -1310,7 +1333,14 @@ protected virtual Project ApplyCompilationOptions(Project project) return solution.GetProject(project.Id); } - public virtual AdhocWorkspace CreateWorkspace() + public Workspace CreateWorkspace() + { + var workspace = CreateWorkspaceImpl(); + _workspaces.Add(workspace); + return workspace; + } + + protected virtual Workspace CreateWorkspaceImpl() { var exportProvider = ExportProviderFactory.Value.CreateExportProvider(); var host = MefHostServices.Create(exportProvider.AsCompositionContext()); diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt index cd1037a9e2..2ab84d52f8 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt @@ -3,6 +3,7 @@ Microsoft.CodeAnalysis.Testing.AnalyzerTest.AnalyzerTest() -> void Microsoft.CodeAnalysis.Testing.AnalyzerTest.CompilerDiagnostics.get -> Microsoft.CodeAnalysis.Testing.CompilerDiagnostics Microsoft.CodeAnalysis.Testing.AnalyzerTest.CompilerDiagnostics.set -> void Microsoft.CodeAnalysis.Testing.AnalyzerTest.CreateProjectAsync(Microsoft.CodeAnalysis.Testing.Model.EvaluatedProjectState primaryProject, System.Collections.Immutable.ImmutableArray additionalProjects, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task +Microsoft.CodeAnalysis.Testing.AnalyzerTest.CreateWorkspace() -> Microsoft.CodeAnalysis.Workspace Microsoft.CodeAnalysis.Testing.AnalyzerTest.DiagnosticVerifier.get -> System.Action Microsoft.CodeAnalysis.Testing.AnalyzerTest.DiagnosticVerifier.set -> void Microsoft.CodeAnalysis.Testing.AnalyzerTest.DisabledDiagnostics.get -> System.Collections.Generic.List @@ -16,6 +17,7 @@ Microsoft.CodeAnalysis.Testing.AnalyzerTest.MatchDiagnosticsTimeout.s Microsoft.CodeAnalysis.Testing.AnalyzerTest.OptionsTransforms.get -> System.Collections.Generic.List> Microsoft.CodeAnalysis.Testing.AnalyzerTest.ReferenceAssemblies.get -> Microsoft.CodeAnalysis.Testing.ReferenceAssemblies Microsoft.CodeAnalysis.Testing.AnalyzerTest.ReferenceAssemblies.set -> void +Microsoft.CodeAnalysis.Testing.AnalyzerTest.RunAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task Microsoft.CodeAnalysis.Testing.AnalyzerTest.SolutionTransforms.get -> System.Collections.Generic.List> Microsoft.CodeAnalysis.Testing.AnalyzerTest.TestBehaviors.get -> Microsoft.CodeAnalysis.Testing.TestBehaviors Microsoft.CodeAnalysis.Testing.AnalyzerTest.TestBehaviors.set -> void @@ -320,7 +322,7 @@ static readonly Microsoft.CodeAnalysis.Testing.DiagnosticResult.EmptyDiagnosticR virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.ApplyCompilationOptions(Microsoft.CodeAnalysis.Project project) -> Microsoft.CodeAnalysis.Project virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.CreateProjectImplAsync(Microsoft.CodeAnalysis.Testing.Model.EvaluatedProjectState primaryProject, System.Collections.Immutable.ImmutableArray additionalProjects, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.CreateSolutionAsync(Microsoft.CodeAnalysis.ProjectId projectId, Microsoft.CodeAnalysis.Testing.Model.EvaluatedProjectState projectState, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task -virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.CreateWorkspace() -> Microsoft.CodeAnalysis.AdhocWorkspace +virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.CreateWorkspaceImpl() -> Microsoft.CodeAnalysis.Workspace virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.DefaultFilePath.get -> string virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.DefaultFilePathPrefix.get -> string virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.DefaultTestProjectName.get -> string @@ -328,7 +330,7 @@ virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.GetAnalyzerOption virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.GetDefaultDiagnostic(Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer[] analyzers) -> Microsoft.CodeAnalysis.DiagnosticDescriptor virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.GetProjectCompilationAsync(Microsoft.CodeAnalysis.Project project, Microsoft.CodeAnalysis.Testing.IVerifier verifier, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.IsCompilerDiagnosticIncluded(Microsoft.CodeAnalysis.Diagnostic diagnostic, Microsoft.CodeAnalysis.Testing.CompilerDiagnostics compilerDiagnostics) -> bool -virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.RunAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +virtual Microsoft.CodeAnalysis.Testing.AnalyzerTest.RunImplAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task virtual Microsoft.CodeAnalysis.Testing.CodeActionTest.FilterCodeActions(System.Collections.Immutable.ImmutableArray actions) -> System.Collections.Immutable.ImmutableArray virtual Microsoft.CodeAnalysis.Testing.DefaultVerifier.CreateMessage(string message) -> string virtual Microsoft.CodeAnalysis.Testing.DefaultVerifier.Empty(string collectionName, System.Collections.Generic.IEnumerable collection) -> void diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs index 0ee1628190..c207545c87 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs @@ -216,7 +216,7 @@ bool CodeFixProvidersHandleDiagnostic(Diagnostic localDiagnostic) } } - public override async Task RunAsync(CancellationToken cancellationToken = default) + protected override async Task RunImplAsync(CancellationToken cancellationToken) { Verify.NotEmpty($"{nameof(TestState)}.{nameof(SolutionState.Sources)}", TestState.Sources); diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/PublicAPI.Unshipped.txt index 6ec73c7a28..6e09256b2a 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/PublicAPI.Unshipped.txt @@ -36,7 +36,7 @@ Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider.EmptyCodeFixProvider() -> void abstract Microsoft.CodeAnalysis.Testing.CodeFixTest.GetCodeFixProviders() -> System.Collections.Generic.IEnumerable override Microsoft.CodeAnalysis.Testing.CodeFixTest.IsCompilerDiagnosticIncluded(Microsoft.CodeAnalysis.Diagnostic diagnostic, Microsoft.CodeAnalysis.Testing.CompilerDiagnostics compilerDiagnostics) -> bool -override Microsoft.CodeAnalysis.Testing.CodeFixTest.RunAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +override Microsoft.CodeAnalysis.Testing.CodeFixTest.RunImplAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task override Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider.FixableDiagnosticIds.get -> System.Collections.Immutable.ImmutableArray override Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider.RegisterCodeFixesAsync(Microsoft.CodeAnalysis.CodeFixes.CodeFixContext context) -> System.Threading.Tasks.Task static Microsoft.CodeAnalysis.Testing.CodeFixVerifier.Diagnostic() -> Microsoft.CodeAnalysis.Testing.DiagnosticResult diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs index 441845d598..3b2e0def15 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs @@ -64,7 +64,7 @@ protected override IEnumerable GetDiagnosticAnalyzers() /// The to be used. protected abstract IEnumerable GetCodeRefactoringProviders(); - public override async Task RunAsync(CancellationToken cancellationToken = default) + protected override async Task RunImplAsync(CancellationToken cancellationToken) { Verify.NotEmpty($"{nameof(TestState)}.{nameof(SolutionState.Sources)}", TestState.Sources); diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/PublicAPI.Unshipped.txt index 74ed5b3860..f2aaec4295 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/PublicAPI.Unshipped.txt @@ -12,7 +12,7 @@ Microsoft.CodeAnalysis.Testing.EmptyCodeRefactoringProvider.EmptyCodeRefactoring abstract Microsoft.CodeAnalysis.Testing.CodeRefactoringTest.GetCodeRefactoringProviders() -> System.Collections.Generic.IEnumerable override Microsoft.CodeAnalysis.Testing.CodeRefactoringTest.GetDefaultDiagnostic(Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer[] analyzers) -> Microsoft.CodeAnalysis.DiagnosticDescriptor override Microsoft.CodeAnalysis.Testing.CodeRefactoringTest.GetDiagnosticAnalyzers() -> System.Collections.Generic.IEnumerable -override Microsoft.CodeAnalysis.Testing.CodeRefactoringTest.RunAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +override Microsoft.CodeAnalysis.Testing.CodeRefactoringTest.RunImplAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task override Microsoft.CodeAnalysis.Testing.EmptyCodeRefactoringProvider.ComputeRefactoringsAsync(Microsoft.CodeAnalysis.CodeRefactorings.CodeRefactoringContext context) -> System.Threading.Tasks.Task static Microsoft.CodeAnalysis.Testing.CodeRefactoringTest.TriggerSpanDescriptor.get -> Microsoft.CodeAnalysis.DiagnosticDescriptor static Microsoft.CodeAnalysis.Testing.CodeRefactoringVerifier.VerifyRefactoringAsync(string source, Microsoft.CodeAnalysis.Testing.DiagnosticResult expected, string fixedSource) -> System.Threading.Tasks.Task diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/PublicAPI.Unshipped.txt index c5004ff9db..09cd1e21f3 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/PublicAPI.Unshipped.txt @@ -11,4 +11,4 @@ abstract Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.CreateGen abstract Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.GetSourceGenerators() -> System.Collections.Generic.IEnumerable override Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.GetDiagnosticAnalyzers() -> System.Collections.Generic.IEnumerable override Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.GetProjectCompilationAsync(Microsoft.CodeAnalysis.Project project, Microsoft.CodeAnalysis.Testing.IVerifier verifier, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task -override Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.RunAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task +override Microsoft.CodeAnalysis.Testing.SourceGeneratorTest.RunImplAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/SourceGeneratorTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/SourceGeneratorTest`1.cs index f7ac4fb3fd..394b9bae32 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/SourceGeneratorTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.SourceGenerators.Testing/SourceGeneratorTest`1.cs @@ -33,7 +33,7 @@ protected override IEnumerable GetDiagnosticAnalyzers() protected abstract GeneratorDriver CreateGeneratorDriver(Project project, ImmutableArray sourceGenerators); - public override async Task RunAsync(CancellationToken cancellationToken = default) + protected override async Task RunImplAsync(CancellationToken cancellationToken) { var analyzers = GetDiagnosticAnalyzers().ToArray(); var defaultDiagnostic = GetDefaultDiagnostic(analyzers); From 91d1b98f728fdbe81f7cc5b7e25f9db8f48f0e8b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 4 May 2021 12:45:19 +0000 Subject: [PATCH 16/65] Update dependencies from https://github.com/dotnet/arcade build 20210503.2 (#810) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- eng/common/post-build/sourcelink-validation.ps1 | 2 +- eng/common/post-build/symbols-validation.ps1 | 2 +- global.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 28cea99be1..446b563be6 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 46ad27d3cc557f2b84ce30b2c4e27438526dc91d + e9fd640e1ec1890489ea66ad0f59e733448056da diff --git a/eng/common/post-build/sourcelink-validation.ps1 b/eng/common/post-build/sourcelink-validation.ps1 index 1c46f7b634..8c554729b6 100644 --- a/eng/common/post-build/sourcelink-validation.ps1 +++ b/eng/common/post-build/sourcelink-validation.ps1 @@ -14,7 +14,7 @@ param( $global:RepoFiles = @{} # Maximum number of jobs to run in parallel -$MaxParallelJobs = 6 +$MaxParallelJobs = 16 # Wait time between check for system load $SecondsBetweenLoadChecks = 10 diff --git a/eng/common/post-build/symbols-validation.ps1 b/eng/common/post-build/symbols-validation.ps1 index e6d5d2fd05..788321d773 100644 --- a/eng/common/post-build/symbols-validation.ps1 +++ b/eng/common/post-build/symbols-validation.ps1 @@ -8,7 +8,7 @@ param( ) # Maximum number of jobs to run in parallel -$MaxParallelJobs = 6 +$MaxParallelJobs = 16 # Max number of retries $MaxRetry = 5 diff --git a/global.json b/global.json index c9ebb3b028..3ab89ac9f7 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21230.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21253.2" } } From a3c7fce9d50717fbc8dc20d9f534ea48a05ef864 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 6 May 2021 12:45:12 +0000 Subject: [PATCH 17/65] [main] Update dependencies from dotnet/arcade (#811) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- eng/common/build.ps1 | 2 ++ eng/common/cross/build-android-rootfs.sh | 1 - eng/common/cross/build-rootfs.sh | 8 ++++---- eng/common/msbuild.ps1 | 1 + eng/common/templates/job/onelocbuild.yml | 2 ++ eng/common/tools.ps1 | 19 ++++++++++++++++--- global.json | 2 +- 8 files changed, 28 insertions(+), 11 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 446b563be6..00c1e41548 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - e9fd640e1ec1890489ea66ad0f59e733448056da + 01c1af9f5ead4962e390cfbec92396de34118492 diff --git a/eng/common/build.ps1 b/eng/common/build.ps1 index 94a91c0817..8943da242f 100644 --- a/eng/common/build.ps1 +++ b/eng/common/build.ps1 @@ -25,6 +25,7 @@ Param( [switch] $prepareMachine, [string] $runtimeSourceFeed = '', [string] $runtimeSourceFeedKey = '', + [switch] $excludePrereleaseVS, [switch] $help, [Parameter(ValueFromRemainingArguments=$true)][String[]]$properties ) @@ -65,6 +66,7 @@ function Print-Usage() { Write-Host " -prepareMachine Prepare machine for CI run, clean up processes after build" Write-Host " -warnAsError Sets warnaserror msbuild parameter ('true' or 'false')" Write-Host " -msbuildEngine Msbuild engine to use to run build ('dotnet', 'vs', or unspecified)." + Write-Host " -excludePrereleaseVS Set to exclude build engines in prerelease versions of Visual Studio" Write-Host "" Write-Host "Command line arguments not listed above are passed thru to msbuild." diff --git a/eng/common/cross/build-android-rootfs.sh b/eng/common/cross/build-android-rootfs.sh index c29c8267e7..42516bbeeb 100755 --- a/eng/common/cross/build-android-rootfs.sh +++ b/eng/common/cross/build-android-rootfs.sh @@ -106,7 +106,6 @@ __AndroidPackages+=" libandroid-glob" __AndroidPackages+=" liblzma" __AndroidPackages+=" krb5" __AndroidPackages+=" openssl" -__AndroidPackages+=" openldap" for path in $(wget -qO- http://termux.net/dists/stable/main/binary-$__AndroidArch/Packages |\ grep -A15 "Package: \(${__AndroidPackages// /\\|}\)" | grep -v "static\|tool" | grep Filename); do diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh index 81e641a57b..591d8666a8 100755 --- a/eng/common/cross/build-rootfs.sh +++ b/eng/common/cross/build-rootfs.sh @@ -55,13 +55,11 @@ __UbuntuPackages+=" libcurl4-openssl-dev" __UbuntuPackages+=" libkrb5-dev" __UbuntuPackages+=" libssl-dev" __UbuntuPackages+=" zlib1g-dev" -__UbuntuPackages+=" libldap2-dev" __AlpinePackages+=" curl-dev" __AlpinePackages+=" krb5-dev" __AlpinePackages+=" openssl-dev" __AlpinePackages+=" zlib-dev" -__AlpinePackages+=" openldap-dev" __FreeBSDBase="12.1-RELEASE" __FreeBSDPkg="1.12.0" @@ -70,13 +68,15 @@ __FreeBSDPackages+=" icu" __FreeBSDPackages+=" libinotify" __FreeBSDPackages+=" lttng-ust" __FreeBSDPackages+=" krb5" -__FreeBSDPackages+=" libslapi-2.4" __IllumosPackages="icu-64.2nb2" __IllumosPackages+=" mit-krb5-1.16.2nb4" __IllumosPackages+=" openssl-1.1.1e" __IllumosPackages+=" zlib-1.2.11" -__IllumosPackages+=" openldap-client-2.4.49" + +# ML.NET dependencies +__UbuntuPackages+=" libomp5" +__UbuntuPackages+=" libomp-dev" __UseMirror=0 diff --git a/eng/common/msbuild.ps1 b/eng/common/msbuild.ps1 index c640123000..eea19cd845 100644 --- a/eng/common/msbuild.ps1 +++ b/eng/common/msbuild.ps1 @@ -5,6 +5,7 @@ Param( [bool] $nodeReuse = $true, [switch] $ci, [switch] $prepareMachine, + [switch] $excludePrereleaseVS, [Parameter(ValueFromRemainingArguments=$true)][String[]]$extraArgs ) diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml index b27d6faf30..958db4064c 100644 --- a/eng/common/templates/job/onelocbuild.yml +++ b/eng/common/templates/job/onelocbuild.yml @@ -12,6 +12,7 @@ parameters: SourcesDirectory: $(Build.SourcesDirectory) CreatePr: true AutoCompletePr: false + UseLfLineEndings: true UseCheckedInLocProjectJson: false LanguageSet: VS_Main_Languages LclSource: lclFilesInRepo @@ -59,6 +60,7 @@ jobs: isCreatePrSelected: ${{ parameters.CreatePr }} ${{ if eq(parameters.CreatePr, true) }}: isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }} + isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }} packageSourceAuth: patAuth patVariable: ${{ parameters.CeapexPat }} ${{ if eq(parameters.RepoType, 'gitHub') }}: diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index d52467eea1..2d8a74f7d9 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -48,6 +48,9 @@ # True to use global NuGet cache instead of restoring packages to repository-local directory. [bool]$useGlobalNuGetCache = if (Test-Path variable:useGlobalNuGetCache) { $useGlobalNuGetCache } else { !$ci } +# True to exclude prerelease versions Visual Studio during build +[bool]$excludePrereleaseVS = if (Test-Path variable:excludePrereleaseVS) { $excludePrereleaseVS } else { $false } + # An array of names of processes to stop on script exit if prepareMachine is true. $processesToStopOnExit = if (Test-Path variable:processesToStopOnExit) { $processesToStopOnExit } else { @('msbuild', 'dotnet', 'vbcscompiler') } @@ -463,7 +466,11 @@ function LocateVisualStudio([object]$vsRequirements = $null){ } if (!$vsRequirements) { $vsRequirements = $GlobalJson.tools.vs } - $args = @('-latest', '-prerelease', '-format', 'json', '-requires', 'Microsoft.Component.MSBuild', '-products', '*') + $args = @('-latest', '-format', 'json', '-requires', 'Microsoft.Component.MSBuild', '-products', '*') + + if (!$excludePrereleaseVS) { + $args += '-prerelease' + } if (Get-Member -InputObject $vsRequirements -Name 'version') { $args += '-version' @@ -489,7 +496,13 @@ function LocateVisualStudio([object]$vsRequirements = $null){ function InitializeBuildTool() { if (Test-Path variable:global:_BuildTool) { - return $global:_BuildTool + # If the requested msbuild parameters do not match, clear the cached variables. + if($global:_BuildTool.Contains('ExcludePrereleaseVS') -and $global:_BuildTool.ExcludePrereleaseVS -ne $excludePrereleaseVS) { + Remove-Item variable:global:_BuildTool + Remove-Item variable:global:_MSBuildExe + } else { + return $global:_BuildTool + } } if (-not $msbuildEngine) { @@ -517,7 +530,7 @@ function InitializeBuildTool() { ExitWithExitCode 1 } - $buildTool = @{ Path = $msbuildPath; Command = ""; Tool = "vs"; Framework = "net472" } + $buildTool = @{ Path = $msbuildPath; Command = ""; Tool = "vs"; Framework = "net472"; ExcludePrereleaseVS = $excludePrereleaseVS } } else { Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Unexpected value of -msbuildEngine: '$msbuildEngine'." ExitWithExitCode 1 diff --git a/global.json b/global.json index 3ab89ac9f7..db43aaf6db 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21253.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21256.1" } } From 29200c8056d08475e439ff34169c6adfa48c8323 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 7 May 2021 12:45:41 +0000 Subject: [PATCH 18/65] Update dependencies from https://github.com/dotnet/arcade build 20210506.13 (#813) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- eng/common/post-build/symbols-validation.ps1 | 13 +++++++++++-- global.json | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 00c1e41548..44b7dd55e0 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 01c1af9f5ead4962e390cfbec92396de34118492 + f9ce6058792211e652243db3b07fa511cf83486b diff --git a/eng/common/post-build/symbols-validation.ps1 b/eng/common/post-build/symbols-validation.ps1 index 788321d773..f26f6de81f 100644 --- a/eng/common/post-build/symbols-validation.ps1 +++ b/eng/common/post-build/symbols-validation.ps1 @@ -114,6 +114,7 @@ $CountMissingSymbols = { $totalRetries = 0 while ($totalRetries -lt $using:MaxRetry) { + # Save the output and get diagnostic output $output = & $dotnetSymbolExe --symbols --modules $WindowsPdbVerificationParam $TargetServerParam $FullPath -o $SymbolsPath --diagnostics | Out-String @@ -144,8 +145,16 @@ $CountMissingSymbols = { return $null } - $SymbolsOnMSDL = & $FirstMatchingSymbolDescriptionOrDefault $FileName '--microsoft-symbol-server' $SymbolsPath $WindowsPdbVerificationParam - $SymbolsOnSymWeb = & $FirstMatchingSymbolDescriptionOrDefault $FileName '--internal-server' $SymbolsPath $WindowsPdbVerificationParam + $SymbolsOnMSDL = & $FirstMatchingSymbolDescriptionOrDefault ` + -FullPath $FileName ` + -TargetServerParam '--microsoft-symbol-server' ` + -SymbolsPath $SymbolsPath ` + -WindowsPdbVerificationParam $WindowsPdbVerificationParam + $SymbolsOnSymWeb = & $FirstMatchingSymbolDescriptionOrDefault ` + -FullPath $FileName ` + -TargetServerParam '--internal-server' ` + -SymbolsPath $SymbolsPath ` + -WindowsPdbVerificationParam $WindowsPdbVerificationParam Write-Host -NoNewLine "`t Checking file " $FileName "... " diff --git a/global.json b/global.json index db43aaf6db..5a5c4f4351 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21256.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21256.13" } } From 29678a6c65e8576b4b80e1146ccfe071c217821b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 8 May 2021 12:40:49 +0000 Subject: [PATCH 19/65] Update dependencies from https://github.com/dotnet/arcade build 20210507.5 (#814) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 44b7dd55e0..3d324d09bb 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - f9ce6058792211e652243db3b07fa511cf83486b + 5faea1b7965644d1f1c666a7130f6f614abe76c0 diff --git a/global.json b/global.json index 5a5c4f4351..aaed89b071 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21256.13" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21257.5" } } From 971455bf3096e4aecb127e83949d7edf15f97083 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 11 May 2021 12:44:49 +0000 Subject: [PATCH 20/65] Update dependencies from https://github.com/dotnet/arcade build 20210510.1 (#815) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3d324d09bb..fd150a3229 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 5faea1b7965644d1f1c666a7130f6f614abe76c0 + 44324e2d3563921f60b1522fccf3fef45dcfe636 diff --git a/global.json b/global.json index aaed89b071..d5fa7465db 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21257.5" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21260.1" } } From 4021ff0116dd1e898b01eccd3f9d384d569dc64a Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 12 May 2021 12:44:22 +0000 Subject: [PATCH 21/65] Update dependencies from https://github.com/dotnet/arcade build 20210511.6 (#817) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index fd150a3229..187ea59465 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 44324e2d3563921f60b1522fccf3fef45dcfe636 + c5c6ef92686f208055e884bad45d32966f0b1f95 diff --git a/global.json b/global.json index d5fa7465db..372380c3d5 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21260.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21261.6" } } From f6b75d853e940d7d9ef08152939997cba08b7c15 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Wed, 12 May 2021 10:37:56 -0700 Subject: [PATCH 22/65] Enable Arcade v3 publishing --- .vsts-ci.yml | 1 + eng/Publishing.props | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 eng/Publishing.props diff --git a/.vsts-ci.yml b/.vsts-ci.yml index 6799a999dc..f03691593c 100644 --- a/.vsts-ci.yml +++ b/.vsts-ci.yml @@ -121,6 +121,7 @@ stages: - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - template: eng\common\templates\post-build\post-build.yml parameters: + publishingInfraVersion: 3 # Symbol validation is not entirely reliable as of yet, so should be turned off until # https://github.com/dotnet/arcade/issues/2871 is resolved. enableSymbolValidation: false diff --git a/eng/Publishing.props b/eng/Publishing.props new file mode 100644 index 0000000000..797de4ea1d --- /dev/null +++ b/eng/Publishing.props @@ -0,0 +1,6 @@ + + + + 3 + + \ No newline at end of file From 0015f7306b7cea24caaf25f458b00dcc745dedae Mon Sep 17 00:00:00 2001 From: Jon Fortescue Date: Wed, 12 May 2021 11:12:45 -0700 Subject: [PATCH 23/65] Turn on OneLocBuild PRs (#816) --- .vsts-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.vsts-ci.yml b/.vsts-ci.yml index 6799a999dc..99e4b40882 100644 --- a/.vsts-ci.yml +++ b/.vsts-ci.yml @@ -20,7 +20,6 @@ stages: jobs: - template: /eng/common/templates/job/onelocbuild.yml parameters: - CreatePr: false LclSource: lclFilesfromPackage LclPackageId: 'LCL-JUNO-PROD-ROSLYNSDK' From 8d9877272fda4e86e6007bba6ead8a417412c167 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 13 May 2021 12:45:49 +0000 Subject: [PATCH 24/65] Update dependencies from https://github.com/dotnet/arcade build 20210513.1 (#819) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 187ea59465..d2cfa87ea9 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - c5c6ef92686f208055e884bad45d32966f0b1f95 + 6b9758661f4483a70654bcaf6f8d7c6a79ee5660 diff --git a/global.json b/global.json index 372380c3d5..2c70714615 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21261.6" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21263.1" } } From f092fff810b815dbc1488892251da8f3d175bb3a Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 14 May 2021 12:40:51 +0000 Subject: [PATCH 25/65] Update dependencies from https://github.com/dotnet/arcade build 20210513.5 (#821) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 +- .../post-build/sourcelink-validation.ps1 | 78 ++++++++++++------- eng/common/post-build/symbols-validation.ps1 | 21 ++--- global.json | 2 +- 4 files changed, 67 insertions(+), 38 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d2cfa87ea9..80d87b3435 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 6b9758661f4483a70654bcaf6f8d7c6a79ee5660 + e8d0df4f35cfa23174fe7204ef958cf5d1b8e797 diff --git a/eng/common/post-build/sourcelink-validation.ps1 b/eng/common/post-build/sourcelink-validation.ps1 index 8c554729b6..85c8986171 100644 --- a/eng/common/post-build/sourcelink-validation.ps1 +++ b/eng/common/post-build/sourcelink-validation.ps1 @@ -16,6 +16,8 @@ $global:RepoFiles = @{} # Maximum number of jobs to run in parallel $MaxParallelJobs = 16 +$MaxRetries = 5 + # Wait time between check for system load $SecondsBetweenLoadChecks = 10 @@ -29,7 +31,10 @@ $ValidatePackage = { # Ensure input file exist if (!(Test-Path $PackagePath)) { Write-Host "Input file does not exist: $PackagePath" - return 1 + return [pscustomobject]@{ + result = 1 + packagePath = $PackagePath + } } # Extensions for which we'll look for SourceLink information @@ -59,7 +64,10 @@ $ValidatePackage = { # We ignore resource DLLs if ($FileName.EndsWith('.resources.dll')) { - return + return [pscustomobject]@{ + result = 0 + packagePath = $PackagePath + } } [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $TargetFile, $true) @@ -91,36 +99,49 @@ $ValidatePackage = { $Status = 200 $Cache = $using:RepoFiles - if ( !($Cache.ContainsKey($FilePath)) ) { - try { - $Uri = $Link -as [System.URI] - - # Only GitHub links are valid - if ($Uri.AbsoluteURI -ne $null -and ($Uri.Host -match 'github' -or $Uri.Host -match 'githubusercontent')) { - $Status = (Invoke-WebRequest -Uri $Link -UseBasicParsing -Method HEAD -TimeoutSec 5).StatusCode + $totalRetries = 0 + + while ($totalRetries -lt $using:MaxRetries) { + if ( !($Cache.ContainsKey($FilePath)) ) { + try { + $Uri = $Link -as [System.URI] + + # Only GitHub links are valid + if ($Uri.AbsoluteURI -ne $null -and ($Uri.Host -match 'github' -or $Uri.Host -match 'githubusercontent')) { + $Status = (Invoke-WebRequest -Uri $Link -UseBasicParsing -Method HEAD -TimeoutSec 5).StatusCode + } + else { + # If it's not a github link, we want to break out of the loop and not retry. + $Status = 0 + $totalRetries = $using:MaxRetries + } } - else { + catch { + Write-Host $_ $Status = 0 } } - catch { - write-host $_ - $Status = 0 - } - } - if ($Status -ne 200) { - if ($NumFailedLinks -eq 0) { - if ($FailedFiles.Value -eq 0) { - Write-Host + if ($Status -ne 200) { + $totalRetries++ + + if ($totalRetries -ge $using:MaxRetries) { + if ($NumFailedLinks -eq 0) { + if ($FailedFiles.Value -eq 0) { + Write-Host + } + + Write-Host "`tFile $RealPath has broken links:" + } + + Write-Host "`t`tFailed to retrieve $Link" + + $NumFailedLinks++ } - - Write-Host "`tFile $RealPath has broken links:" } - - Write-Host "`t`tFailed to retrieve $Link" - - $NumFailedLinks++ + else { + break + } } } } @@ -136,7 +157,7 @@ $ValidatePackage = { } } catch { - + Write-Host $_ } finally { $zip.Dispose() @@ -220,6 +241,7 @@ function ValidateSourceLinkLinks { # Process each NuGet package in parallel Get-ChildItem "$InputPath\*.symbols.nupkg" | ForEach-Object { + Write-Host "Starting $($_.FullName)" Start-Job -ScriptBlock $ValidatePackage -ArgumentList $_.FullName | Out-Null $NumJobs = @(Get-Job -State 'Running').Count @@ -267,6 +289,10 @@ function InstallSourcelinkCli { try { InstallSourcelinkCli + foreach ($Job in @(Get-Job)) { + Remove-Job -Id $Job.Id + } + ValidateSourceLinkLinks } catch { diff --git a/eng/common/post-build/symbols-validation.ps1 b/eng/common/post-build/symbols-validation.ps1 index f26f6de81f..a5af041ba7 100644 --- a/eng/common/post-build/symbols-validation.ps1 +++ b/eng/common/post-build/symbols-validation.ps1 @@ -133,27 +133,27 @@ $CountMissingSymbols = { elseif (Test-Path $SymbolPath) { return 'Module' } - elseif ($output.Contains("503 Service Unavailable")) { - # If we got a 503 error, we should retry. + else + { $totalRetries++ } - else { - return $null - } } return $null } + $FileGuid = New-Guid + $ExpandedSymbolsPath = Join-Path -Path $SymbolsPath -ChildPath $FileGuid + $SymbolsOnMSDL = & $FirstMatchingSymbolDescriptionOrDefault ` -FullPath $FileName ` -TargetServerParam '--microsoft-symbol-server' ` - -SymbolsPath $SymbolsPath ` + -SymbolsPath "$ExpandedSymbolsPath-msdl" ` -WindowsPdbVerificationParam $WindowsPdbVerificationParam $SymbolsOnSymWeb = & $FirstMatchingSymbolDescriptionOrDefault ` -FullPath $FileName ` -TargetServerParam '--internal-server' ` - -SymbolsPath $SymbolsPath ` + -SymbolsPath "$ExpandedSymbolsPath-symweb" ` -WindowsPdbVerificationParam $WindowsPdbVerificationParam Write-Host -NoNewLine "`t Checking file " $FileName "... " @@ -217,6 +217,7 @@ function CheckSymbolsAvailable { Remove-Item $ExtractPath -Force -Recurse -ErrorAction SilentlyContinue } + $TotalPackages = 0 $TotalFailures = 0 $DupedSymbols = 0 @@ -239,6 +240,8 @@ function CheckSymbolsAvailable { return } + $TotalPackages++ + Start-Job -ScriptBlock $CountMissingSymbols -ArgumentList @($FullName,$WindowsPdbVerificationParam) | Out-Null $NumJobs = @(Get-Job -State 'Running').Count @@ -264,11 +267,11 @@ function CheckSymbolsAvailable { if ($TotalFailures -gt 0 -or $DupedSymbols -gt 0) { if ($TotalFailures -gt 0) { - Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "Symbols missing for $TotalFailures packages" + Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "Symbols missing for $TotalFailures/$TotalPackages packages" } if ($DupedSymbols -gt 0) { - Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "$DupedSymbols packages had duplicated symbol files" + Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "$DupedSymbols/$TotalPackages packages had duplicated symbol files and could not be extracted" } ExitWithExitCode 1 diff --git a/global.json b/global.json index 2c70714615..dc19920104 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21263.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21263.5" } } From 90c8e02ad0da4598fba090f56adcb8cbe70be26e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 15 May 2021 12:45:54 +0000 Subject: [PATCH 26/65] Update dependencies from https://github.com/dotnet/arcade build 20210514.2 (#822) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 80d87b3435..ecc338bcb4 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - e8d0df4f35cfa23174fe7204ef958cf5d1b8e797 + 42de78a825b575a1ddeb73020a01fb8cd9311d09 diff --git a/global.json b/global.json index dc19920104..cabe699d90 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21263.5" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21264.2" } } From c53972245cc8d382a02ac3286d3fb082adffd401 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Wed, 19 May 2021 16:57:45 -0700 Subject: [PATCH 27/65] update versions in preparation for release --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index 2444a3f630..89105515f4 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -3,7 +3,7 @@ 3.2.0 - 1.0.1 + 1.1.0 beta1 true From 9f3f98a32abda5e441522f89a90fe3ced9635d01 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 22 May 2021 12:45:00 +0000 Subject: [PATCH 28/65] Update dependencies from https://github.com/dotnet/arcade build 20210521.3 (#828) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- eng/common/generate-locproject.ps1 | 12 ++++++------ eng/common/templates/job/onelocbuild.yml | 4 ++-- global.json | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ecc338bcb4..4e1c0996e5 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 42de78a825b575a1ddeb73020a01fb8cd9311d09 + 50f5645789f9119c906755cb1d2549acdeb0d0b7 diff --git a/eng/common/generate-locproject.ps1 b/eng/common/generate-locproject.ps1 index 24c00b5be9..de348a2e22 100644 --- a/eng/common/generate-locproject.ps1 +++ b/eng/common/generate-locproject.ps1 @@ -14,7 +14,7 @@ $ErrorActionPreference = "Stop" Import-Module -Name (Join-Path $PSScriptRoot 'native\CommonLibrary.psm1') -$exclusionsFilePath = "$SourcesDirectory\Localize\LocExclusions.json" +$exclusionsFilePath = "$SourcesDirectory\eng\Localize\LocExclusions.json" $exclusions = @{ Exclusions = @() } if (Test-Path -Path $exclusionsFilePath) { @@ -92,14 +92,14 @@ Write-Host "LocProject.json generated:`n`n$json`n`n" Pop-Location if (!$UseCheckedInLocProjectJson) { - New-Item "$SourcesDirectory\Localize\LocProject.json" -Force # Need this to make sure the Localize directory is created - Set-Content "$SourcesDirectory\Localize\LocProject.json" $json + New-Item "$SourcesDirectory\eng\Localize\LocProject.json" -Force # Need this to make sure the Localize directory is created + Set-Content "$SourcesDirectory\eng\Localize\LocProject.json" $json } else { - New-Item "$SourcesDirectory\Localize\LocProject-generated.json" -Force # Need this to make sure the Localize directory is created - Set-Content "$SourcesDirectory\Localize\LocProject-generated.json" $json + New-Item "$SourcesDirectory\eng\Localize\LocProject-generated.json" -Force # Need this to make sure the Localize directory is created + Set-Content "$SourcesDirectory\eng\Localize\LocProject-generated.json" $json - if ((Get-FileHash "$SourcesDirectory\Localize\LocProject-generated.json").Hash -ne (Get-FileHash "$SourcesDirectory\Localize\LocProject.json").Hash) { + if ((Get-FileHash "$SourcesDirectory\eng\Localize\LocProject-generated.json").Hash -ne (Get-FileHash "$SourcesDirectory\eng\Localize\LocProject.json").Hash) { Write-PipelineTelemetryError -Category "OneLocBuild" -Message "Existing LocProject.json differs from generated LocProject.json. Download LocProject-generated.json and compare them." exit 1 diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml index 958db4064c..2acdd5256d 100644 --- a/eng/common/templates/job/onelocbuild.yml +++ b/eng/common/templates/job/onelocbuild.yml @@ -53,7 +53,7 @@ jobs: env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) inputs: - locProj: Localize/LocProject.json + locProj: eng/Localize/LocProject.json outDir: $(Build.ArtifactStagingDirectory) lclSource: ${{ parameters.LclSource }} lclPackageId: ${{ parameters.LclPackageId }} @@ -79,7 +79,7 @@ jobs: - task: PublishBuildArtifacts@1 displayName: Publish LocProject.json inputs: - PathtoPublish: '$(Build.SourcesDirectory)/Localize/' + PathtoPublish: '$(Build.SourcesDirectory)/eng/Localize/' PublishLocation: Container ArtifactName: Loc condition: ${{ parameters.condition }} \ No newline at end of file diff --git a/global.json b/global.json index cabe699d90..a88eed1b04 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21264.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21271.3" } } From 6d4d0aef4ec940e5b997d11178bfac979fa8dd3c Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Mon, 24 May 2021 10:31:52 -0700 Subject: [PATCH 29/65] add vb generator samples to the samples solution --- Samples.sln | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Samples.sln b/Samples.sln index 349b0c8cda..a69935724f 100644 --- a/Samples.sln +++ b/Samples.sln @@ -117,6 +117,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SourceGeneratorSamples", "s EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeneratedDemo", "samples\CSharp\SourceGenerators\GeneratedDemo\GeneratedDemo.csproj", "{EC4DB63B-C2B4-4D06-AF98-15253035C6D5}" EndProject +Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "GeneratedDemo", "samples\VisualBasic\SourceGenerators\GeneratedDemo\GeneratedDemo.vbproj", "{DA924876-9CF5-47E0-AA01-ADAF47653D39}" +EndProject +Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "SourceGeneratorSamples", "samples\VisualBasic\SourceGenerators\SourceGeneratorSamples\SourceGeneratorSamples.vbproj", "{8322B6E4-0CB1-4EC1-A2CC-2E4DB02C834A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SourceGenerators", "SourceGenerators", "{E79B07C8-0859-4B5C-9650-68D855833C6E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -283,6 +289,14 @@ Global {EC4DB63B-C2B4-4D06-AF98-15253035C6D5}.Debug|Any CPU.Build.0 = Debug|Any CPU {EC4DB63B-C2B4-4D06-AF98-15253035C6D5}.Release|Any CPU.ActiveCfg = Release|Any CPU {EC4DB63B-C2B4-4D06-AF98-15253035C6D5}.Release|Any CPU.Build.0 = Release|Any CPU + {DA924876-9CF5-47E0-AA01-ADAF47653D39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA924876-9CF5-47E0-AA01-ADAF47653D39}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA924876-9CF5-47E0-AA01-ADAF47653D39}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA924876-9CF5-47E0-AA01-ADAF47653D39}.Release|Any CPU.Build.0 = Release|Any CPU + {8322B6E4-0CB1-4EC1-A2CC-2E4DB02C834A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8322B6E4-0CB1-4EC1-A2CC-2E4DB02C834A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8322B6E4-0CB1-4EC1-A2CC-2E4DB02C834A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8322B6E4-0CB1-4EC1-A2CC-2E4DB02C834A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -342,6 +356,9 @@ Global {14D18F51-6B59-49D5-9AB7-08B38417A459} = {C3FB27E9-C8EE-4F76-B0AA-7CD67A7E652B} {2ADE5CFA-5DF4-44A9-BD67-E884BCFBA045} = {14D18F51-6B59-49D5-9AB7-08B38417A459} {EC4DB63B-C2B4-4D06-AF98-15253035C6D5} = {14D18F51-6B59-49D5-9AB7-08B38417A459} + {DA924876-9CF5-47E0-AA01-ADAF47653D39} = {E79B07C8-0859-4B5C-9650-68D855833C6E} + {8322B6E4-0CB1-4EC1-A2CC-2E4DB02C834A} = {E79B07C8-0859-4B5C-9650-68D855833C6E} + {E79B07C8-0859-4B5C-9650-68D855833C6E} = {CDA94F62-E35A-4913-8045-D9D42416513C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B849838B-3D7A-4B6B-BE07-285DCB1588F4} From dfa1b4a523522c88fc50bd7c4ecdeac13b5c1010 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Mon, 24 May 2021 10:55:16 -0700 Subject: [PATCH 30/65] fix symbol comparison --- .../SourceGeneratorSamples/AutoNotifyGenerator.vb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb index 981ae965de..a5441ec9c6 100644 --- a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb @@ -1,4 +1,4 @@ -Option Explicit On +Option Explicit On Option Infer On Option Strict On @@ -76,7 +76,7 @@ End Namespace Next ' group the fields by class, and generate the source - For Each group In fieldSymbols.GroupBy(Function(f) f.ContainingType) + For Each group In fieldSymbols.GroupBy(Function(f) f.ContainingType, SymbolEqualityComparer.Default) Dim classSource = ProcessClass(group.Key, group.ToList(), attributeSymbol, notifySymbol) context.AddSource($"{group.Key.Name}_AutoNotify.vb", SourceText.From(classSource, Encoding.UTF8)) Next @@ -198,4 +198,4 @@ End Namespace") End Class -End Namespace \ No newline at end of file +End Namespace From c969e6635b77c7aed9d0111a2e7ac00efc03a8ad Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Mon, 24 May 2021 10:56:28 -0700 Subject: [PATCH 31/65] fix formatting --- .../SourceGenerators/GeneratedDemo/Program.vb | 26 +- .../GeneratedDemo/UseAutoNotifyGenerator.vb | 40 +-- .../GeneratedDemo/UseCsvGenerator.vb | 14 +- .../GeneratedDemo/UseHelloWorldGenerator.vb | 8 +- .../GeneratedDemo/UseMustacheGenerator.vb | 38 +-- .../GeneratedDemo/UseXmlSettingsGenerator.vb | 28 +- .../AutoNotifyGenerator.vb | 238 +++++++-------- .../SourceGeneratorSamples/CsvGenerator.vb | 288 +++++++++--------- .../HelloWorldGenerator.vb | 46 +-- .../MustacheGenerator.vb | 138 ++++----- .../SettingsXmlGenerator.vb | 86 +++--- 11 files changed, 475 insertions(+), 475 deletions(-) diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/Program.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/Program.vb index 154f716e0e..f6b18bf08f 100644 --- a/samples/VisualBasic/SourceGenerators/GeneratedDemo/Program.vb +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/Program.vb @@ -4,36 +4,36 @@ Option Infer On Module Program - Public Sub Main() + Public Sub Main() - Console.WriteLine("Running HelloWorld: + Console.WriteLine("Running HelloWorld: ") - UseHelloWorldGenerator.Run() + UseHelloWorldGenerator.Run() - Console.WriteLine(" + Console.WriteLine(" Running AutoNotify: ") - UseAutoNotifyGenerator.Run() + UseAutoNotifyGenerator.Run() - Console.WriteLine(" + Console.WriteLine(" Running XmlSettings: ") - UseXmlSettingsGenerator.Run() + UseXmlSettingsGenerator.Run() - Console.WriteLine(" + Console.WriteLine(" Running CsvGenerator: ") - UseCsvGenerator.Run() + UseCsvGenerator.Run() - Console.WriteLine(" + Console.WriteLine(" Running MustacheGenerator: ") - UseMustacheGenerator.Run() + UseMustacheGenerator.Run() - End Sub + End Sub -End Module \ No newline at end of file +End Module diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseAutoNotifyGenerator.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseAutoNotifyGenerator.vb index ea1a1a3d83..f810bd4a63 100644 --- a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseAutoNotifyGenerator.vb +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseAutoNotifyGenerator.vb @@ -7,36 +7,36 @@ Imports AutoNotify ' The view model we'd like to augment Partial Public Class ExampleViewModel - - Private _text As String = "private field text" + + Private _text As String = "private field text" - - Private _amount As Integer = 5 + + Private _amount As Integer = 5 End Class Public Module UseAutoNotifyGenerator - Public Sub Run() + Public Sub Run() - Dim vm As New ExampleViewModel() + Dim vm As New ExampleViewModel() - ' we didn't explicitly create the 'Text' property, it was generated for us - Dim text = vm.Text - Console.WriteLine($"Text = {text}") + ' we didn't explicitly create the 'Text' property, it was generated for us + Dim text = vm.Text + Console.WriteLine($"Text = {text}") - ' Properties can have differnt names generated based on the PropertyName argument of the attribute - Dim count = vm.Count - Console.WriteLine($"Count = {count}") + ' Properties can have differnt names generated based on the PropertyName argument of the attribute + Dim count = vm.Count + Console.WriteLine($"Count = {count}") - ' the viewmodel will automatically implement INotifyPropertyChanged - AddHandler vm.PropertyChanged, Sub(o, e) Console.WriteLine($"Property {e.PropertyName} was changed") - vm.Text = "abc" - vm.Count = 123 + ' the viewmodel will automatically implement INotifyPropertyChanged + AddHandler vm.PropertyChanged, Sub(o, e) Console.WriteLine($"Property {e.PropertyName} was changed") + vm.Text = "abc" + vm.Count = 123 - ' Try adding fields to the ExampleViewModel class above and tagging them with the attribute - ' You'll see the matching generated properties visibile in IntelliSense in realtime + ' Try adding fields to the ExampleViewModel class above and tagging them with the attribute + ' You'll see the matching generated properties visibile in IntelliSense in realtime - End Sub + End Sub -End Module \ No newline at end of file +End Module diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseCsvGenerator.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseCsvGenerator.vb index 78c1993265..f4c0558355 100644 --- a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseCsvGenerator.vb +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseCsvGenerator.vb @@ -6,13 +6,13 @@ Imports CSV Friend Class UseCsvGenerator - Public Shared Sub Run() + Public Shared Sub Run() - Console.WriteLine("## CARS") - Cars.All.ToList().ForEach(Sub(c) Console.WriteLine(c.Brand & vbTab & c.Model & vbTab & c.Year & vbTab & c.Cc & vbTab & c.Favorite)) - Console.WriteLine(vbCr & "## PEOPLE") - People.All.ToList().ForEach(Sub(p) Console.WriteLine(p.Name & vbTab & p.Address & vbTab & p._11Age)) + Console.WriteLine("## CARS") + Cars.All.ToList().ForEach(Sub(c) Console.WriteLine(c.Brand & vbTab & c.Model & vbTab & c.Year & vbTab & c.Cc & vbTab & c.Favorite)) + Console.WriteLine(vbCr & "## PEOPLE") + People.All.ToList().ForEach(Sub(p) Console.WriteLine(p.Name & vbTab & p.Address & vbTab & p._11Age)) - End Sub + End Sub -End Class \ No newline at end of file +End Class diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseHelloWorldGenerator.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseHelloWorldGenerator.vb index 78a173ca73..89fa11b478 100644 --- a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseHelloWorldGenerator.vb +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseHelloWorldGenerator.vb @@ -1,8 +1,8 @@ Public Module UseHelloWorldGenerator - Public Sub Run() - ' The static call below is generated at build time, and will list the syntax trees used in the compilation - HelloWorldGenerated.HelloWorld.SayHello() - End Sub + Public Sub Run() + ' The static call below is generated at build time, and will list the syntax trees used in the compilation + HelloWorldGenerated.HelloWorld.SayHello() + End Sub End Module diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseMustacheGenerator.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseMustacheGenerator.vb index 3c9a97c414..2717aab0e3 100644 --- a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseMustacheGenerator.vb +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseMustacheGenerator.vb @@ -12,23 +12,23 @@ Imports GeneratedDemo.UseMustacheGenerator Friend Class UseMustacheGenerator - Public Shared Sub Run() - Console.WriteLine(Mustache.Constants.Lottery) - Console.WriteLine(Mustache.Constants.HR) - Console.WriteLine(Mustache.Constants.HTML) - Console.WriteLine(Mustache.Constants.Section) - Console.WriteLine(Mustache.Constants.NestedSection) - End Sub + Public Shared Sub Run() + Console.WriteLine(Mustache.Constants.Lottery) + Console.WriteLine(Mustache.Constants.HR) + Console.WriteLine(Mustache.Constants.HTML) + Console.WriteLine(Mustache.Constants.Section) + Console.WriteLine(Mustache.Constants.NestedSection) + End Sub - ' Mustache templates and hashes from the manual at https://mustache.github.io/mustache.1.html... - Public Const t1 As String = " + ' Mustache templates and hashes from the manual at https://mustache.github.io/mustache.1.html... + Public Const t1 As String = " Hello {{name}} You have just won {{value}} dollars! {{#in_ca}} Well, {{taxed_value}} dollars, after taxes. {{/in_ca}} " - Public Const h1 As String = " + Public Const h1 As String = " { ""name"": ""Chris"", ""value"": 10000, @@ -36,35 +36,35 @@ Well, {{taxed_value}} dollars, after taxes. ""in_ca"": true } " - Public Const t2 As String = " + Public Const t2 As String = " * {{name}} * {{age}} * {{company}} * {{{company}}} " - Public Const h2 As String = " + Public Const h2 As String = " { ""name"": ""Chris"", ""company"": ""GitHub"" } " - Public Const t3 As String = " + Public Const t3 As String = " Shown {{#person}} Never shown! {{/person}} " - Public Const h3 As String = " + Public Const h3 As String = " { ""person"": false } " - Public Const t4 As String = " + Public Const t4 As String = " {{#repo}} {{name}} {{/repo}} " - Public Const h4 As String = " + Public Const h4 As String = " { ""repo"": [ { ""name"": ""resque"" }, @@ -73,7 +73,7 @@ Well, {{taxed_value}} dollars, after taxes. ] } " - Public Const t5 As String = " + Public Const t5 As String = " {{#repo}} {{name}} {{#nested}} @@ -81,7 +81,7 @@ Well, {{taxed_value}} dollars, after taxes. {{/nested}} {{/repo}} " - Public Const h5 As String = " + Public Const h5 As String = " { ""repo"": [ { ""name"": ""resque"", ""nested"":[{""name"":""nestedResque""}] }, @@ -91,4 +91,4 @@ Well, {{taxed_value}} dollars, after taxes. } " -End Class \ No newline at end of file +End Class diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseXmlSettingsGenerator.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseXmlSettingsGenerator.vb index 0ace59e747..eb9a8e730a 100644 --- a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseXmlSettingsGenerator.vb +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseXmlSettingsGenerator.vb @@ -2,24 +2,24 @@ Public Module UseXmlSettingsGenerator - Public Sub Run() + Public Sub Run() - ' This XmlSettings generator makes a static property in the XmlSettings class for each .xmlsettings file + ' This XmlSettings generator makes a static property in the XmlSettings class for each .xmlsettings file - ' here we have the 'Main' settings file from MainSettings.xmlsettings - ' the name is determined by the 'name' attribute of the root settings element - Dim main As XmlSettings.MainSettings = XmlSettings.Main - Console.WriteLine($"Reading settings from {main.GetLocation()}") + ' here we have the 'Main' settings file from MainSettings.xmlsettings + ' the name is determined by the 'name' attribute of the root settings element + Dim main As XmlSettings.MainSettings = XmlSettings.Main + Console.WriteLine($"Reading settings from {main.GetLocation()}") - ' settings are strongly typed and can be read directly from the static instance - Dim firstRun As Boolean = XmlSettings.Main.FirstRun - Console.WriteLine($"Setting firstRun = {firstRun}") + ' settings are strongly typed and can be read directly from the static instance + Dim firstRun As Boolean = XmlSettings.Main.FirstRun + Console.WriteLine($"Setting firstRun = {firstRun}") - Dim cacheSize As Integer = XmlSettings.Main.CacheSize - Console.WriteLine($"Setting cacheSize = {cacheSize}") + Dim cacheSize As Integer = XmlSettings.Main.CacheSize + Console.WriteLine($"Setting cacheSize = {cacheSize}") - ' Try adding some keys to the settings file and see the settings become available to read from + ' Try adding some keys to the settings file and see the settings become available to read from - End Sub + End Sub -End Module \ No newline at end of file +End Module diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb index a5441ec9c6..2a8768eba9 100644 --- a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb @@ -11,11 +11,11 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace SourceGeneratorSamples - - Public Class AutoNotifyGenerator - Implements ISourceGenerator + + Public Class AutoNotifyGenerator + Implements ISourceGenerator - Private Const ATTRIBUTE_TEXT As String = " + Private Const ATTRIBUTE_TEXT As String = " Imports System Namespace Global.AutoNotify @@ -31,68 +31,68 @@ Namespace Global.AutoNotify End Namespace " - Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize - ' Register a syntax receiver that will be created for each generation pass - context.RegisterForSyntaxNotifications(Function() As ISyntaxReceiver - Return New SyntaxReceiver - End Function) - End Sub - - Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute - - ' add the attribute text - context.AddSource("AutoNotifyAttribute", SourceText.From(ATTRIBUTE_TEXT, Encoding.UTF8)) - - ' retreive the populated receiver - Dim tempVar = TypeOf context.SyntaxReceiver Is SyntaxReceiver - Dim receiver = TryCast(context.SyntaxReceiver, SyntaxReceiver) - If Not tempVar Then - Return - End If - - ' we're going to create a new compilation that contains the attribute. - ' TODO: we should allow source generators to provide source during initialize, so that this step isn't required. - Dim options1 = context.Compilation.SyntaxTrees.First().Options - Dim compilation1 = context.Compilation.AddSyntaxTrees(VisualBasicSyntaxTree.ParseText(SourceText.From(ATTRIBUTE_TEXT, Encoding.UTF8), CType(options1, VisualBasicParseOptions))) - - ' get the newly bound attribute, and INotifyPropertyChanged - Dim attributeSymbol = compilation1.GetTypeByMetadataName("AutoNotify.AutoNotifyAttribute") - Dim notifySymbol = compilation1.GetTypeByMetadataName("System.ComponentModel.INotifyPropertyChanged") - - ' loop over the candidate fields, and keep the ones that are actually annotated - Dim fieldSymbols As New List(Of IFieldSymbol) - - For Each field In receiver.CandidateFields - Dim model = compilation1.GetSemanticModel(field.SyntaxTree) - For Each variable In field.Declarators - For Each name In variable.Names - ' Get the symbol being decleared by the field, and keep it if its annotated - Dim fieldSymbol = TryCast(model.GetDeclaredSymbol(name), IFieldSymbol) - If fieldSymbol.GetAttributes().Any(Function(ad) ad.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.[Default])) Then - fieldSymbols.Add(fieldSymbol) + Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize + ' Register a syntax receiver that will be created for each generation pass + context.RegisterForSyntaxNotifications(Function() As ISyntaxReceiver + Return New SyntaxReceiver + End Function) + End Sub + + Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute + + ' add the attribute text + context.AddSource("AutoNotifyAttribute", SourceText.From(ATTRIBUTE_TEXT, Encoding.UTF8)) + + ' retreive the populated receiver + Dim tempVar = TypeOf context.SyntaxReceiver Is SyntaxReceiver + Dim receiver = TryCast(context.SyntaxReceiver, SyntaxReceiver) + If Not tempVar Then + Return End If - Next - Next - Next - ' group the fields by class, and generate the source - For Each group In fieldSymbols.GroupBy(Function(f) f.ContainingType, SymbolEqualityComparer.Default) - Dim classSource = ProcessClass(group.Key, group.ToList(), attributeSymbol, notifySymbol) - context.AddSource($"{group.Key.Name}_AutoNotify.vb", SourceText.From(classSource, Encoding.UTF8)) - Next + ' we're going to create a new compilation that contains the attribute. + ' TODO: we should allow source generators to provide source during initialize, so that this step isn't required. + Dim options1 = context.Compilation.SyntaxTrees.First().Options + Dim compilation1 = context.Compilation.AddSyntaxTrees(VisualBasicSyntaxTree.ParseText(SourceText.From(ATTRIBUTE_TEXT, Encoding.UTF8), CType(options1, VisualBasicParseOptions))) + + ' get the newly bound attribute, and INotifyPropertyChanged + Dim attributeSymbol = compilation1.GetTypeByMetadataName("AutoNotify.AutoNotifyAttribute") + Dim notifySymbol = compilation1.GetTypeByMetadataName("System.ComponentModel.INotifyPropertyChanged") + + ' loop over the candidate fields, and keep the ones that are actually annotated + Dim fieldSymbols As New List(Of IFieldSymbol) + + For Each field In receiver.CandidateFields + Dim model = compilation1.GetSemanticModel(field.SyntaxTree) + For Each variable In field.Declarators + For Each name In variable.Names + ' Get the symbol being decleared by the field, and keep it if its annotated + Dim fieldSymbol = TryCast(model.GetDeclaredSymbol(name), IFieldSymbol) + If fieldSymbol.GetAttributes().Any(Function(ad) ad.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.[Default])) Then + fieldSymbols.Add(fieldSymbol) + End If + Next + Next + Next + + ' group the fields by class, and generate the source + For Each group In fieldSymbols.GroupBy(Function(f) f.ContainingType, SymbolEqualityComparer.Default) + Dim classSource = ProcessClass(group.Key, group.ToList(), attributeSymbol, notifySymbol) + context.AddSource($"{group.Key.Name}_AutoNotify.vb", SourceText.From(classSource, Encoding.UTF8)) + Next - End Sub + End Sub - Private Function ProcessClass(classSymbol As INamedTypeSymbol, fields As List(Of IFieldSymbol), attributeSymbol As ISymbol, notifySymbol As ISymbol) As String + Private Function ProcessClass(classSymbol As INamedTypeSymbol, fields As List(Of IFieldSymbol), attributeSymbol As ISymbol, notifySymbol As ISymbol) As String - If Not classSymbol.ContainingSymbol.Equals(classSymbol.ContainingNamespace, SymbolEqualityComparer.[Default]) Then - Return Nothing 'TODO: issue a diagnostic that it must be top level - End If + If Not classSymbol.ContainingSymbol.Equals(classSymbol.ContainingNamespace, SymbolEqualityComparer.[Default]) Then + Return Nothing 'TODO: issue a diagnostic that it must be top level + End If - Dim namespaceName = classSymbol.ContainingNamespace.ToDisplayString() + Dim namespaceName = classSymbol.ContainingNamespace.ToDisplayString() - ' begin building the generated source - Dim source = New StringBuilder($"Option Explicit On + ' begin building the generated source + Dim source = New StringBuilder($"Option Explicit On Option Strict On Option Infer On @@ -103,63 +103,63 @@ Namespace Global.{namespaceName} ") - ' if the class doesn't implement INotifyPropertyChanged already, add it - If Not classSymbol.Interfaces.Contains(CType(notifySymbol, INamedTypeSymbol)) Then - source.Append(" Public Event PropertyChanged As System.ComponentModel.PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged + ' if the class doesn't implement INotifyPropertyChanged already, add it + If Not classSymbol.Interfaces.Contains(CType(notifySymbol, INamedTypeSymbol)) Then + source.Append(" Public Event PropertyChanged As System.ComponentModel.PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged ") - End If + End If - ' create properties for each field - For Each fieldSymbol In fields - ProcessField(source, fieldSymbol, attributeSymbol) - Next + ' create properties for each field + For Each fieldSymbol In fields + ProcessField(source, fieldSymbol, attributeSymbol) + Next - source.Append(" + source.Append(" End Class End Namespace") - Return source.ToString() + Return source.ToString() - End Function + End Function - Private Sub ProcessField(source As StringBuilder, fieldSymbol As IFieldSymbol, attributeSymbol As ISymbol) + Private Sub ProcessField(source As StringBuilder, fieldSymbol As IFieldSymbol, attributeSymbol As ISymbol) - Dim chooseName As Func(Of String, TypedConstant, String) = + Dim chooseName As Func(Of String, TypedConstant, String) = Function(fieldName1 As String, overridenNameOpt1 As TypedConstant) As String - If Not overridenNameOpt1.IsNull Then - Return overridenNameOpt1.Value.ToString() - End If + If Not overridenNameOpt1.IsNull Then + Return overridenNameOpt1.Value.ToString() + End If - fieldName1 = fieldName1.TrimStart("_"c) - If fieldName1.Length = 0 Then - Return String.Empty - End If + fieldName1 = fieldName1.TrimStart("_"c) + If fieldName1.Length = 0 Then + Return String.Empty + End If - If fieldName1.Length = 1 Then - Return fieldName1.ToUpper() - End If + If fieldName1.Length = 1 Then + Return fieldName1.ToUpper() + End If - Return fieldName1.Substring(0, 1).ToUpper() & fieldName1.Substring(1) + Return fieldName1.Substring(0, 1).ToUpper() & fieldName1.Substring(1) End Function - ' get the name and type of the field - Dim fieldName = fieldSymbol.Name - Dim fieldType = fieldSymbol.Type + ' get the name and type of the field + Dim fieldName = fieldSymbol.Name + Dim fieldType = fieldSymbol.Type - ' get the AutoNotify attribute from the field, and any associated data - Dim attributeData = fieldSymbol.GetAttributes().[Single](Function(ad) ad.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.[Default])) - Dim overridenNameOpt = attributeData.NamedArguments.SingleOrDefault(Function(kvp) kvp.Key = "PropertyName").Value + ' get the AutoNotify attribute from the field, and any associated data + Dim attributeData = fieldSymbol.GetAttributes().[Single](Function(ad) ad.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.[Default])) + Dim overridenNameOpt = attributeData.NamedArguments.SingleOrDefault(Function(kvp) kvp.Key = "PropertyName").Value - Dim propertyName = chooseName(fieldName, overridenNameOpt) - If propertyName.Length = 0 OrElse propertyName = fieldName Then - 'TODO: issue a diagnostic that we can't process this field - Return - End If + Dim propertyName = chooseName(fieldName, overridenNameOpt) + If propertyName.Length = 0 OrElse propertyName = fieldName Then + 'TODO: issue a diagnostic that we can't process this field + Return + End If - source.Append($" + source.Append($" Public Property {propertyName} As {fieldType} Get Return Me.{fieldName} @@ -171,31 +171,31 @@ End Namespace") End Property ") - End Sub - - ''' - ''' Created on demand before each generation pass - ''' - Class SyntaxReceiver - Implements ISyntaxReceiver - - Public ReadOnly Property CandidateFields As List(Of FieldDeclarationSyntax) = New List(Of FieldDeclarationSyntax) - - ''' - ''' Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation - ''' - Public Sub OnVisitSyntaxNode(syntaxNode As SyntaxNode) Implements ISyntaxReceiver.OnVisitSyntaxNode - ' any field with at least one attribute is a candidate for property generation - If TypeOf syntaxNode Is FieldDeclarationSyntax Then - Dim fieldDeclarationSyntax = TryCast(syntaxNode, FieldDeclarationSyntax) - If fieldDeclarationSyntax.AttributeLists.Count > 0 Then - CandidateFields.Add(fieldDeclarationSyntax) - End If - End If - End Sub + End Sub - End Class + ''' + ''' Created on demand before each generation pass + ''' + Class SyntaxReceiver + Implements ISyntaxReceiver + + Public ReadOnly Property CandidateFields As List(Of FieldDeclarationSyntax) = New List(Of FieldDeclarationSyntax) + + ''' + ''' Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation + ''' + Public Sub OnVisitSyntaxNode(syntaxNode As SyntaxNode) Implements ISyntaxReceiver.OnVisitSyntaxNode + ' any field with at least one attribute is a candidate for property generation + If TypeOf syntaxNode Is FieldDeclarationSyntax Then + Dim fieldDeclarationSyntax = TryCast(syntaxNode, FieldDeclarationSyntax) + If fieldDeclarationSyntax.AttributeLists.Count > 0 Then + CandidateFields.Add(fieldDeclarationSyntax) + End If + End If + End Sub + + End Class - End Class + End Class End Namespace diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.vb index d474fdca29..fa7d13b907 100644 --- a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.vb +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.vb @@ -14,72 +14,72 @@ Imports NotVisualBasic.FileIO Namespace SourceGeneratorSamples - - Public Class CsvGenerator - Implements ISourceGenerator - - Public Enum CsvLoadType - Startup - OnDemand - End Enum - - Public Sub Initialize(context As GeneratorInitializationContext) Implements Microsoft.CodeAnalysis.ISourceGenerator.Initialize - - End Sub - - Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute - Dim options As IEnumerable(Of (CsvLoadType, Boolean, AdditionalText)) = GetLoadOptions(context) - Dim nameCodeSequence As IEnumerable(Of (Name As String, Code As String)) = SourceFilesFromAdditionalFiles(options) - For Each entry In nameCodeSequence - context.AddSource($"Csv_{entry.Name}", SourceText.From(entry.Code, Encoding.UTF8)) - Next - End Sub - - ' Guesses type of property for the object from the value of a csv field - Public Shared Function GetCsvFieldType(exemplar As String) As String - Dim garbageBoolean As Boolean - Dim garbageInteger As Integer - Dim garbageDouble As Double - Select Case True - Case Boolean.TryParse(exemplar, garbageBoolean) : Return "Boolean" - Case Integer.TryParse(exemplar, garbageInteger) : Return "Integer" - Case Double.TryParse(exemplar, garbageDouble) : Return "Double" - Case Else : Return "String" - End Select - End Function - - ' Examines the header row and the first row in the csv file to gather all header types and names - ' Also it returns the first row of data, because it must be read to figure out the types, - ' As the CsvTextFieldParser cannot 'Peek' ahead of one line. If there is no first line, - ' it consider all properties as strings. The generator returns an empty list of properly - ' typed objects in such case. If the file is completely empty, an error is generated. - Public Shared Function ExtractProperties(parser As CsvTextFieldParser) As (Types As String(), Names As String(), Fields As String()) - - Dim headerFields = parser.ReadFields() - If headerFields Is Nothing Then - Throw New Exception("Empty csv file!") - End If - - Dim firstLineFields = parser.ReadFields() - If firstLineFields Is Nothing Then - Return (Enumerable.Repeat("String", headerFields.Length).ToArray(), headerFields, firstLineFields) - Else - Return (firstLineFields.[Select](Function(field) GetCsvFieldType(field)).ToArray(), headerFields.[Select](New Func(Of String, String)(AddressOf StringToValidPropertyName)).ToArray(), firstLineFields) - End If - - End Function - - ' Adds a class to the `CSV` namespace for each `csv` file passed in. The class has a static property - ' named `All` that returns the list of strongly typed objects generated on demand at first access. - ' There is the slight chance of a race condition in a multi-thread program, but the result is relatively benign - ' , loading the collection multiple times instead of once. Measures could be taken to avoid that. - Public Shared Function GenerateClassFile(className As String, csvText As String, loadTime As CsvLoadType, cacheObjects As Boolean) As String - - Dim sb As New StringBuilder - Dim parser As New CsvTextFieldParser(New StringReader(csvText)) - - ''' Imports - sb.Append("Option Explicit On + + Public Class CsvGenerator + Implements ISourceGenerator + + Public Enum CsvLoadType + Startup + OnDemand + End Enum + + Public Sub Initialize(context As GeneratorInitializationContext) Implements Microsoft.CodeAnalysis.ISourceGenerator.Initialize + + End Sub + + Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute + Dim options As IEnumerable(Of (CsvLoadType, Boolean, AdditionalText)) = GetLoadOptions(context) + Dim nameCodeSequence As IEnumerable(Of (Name As String, Code As String)) = SourceFilesFromAdditionalFiles(options) + For Each entry In nameCodeSequence + context.AddSource($"Csv_{entry.Name}", SourceText.From(entry.Code, Encoding.UTF8)) + Next + End Sub + + ' Guesses type of property for the object from the value of a csv field + Public Shared Function GetCsvFieldType(exemplar As String) As String + Dim garbageBoolean As Boolean + Dim garbageInteger As Integer + Dim garbageDouble As Double + Select Case True + Case Boolean.TryParse(exemplar, garbageBoolean) : Return "Boolean" + Case Integer.TryParse(exemplar, garbageInteger) : Return "Integer" + Case Double.TryParse(exemplar, garbageDouble) : Return "Double" + Case Else : Return "String" + End Select + End Function + + ' Examines the header row and the first row in the csv file to gather all header types and names + ' Also it returns the first row of data, because it must be read to figure out the types, + ' As the CsvTextFieldParser cannot 'Peek' ahead of one line. If there is no first line, + ' it consider all properties as strings. The generator returns an empty list of properly + ' typed objects in such case. If the file is completely empty, an error is generated. + Public Shared Function ExtractProperties(parser As CsvTextFieldParser) As (Types As String(), Names As String(), Fields As String()) + + Dim headerFields = parser.ReadFields() + If headerFields Is Nothing Then + Throw New Exception("Empty csv file!") + End If + + Dim firstLineFields = parser.ReadFields() + If firstLineFields Is Nothing Then + Return (Enumerable.Repeat("String", headerFields.Length).ToArray(), headerFields, firstLineFields) + Else + Return (firstLineFields.[Select](Function(field) GetCsvFieldType(field)).ToArray(), headerFields.[Select](New Func(Of String, String)(AddressOf StringToValidPropertyName)).ToArray(), firstLineFields) + End If + + End Function + + ' Adds a class to the `CSV` namespace for each `csv` file passed in. The class has a static property + ' named `All` that returns the list of strongly typed objects generated on demand at first access. + ' There is the slight chance of a race condition in a multi-thread program, but the result is relatively benign + ' , loading the collection multiple times instead of once. Measures could be taken to avoid that. + Public Shared Function GenerateClassFile(className As String, csvText As String, loadTime As CsvLoadType, cacheObjects As Boolean) As String + + Dim sb As New StringBuilder + Dim parser As New CsvTextFieldParser(New StringReader(csvText)) + + ''' Imports + sb.Append("Option Explicit On Option Strict On Option Infer On @@ -88,121 +88,121 @@ Imports System.Collections.Generic Namespace Global.CSV ") - ''' Class Definition - sb.Append($" + ''' Class Definition + sb.Append($" Public Class {className} ") - If loadTime = CsvLoadType.Startup Then - sb.Append($" Shared Sub New() + If loadTime = CsvLoadType.Startup Then + sb.Append($" Shared Sub New() Dim x = All End Sub ") - End If + End If - Dim tupleTemp = ExtractProperties(parser) : Dim types = tupleTemp.Types, names = tupleTemp.Names, fields = tupleTemp.Fields - Dim minLen = Math.Min(types.Length, names.Length) + Dim tupleTemp = ExtractProperties(parser) : Dim types = tupleTemp.Types, names = tupleTemp.Names, fields = tupleTemp.Fields + Dim minLen = Math.Min(types.Length, names.Length) - For i = 0 To minLen - 1 - sb.AppendLine($" Public Property {StringToValidPropertyName(names(i))} As {types(i)}") - Next + For i = 0 To minLen - 1 + sb.AppendLine($" Public Property {StringToValidPropertyName(names(i))} As {types(i)}") + Next - ''' Loading data - sb.Append($" + ''' Loading data + sb.Append($" Private Shared m_all As IEnumerable(Of {className}) Public Shared ReadOnly Property All As IEnumerable(Of {className}) Get ") - If cacheObjects Then - sb.Append(" If m_all IsNot Nothing Then + If cacheObjects Then + sb.Append(" If m_all IsNot Nothing Then Return m_all End If ") - End If + End If - sb.Append($" Dim l As New List(Of {className})() + sb.Append($" Dim l As New List(Of {className})() Dim c As {className} ") - Do + Do - If fields Is Nothing Then - Continue Do - End If - If fields.Length < minLen Then - Throw New Exception("Not enough fields in CSV file.") - End If + If fields Is Nothing Then + Continue Do + End If + If fields.Length < minLen Then + Throw New Exception("Not enough fields in CSV file.") + End If - sb.AppendLine($" c = New {className}()") + sb.AppendLine($" c = New {className}()") - Dim value As String '= "" - For i As Integer = 0 To minLen - 1 - ' Wrap strings in quotes. - value = If(GetCsvFieldType(fields(i)) = "String", $"""{fields(i).Trim().Trim(New Char() {""""c})}""", fields(i)) - sb.AppendLine($" c.{names(i)} = {value}") - Next + Dim value As String '= "" + For i As Integer = 0 To minLen - 1 + ' Wrap strings in quotes. + value = If(GetCsvFieldType(fields(i)) = "String", $"""{fields(i).Trim().Trim(New Char() {""""c})}""", fields(i)) + sb.AppendLine($" c.{names(i)} = {value}") + Next - sb.AppendLine(" l.Add(c)") + sb.AppendLine(" l.Add(c)") - fields = parser.ReadFields() + fields = parser.ReadFields() - Loop While fields IsNot Nothing + Loop While fields IsNot Nothing - sb.Append($" m_all = l + sb.Append($" m_all = l Return l ") - ' Close things (property, class, namespace) - sb.Append(" End Get + ' Close things (property, class, namespace) + sb.Append(" End Get End Property End Class End Namespace") - Return sb.ToString() - - End Function - - Private Shared Function StringToValidPropertyName(s As String) As String - s = s.Trim() - s = If(Char.IsLetter(s(0)), Char.ToUpper(s(0)) & s.Substring(1), s) - s = If(Char.IsDigit(s.Trim()(0)), "_" & s, s) - s = New String(s.[Select](Function(ch) If(Char.IsDigit(ch) OrElse Char.IsLetter(ch), ch, "_"c)).ToArray()) - Return s - End Function - - Private Shared Function SourceFilesFromAdditionalFile(loadType As CsvLoadType, cacheObjects As Boolean, file As AdditionalText) As IEnumerable(Of (Name As String, Code As String)) - Dim className = Path.GetFileNameWithoutExtension(file.Path) - Dim csvText = file.GetText().ToString() - Return New(String, String)() {(className, GenerateClassFile(className, csvText, loadType, cacheObjects))} - End Function - - Private Shared Function SourceFilesFromAdditionalFiles(pathsData As IEnumerable(Of (LoadType As CsvLoadType, CacheObjects As Boolean, File As AdditionalText))) As IEnumerable(Of (Name As String, Code As String)) - Return pathsData.SelectMany(Function(d) SourceFilesFromAdditionalFile(d.LoadType, d.CacheObjects, d.File)) - End Function - - Private Shared Iterator Function GetLoadOptions(context As GeneratorExecutionContext) As IEnumerable(Of (LoadType As CsvLoadType, CacheObjects As Boolean, File As AdditionalText)) - For Each file In context.AdditionalFiles - If Path.GetExtension(file.Path).Equals(".csv", StringComparison.OrdinalIgnoreCase) Then - ' are there any options for it? - Dim loadTimeString As String = Nothing - context.AnalyzerConfigOptions.GetOptions(file).TryGetValue("build_metadata.additionalfiles.CsvLoadType", loadTimeString) - Dim loadType As CsvLoadType = Nothing - [Enum].TryParse(loadTimeString, ignoreCase:=True, loadType) - Dim cacheObjectsString As String = Nothing - context.AnalyzerConfigOptions.GetOptions(file).TryGetValue("build_metadata.additionalfiles.CacheObjects", cacheObjectsString) - Dim cacheObjects As Boolean = Nothing - Boolean.TryParse(cacheObjectsString, cacheObjects) - Yield (loadType, cacheObjects, file) - End If - Next - End Function - - End Class - -End Namespace \ No newline at end of file + Return sb.ToString() + + End Function + + Private Shared Function StringToValidPropertyName(s As String) As String + s = s.Trim() + s = If(Char.IsLetter(s(0)), Char.ToUpper(s(0)) & s.Substring(1), s) + s = If(Char.IsDigit(s.Trim()(0)), "_" & s, s) + s = New String(s.[Select](Function(ch) If(Char.IsDigit(ch) OrElse Char.IsLetter(ch), ch, "_"c)).ToArray()) + Return s + End Function + + Private Shared Function SourceFilesFromAdditionalFile(loadType As CsvLoadType, cacheObjects As Boolean, file As AdditionalText) As IEnumerable(Of (Name As String, Code As String)) + Dim className = Path.GetFileNameWithoutExtension(file.Path) + Dim csvText = file.GetText().ToString() + Return New(String, String)() {(className, GenerateClassFile(className, csvText, loadType, cacheObjects))} + End Function + + Private Shared Function SourceFilesFromAdditionalFiles(pathsData As IEnumerable(Of (LoadType As CsvLoadType, CacheObjects As Boolean, File As AdditionalText))) As IEnumerable(Of (Name As String, Code As String)) + Return pathsData.SelectMany(Function(d) SourceFilesFromAdditionalFile(d.LoadType, d.CacheObjects, d.File)) + End Function + + Private Shared Iterator Function GetLoadOptions(context As GeneratorExecutionContext) As IEnumerable(Of (LoadType As CsvLoadType, CacheObjects As Boolean, File As AdditionalText)) + For Each file In context.AdditionalFiles + If Path.GetExtension(file.Path).Equals(".csv", StringComparison.OrdinalIgnoreCase) Then + ' are there any options for it? + Dim loadTimeString As String = Nothing + context.AnalyzerConfigOptions.GetOptions(file).TryGetValue("build_metadata.additionalfiles.CsvLoadType", loadTimeString) + Dim loadType As CsvLoadType = Nothing + [Enum].TryParse(loadTimeString, ignoreCase:=True, loadType) + Dim cacheObjectsString As String = Nothing + context.AnalyzerConfigOptions.GetOptions(file).TryGetValue("build_metadata.additionalfiles.CacheObjects", cacheObjectsString) + Dim cacheObjects As Boolean = Nothing + Boolean.TryParse(cacheObjectsString, cacheObjects) + Yield (loadType, cacheObjects, file) + End If + Next + End Function + + End Class + +End Namespace diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/HelloWorldGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/HelloWorldGenerator.vb index 792c3b62ae..ff4c51ba22 100644 --- a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/HelloWorldGenerator.vb +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/HelloWorldGenerator.vb @@ -9,19 +9,19 @@ Imports Microsoft.CodeAnalysis.Text Namespace SourceGeneratorSamples - - Public Class HelloWorldGenerator - Implements ISourceGenerator + + Public Class HelloWorldGenerator + Implements ISourceGenerator - Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize - ' No initialization required - End Sub + Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize + ' No initialization required + End Sub - Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute + Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute - ' begin creating the source we'll inject into the users compilation + ' begin creating the source we'll inject into the users compilation - Dim sourceBuilder = New StringBuilder("Option Explicit On + Dim sourceBuilder = New StringBuilder("Option Explicit On Option Strict On Option Infer On @@ -35,19 +35,19 @@ Namespace Global.HelloWorldGenerated Console.WriteLine(""The following syntax trees existed in the compilation that created this program:"") ") - ' for testing... let's include a comment with the current date/time. - sourceBuilder.AppendLine($" ' Generated at {DateTime.Now}") + ' for testing... let's include a comment with the current date/time. + sourceBuilder.AppendLine($" ' Generated at {DateTime.Now}") - ' using the context, get a list of syntax trees in the users compilation - ' add the filepath of each tree to the class we're building + ' using the context, get a list of syntax trees in the users compilation + ' add the filepath of each tree to the class we're building - For Each tree In context.Compilation.SyntaxTrees - sourceBuilder.AppendLine($" Console.WriteLine("" - {tree.FilePath}"")") - Next + For Each tree In context.Compilation.SyntaxTrees + sourceBuilder.AppendLine($" Console.WriteLine("" - {tree.FilePath}"")") + Next - ' finish creating the source to inject + ' finish creating the source to inject - sourceBuilder.Append(" + sourceBuilder.Append(" End Sub @@ -55,12 +55,12 @@ Namespace Global.HelloWorldGenerated End Namespace") - ' inject the created source into the users compilation + ' inject the created source into the users compilation - context.AddSource("HelloWorldGenerated", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8)) + context.AddSource("HelloWorldGenerated", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8)) - End Sub + End Sub - End Class + End Class -End Namespace \ No newline at end of file +End Namespace diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb index 38004dbe7a..e8a9074943 100644 --- a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb @@ -13,17 +13,17 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace SourceGeneratorSamples - - Public Class MustacheGenerator - Implements ISourceGenerator + + Public Class MustacheGenerator + Implements ISourceGenerator - Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize - ' No initialization required - End Sub + Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize + ' No initialization required + End Sub - Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute + Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute - Dim attributeSource = "Option Explicit On + Dim attributeSource = "Option Explicit On Option Strict On Option Infer On @@ -48,87 +48,87 @@ Namespace Global End Namespace " - context.AddSource("Mustache_MainAttributes__", SourceText.From(attributeSource, Encoding.UTF8)) + context.AddSource("Mustache_MainAttributes__", SourceText.From(attributeSource, Encoding.UTF8)) - Dim compilation = context.Compilation + Dim compilation = context.Compilation - Dim options = GetMustacheOptions(compilation) - Dim namesSources = SourceFilesFromMustachePaths(options) + Dim options = GetMustacheOptions(compilation) + Dim namesSources = SourceFilesFromMustachePaths(options) - For Each entry In namesSources - context.AddSource($"Mustache{entry.Item1}", SourceText.From(entry.Item2, Encoding.UTF8)) - Next + For Each entry In namesSources + context.AddSource($"Mustache{entry.Item1}", SourceText.From(entry.Item2, Encoding.UTF8)) + Next - End Sub + End Sub - Private Shared Iterator Function GetMustacheOptions(compilation As Compilation) As IEnumerable(Of (String, String, String)) + Private Shared Iterator Function GetMustacheOptions(compilation As Compilation) As IEnumerable(Of (String, String, String)) - ' Get all Mustache attributes + ' Get all Mustache attributes - Dim allNodes = compilation.SyntaxTrees.SelectMany(Function(s) s.GetRoot().DescendantNodes()) + Dim allNodes = compilation.SyntaxTrees.SelectMany(Function(s) s.GetRoot().DescendantNodes()) - Dim allAttributes = allNodes.Where(Function(d) d.IsKind(SyntaxKind.Attribute)).OfType(Of AttributeSyntax)() - Dim attributes = allAttributes.Where(Function(d) d.Name.ToString() = "Mustache").ToImmutableArray() + Dim allAttributes = allNodes.Where(Function(d) d.IsKind(SyntaxKind.Attribute)).OfType(Of AttributeSyntax)() + Dim attributes = allAttributes.Where(Function(d) d.Name.ToString() = "Mustache").ToImmutableArray() - Dim models = compilation.SyntaxTrees.[Select](Function(st) compilation.GetSemanticModel(st)) - For Each att In attributes + Dim models = compilation.SyntaxTrees.[Select](Function(st) compilation.GetSemanticModel(st)) + For Each att In attributes - Dim mustacheName = "" - Dim template = "" - Dim hash = "" - Dim index = 0 + Dim mustacheName = "" + Dim template = "" + Dim hash = "" + Dim index = 0 - If att.ArgumentList Is Nothing Then - Throw New Exception("Can't be null here") - End If + If att.ArgumentList Is Nothing Then + Throw New Exception("Can't be null here") + End If - Dim m = compilation.GetSemanticModel(att.SyntaxTree) + Dim m = compilation.GetSemanticModel(att.SyntaxTree) - For Each arg In att.ArgumentList.Arguments + For Each arg In att.ArgumentList.Arguments - Dim expr As ExpressionSyntax = Nothing - If TypeOf arg Is SimpleArgumentSyntax Then - expr = TryCast(arg, SimpleArgumentSyntax).Expression - End If - If expr Is Nothing Then - Continue For - End If + Dim expr As ExpressionSyntax = Nothing + If TypeOf arg Is SimpleArgumentSyntax Then + expr = TryCast(arg, SimpleArgumentSyntax).Expression + End If + If expr Is Nothing Then + Continue For + End If - Dim t = m.GetTypeInfo(expr) - Dim v = m.GetConstantValue(expr) - If index = 0 Then - mustacheName = v.ToString() - ElseIf index = 1 Then - template = v.ToString() - Else - hash = v.ToString() - End If - index += 1 + Dim t = m.GetTypeInfo(expr) + Dim v = m.GetConstantValue(expr) + If index = 0 Then + mustacheName = v.ToString() + ElseIf index = 1 Then + template = v.ToString() + Else + hash = v.ToString() + End If + index += 1 - Next + Next - Yield (mustacheName, template, hash) + Yield (mustacheName, template, hash) - Next + Next - End Function + End Function - Private Shared Function SourceFileFromMustachePath(name As String, template As String, hash As String) As String - Dim tree = HandlebarsDotNet.Handlebars.Compile(template) - Dim o = Newtonsoft.Json.JsonConvert.DeserializeObject(hash) - Dim mustacheText = tree(o) - Return GenerateMustacheClass(name, mustacheText) - End Function + Private Shared Function SourceFileFromMustachePath(name As String, template As String, hash As String) As String + Dim tree = HandlebarsDotNet.Handlebars.Compile(template) + Dim o = Newtonsoft.Json.JsonConvert.DeserializeObject(hash) + Dim mustacheText = tree(o) + Return GenerateMustacheClass(name, mustacheText) + End Function - Private Shared Iterator Function SourceFilesFromMustachePaths(pathsData As IEnumerable(Of (Name As String, Template As String, Hash As String))) As IEnumerable(Of (Name As String, Code As String)) - For Each entry In pathsData - Yield (entry.Name, SourceFileFromMustachePath(entry.Name, entry.Template, entry.Hash)) - Next - End Function + Private Shared Iterator Function SourceFilesFromMustachePaths(pathsData As IEnumerable(Of (Name As String, Template As String, Hash As String))) As IEnumerable(Of (Name As String, Code As String)) + For Each entry In pathsData + Yield (entry.Name, SourceFileFromMustachePath(entry.Name, entry.Template, entry.Hash)) + Next + End Function - Private Shared Function GenerateMustacheClass(className As String, mustacheText As String) As String - Return $" + Private Shared Function GenerateMustacheClass(className As String, mustacheText As String) As String + Return $" Namespace Global.Mustache @@ -139,8 +139,8 @@ Namespace Global.Mustache End Module End Namespace" - End Function + End Function - End Class + End Class -End Namespace \ No newline at end of file +End Namespace diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SettingsXmlGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SettingsXmlGenerator.vb index 1754315d85..d1ecd628fa 100644 --- a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SettingsXmlGenerator.vb +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SettingsXmlGenerator.vb @@ -11,38 +11,38 @@ Imports Microsoft.CodeAnalysis.Text Namespace SourceGeneratorSamples - - Public Class SettingsXmlGenerator - Implements ISourceGenerator - - Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize - - End Sub - - Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute - ' Using the context, get any additional files that end in .xmlsettings - For Each settingsFile In context.AdditionalFiles.Where(Function(at) at.Path.EndsWith(".xmlsettings")) - ProcessSettingsFile(settingsFile, context) - Next - End Sub - - Private Sub ProcessSettingsFile(xmlFile As AdditionalText, context As GeneratorExecutionContext) - - ' try and load the settings file - Dim xmlDoc As New XmlDocument - Dim text = xmlFile.GetText(context.CancellationToken).ToString() - Try - xmlDoc.LoadXml(text) - Catch - 'TODO: issue a diagnostic that says we couldn't parse it - Return - End Try - - ' create a class in the XmlSetting class that represnts this entry, and a static field that contains a singleton instance. - Dim fileName = Path.GetFileName(xmlFile.Path) - Dim name = xmlDoc.DocumentElement.GetAttribute("name") - - Dim sb = New StringBuilder($"Option Explicit On + + Public Class SettingsXmlGenerator + Implements ISourceGenerator + + Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize + + End Sub + + Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute + ' Using the context, get any additional files that end in .xmlsettings + For Each settingsFile In context.AdditionalFiles.Where(Function(at) at.Path.EndsWith(".xmlsettings")) + ProcessSettingsFile(settingsFile, context) + Next + End Sub + + Private Sub ProcessSettingsFile(xmlFile As AdditionalText, context As GeneratorExecutionContext) + + ' try and load the settings file + Dim xmlDoc As New XmlDocument + Dim text = xmlFile.GetText(context.CancellationToken).ToString() + Try + xmlDoc.LoadXml(text) + Catch + 'TODO: issue a diagnostic that says we couldn't parse it + Return + End Try + + ' create a class in the XmlSetting class that represnts this entry, and a static field that contains a singleton instance. + Dim fileName = Path.GetFileName(xmlFile.Path) + Dim name = xmlDoc.DocumentElement.GetAttribute("name") + + Dim sb = New StringBuilder($"Option Explicit On Option Strict On Option Infer On @@ -69,13 +69,13 @@ Namespace Global.AutoSettings Return m_fileName End Function") - For i = 0 To xmlDoc.DocumentElement.ChildNodes.Count - 1 + For i = 0 To xmlDoc.DocumentElement.ChildNodes.Count - 1 - Dim setting = CType(xmlDoc.DocumentElement.ChildNodes(i), XmlElement) - Dim settingName = setting.GetAttribute("name") - Dim settingType = setting.GetAttribute("type") + Dim setting = CType(xmlDoc.DocumentElement.ChildNodes(i), XmlElement) + Dim settingName = setting.GetAttribute("name") + Dim settingType = setting.GetAttribute("type") - sb.Append($" + sb.Append($" Public ReadOnly Property {settingName} As {settingType} Get @@ -83,9 +83,9 @@ Namespace Global.AutoSettings End Get End Property") - Next + Next - sb.Append(" + sb.Append(" End Class @@ -93,10 +93,10 @@ Namespace Global.AutoSettings End Namespace") - context.AddSource($"Settings_{name}", SourceText.From(sb.ToString(), Encoding.UTF8)) + context.AddSource($"Settings_{name}", SourceText.From(sb.ToString(), Encoding.UTF8)) - End Sub + End Sub - End Class + End Class -End Namespace \ No newline at end of file +End Namespace From 54991d540ea347bffe9e034185df66a3c81c0cd6 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Mon, 24 May 2021 11:16:27 -0700 Subject: [PATCH 32/65] explicitly cast --- .../SourceGeneratorSamples/AutoNotifyGenerator.vb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb index 2a8768eba9..4c1ca4af8d 100644 --- a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb @@ -77,7 +77,7 @@ End Namespace ' group the fields by class, and generate the source For Each group In fieldSymbols.GroupBy(Function(f) f.ContainingType, SymbolEqualityComparer.Default) - Dim classSource = ProcessClass(group.Key, group.ToList(), attributeSymbol, notifySymbol) + Dim classSource = ProcessClass(CType(group.Key, INamedTypeSymbol), group.ToList(), attributeSymbol, notifySymbol) context.AddSource($"{group.Key.Name}_AutoNotify.vb", SourceText.From(classSource, Encoding.UTF8)) Next From fc346e8db208050fd7447564d7b7212998c4c3ff Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Mon, 24 May 2021 11:32:05 -0700 Subject: [PATCH 33/65] rename projects to distinguish language --- Samples.sln | 12 ++++++------ ...neratedDemo.csproj => CSharpGeneratedDemo.csproj} | 2 +- ...es.csproj => CSharpSourceGeneratorSamples.csproj} | 0 ...edDemo.vbproj => VisualBasicGeneratedDemo.vbproj} | 2 +- ...proj => VisualBasicSourceGeneratorSamples.vbproj} | 0 5 files changed, 8 insertions(+), 8 deletions(-) rename samples/CSharp/SourceGenerators/GeneratedDemo/{GeneratedDemo.csproj => CSharpGeneratedDemo.csproj} (82%) rename samples/CSharp/SourceGenerators/SourceGeneratorSamples/{SourceGeneratorSamples.csproj => CSharpSourceGeneratorSamples.csproj} (100%) rename samples/VisualBasic/SourceGenerators/GeneratedDemo/{GeneratedDemo.vbproj => VisualBasicGeneratedDemo.vbproj} (84%) rename samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/{SourceGeneratorSamples.vbproj => VisualBasicSourceGeneratorSamples.vbproj} (100%) diff --git a/Samples.sln b/Samples.sln index a69935724f..f74896c907 100644 --- a/Samples.sln +++ b/Samples.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28606.18 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31321.66 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CSharp", "CSharp", "{C3FB27E9-C8EE-4F76-B0AA-7CD67A7E652B}" EndProject @@ -113,13 +113,13 @@ Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "VisualBasicToCSharpConverte EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SourceGenerators", "SourceGenerators", "{14D18F51-6B59-49D5-9AB7-08B38417A459}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SourceGeneratorSamples", "samples\CSharp\SourceGenerators\SourceGeneratorSamples\SourceGeneratorSamples.csproj", "{2ADE5CFA-5DF4-44A9-BD67-E884BCFBA045}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSharpSourceGeneratorSamples", "samples\CSharp\SourceGenerators\SourceGeneratorSamples\CSharpSourceGeneratorSamples.csproj", "{2ADE5CFA-5DF4-44A9-BD67-E884BCFBA045}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeneratedDemo", "samples\CSharp\SourceGenerators\GeneratedDemo\GeneratedDemo.csproj", "{EC4DB63B-C2B4-4D06-AF98-15253035C6D5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSharpGeneratedDemo", "samples\CSharp\SourceGenerators\GeneratedDemo\CSharpGeneratedDemo.csproj", "{EC4DB63B-C2B4-4D06-AF98-15253035C6D5}" EndProject -Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "GeneratedDemo", "samples\VisualBasic\SourceGenerators\GeneratedDemo\GeneratedDemo.vbproj", "{DA924876-9CF5-47E0-AA01-ADAF47653D39}" +Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "VisualBasicGeneratedDemo", "samples\VisualBasic\SourceGenerators\GeneratedDemo\VisualBasicGeneratedDemo.vbproj", "{DA924876-9CF5-47E0-AA01-ADAF47653D39}" EndProject -Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "SourceGeneratorSamples", "samples\VisualBasic\SourceGenerators\SourceGeneratorSamples\SourceGeneratorSamples.vbproj", "{8322B6E4-0CB1-4EC1-A2CC-2E4DB02C834A}" +Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "VisualBasicSourceGeneratorSamples", "samples\VisualBasic\SourceGenerators\SourceGeneratorSamples\VisualBasicSourceGeneratorSamples.vbproj", "{8322B6E4-0CB1-4EC1-A2CC-2E4DB02C834A}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SourceGenerators", "SourceGenerators", "{E79B07C8-0859-4B5C-9650-68D855833C6E}" EndProject diff --git a/samples/CSharp/SourceGenerators/GeneratedDemo/GeneratedDemo.csproj b/samples/CSharp/SourceGenerators/GeneratedDemo/CSharpGeneratedDemo.csproj similarity index 82% rename from samples/CSharp/SourceGenerators/GeneratedDemo/GeneratedDemo.csproj rename to samples/CSharp/SourceGenerators/GeneratedDemo/CSharpGeneratedDemo.csproj index b95bde39c0..4b3054e9fc 100644 --- a/samples/CSharp/SourceGenerators/GeneratedDemo/GeneratedDemo.csproj +++ b/samples/CSharp/SourceGenerators/GeneratedDemo/CSharpGeneratedDemo.csproj @@ -13,7 +13,7 @@ - + diff --git a/samples/CSharp/SourceGenerators/SourceGeneratorSamples/SourceGeneratorSamples.csproj b/samples/CSharp/SourceGenerators/SourceGeneratorSamples/CSharpSourceGeneratorSamples.csproj similarity index 100% rename from samples/CSharp/SourceGenerators/SourceGeneratorSamples/SourceGeneratorSamples.csproj rename to samples/CSharp/SourceGenerators/SourceGeneratorSamples/CSharpSourceGeneratorSamples.csproj diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/GeneratedDemo.vbproj b/samples/VisualBasic/SourceGenerators/GeneratedDemo/VisualBasicGeneratedDemo.vbproj similarity index 84% rename from samples/VisualBasic/SourceGenerators/GeneratedDemo/GeneratedDemo.vbproj rename to samples/VisualBasic/SourceGenerators/GeneratedDemo/VisualBasicGeneratedDemo.vbproj index 08120ed6f7..6df6a390cc 100644 --- a/samples/VisualBasic/SourceGenerators/GeneratedDemo/GeneratedDemo.vbproj +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/VisualBasicGeneratedDemo.vbproj @@ -14,7 +14,7 @@ - + diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SourceGeneratorSamples.vbproj b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj similarity index 100% rename from samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SourceGeneratorSamples.vbproj rename to samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj From 2136e57818a1e52e2989ddd0e60fdb8aee819ce5 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Mon, 24 May 2021 13:00:42 -0700 Subject: [PATCH 34/65] use correct dependencies --- .../VisualBasicSourceGeneratorSamples.vbproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj index f719a9496d..4132a0c22c 100644 --- a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj @@ -12,8 +12,8 @@ - - + + From 852a7382436a893088571457b195e21ad9413f43 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Mon, 24 May 2021 15:53:35 -0700 Subject: [PATCH 35/65] Always publish build logs. --- .vsts-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vsts-ci.yml b/.vsts-ci.yml index cecb65b095..c8caabee37 100644 --- a/.vsts-ci.yml +++ b/.vsts-ci.yml @@ -77,7 +77,7 @@ stages: PathtoPublish: '$(Build.SourcesDirectory)\artifacts\log\$(BuildConfiguration)' ArtifactName: 'Logs' continueOnError: true - condition: not(succeeded()) + condition: always() # Publish an artifact that the RoslynInsertionTool is able to find by its name. - task: PublishBuildArtifacts@1 From 9cf8ddd2e79f5cfa516f2f5777ef2efffe6a6689 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Mon, 24 May 2021 18:18:16 -0700 Subject: [PATCH 36/65] use latest apis --- .../MustacheGenerator.vb | 120 +++++------------- .../VisualBasicSourceGeneratorSamples.vbproj | 2 +- 2 files changed, 34 insertions(+), 88 deletions(-) diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb index e8a9074943..532c91bad7 100644 --- a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb @@ -2,11 +2,7 @@ Option Infer On Option Strict On -Imports System.Collections.Immutable -Imports System.Text - Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -17,13 +13,7 @@ Namespace SourceGeneratorSamples Public Class MustacheGenerator Implements ISourceGenerator - Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize - ' No initialization required - End Sub - - Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute - - Dim attributeSource = "Option Explicit On + Const attributeSource = "Option Explicit On Option Strict On Option Infer On @@ -48,99 +38,55 @@ Namespace Global End Namespace " - context.AddSource("Mustache_MainAttributes__", SourceText.From(attributeSource, Encoding.UTF8)) - - Dim compilation = context.Compilation - - Dim options = GetMustacheOptions(compilation) - Dim namesSources = SourceFilesFromMustachePaths(options) - - For Each entry In namesSources - context.AddSource($"Mustache{entry.Item1}", SourceText.From(entry.Item2, Encoding.UTF8)) + Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute + Dim rx = CType(context.SyntaxContextReceiver, SyntaxReceiver) + For Each element In rx.TemplateInfo + Dim source = SourceFileFromMustachePath(element.name, element.template, element.hash) + context.AddSource($"Mustache{element.name}", source) Next - End Sub - Private Shared Iterator Function GetMustacheOptions(compilation As Compilation) As IEnumerable(Of (String, String, String)) - - ' Get all Mustache attributes - - Dim allNodes = compilation.SyntaxTrees.SelectMany(Function(s) s.GetRoot().DescendantNodes()) - - - Dim allAttributes = allNodes.Where(Function(d) d.IsKind(SyntaxKind.Attribute)).OfType(Of AttributeSyntax)() - Dim attributes = allAttributes.Where(Function(d) d.Name.ToString() = "Mustache").ToImmutableArray() - - Dim models = compilation.SyntaxTrees.[Select](Function(st) compilation.GetSemanticModel(st)) - For Each att In attributes - - Dim mustacheName = "" - Dim template = "" - Dim hash = "" - Dim index = 0 - - If att.ArgumentList Is Nothing Then - Throw New Exception("Can't be null here") - End If - - Dim m = compilation.GetSemanticModel(att.SyntaxTree) - - For Each arg In att.ArgumentList.Arguments - - Dim expr As ExpressionSyntax = Nothing - If TypeOf arg Is SimpleArgumentSyntax Then - expr = TryCast(arg, SimpleArgumentSyntax).Expression - End If - If expr Is Nothing Then - Continue For - End If - - Dim t = m.GetTypeInfo(expr) - Dim v = m.GetConstantValue(expr) - If index = 0 Then - mustacheName = v.ToString() - ElseIf index = 1 Then - template = v.ToString() - Else - hash = v.ToString() - End If - index += 1 - - Next - - Yield (mustacheName, template, hash) - - Next - - End Function - Private Shared Function SourceFileFromMustachePath(name As String, template As String, hash As String) As String Dim tree = HandlebarsDotNet.Handlebars.Compile(template) - Dim o = Newtonsoft.Json.JsonConvert.DeserializeObject(hash) - Dim mustacheText = tree(o) - Return GenerateMustacheClass(name, mustacheText) - End Function + Dim [object] = Newtonsoft.Json.JsonConvert.DeserializeObject(hash) + Dim mustacheText = tree([object]) - Private Shared Iterator Function SourceFilesFromMustachePaths(pathsData As IEnumerable(Of (Name As String, Template As String, Hash As String))) As IEnumerable(Of (Name As String, Code As String)) - For Each entry In pathsData - Yield (entry.Name, SourceFileFromMustachePath(entry.Name, entry.Template, entry.Hash)) - Next - End Function - - Private Shared Function GenerateMustacheClass(className As String, mustacheText As String) As String Return $" - Namespace Global.Mustache Partial Public Module Constants - Public Const {className} As String = ""{mustacheText.Replace("""", """""")}"" + Public Const {name} As String = ""{mustacheText.Replace("""", """""")}"" End Module End Namespace" End Function + Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize + context.RegisterForPostInitialization(Sub(pi) pi.AddSource("Mustache_MainAttributes__", attributeSource)) + context.RegisterForSyntaxNotifications(Function() New SyntaxReceiver()) + End Sub + + Private Class SyntaxReceiver + Implements ISyntaxContextReceiver + + Public TemplateInfo As New List(Of (name As String, template As String, hash As String)) + + Public Sub OnVisitSyntaxNode(context As GeneratorSyntaxContext) Implements ISyntaxContextReceiver.OnVisitSyntaxNode + If context.Node.Kind() = SyntaxKind.Attribute Then + Dim attrib = CType(context.Node, AttributeSyntax) + If attrib.ArgumentList?.Arguments.Count = 3 AndAlso + context.SemanticModel.GetTypeInfo(attrib).Type?.ToDisplayString() = "MustacheAttribute" Then + Dim name = context.SemanticModel.GetConstantValue(attrib.ArgumentList.Arguments(0).GetExpression).ToString() + Dim template = context.SemanticModel.GetConstantValue(attrib.ArgumentList.Arguments(1).GetExpression).ToString() + Dim hash = context.SemanticModel.GetConstantValue(attrib.ArgumentList.Arguments(2).GetExpression).ToString() + TemplateInfo.Add((name, template, hash)) + End If + End If + End Sub + End Class + End Class End Namespace diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj index 4132a0c22c..845eb4fd1b 100644 --- a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj @@ -5,7 +5,7 @@ - + From 3fb02cc52ed244befe4489c566f313f360f846d3 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Mon, 24 May 2021 18:19:04 -0700 Subject: [PATCH 37/65] do not increment solution version number --- Samples.sln | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Samples.sln b/Samples.sln index f74896c907..71d51bee65 100644 --- a/Samples.sln +++ b/Samples.sln @@ -1,7 +1,7 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31321.66 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28606.18 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CSharp", "CSharp", "{C3FB27E9-C8EE-4F76-B0AA-7CD67A7E652B}" EndProject From a60d313f9818a11b65d78b48a2b010f92f4fb25d Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Mon, 24 May 2021 19:19:21 -0700 Subject: [PATCH 38/65] remove vb mustache generator --- .../GeneratedDemo/UseMustacheGenerator.vb | 94 ------------------- .../MustacheGenerator.vb | 92 ------------------ .../VisualBasicSourceGeneratorSamples.vbproj | 4 - 3 files changed, 190 deletions(-) delete mode 100644 samples/VisualBasic/SourceGenerators/GeneratedDemo/UseMustacheGenerator.vb delete mode 100644 samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseMustacheGenerator.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseMustacheGenerator.vb deleted file mode 100644 index 2717aab0e3..0000000000 --- a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseMustacheGenerator.vb +++ /dev/null @@ -1,94 +0,0 @@ -Option Explicit On -Option Strict On -Option Infer On - -Imports GeneratedDemo.UseMustacheGenerator - - - - - - - -Friend Class UseMustacheGenerator - - Public Shared Sub Run() - Console.WriteLine(Mustache.Constants.Lottery) - Console.WriteLine(Mustache.Constants.HR) - Console.WriteLine(Mustache.Constants.HTML) - Console.WriteLine(Mustache.Constants.Section) - Console.WriteLine(Mustache.Constants.NestedSection) - End Sub - - ' Mustache templates and hashes from the manual at https://mustache.github.io/mustache.1.html... - Public Const t1 As String = " -Hello {{name}} -You have just won {{value}} dollars! -{{#in_ca}} -Well, {{taxed_value}} dollars, after taxes. -{{/in_ca}} -" - Public Const h1 As String = " -{ - ""name"": ""Chris"", - ""value"": 10000, - ""taxed_value"": 5000, - ""in_ca"": true -} -" - Public Const t2 As String = " -* {{name}} -* {{age}} -* {{company}} -* {{{company}}} -" - Public Const h2 As String = " -{ - ""name"": ""Chris"", - ""company"": ""GitHub"" -} -" - Public Const t3 As String = " - Shown - {{#person}} - Never shown! - {{/person}} - " - Public Const h3 As String = " -{ - ""person"": false -} -" - Public Const t4 As String = " -{{#repo}} - {{name}} -{{/repo}} -" - Public Const h4 As String = " -{ - ""repo"": [ - { ""name"": ""resque"" }, - { ""name"": ""hub"" }, - { ""name"": ""rip"" } - ] -} -" - Public Const t5 As String = " -{{#repo}} - {{name}} - {{#nested}} - NestedName: {{name}} - {{/nested}} -{{/repo}} -" - Public Const h5 As String = " -{ - ""repo"": [ - { ""name"": ""resque"", ""nested"":[{""name"":""nestedResque""}] }, - { ""name"": ""hub"" }, - { ""name"": ""rip"" } - ] -} -" - -End Class diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb deleted file mode 100644 index 532c91bad7..0000000000 --- a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/MustacheGenerator.vb +++ /dev/null @@ -1,92 +0,0 @@ -Option Explicit On -Option Infer On -Option Strict On - -Imports Microsoft.CodeAnalysis - -Imports Microsoft.CodeAnalysis.VisualBasic -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - -Namespace SourceGeneratorSamples - - - Public Class MustacheGenerator - Implements ISourceGenerator - - Const attributeSource = "Option Explicit On -Option Strict On -Option Infer On - -Namespace Global - - - Friend NotInheritable Class MustacheAttribute - Inherits System.Attribute - - Public ReadOnly Property Name As String - Public ReadOnly Property Template As String - Public ReadOnly Property Hash As String - - Public Sub New(name As String, template As String, hash As String) - Me.Name = name - Me.Template = template - Me.Hash = hash - End Sub - - End Class - -End Namespace -" - - Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute - Dim rx = CType(context.SyntaxContextReceiver, SyntaxReceiver) - For Each element In rx.TemplateInfo - Dim source = SourceFileFromMustachePath(element.name, element.template, element.hash) - context.AddSource($"Mustache{element.name}", source) - Next - End Sub - - Private Shared Function SourceFileFromMustachePath(name As String, template As String, hash As String) As String - Dim tree = HandlebarsDotNet.Handlebars.Compile(template) - Dim [object] = Newtonsoft.Json.JsonConvert.DeserializeObject(hash) - Dim mustacheText = tree([object]) - - Return $" -Namespace Global.Mustache - - Partial Public Module Constants - - Public Const {name} As String = ""{mustacheText.Replace("""", """""")}"" - - End Module - -End Namespace" - End Function - - Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize - context.RegisterForPostInitialization(Sub(pi) pi.AddSource("Mustache_MainAttributes__", attributeSource)) - context.RegisterForSyntaxNotifications(Function() New SyntaxReceiver()) - End Sub - - Private Class SyntaxReceiver - Implements ISyntaxContextReceiver - - Public TemplateInfo As New List(Of (name As String, template As String, hash As String)) - - Public Sub OnVisitSyntaxNode(context As GeneratorSyntaxContext) Implements ISyntaxContextReceiver.OnVisitSyntaxNode - If context.Node.Kind() = SyntaxKind.Attribute Then - Dim attrib = CType(context.Node, AttributeSyntax) - If attrib.ArgumentList?.Arguments.Count = 3 AndAlso - context.SemanticModel.GetTypeInfo(attrib).Type?.ToDisplayString() = "MustacheAttribute" Then - Dim name = context.SemanticModel.GetConstantValue(attrib.ArgumentList.Arguments(0).GetExpression).ToString() - Dim template = context.SemanticModel.GetConstantValue(attrib.ArgumentList.Arguments(1).GetExpression).ToString() - Dim hash = context.SemanticModel.GetConstantValue(attrib.ArgumentList.Arguments(2).GetExpression).ToString() - TemplateInfo.Add((name, template, hash)) - End If - End If - End Sub - End Class - - End Class - -End Namespace diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj index 845eb4fd1b..9e9f125655 100644 --- a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj +++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj @@ -12,8 +12,6 @@ - - @@ -23,8 +21,6 @@ - - From 074c879bb530f32a26ce35f3bdd9a9ffd6d98dc2 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Tue, 25 May 2021 14:14:43 -0700 Subject: [PATCH 39/65] repack nuget packages for shipping --- eng/Versions.props | 1 + 1 file changed, 1 insertion(+) diff --git a/eng/Versions.props b/eng/Versions.props index 89105515f4..9f7c163167 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -10,6 +10,7 @@ true true true + true 3.9.0 16.1.1 From 02a5cc4fd0de7b2d1d3e2b71c671358af1e6c726 Mon Sep 17 00:00:00 2001 From: Chris Sienkiewicz Date: Tue, 25 May 2021 14:56:58 -0700 Subject: [PATCH 40/65] Use verion.props for component debugger project --- eng/Versions.props | 5 +++++ .../Roslyn.ComponentDebugger.csproj | 14 +++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index 89105515f4..e23f8edf5c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -28,12 +28,15 @@ 8.0.1 2.7.100 16.8.239 + 16.9.6-alpha 16.8.239 16.8.239 16.7.30328.74 16.7.30328.74 16.7.30329.63 16.8.239 + 16.8.1-beta1-1008-05 + 16.8.1-beta1-1008-05 16.7.9 16.7.30329.88 16.7.30329.88 @@ -41,9 +44,11 @@ 16.7.30328.74 16.7.30328.74 16.7.30328.74 + 16.7.30328.74 16.7.30328.74 16.7.30328.74 16.7.30328.74 + 16.7.30328.74 16.7.30328.74 16.7.30328.74 16.8.239 diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj index 44588ee000..b9c3af4adb 100644 --- a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj @@ -10,14 +10,14 @@ NU1603;NU1605 - - + + - - - - - + + + + + From 6da4207e998ed727f97944e38659d065b314e987 Mon Sep 17 00:00:00 2001 From: Chris Sienkiewicz Date: Tue, 25 May 2021 15:27:13 -0700 Subject: [PATCH 41/65] Unify nuget references and remove warning suppression --- eng/Versions.props | 15 ++++++++------- .../Roslyn.ComponentDebugger.csproj | 5 ++++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index e23f8edf5c..9c9d059435 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,16 +24,16 @@ 3.9.0 3.9.0 - 8.0.0 + 16.8.30406.65 8.0.1 2.7.100 16.8.239 16.9.6-alpha 16.8.239 16.8.239 - 16.7.30328.74 - 16.7.30328.74 - 16.7.30329.63 + 16.8.30406.65-pre + 16.8.30406.65 + 16.8.30406.65-pre 16.8.239 16.8.1-beta1-1008-05 16.8.1-beta1-1008-05 @@ -48,8 +48,8 @@ 16.7.30328.74 16.7.30328.74 16.7.30328.74 - 16.7.30328.74 - 16.7.30328.74 + 16.8.30406.65 + 16.8.30406.65 16.7.30328.74 16.8.239 16.8.239 @@ -58,7 +58,8 @@ 16.8.55 16.3.23 16.8.33 - 5.6.0 + 5.8.0-preview.2.6776 + 5.8.0-preview.2.6776 2.6.121 16.7.30508.193 12.0.4 diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj index b9c3af4adb..f400ab7b73 100644 --- a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj @@ -7,9 +7,9 @@ net472 enable true - NU1603;NU1605 + @@ -19,5 +19,8 @@ + + + From 9539ad95cc1ee65cda5fd62a5ce2d5dc427e17c5 Mon Sep 17 00:00:00 2001 From: Chris Sienkiewicz Date: Tue, 25 May 2021 15:55:25 -0700 Subject: [PATCH 42/65] Dte8 version --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index 9c9d059435..d92af55220 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,7 +24,7 @@ 3.9.0 3.9.0 - 16.8.30406.65 + 16.8.30705.32 8.0.1 2.7.100 16.8.239 From febc3b55b3dad2d04adc23a41ac49147b20de7ad Mon Sep 17 00:00:00 2001 From: Chris Sienkiewicz Date: Tue, 25 May 2021 18:09:17 -0700 Subject: [PATCH 43/65] lots more nuget updates --- NuGet.config | 1 + eng/Versions.props | 30 +++++++++++-------- .../Roslyn.ComponentDebugger.csproj | 5 ++++ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/NuGet.config b/NuGet.config index 687b1bf8e6..d92daf4842 100644 --- a/NuGet.config +++ b/NuGet.config @@ -7,6 +7,7 @@ + diff --git a/eng/Versions.props b/eng/Versions.props index d92af55220..3a0718cbf5 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,43 +24,47 @@ 3.9.0 3.9.0 - 16.8.30705.32 - 8.0.1 - 2.7.100 + 16.9.30921.233 + 16.8.30705.32 + 16.9.31023.347 + 16.9.30921.233 + 2.7.339 16.8.239 16.9.6-alpha 16.8.239 16.8.239 - 16.8.30406.65-pre - 16.8.30406.65 + 16.8.30709.132 + 16.8.30705.32 16.8.30406.65-pre 16.8.239 16.8.1-beta1-1008-05 16.8.1-beta1-1008-05 + 16.9.23-alpha 16.7.9 16.7.30329.88 16.7.30329.88 - 16.7.30328.74 - 16.7.30328.74 + 16.9.30921.233 + 16.9.30921.233 16.7.30328.74 16.7.30328.74 - 16.7.30328.74 + 16.9.30921.233 16.7.30328.74 - 16.7.30328.74 + 16.9.30921.233 16.7.30328.74 - 16.8.30406.65 - 16.8.30406.65 + 16.9.31023.347 + 16.9.31023.347 16.7.30328.74 16.8.239 16.8.239 - 16.7.30328.74 + 16.9.30921.233 16.8.239 16.8.55 16.3.23 16.8.33 5.8.0-preview.2.6776 5.8.0-preview.2.6776 - 2.6.121 + 1.1.0-beta3.20374.2 + 2.7.67 16.7.30508.193 12.0.4 diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj index f400ab7b73..c64c4c359d 100644 --- a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj @@ -10,6 +10,9 @@ + + + @@ -18,9 +21,11 @@ + + From e06be22154a182f87864c23550c3e91793e139b8 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 26 May 2021 12:49:46 +0000 Subject: [PATCH 44/65] [main] Update dependencies from dotnet/arcade (#832) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- eng/common/sdk-task.ps1 | 4 ++-- eng/common/templates/job/source-build.yml | 3 +++ .../post-build/channels/generic-internal-channel.yml | 6 ++++++ .../post-build/channels/generic-public-channel.yml | 6 ++++++ eng/common/templates/steps/source-build.yml | 7 ++++++- global.json | 2 +- 7 files changed, 26 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 4e1c0996e5..3578584612 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 50f5645789f9119c906755cb1d2549acdeb0d0b7 + 579b548c545da1a9747bc5df599f38fe86d66251 diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1 index f55c43c6f4..65f1d75f3d 100644 --- a/eng/common/sdk-task.ps1 +++ b/eng/common/sdk-task.ps1 @@ -53,7 +53,7 @@ try { } if ($task -eq "") { - Write-PipelineTelemetryError -Category 'Build' -Message "Missing required parameter '-task '" -ForegroundColor Red + Write-PipelineTelemetryError -Category 'Build' -Message "Missing required parameter '-task '" Print-Usage ExitWithExitCode 1 } @@ -78,7 +78,7 @@ try { $taskProject = GetSdkTaskProject $task if (!(Test-Path $taskProject)) { - Write-PipelineTelemetryError -Category 'Build' -Message "Unknown task: $task" -ForegroundColor Red + Write-PipelineTelemetryError -Category 'Build' -Message "Unknown task: $task" ExitWithExitCode 1 } diff --git a/eng/common/templates/job/source-build.yml b/eng/common/templates/job/source-build.yml index aad4146492..5023d36dcb 100644 --- a/eng/common/templates/job/source-build.yml +++ b/eng/common/templates/job/source-build.yml @@ -15,6 +15,9 @@ parameters: # nonPortable: false # Enables non-portable mode. This means a more specific RID (e.g. fedora.32-x64 rather than # linux-x64), and compiling against distro-provided packages rather than portable ones. + # skipPublishValidation: false + # Disables publishing validation. By default, a check is performed to ensure no packages are + # published by source-build. # container: '' # A container to use. Runs in docker. # pool: {} diff --git a/eng/common/templates/post-build/channels/generic-internal-channel.yml b/eng/common/templates/post-build/channels/generic-internal-channel.yml index 58fa9a35b8..8990dfc8c8 100644 --- a/eng/common/templates/post-build/channels/generic-internal-channel.yml +++ b/eng/common/templates/post-build/channels/generic-internal-channel.yml @@ -40,6 +40,9 @@ stages: pool: vmImage: 'windows-2019' steps: + - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions." + displayName: Warn about v2 Arcade Publishing Usage + # This is necessary whenever we want to publish/restore to an AzDO private feed - task: NuGetAuthenticate@0 displayName: 'Authenticate to AzDO Feeds' @@ -110,6 +113,9 @@ stages: pool: vmImage: 'windows-2019' steps: + - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions." + displayName: Warn about v2 Arcade Publishing Usage + - task: DownloadBuildArtifacts@0 displayName: Download Build Assets continueOnError: true diff --git a/eng/common/templates/post-build/channels/generic-public-channel.yml b/eng/common/templates/post-build/channels/generic-public-channel.yml index b50c0b3bdb..3220c6a4f9 100644 --- a/eng/common/templates/post-build/channels/generic-public-channel.yml +++ b/eng/common/templates/post-build/channels/generic-public-channel.yml @@ -42,6 +42,9 @@ stages: pool: vmImage: 'windows-2019' steps: + - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions." + displayName: Warn about v2 Arcade Publishing Usage + - task: DownloadBuildArtifacts@0 displayName: Download Build Assets continueOnError: true @@ -109,6 +112,9 @@ stages: pool: vmImage: 'windows-2019' steps: + - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions." + displayName: Warn about v2 Arcade Publishing Usage + - task: DownloadBuildArtifacts@0 displayName: Download Build Assets continueOnError: true diff --git a/eng/common/templates/steps/source-build.yml b/eng/common/templates/steps/source-build.yml index 65ee5992bf..e20637ed6a 100644 --- a/eng/common/templates/steps/source-build.yml +++ b/eng/common/templates/steps/source-build.yml @@ -34,9 +34,14 @@ steps: targetRidArgs='/p:TargetRid=${{ parameters.platform.targetRID }}' fi + publishArgs= + if [ '${{ parameters.platform.skipPublishValidation }}' != 'true' ]; then + publishArgs='--publish' + fi + ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \ --configuration $buildConfig \ - --restore --build --pack --publish -bl \ + --restore --build --pack $publishArgs -bl \ $officialBuildArgs \ $targetRidArgs \ /p:SourceBuildNonPortable=${{ parameters.platform.nonPortable }} \ diff --git a/global.json b/global.json index a88eed1b04..ca6a82d12e 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21271.3" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21275.5" } } From 856b8ed9761928c6bbbfd41f82f13d4454b47e35 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 27 May 2021 12:50:49 +0000 Subject: [PATCH 45/65] Update dependencies from https://github.com/dotnet/arcade build 20210526.5 (#839) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3578584612..d3970bf6c3 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 579b548c545da1a9747bc5df599f38fe86d66251 + c2a8af3f309fc27402fa9c18bac6df757a9c41ed diff --git a/global.json b/global.json index ca6a82d12e..6e927fa718 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21275.5" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21276.5" } } From af14381a15799d04cea5a9a7874629305300ec76 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 28 May 2021 12:45:23 +0000 Subject: [PATCH 46/65] Update dependencies from https://github.com/dotnet/arcade build 20210527.1 (#841) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d3970bf6c3..f32756b939 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - c2a8af3f309fc27402fa9c18bac6df757a9c41ed + c3e0e4070f6cd3873b775e3f4136e29f4d66cb49 diff --git a/global.json b/global.json index 6e927fa718..e76c91cc6e 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21276.5" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21277.1" } } From d7d61eb8e97ca758cd29bacd2599a29e887d181f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 30 May 2021 12:35:02 +0000 Subject: [PATCH 47/65] Update dependencies from https://github.com/dotnet/arcade build 20210528.1 (#844) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f32756b939..7664a7aecf 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - c3e0e4070f6cd3873b775e3f4136e29f4d66cb49 + b5ca0997b26992dcc4e55ec3d87d71000be295ce diff --git a/global.json b/global.json index e76c91cc6e..de27d3372b 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21277.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21278.1" } } From 444f049fc46e5cfc205067027987d6ac13d39580 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 12:50:32 +0000 Subject: [PATCH 48/65] Update dependencies from https://github.com/dotnet/arcade build 20210531.1 (#847) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 7664a7aecf..aa63b50b77 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - b5ca0997b26992dcc4e55ec3d87d71000be295ce + c7d6bd607715f334cda90e01967bb0c02dee09be diff --git a/global.json b/global.json index de27d3372b..7bdd22a87d 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21278.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21281.1" } } From d48a157cf3c61604fdc5d876599371248b5f3121 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Tue, 1 Jun 2021 15:15:33 -0700 Subject: [PATCH 49/65] remove call in Main --- .../VisualBasic/SourceGenerators/GeneratedDemo/Program.vb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/Program.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/Program.vb index f6b18bf08f..fd209d06bd 100644 --- a/samples/VisualBasic/SourceGenerators/GeneratedDemo/Program.vb +++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/Program.vb @@ -28,12 +28,6 @@ Running CsvGenerator: ") UseCsvGenerator.Run() - Console.WriteLine(" - -Running MustacheGenerator: -") - UseMustacheGenerator.Run() - End Sub End Module From d542fb76da25d08299259636fcb30d81c9ac0bc3 Mon Sep 17 00:00:00 2001 From: Zachary Patten Date: Wed, 2 Jun 2021 21:02:11 -0400 Subject: [PATCH 50/65] fix SourceGenerators.sln project references --- samples/CSharp/SourceGenerators/SourceGenerators.sln | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/CSharp/SourceGenerators/SourceGenerators.sln b/samples/CSharp/SourceGenerators/SourceGenerators.sln index 1e5b737dca..1732a9c41b 100644 --- a/samples/CSharp/SourceGenerators/SourceGenerators.sln +++ b/samples/CSharp/SourceGenerators/SourceGenerators.sln @@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30022.13 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SourceGeneratorSamples", "SourceGeneratorSamples\SourceGeneratorSamples.csproj", "{B452269D-856C-4FE6-8900-3D81461AF864}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SourceGeneratorSamples", "SourceGeneratorSamples\CSharpSourceGeneratorSamples.csproj", "{B452269D-856C-4FE6-8900-3D81461AF864}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeneratedDemo", "GeneratedDemo\GeneratedDemo.csproj", "{DB138C8B-7C34-4AC7-A443-A0B29D1CE8A5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeneratedDemo", "GeneratedDemo\CSharpGeneratedDemo.csproj", "{DB138C8B-7C34-4AC7-A443-A0B29D1CE8A5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From 93f58ae7bcb947ec75484f0da9c7382b27357aaf Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 3 Jun 2021 12:51:03 +0000 Subject: [PATCH 51/65] Update dependencies from https://github.com/dotnet/arcade build 20210602.1 (#853) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index aa63b50b77..dd427b6725 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - c7d6bd607715f334cda90e01967bb0c02dee09be + 9945dc4ebbb511b027df34cb5ab579f6395d1dda diff --git a/global.json b/global.json index 7bdd22a87d..2214715101 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21281.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21302.1" } } From a9ea478554c65bbf912070bc3dd546ba6cb1bce6 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Thu, 3 Jun 2021 10:51:43 -0700 Subject: [PATCH 52/65] using nuget,org versions of test framework --- .../RoslynSDKRootTemplateWizard.cs | 30 ------------------- .../CSharp/Diagnostic/Test/Test.csproj | 12 ++++---- .../Diagnostic/Test/UnitTestProject.vbproj | 12 ++++---- 3 files changed, 12 insertions(+), 42 deletions(-) diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKRootTemplateWizard.cs b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKRootTemplateWizard.cs index 9875b5f8d3..a74df4b699 100644 --- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKRootTemplateWizard.cs +++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKRootTemplateWizard.cs @@ -9,19 +9,6 @@ public partial class RoslynSDKRootTemplateWizard { - private const string NuGetConfig = @" - - - - - - - - - - -"; - public static Dictionary GlobalDictionary = new Dictionary(); private void OnRunStarted(DTE dte, Dictionary replacementsDictionary, WizardRunKind runKind, object[] customParams) @@ -31,22 +18,5 @@ private void OnRunStarted(DTE dte, Dictionary replacementsDictio // add the root project name (the name the user passed in) to the global replacement dictionary GlobalDictionary["$saferootprojectname$"] = replacementsDictionary["$safeprojectname$"]; GlobalDictionary["$saferootidentifiername$"] = replacementsDictionary["$safeprojectname$"].Replace(".",""); - - if (!replacementsDictionary.TryGetValue("$solutiondirectory$", out var solutionFolder)) - { - var solutionFile = dte.Solution.FullName; - if (string.IsNullOrEmpty(solutionFile)) - return; - - solutionFolder = Path.GetDirectoryName(solutionFile); - } - - if (Directory.Exists(solutionFolder)) - { - File.WriteAllText( - Path.Combine(solutionFolder, "NuGet.config"), - NuGetConfig, - Encoding.UTF8); - } } } diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Test/Test.csproj b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Test/Test.csproj index 9c07533daa..3ff076d889 100644 --- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Test/Test.csproj +++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Test/Test.csproj @@ -12,12 +12,12 @@ - - - - - - + + + + + + diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Test/UnitTestProject.vbproj b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Test/UnitTestProject.vbproj index 75b2bcd1f9..5704446480 100644 --- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Test/UnitTestProject.vbproj +++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Test/UnitTestProject.vbproj @@ -12,12 +12,12 @@ - - - - - - + + + + + + From 8652089a7dc877a658422779a32813ae483fbe70 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 4 Jun 2021 12:51:05 +0000 Subject: [PATCH 53/65] Update dependencies from https://github.com/dotnet/arcade build 20210603.2 (#857) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index dd427b6725..b4f422f8b8 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 9945dc4ebbb511b027df34cb5ab579f6395d1dda + 78da7776965b428ff31da8f1ff2cb073506212b7 diff --git a/global.json b/global.json index 2214715101..3860f4eb4d 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21302.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21303.2" } } From 9b100e89fb018ebc5eb63be01b8f52cf6458ef64 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 5 Jun 2021 12:49:48 +0000 Subject: [PATCH 54/65] Update dependencies from https://github.com/dotnet/arcade build 20210604.1 (#861) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b4f422f8b8..90c1df549c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 78da7776965b428ff31da8f1ff2cb073506212b7 + 85a65ea1fca1d0867f699fed44d191358270bf6a diff --git a/global.json b/global.json index 3860f4eb4d..382a76cc40 100644 --- a/global.json +++ b/global.json @@ -17,6 +17,6 @@ "xcopy-msbuild": "16.8.0-preview2.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21303.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21304.1" } } From 876f52e9ff9491c5f0191927b1617c18d2cc3809 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 21 Jun 2021 09:46:26 -0700 Subject: [PATCH 55/65] Fix support for multiple languages in AdditionalProjects --- .../ProjectCollection.cs | 17 +- .../MultipleProjectsTests.cs | 257 ++++++++++++++++++ 2 files changed, 273 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/ProjectCollection.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/ProjectCollection.cs index 07ee2603da..12b69c14e8 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/ProjectCollection.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/ProjectCollection.cs @@ -35,7 +35,22 @@ public ProjectCollection(string defaultLanguage, string defaultExtension) { get { - var project = this.GetOrAdd(projectName, () => new ProjectState(projectName, _defaultLanguage, $"/{projectName}/Test", _defaultExtension)); + string extension; + if (language == _defaultLanguage) + { + extension = _defaultExtension; + } + else + { + extension = language switch + { + LanguageNames.CSharp => "cs", + LanguageNames.VisualBasic => "vb", + _ => throw new ArgumentOutOfRangeException(nameof(language)), + }; + } + + var project = this.GetOrAdd(projectName, () => new ProjectState(projectName, language, $"/{projectName}/Test", extension)); if (project.Language != language) { throw new InvalidOperationException(); diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MultipleProjectsTests.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MultipleProjectsTests.cs index 0ecfcd1e91..118ba2b016 100644 --- a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MultipleProjectsTests.cs +++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MultipleProjectsTests.cs @@ -12,6 +12,8 @@ Microsoft.CodeAnalysis.Testing.TestAnalyzers.HighlightBracesAnalyzer, Microsoft.CodeAnalysis.Testing.TestAnalyzers.CSharpAnalyzerTest, Microsoft.CodeAnalysis.Testing.DefaultVerifier>; +using VisualBasicTest = Microsoft.CodeAnalysis.Testing.TestAnalyzers.VisualBasicAnalyzerTest< + Microsoft.CodeAnalysis.Testing.TestAnalyzers.HighlightBracesAnalyzer>; namespace Microsoft.CodeAnalysis.Testing { @@ -44,6 +46,87 @@ public async Task TwoCSharpProjects_Independent() }.RunAsync(); } + [Fact] + public async Task TwoVisualBasicProjects_Independent() + { + await new VisualBasicTest + { + TestState = + { + Sources = + { + @"Public Class Derived1 : Inherits {|BC30002:Base2|} : End Class", + @"Public Class Base1 : End Class", + }, + AdditionalProjects = + { + ["Secondary"] = + { + Sources = + { + @"Public Class Derived2 : Inherits {|BC30002:Base1|} : End Class", + @"Public Class Base2 : End Class", + }, + }, + }, + }, + }.RunAsync(); + } + + [Fact] + public async Task OneCSharpProjectOneVisualBasicProject_Independent() + { + await new CSharpTest + { + TestState = + { + Sources = + { + @"public class Derived1 : {|CS0246:Base2|} [|{|] }", + @"public class Base1 [|{|] }", + }, + AdditionalProjects = + { + ["Secondary", LanguageNames.VisualBasic] = + { + Sources = + { + @"Public Class Derived2 : Inherits {|BC30002:Base1|} : End Class", + @"Public Class Base2 : End Class", + }, + }, + }, + }, + }.RunAsync(); + } + + [Fact] + public async Task OneVisualBasicProjectOneCSharpProject_Independent() + { + await new VisualBasicTest + { + TestState = + { + Sources = + { + @"Public Class Derived1 : Inherits {|BC30002:Base2|} : End Class", + @"Public Class Base1 : End Class", + }, + AdditionalProjects = + { + ["Secondary", LanguageNames.CSharp] = + { + Sources = + { + @"public class Derived2 : {|CS0246:Base1|} [|{|] }", + @"public class Base2 [|{|] }", + }, + }, + }, + }, + }.RunAsync(); + } + [Fact] public async Task TwoCSharpProjects_IndependentWithMarkupLocations() { @@ -120,6 +203,93 @@ public async Task TwoCSharpProjects_PrimaryReferencesSecondary() }.RunAsync(); } + [Fact] + public async Task TwoVisualBasicProjects_PrimaryReferencesSecondary() + { + // TestProject references Secondary + await new VisualBasicTest + { + TestState = + { + Sources = + { + @"Public Class Derived1 : Inherits Base2 : End Class", + @"Public Class Base1 : End Class", + }, + AdditionalProjectReferences = { "Secondary", }, + AdditionalProjects = + { + ["Secondary"] = + { + Sources = + { + @"Public Class Derived2 : Inherits {|BC30002:Base1|} : End Class", + @"Public Class Base2 : End Class", + }, + }, + }, + }, + }.RunAsync(); + } + + [Fact] + public async Task OneCSharpProjectOneVisualBasicProject_PrimaryReferencesSecondary() + { + // TestProject references Secondary + await new CSharpTest + { + TestState = + { + Sources = + { + @"public class Type1 [|{|] object field = new Type3(); }", + @"public class Type2 [|{|] }", + }, + AdditionalProjectReferences = { "Secondary", }, + AdditionalProjects = + { + ["Secondary", LanguageNames.VisualBasic] = + { + Sources = + { + @"Public Class Type3 : Private field As Object = New {|BC30002:Type1|}() : End Class", + @"Public Class Type4 : End Class", + }, + }, + }, + }, + }.RunAsync(); + } + + [Fact] + public async Task OneVisualBasicProjectOneCSharpProject_PrimaryReferencesSecondary() + { + // TestProject references Secondary + await new VisualBasicTest + { + TestState = + { + Sources = + { + @"Public Class Type1 : Private field As Object = New Type3() : End Class", + @"Public Class Type2 : End Class", + }, + AdditionalProjectReferences = { "Secondary", }, + AdditionalProjects = + { + ["Secondary", LanguageNames.CSharp] = + { + Sources = + { + @"public class Type3 [|{|] object field = new {|CS0246:Type1|}(); }", + @"public class Type4 [|{|] }", + }, + }, + }, + }, + }.RunAsync(); + } + [Fact] public async Task TwoCSharpProjects_SecondaryReferencesPrimary() { @@ -149,6 +319,93 @@ public async Task TwoCSharpProjects_SecondaryReferencesPrimary() }.RunAsync(); } + [Fact] + public async Task TwoVisualBasicProjects_SecondaryReferencesPrimary() + { + // TestProject references Secondary + await new VisualBasicTest + { + TestState = + { + Sources = + { + @"Public Class Derived1 : Inherits {|BC30002:Base2|} : End Class", + @"Public Class Base1 : End Class", + }, + AdditionalProjects = + { + ["Secondary"] = + { + Sources = + { + @"Public Class Derived2 : Inherits Base1 : End Class", + @"Public Class Base2 : End Class", + }, + AdditionalProjectReferences = { "TestProject" }, + }, + }, + }, + }.RunAsync(); + } + + [Fact] + public async Task OneCSharpProjectOneVisualBasicProject_SecondaryReferencesPrimary() + { + // TestProject references Secondary + await new CSharpTest + { + TestState = + { + Sources = + { + @"public class Type1 [|{|] object field = new {|CS0246:Type3|}(); }", + @"public class Type2 [|{|] }", + }, + AdditionalProjects = + { + ["Secondary", LanguageNames.VisualBasic] = + { + Sources = + { + @"Public Class Type3 : Private field As Object = New Type1() : End Class", + @"Public Class Type4 : End Class", + }, + AdditionalProjectReferences = { "TestProject" }, + }, + }, + }, + }.RunAsync(); + } + + [Fact] + public async Task OneVisualBasicProjectOneCSharpProject_SecondaryReferencesPrimary() + { + // TestProject references Secondary + await new VisualBasicTest + { + TestState = + { + Sources = + { + @"Public Class Type1 : Private field As Object = New {|BC30002:Type3|}() : End Class", + @"Public Class Type2 : End Class", + }, + AdditionalProjects = + { + ["Secondary", LanguageNames.CSharp] = + { + Sources = + { + @"public class Type3 [|{|] object field = new Type1(); }", + @"public class Type4 [|{|] }", + }, + AdditionalProjectReferences = { "TestProject" }, + }, + }, + }, + }.RunAsync(); + } + [Fact] public async Task TwoCSharpProjects_DefaultPaths() { From 815b3772cb0ea732c1b34cf5a813619b942f473a Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 21 Jun 2021 16:31:23 -0700 Subject: [PATCH 56/65] Improve triggering and validation for multi-project scenarios Fixes #806 --- eng/Versions.props | 1 + .../CodeActionTest`1.cs | 38 ++- ...osoft.CodeAnalysis.Analyzer.Testing.csproj | 1 + .../PublicAPI.Unshipped.txt | 2 +- .../CodeFixTest`1.cs | 135 ++++++-- .../PublicAPI.Unshipped.txt | 2 + .../CodeRefactoringTest`1.cs | 50 ++- .../CodeFixIterationTests.cs | 81 +---- .../FixMultipleProjectsTests.cs | 306 ++++++++++++++++++ .../RefactoringValidationTests.cs | 87 +++++ ...soft.CodeAnalysis.Testing.Utilities.csproj | 1 + .../TestAnalyzers/LiteralUnderFiveAnalyzer.cs | 41 +++ .../TestFixes/IncrementFix.cs | 65 ++++ 13 files changed, 698 insertions(+), 112 deletions(-) create mode 100644 tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/FixMultipleProjectsTests.cs create mode 100644 tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestAnalyzers/LiteralUnderFiveAnalyzer.cs create mode 100644 tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestFixes/IncrementFix.cs diff --git a/eng/Versions.props b/eng/Versions.props index a0188b0fa0..bdaa950b9e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -74,6 +74,7 @@ 2.6.1 3.9.0 1.0.1-beta1.20374.2 + $(xunitVersion) 1.2.7 0.1.49-beta diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/CodeActionTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/CodeActionTest`1.cs index 4593954579..73f93a6270 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/CodeActionTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/CodeActionTest`1.cs @@ -70,12 +70,44 @@ protected static bool CodeActionExpected(SolutionState state) || state.AdditionalFilesFactories.Any(); } - protected static bool HasAnyChange(SolutionState oldState, SolutionState newState) + protected static bool HasAnyChange(ProjectState oldState, ProjectState newState, bool recursive) { - return !oldState.Sources.SequenceEqual(newState.Sources, SourceFileEqualityComparer.Instance) + if (!oldState.Sources.SequenceEqual(newState.Sources, SourceFileEqualityComparer.Instance) || !oldState.GeneratedSources.SequenceEqual(newState.GeneratedSources, SourceFileEqualityComparer.Instance) || !oldState.AdditionalFiles.SequenceEqual(newState.AdditionalFiles, SourceFileEqualityComparer.Instance) - || !oldState.AnalyzerConfigFiles.SequenceEqual(newState.AnalyzerConfigFiles, SourceFileEqualityComparer.Instance); + || !oldState.AnalyzerConfigFiles.SequenceEqual(newState.AnalyzerConfigFiles, SourceFileEqualityComparer.Instance)) + { + return true; + } + + if (!recursive) + { + return false; + } + + if (oldState is SolutionState oldSolutionState) + { + if (!(newState is SolutionState newSolutionState)) + { + throw new ArgumentException("Unexpected mismatch of SolutionState with ProjectState."); + } + + if (oldSolutionState.AdditionalProjects.Count != newSolutionState.AdditionalProjects.Count) + { + return true; + } + + foreach (var oldAdditionalState in oldSolutionState.AdditionalProjects) + { + if (!newSolutionState.AdditionalProjects.TryGetValue(oldAdditionalState.Key, out var newAdditionalState) + || HasAnyChange(oldAdditionalState.Value, newAdditionalState, recursive: true)) + { + return true; + } + } + } + + return false; } protected static CodeAction? TryGetCodeActionToApply(ImmutableArray actions, int? codeActionIndex, string? codeActionEquivalenceKey, Action? codeActionVerifier, IVerifier verifier) diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.csproj b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.csproj index d108fdc130..91f8237e90 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.csproj +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.csproj @@ -38,6 +38,7 @@ + diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt index 2ab84d52f8..14d5b1ccb0 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt @@ -245,7 +245,7 @@ static Microsoft.CodeAnalysis.Testing.AnalyzerVerifier.Diagnostic(string diagnosticId) -> Microsoft.CodeAnalysis.Testing.DiagnosticResult static Microsoft.CodeAnalysis.Testing.AnalyzerVerifier.VerifyAnalyzerAsync(string source, params Microsoft.CodeAnalysis.Testing.DiagnosticResult[] expected) -> System.Threading.Tasks.Task static Microsoft.CodeAnalysis.Testing.CodeActionTest.CodeActionExpected(Microsoft.CodeAnalysis.Testing.SolutionState state) -> bool -static Microsoft.CodeAnalysis.Testing.CodeActionTest.HasAnyChange(Microsoft.CodeAnalysis.Testing.SolutionState oldState, Microsoft.CodeAnalysis.Testing.SolutionState newState) -> bool +static Microsoft.CodeAnalysis.Testing.CodeActionTest.HasAnyChange(Microsoft.CodeAnalysis.Testing.ProjectState oldState, Microsoft.CodeAnalysis.Testing.ProjectState newState, bool recursive) -> bool static Microsoft.CodeAnalysis.Testing.CodeActionTest.TryGetCodeActionToApply(System.Collections.Immutable.ImmutableArray actions, int? codeActionIndex, string codeActionEquivalenceKey, System.Action codeActionVerifier, Microsoft.CodeAnalysis.Testing.IVerifier verifier) -> Microsoft.CodeAnalysis.CodeActions.CodeAction static Microsoft.CodeAnalysis.Testing.DiagnosticResult.CompilerError(string identifier) -> Microsoft.CodeAnalysis.Testing.DiagnosticResult static Microsoft.CodeAnalysis.Testing.DiagnosticResult.CompilerWarning(string identifier) -> Microsoft.CodeAnalysis.Testing.DiagnosticResult diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs index c207545c87..de2c8c122a 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs @@ -122,7 +122,8 @@ public string BatchFixedCode /// /// /// If the expected Fix All output equals the input sources, the default value is treated as 0. - /// Otherwise, the default value is treated as 1. + /// If all projects in the solution have the same , the default value is treated as 1. + /// Otherwise, the default value is treated as new negative of the number of languages represented by projects in the solution. /// /// /// @@ -158,6 +159,31 @@ public string BatchFixedCode /// public int? NumberOfFixAllInDocumentIterations { get; set; } + /// + /// Gets or sets the number of code fix iterations expected during code fix testing for Fix All in Project + /// scenarios. + /// + /// + /// See the property for an overview of the behavior of this + /// property. If the number of Fix All in Project iterations is not specified, the value is automatically + /// selected according to the current test configuration: + /// + /// + /// If a value has been explicitly provided for , the value is used as-is. + /// If the expected Fix All output equals the input sources, the default value is treated as 0. + /// Otherwise, the default value is treated as the negative of the number of distinct projects containing fixable diagnostics (typically -1). + /// + /// + /// + /// The default value for this property can be interpreted as "Fix All in Project operations are expected + /// to complete after at most one operation for each fixable project in the input source has been applied. + /// Completing in fewer iterations is acceptable." + /// + /// + /// + /// + public int? NumberOfFixAllInProjectIterations { get; set; } + /// /// Gets or sets the code fix test behaviors applying to this test. The default value is /// . @@ -266,8 +292,12 @@ private bool CodeFixExpected() /// A representing the asynchronous operation. protected async Task VerifyFixAsync(SolutionState testState, SolutionState fixedState, SolutionState batchFixedState, IVerifier verifier, CancellationToken cancellationToken) { + var fixers = GetCodeFixProviders().ToImmutableArray(); + var fixableDiagnostics = testState.ExpectedDiagnostics.Where(diagnostic => fixers.Any(fixer => fixer.FixableDiagnosticIds.Contains(diagnostic.Id))).ToImmutableArray(); + int numberOfIncrementalIterations; int numberOfFixAllIterations; + int numberOfFixAllInProjectIterations; int numberOfFixAllInDocumentIterations; if (NumberOfIncrementalIterations != null) { @@ -275,16 +305,14 @@ protected async Task VerifyFixAsync(SolutionState testState, SolutionState fixed } else { - if (!HasAnyChange(testState, fixedState)) + if (!HasAnyChange(testState, fixedState, recursive: true)) { numberOfIncrementalIterations = 0; } else { // Expect at most one iteration per fixable diagnostic - var fixers = GetCodeFixProviders().ToArray(); - var fixableExpectedDiagnostics = testState.ExpectedDiagnostics.Count(diagnostic => fixers.Any(fixer => fixer.FixableDiagnosticIds.Contains(diagnostic.Id))); - numberOfIncrementalIterations = -fixableExpectedDiagnostics; + numberOfIncrementalIterations = -fixableDiagnostics.Count(); } } @@ -294,13 +322,44 @@ protected async Task VerifyFixAsync(SolutionState testState, SolutionState fixed } else { - if (!HasAnyChange(testState, batchFixedState)) + if (!HasAnyChange(testState, batchFixedState, recursive: true)) { numberOfFixAllIterations = 0; } else { - numberOfFixAllIterations = 1; + // Expect at most one iteration per language with fixable diagnostics. Since we can't tell the + // language from ExpectedDiagnostic, use a conservative value from the number of project languages + // present. + numberOfFixAllIterations = -Enumerable.Repeat(testState.Language, 1).Concat(testState.AdditionalProjects.Select(p => p.Value.Language)).Distinct().Count(); + } + } + + if (NumberOfFixAllInProjectIterations != null) + { + numberOfFixAllInProjectIterations = NumberOfFixAllInProjectIterations.Value; + } + else if (NumberOfFixAllIterations != null) + { + numberOfFixAllInProjectIterations = NumberOfFixAllIterations.Value; + } + else + { + numberOfFixAllInProjectIterations = 0; + if (HasAnyChange(testState, batchFixedState, recursive: false)) + { + // Expect at most one iteration for a fixable primary project + numberOfFixAllInProjectIterations--; + } + + foreach (var (name, state) in testState.AdditionalProjects) + { + if (!batchFixedState.AdditionalProjects.TryGetValue(name, out var expected) + || HasAnyChange(state, expected, recursive: true)) + { + // Expect at most one iteration for each fixable additional project + numberOfFixAllInProjectIterations--; + } } } @@ -314,15 +373,13 @@ protected async Task VerifyFixAsync(SolutionState testState, SolutionState fixed } else { - if (!HasAnyChange(testState, batchFixedState)) + if (!HasAnyChange(testState, batchFixedState, recursive: false)) { numberOfFixAllInDocumentIterations = 0; } else { // Expect at most one iteration per fixable document - var fixers = GetCodeFixProviders().ToArray(); - var fixableDiagnostics = testState.ExpectedDiagnostics.Where(diagnostic => fixers.Any(fixer => fixer.FixableDiagnosticIds.Contains(diagnostic.Id))); numberOfFixAllInDocumentIterations = -fixableDiagnostics.GroupBy(diagnostic => diagnostic.Spans.FirstOrDefault().Span.Path).Count(); } } @@ -352,7 +409,7 @@ protected async Task VerifyFixAsync(SolutionState testState, SolutionState fixed var t3 = CodeFixTestBehaviors.HasFlag(CodeFixTestBehaviors.SkipFixAllInProjectCheck) ? ((Task)Task.FromResult(true)).ConfigureAwait(false) - : VerifyFixAsync(Language, GetDiagnosticAnalyzers().ToImmutableArray(), GetCodeFixProviders().ToImmutableArray(), testState, batchFixedState, numberOfFixAllIterations, FixAllAnalyzerDiagnosticsInProjectAsync, verifier.PushContext("Fix all in project"), cancellationToken).ConfigureAwait(false); + : VerifyFixAsync(Language, GetDiagnosticAnalyzers().ToImmutableArray(), GetCodeFixProviders().ToImmutableArray(), testState, batchFixedState, numberOfFixAllInProjectIterations, FixAllAnalyzerDiagnosticsInProjectAsync, verifier.PushContext("Fix all in project"), cancellationToken).ConfigureAwait(false); if (Debugger.IsAttached) { await t3; @@ -404,6 +461,21 @@ private async Task VerifyFixAsync( ExceptionDispatchInfo? iterationCountFailure; (project, iterationCountFailure) = await getFixedProject(analyzers, codeFixProviders, CodeActionIndex, CodeActionEquivalenceKey, CodeActionVerifier, project, numberOfIterations, verifier, cancellationToken).ConfigureAwait(false); + // After applying all of the code fixes, compare the resulting string to the inputted one + await VerifyProjectAsync(newState, project, verifier, cancellationToken).ConfigureAwait(false); + + foreach (var additionalProject in newState.AdditionalProjects) + { + var actualProject = project.Solution.Projects.Single(p => p.Name == additionalProject.Key); + await VerifyProjectAsync(additionalProject.Value, actualProject, verifier, cancellationToken); + } + + // Validate the iteration counts after validating the content + iterationCountFailure?.Throw(); + } + + private async Task VerifyProjectAsync(ProjectState newState, Project project, IVerifier verifier, CancellationToken cancellationToken) + { // After applying all of the code fixes, compare the resulting string to the inputted one var updatedDocuments = project.Documents.ToArray(); @@ -443,13 +515,17 @@ private async Task VerifyFixAsync( verifier.Equal(newState.AnalyzerConfigFiles[i].content.ChecksumAlgorithm, actual.ChecksumAlgorithm, $"checksum algorithm of '{newState.AnalyzerConfigFiles[i].filename}' was expected to be '{newState.AnalyzerConfigFiles[i].content.ChecksumAlgorithm}' but was '{actual.ChecksumAlgorithm}'"); verifier.Equal(newState.AnalyzerConfigFiles[i].filename, updatedAnalyzerConfigDocuments[i].Name, $"file name was expected to be '{newState.AnalyzerConfigFiles[i].filename}' but was '{updatedAnalyzerConfigDocuments[i].Name}'"); } - - // Validate the iteration counts after validating the content - iterationCountFailure?.Throw(); } private async Task<(Project project, ExceptionDispatchInfo? iterationCountFailure)> FixEachAnalyzerDiagnosticAsync(ImmutableArray analyzers, ImmutableArray codeFixProviders, int? codeFixIndex, string? codeFixEquivalenceKey, Action? codeActionVerifier, Project project, int numberOfIterations, IVerifier verifier, CancellationToken cancellationToken) { + if (numberOfIterations == -1) + { + // For better error messages, use '==' instead of '<=' for iteration comparison when the right hand + // side is 1. + numberOfIterations = 1; + } + var expectedNumberOfIterations = numberOfIterations; if (numberOfIterations < 0) { @@ -485,7 +561,7 @@ private async Task VerifyFixAsync( var fixableDiagnostics = analyzerDiagnostics .Where(diagnostic => codeFixProviders.Any(provider => provider.FixableDiagnosticIds.Contains(diagnostic.Id))) - .Where(diagnostic => project.GetDocument(diagnostic.Location.SourceTree) is object) + .Where(diagnostic => project.Solution.GetDocument(diagnostic.Location.SourceTree) is object) .ToImmutableArray(); if (CodeFixTestBehaviors.HasFlag(CodeFixTestBehaviors.FixOne)) @@ -500,6 +576,7 @@ private async Task VerifyFixAsync( { var actions = ImmutableArray.CreateBuilder(); + var fixableDocument = project.Solution.GetDocument(diagnostic.Location.SourceTree); foreach (var codeFixProvider in codeFixProviders) { if (!codeFixProvider.FixableDiagnosticIds.Contains(diagnostic.Id)) @@ -508,7 +585,7 @@ private async Task VerifyFixAsync( continue; } - var context = new CodeFixContext(project.GetDocument(diagnostic.Location.SourceTree), diagnostic, (a, d) => actions.Add(a), cancellationToken); + var context = new CodeFixContext(fixableDocument, diagnostic, (a, d) => actions.Add(a), cancellationToken); await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false); } @@ -518,11 +595,12 @@ private async Task VerifyFixAsync( { anyActions = true; - var fixedProject = await ApplyCodeActionAsync(project, actionToApply, verifier, cancellationToken).ConfigureAwait(false); - if (fixedProject != project) + var originalProjectId = project.Id; + var fixedProject = await ApplyCodeActionAsync(fixableDocument.Project, actionToApply, verifier, cancellationToken).ConfigureAwait(false); + if (fixedProject != fixableDocument.Project) { done = false; - project = fixedProject; + project = fixedProject.Solution.GetProject(originalProjectId); break; } } @@ -579,6 +657,13 @@ private async Task VerifyFixAsync( private async Task<(Project project, ExceptionDispatchInfo? iterationCountFailure)> FixAllAnalyerDiagnosticsInScopeAsync(FixAllScope scope, ImmutableArray analyzers, ImmutableArray codeFixProviders, int? codeFixIndex, string? codeFixEquivalenceKey, Action? codeActionVerifier, Project project, int numberOfIterations, IVerifier verifier, CancellationToken cancellationToken) { + if (numberOfIterations == -1) + { + // For better error messages, use '==' instead of '<=' for iteration comparison when the right hand + // side is 1. + numberOfIterations = 1; + } + var expectedNumberOfIterations = numberOfIterations; if (numberOfIterations < 0) { @@ -620,7 +705,7 @@ private async Task VerifyFixAsync( foreach (var codeFixProvider in codeFixProviders) { if (!codeFixProvider.FixableDiagnosticIds.Contains(diagnostic.Id) - || !(project.GetDocument(diagnostic.Location.SourceTree) is { } document)) + || !(project.Solution.GetDocument(diagnostic.Location.SourceTree) is { } document)) { // do not pass unsupported diagnostics to a code fix provider continue; @@ -655,11 +740,12 @@ private async Task VerifyFixAsync( FixAllContext.DiagnosticProvider fixAllDiagnosticProvider = TestDiagnosticProvider.Create(analyzerDiagnostics); + var fixableDocument = project.Solution.GetDocument(firstDiagnostic.Location.SourceTree); var analyzerDiagnosticIds = analyzers.SelectMany(x => x.SupportedDiagnostics).Select(x => x.Id); var compilerDiagnosticIds = codeFixProviders.SelectMany(codeFixProvider => codeFixProvider.FixableDiagnosticIds).Where(x => x.StartsWith("CS", StringComparison.Ordinal) || x.StartsWith("BC", StringComparison.Ordinal)); var disabledDiagnosticIds = project.CompilationOptions.SpecificDiagnosticOptions.Where(x => x.Value == ReportDiagnostic.Suppress).Select(x => x.Key); var relevantIds = analyzerDiagnosticIds.Concat(compilerDiagnosticIds).Except(disabledDiagnosticIds).Distinct(); - var fixAllContext = new FixAllContext(project.GetDocument(firstDiagnostic.Location.SourceTree), effectiveCodeFixProvider, scope, equivalenceKey, relevantIds, fixAllDiagnosticProvider, cancellationToken); + var fixAllContext = new FixAllContext(fixableDocument, effectiveCodeFixProvider, scope, equivalenceKey, relevantIds, fixAllDiagnosticProvider, cancellationToken); var action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false); if (action == null) @@ -667,11 +753,12 @@ private async Task VerifyFixAsync( return (project, null); } - var fixedProject = await ApplyCodeActionAsync(project, action, verifier, cancellationToken).ConfigureAwait(false); - if (fixedProject != project) + var originalProjectId = project.Id; + var fixedProject = await ApplyCodeActionAsync(fixableDocument.Project, action, verifier, cancellationToken).ConfigureAwait(false); + if (fixedProject != fixableDocument.Project) { done = false; - project = fixedProject; + project = fixedProject.Solution.GetProject(originalProjectId); } if (CodeFixTestBehaviors.HasFlag(CodeFixTestBehaviors.FixOne)) diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/PublicAPI.Unshipped.txt index 6e09256b2a..1552a9842b 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/PublicAPI.Unshipped.txt @@ -14,6 +14,8 @@ Microsoft.CodeAnalysis.Testing.CodeFixTest.FixedCode.set -> void Microsoft.CodeAnalysis.Testing.CodeFixTest.FixedState.get -> Microsoft.CodeAnalysis.Testing.SolutionState Microsoft.CodeAnalysis.Testing.CodeFixTest.NumberOfFixAllInDocumentIterations.get -> int? Microsoft.CodeAnalysis.Testing.CodeFixTest.NumberOfFixAllInDocumentIterations.set -> void +Microsoft.CodeAnalysis.Testing.CodeFixTest.NumberOfFixAllInProjectIterations.get -> int? +Microsoft.CodeAnalysis.Testing.CodeFixTest.NumberOfFixAllInProjectIterations.set -> void Microsoft.CodeAnalysis.Testing.CodeFixTest.NumberOfFixAllIterations.get -> int? Microsoft.CodeAnalysis.Testing.CodeFixTest.NumberOfFixAllIterations.set -> void Microsoft.CodeAnalysis.Testing.CodeFixTest.NumberOfIncrementalIterations.get -> int? diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs index 3b2e0def15..80ee3581f0 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs @@ -114,7 +114,7 @@ private bool CodeActionExpected() return CodeActionExpected(FixedState); } - protected override DiagnosticDescriptor? GetDefaultDiagnostic(DiagnosticAnalyzer[] analyzers) + protected internal override DiagnosticDescriptor? GetDefaultDiagnostic(DiagnosticAnalyzer[] analyzers) { if (base.GetDefaultDiagnostic(analyzers) is { } descriptor) { @@ -135,7 +135,7 @@ private bool CodeActionExpected() /// A representing the asynchronous operation. protected async Task VerifyRefactoringAsync(SolutionState testState, SolutionState fixedState, DiagnosticResult triggerSpan, IVerifier verifier, CancellationToken cancellationToken) { - var numberOfIncrementalIterations = OffersEmptyRefactoring || HasAnyChange(testState, fixedState) ? 1 : 0; + var numberOfIncrementalIterations = OffersEmptyRefactoring || HasAnyChange(testState, fixedState, recursive: true) ? 1 : 0; await VerifyRefactoringAsync(Language, triggerSpan, GetCodeRefactoringProviders().ToImmutableArray(), testState, fixedState, numberOfIncrementalIterations, ApplyRefactoringAsync, verifier.PushContext("Code refactoring application"), cancellationToken); } @@ -156,6 +156,21 @@ private async Task VerifyRefactoringAsync( ExceptionDispatchInfo? iterationCountFailure; (project, iterationCountFailure) = await getFixedProject(triggerSpan, codeRefactoringProviders, CodeActionIndex, CodeActionEquivalenceKey, CodeActionVerifier, project, numberOfIterations, verifier, cancellationToken).ConfigureAwait(false); + // After applying the refactoring, compare the resulting string to the inputted one + await VerifyProjectAsync(newState, project, verifier, cancellationToken).ConfigureAwait(false); + + foreach (var additionalProject in newState.AdditionalProjects) + { + var actualProject = project.Solution.Projects.Single(p => p.Name == additionalProject.Key); + await VerifyProjectAsync(additionalProject.Value, actualProject, verifier, cancellationToken); + } + + // Validate the iteration counts after validating the content + iterationCountFailure?.Throw(); + } + + private async Task VerifyProjectAsync(ProjectState newState, Project project, IVerifier verifier, CancellationToken cancellationToken) + { // After applying the refactoring, compare the resulting string to the inputted one var updatedDocuments = project.Documents.ToArray(); @@ -183,12 +198,29 @@ private async Task VerifyRefactoringAsync( verifier.Equal(newState.AdditionalFiles[i].filename, updatedAdditionalDocuments[i].Name, $"file name was expected to be '{newState.AdditionalFiles[i].filename}' but was '{updatedAdditionalDocuments[i].Name}'"); } - // Validate the iteration counts after validating the content - iterationCountFailure?.Throw(); + var updatedAnalyzerConfigDocuments = project.AnalyzerConfigDocuments().ToArray(); + + verifier.Equal(newState.AnalyzerConfigFiles.Count, updatedAnalyzerConfigDocuments.Length, $"expected '{nameof(newState)}.{nameof(SolutionState.AnalyzerConfigFiles)}' and '{nameof(updatedAnalyzerConfigDocuments)}' to be equal but '{nameof(newState)}.{nameof(SolutionState.AnalyzerConfigFiles)}' contains '{newState.AnalyzerConfigFiles.Count}' documents and '{nameof(updatedAnalyzerConfigDocuments)}' contains '{updatedAnalyzerConfigDocuments.Length}' documents"); + + for (var i = 0; i < updatedAnalyzerConfigDocuments.Length; i++) + { + var actual = await updatedAnalyzerConfigDocuments[i].GetTextAsync(cancellationToken).ConfigureAwait(false); + verifier.EqualOrDiff(newState.AnalyzerConfigFiles[i].content.ToString(), actual.ToString(), $"content of '{newState.AnalyzerConfigFiles[i].filename}' did not match. Diff shown with expected as baseline:"); + verifier.Equal(newState.AnalyzerConfigFiles[i].content.Encoding, actual.Encoding, $"encoding of '{newState.AnalyzerConfigFiles[i].filename}' was expected to be '{newState.AnalyzerConfigFiles[i].content.Encoding?.WebName}' but was '{actual.Encoding?.WebName}'"); + verifier.Equal(newState.AnalyzerConfigFiles[i].content.ChecksumAlgorithm, actual.ChecksumAlgorithm, $"checksum algorithm of '{newState.AnalyzerConfigFiles[i].filename}' was expected to be '{newState.AnalyzerConfigFiles[i].content.ChecksumAlgorithm}' but was '{actual.ChecksumAlgorithm}'"); + verifier.Equal(newState.AnalyzerConfigFiles[i].filename, updatedAnalyzerConfigDocuments[i].Name, $"file name was expected to be '{newState.AnalyzerConfigFiles[i].filename}' but was '{updatedAnalyzerConfigDocuments[i].Name}'"); + } } private async Task<(Project project, ExceptionDispatchInfo? iterationCountFailure)> ApplyRefactoringAsync(DiagnosticResult triggerSpan, ImmutableArray codeRefactoringProviders, int? codeActionIndex, string? codeActionEquivalenceKey, Action? codeActionVerifier, Project project, int numberOfIterations, IVerifier verifier, CancellationToken cancellationToken) { + if (numberOfIterations == -1) + { + // For better error messages, use '==' instead of '<=' for iteration comparison when the right hand + // side is 1. + numberOfIterations = 1; + } + var expectedNumberOfIterations = numberOfIterations; if (numberOfIterations < 0) { @@ -212,10 +244,11 @@ private async Task VerifyRefactoringAsync( var actions = ImmutableArray.CreateBuilder(); var location = await GetTriggerLocationAsync(); + var triggerDocument = project.Solution.GetDocument(location.SourceTree); foreach (var codeRefactoringProvider in codeRefactoringProviders) { - var context = new CodeRefactoringContext(project.GetDocument(location.SourceTree), location.SourceSpan, actions.Add, cancellationToken); + var context = new CodeRefactoringContext(triggerDocument, location.SourceSpan, actions.Add, cancellationToken); await codeRefactoringProvider.ComputeRefactoringsAsync(context).ConfigureAwait(false); } @@ -225,11 +258,12 @@ private async Task VerifyRefactoringAsync( { anyActions = true; - var fixedProject = await ApplyCodeActionAsync(project, actionToApply, verifier, cancellationToken).ConfigureAwait(false); - if (fixedProject != project) + var originalProjectId = project.Id; + var fixedProject = await ApplyCodeActionAsync(triggerDocument.Project, actionToApply, verifier, cancellationToken).ConfigureAwait(false); + if (fixedProject != triggerDocument.Project) { done = false; - project = fixedProject; + project = fixedProject.Solution.GetProject(originalProjectId); break; } } diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/CodeFixIterationTests.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/CodeFixIterationTests.cs index 43704cacfb..5b38386b76 100644 --- a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/CodeFixIterationTests.cs +++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/CodeFixIterationTests.cs @@ -3,18 +3,10 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; -using System.Composition; -using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing.TestAnalyzers; using Microsoft.CodeAnalysis.Testing.TestFixes; -using Microsoft.CodeAnalysis.Text; using Xunit; namespace Microsoft.CodeAnalysis.Testing @@ -220,11 +212,11 @@ class TestClass { }.RunAsync(); }); - new DefaultVerifier().EqualOrDiff($"Context: Iterative code fix application{Environment.NewLine}The upper limit for the number of code fix iterations was exceeded", exception.Message); + new DefaultVerifier().EqualOrDiff($"Context: Iterative code fix application{Environment.NewLine}Expected '1' iterations but found '2' iterations.", exception.Message); } [Theory] - [InlineData(-1, "The upper limit for the number of code fix iterations was exceeded", " 5")] + [InlineData(-1, "Expected '1' iterations but found '2' iterations.", " 5")] [InlineData(0, "The upper limit for the number of code fix iterations was exceeded", " [|4|]")] [InlineData(1, "Expected '1' iterations but found '2' iterations.", " 5")] public async Task TestTwoIterationsRequiredButIncrementalDeclaredIncorrectly(int declaredIncrementalIterations, string message, string replacement) @@ -284,11 +276,11 @@ class TestClass { }.RunAsync(); }); - Assert.Equal($"Context: Fix all in document{Environment.NewLine}The upper limit for the number of code fix iterations was exceeded", exception.Message); + Assert.Equal($"Context: Fix all in document{Environment.NewLine}Expected '1' iterations but found '2' iterations.", exception.Message); } [Theory] - [InlineData(-1, "The upper limit for the number of code fix iterations was exceeded", " 5")] + [InlineData(-1, "Expected '1' iterations but found '2' iterations.", " 5")] [InlineData(0, "The upper limit for the number of fix all iterations was exceeded", " [|4|]")] [InlineData(1, "Expected '1' iterations but found '2' iterations.", " 5")] public async Task TestTwoIterationsRequiredButFixAllDeclaredIncorrectly(int declaredFixAllIterations, string message, string replacement) @@ -403,69 +395,6 @@ class TestClass2 { Assert.Equal($"Context: {context}{Environment.NewLine}Expected '2' iterations but found '1' iterations.", exception.Message); } - /// - /// Reports a diagnostic on any integer literal token with a value less than five. - /// - [DiagnosticAnalyzer(LanguageNames.CSharp)] - private class LiteralUnderFiveAnalyzer : DiagnosticAnalyzer - { - internal static readonly DiagnosticDescriptor Descriptor = - new DiagnosticDescriptor("LiteralUnderFive", "title", "message", "category", DiagnosticSeverity.Warning, isEnabledByDefault: true); - - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Descriptor); - - public override void Initialize(AnalysisContext context) - { - context.EnableConcurrentExecution(); - context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); - - context.RegisterSyntaxNodeAction(HandleNumericLiteralExpression, SyntaxKind.NumericLiteralExpression); - } - - private void HandleNumericLiteralExpression(SyntaxNodeAnalysisContext context) - { - var node = (LiteralExpressionSyntax)context.Node; - if (int.TryParse(node.Token.ValueText, out var value) && value < 5) - { - context.ReportDiagnostic(Diagnostic.Create(Descriptor, node.Token.GetLocation())); - } - } - } - - [ExportCodeFixProvider(LanguageNames.CSharp)] - [PartNotDiscoverable] - private class IncrementFix : CodeFixProvider - { - public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(LiteralUnderFiveAnalyzer.Descriptor.Id); - - public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - - public override Task RegisterCodeFixesAsync(CodeFixContext context) - { - foreach (var diagnostic in context.Diagnostics) - { - context.RegisterCodeFix( - CodeAction.Create( - "LiteralUnderFive", - cancellationToken => CreateChangedDocument(context.Document, diagnostic.Location.SourceSpan, cancellationToken), - nameof(IncrementFix)), - diagnostic); - } - - return Task.CompletedTask; - } - - private async Task CreateChangedDocument(Document document, TextSpan sourceSpan, CancellationToken cancellationToken) - { - var tree = (await document.GetSyntaxTreeAsync(cancellationToken))!; - var root = await tree.GetRootAsync(cancellationToken); - var token = root.FindToken(sourceSpan.Start); - var replacement = int.Parse(token.ValueText) + 1; - var newToken = SyntaxFactory.Literal(token.LeadingTrivia, " " + replacement.ToString(), replacement, token.TrailingTrivia); - return document.WithSyntaxRoot(root.ReplaceToken(token, newToken)); - } - } - private class CSharpTest : CSharpCodeFixTest { public int DiagnosticIndexToFix { get; set; } diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/FixMultipleProjectsTests.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/FixMultipleProjectsTests.cs new file mode 100644 index 0000000000..35059a454a --- /dev/null +++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/FixMultipleProjectsTests.cs @@ -0,0 +1,306 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading.Tasks; +using Xunit; +using CSharpTest = Microsoft.CodeAnalysis.Testing.TestFixes.CSharpCodeFixTest< + Microsoft.CodeAnalysis.Testing.TestAnalyzers.LiteralUnderFiveAnalyzer, + Microsoft.CodeAnalysis.Testing.TestFixes.IncrementFix>; +using VisualBasicTest = Microsoft.CodeAnalysis.Testing.TestFixes.VisualBasicCodeFixTest< + Microsoft.CodeAnalysis.Testing.TestAnalyzers.LiteralUnderFiveAnalyzer, + Microsoft.CodeAnalysis.Testing.TestFixes.IncrementFix>; + +namespace Microsoft.CodeAnalysis.Testing +{ + public class FixMultipleProjectsTests + { + [Fact] + public async Task TwoCSharpProjects_Independent() + { + await new CSharpTest + { + TestState = + { + Sources = + { + @"public class Type1 { int field = [|4|]; }", + @"public class Type2 { int field = [|4|]; }", + }, + AdditionalProjects = + { + ["Secondary"] = + { + Sources = + { + @"public class Type3 { int field = [|4|]; }", + @"public class Type4 { int field = [|4|]; }", + }, + }, + }, + }, + FixedState = + { + Sources = + { + @"public class Type1 { int field = 5; }", + @"public class Type2 { int field = 5; }", + }, + AdditionalProjects = + { + ["Secondary"] = + { + Sources = + { + @"public class Type3 { int field = 5; }", + @"public class Type4 { int field = 5; }", + }, + }, + }, + }, + }.RunAsync(); + } + + [Fact] + public async Task TwoVisualBasicProjects_Independent() + { + await new VisualBasicTest + { + TestState = + { + Sources = + { + @"Public Class Type1 : Private field = [|4|] : End Class", + @"Public Class Type2 : Private field = [|4|] : End Class", + }, + AdditionalProjects = + { + ["Secondary"] = + { + Sources = + { + @"Public Class Type3 : Private field = [|4|] : End Class", + @"Public Class Type4 : Private field = [|4|] : End Class", + }, + }, + }, + }, + FixedState = + { + Sources = + { + @"Public Class Type1 : Private field = 5 : End Class", + @"Public Class Type2 : Private field = 5 : End Class", + }, + AdditionalProjects = + { + ["Secondary"] = + { + Sources = + { + @"Public Class Type3 : Private field = 5 : End Class", + @"Public Class Type4 : Private field = 5 : End Class", + }, + }, + }, + }, + }.RunAsync(); + } + + [Fact] + public async Task OneCSharpProjectOneVisualBasicProject_Independent() + { + await new CSharpTest + { + TestState = + { + Sources = + { + @"public class Type1 { int field = [|4|]; }", + @"public class Type2 { int field = [|4|]; }", + }, + AdditionalProjects = + { + ["Secondary", LanguageNames.VisualBasic] = + { + Sources = + { + @"Public Class Type3 : Private field = [|4|] : End Class", + @"Public Class Type4 : Private field = [|4|] : End Class", + }, + }, + }, + }, + FixedState = + { + Sources = + { + @"public class Type1 { int field = 5; }", + @"public class Type2 { int field = 5; }", + }, + AdditionalProjects = + { + ["Secondary", LanguageNames.VisualBasic] = + { + Sources = + { + @"Public Class Type3 : Private field = 5 : End Class", + @"Public Class Type4 : Private field = 5 : End Class", + }, + }, + }, + }, + }.RunAsync(); + } + + [Fact] + public async Task OneVisualBasicProjectOneCSharpProject_Independent() + { + await new VisualBasicTest + { + TestState = + { + Sources = + { + @"Public Class Type1 : Private field = [|4|] : End Class", + @"Public Class Type2 : Private field = [|4|] : End Class", + }, + AdditionalProjects = + { + ["Secondary", LanguageNames.CSharp] = + { + Sources = + { + @"public class Type3 { int field = [|4|]; }", + @"public class Type4 { int field = [|4|]; }", + }, + }, + }, + }, + FixedState = + { + Sources = + { + @"Public Class Type1 : Private field = 5 : End Class", + @"Public Class Type2 : Private field = 5 : End Class", + }, + AdditionalProjects = + { + ["Secondary", LanguageNames.CSharp] = + { + Sources = + { + @"public class Type3 { int field = 5; }", + @"public class Type4 { int field = 5; }", + }, + }, + }, + }, + }.RunAsync(); + } + + [Fact] + public async Task TwoCSharpProjects_Independent_UnexpectedDiagnostic() + { + var exception = await Assert.ThrowsAsync(async () => + { + await new CSharpTest + { + TestState = + { + Sources = + { + @"public class Type1 { int field = [|4|]; }", + @"public class Type2 { int field = [|4|]; }", + }, + AdditionalProjects = + { + ["Secondary"] = + { + Sources = + { + @"public class Type3 { int field = [|4|]; }", + @"public class Type4 { int field = [|4|]; }", + }, + }, + }, + }, + FixedState = + { + Sources = + { + @"public class Type1 { int field = 5; }", + @"public class Type2 { int field = 5; }", + }, + AdditionalProjects = + { + ["Secondary"] = + { + Sources = + { + @"public class Type3 { int field = [|5|]; }", + @"public class Type4 { int field = 5; }", + }, + }, + }, + MarkupHandling = MarkupMode.Allow, + }, + }.RunAsync(); + }); + + new DefaultVerifier().EqualOrDiff($"Context: Diagnostics of fixed state{Environment.NewLine}Mismatch between number of diagnostics returned, expected \"1\" actual \"0\"{Environment.NewLine}{Environment.NewLine}Diagnostics:{Environment.NewLine} NONE.{Environment.NewLine}", exception.Message); + } + + [Fact] + public async Task TwoCSharpProjects_Independent_UnexpectedContent() + { + var exception = await Assert.ThrowsAsync(async () => + { + await new CSharpTest + { + TestState = + { + Sources = + { + @"public class Type1 { int field = [|4|]; }", + @"public class Type2 { int field = [|4|]; }", + }, + AdditionalProjects = + { + ["Secondary"] = + { + Sources = + { + @"public class Type3 { int field = [|4|]; }", + @"public class Type4 { int field = [|4|]; }", + }, + }, + }, + }, + FixedState = + { + Sources = + { + @"public class Type1 { int field = 5; }", + @"public class Type2 { int field = 5; }", + }, + AdditionalProjects = + { + ["Secondary"] = + { + Sources = + { + @"public class Type3 { int field = 5; }", + @"public class Type4 { int field = 5; }", + }, + }, + }, + }, + }.RunAsync(); + }); + + new DefaultVerifier().EqualOrDiff($"Context: Iterative code fix application{Environment.NewLine}content of '/Secondary/Test0.cs' did not match. Diff shown with expected as baseline:{Environment.NewLine}-public class Type3 {{ int field = 5; }}{Environment.NewLine}+public class Type3 {{ int field = 5; }}{Environment.NewLine}", exception.Message); + } + } +} diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing.UnitTests/RefactoringValidationTests.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing.UnitTests/RefactoringValidationTests.cs index b47c232dcb..03780afb8a 100644 --- a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing.UnitTests/RefactoringValidationTests.cs +++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing.UnitTests/RefactoringValidationTests.cs @@ -290,6 +290,68 @@ public async Task TestNoValidationPassesFull() }.RunAsync(); } + [Fact] + [WorkItem(806, "https://github.com/dotnet/roslyn-sdk/issues/806")] + public async Task TestWithAdditionalProject_SameLanguage() + { + await new ReplaceThisWithBaseTest + { + TestState = + { + Sources = { "public class Ignored { }" }, + AdditionalProjects = + { + ["Additional"] = + { + Sources = { ReplaceThisWithBaseTestCode }, + }, + }, + }, + FixedState = + { + Sources = { "public class Ignored { }" }, + AdditionalProjects = + { + ["Additional"] = + { + Sources = { ReplaceThisWithBaseFixedCode }, + }, + }, + }, + }.RunAsync(); + } + + [Fact] + [WorkItem(806, "https://github.com/dotnet/roslyn-sdk/issues/806")] + public async Task TestWithAdditionalProject_DifferentLanguage() + { + await new ReplaceThisWithBaseTestVisualBasic + { + TestState = + { + Sources = { "Public Class Ignored : End Class" }, + AdditionalProjects = + { + ["Additional", LanguageNames.CSharp] = + { + Sources = { ReplaceThisWithBaseTestCode }, + }, + }, + }, + FixedState = + { + Sources = { "Public Class Ignored : End Class" }, + AdditionalProjects = + { + ["Additional", LanguageNames.CSharp] = + { + Sources = { ReplaceThisWithBaseFixedCode }, + }, + }, + }, + }.RunAsync(); + } + [ExportCodeRefactoringProvider(LanguageNames.CSharp)] [PartNotDiscoverable] private class ReplaceThisWithBaseTokenFix : CodeRefactoringProvider @@ -405,5 +467,30 @@ protected override IEnumerable GetCodeRefactoringProvid yield return new TCodeRefactoring(); } } + + private class ReplaceThisWithBaseTestVisualBasic : CodeRefactoringTest + where TCodeRefactoring : CodeRefactoringProvider, new() + { + public override string Language => LanguageNames.VisualBasic; + + public override Type SyntaxKindType => typeof(VisualBasic.SyntaxKind); + + protected override string DefaultFileExt => "vb"; + + protected override CompilationOptions CreateCompilationOptions() + { + return new VisualBasic.VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary); + } + + protected override ParseOptions CreateParseOptions() + { + return new VisualBasic.VisualBasicParseOptions(VisualBasic.LanguageVersion.Default, DocumentationMode.Diagnose); + } + + protected override IEnumerable GetCodeRefactoringProviders() + { + yield return new TCodeRefactoring(); + } + } } } diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/Microsoft.CodeAnalysis.Testing.Utilities.csproj b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/Microsoft.CodeAnalysis.Testing.Utilities.csproj index 614d810052..184f5e0fec 100644 --- a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/Microsoft.CodeAnalysis.Testing.Utilities.csproj +++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/Microsoft.CodeAnalysis.Testing.Utilities.csproj @@ -36,5 +36,6 @@ + diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestAnalyzers/LiteralUnderFiveAnalyzer.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestAnalyzers/LiteralUnderFiveAnalyzer.cs new file mode 100644 index 0000000000..281dd7808a --- /dev/null +++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestAnalyzers/LiteralUnderFiveAnalyzer.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; + +namespace Microsoft.CodeAnalysis.Testing.TestAnalyzers +{ + /// + /// Reports a diagnostic on any integer literal with a value less than five. + /// + [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] + public class LiteralUnderFiveAnalyzer : DiagnosticAnalyzer + { + internal static readonly DiagnosticDescriptor Descriptor = + new DiagnosticDescriptor("LiteralUnderFive", "title", "message", "category", DiagnosticSeverity.Warning, isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Descriptor); + + public override void Initialize(AnalysisContext context) + { + context.EnableConcurrentExecution(); + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + + context.RegisterOperationAction(HandleLiteralOperation, OperationKind.Literal); + } + + private void HandleLiteralOperation(OperationAnalysisContext context) + { + var operation = (ILiteralOperation)context.Operation; + if (operation.ConstantValue.HasValue + && operation.ConstantValue.Value is int value + && value < 5) + { + context.ReportDiagnostic(Diagnostic.Create(Descriptor, operation.Syntax.GetLocation())); + } + } + } +} diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestFixes/IncrementFix.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestFixes/IncrementFix.cs new file mode 100644 index 0000000000..dadff19f90 --- /dev/null +++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestFixes/IncrementFix.cs @@ -0,0 +1,65 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Testing.TestAnalyzers; +using Microsoft.CodeAnalysis.Text; +using Xunit; + +namespace Microsoft.CodeAnalysis.Testing.TestFixes +{ + [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic)] + [PartNotDiscoverable] + public class IncrementFix : CodeFixProvider + { + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(LiteralUnderFiveAnalyzer.Descriptor.Id); + + public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + + public override Task RegisterCodeFixesAsync(CodeFixContext context) + { + foreach (var diagnostic in context.Diagnostics) + { + context.RegisterCodeFix( + CodeAction.Create( + "LiteralUnderFive", + cancellationToken => CreateChangedDocument(context.Document, diagnostic.Location.SourceSpan, cancellationToken), + nameof(IncrementFix)), + diagnostic); + } + + return Task.CompletedTask; + } + + private async Task CreateChangedDocument(Document document, TextSpan sourceSpan, CancellationToken cancellationToken) + { + var tree = (await document.GetSyntaxTreeAsync(cancellationToken))!; + var root = await tree.GetRootAsync(cancellationToken); + var token = root.FindToken(sourceSpan.Start); + var replacement = int.Parse(token.ValueText) + 1; + var generator = SyntaxGenerator.GetGenerator(document); + + var originalLeadingTrivia = token.LeadingTrivia; + SyntaxTriviaList newLeadingTrivia; + Assert.Equal(0, originalLeadingTrivia.Count); + if (document.Project.Language == LanguageNames.CSharp) + { + newLeadingTrivia = CSharp.SyntaxFactory.TriviaList(CSharp.SyntaxFactory.Space); + } + else + { + newLeadingTrivia = VisualBasic.SyntaxFactory.TriviaList(VisualBasic.SyntaxFactory.Space); + } + + var newExpression = generator.LiteralExpression(replacement).WithLeadingTrivia(newLeadingTrivia).WithTrailingTrivia(token.TrailingTrivia); + return document.WithSyntaxRoot(root.ReplaceNode(token.Parent!, newExpression)); + } + } +} From c7a834711102ed9329486fb586cf920236a1b565 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 21 Jun 2021 22:10:43 -0700 Subject: [PATCH 57/65] Track projects where diagnostics are reported --- .../AnalyzerTest`1.cs | 78 ++++++++++--------- .../PublicAPI.Unshipped.txt | 2 +- .../CodeFixTest`1.cs | 27 +++---- .../TestDiagnosticProvider.cs | 12 +-- 4 files changed, 61 insertions(+), 58 deletions(-) diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs index e17ac7b5db..6410ab7e1f 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs @@ -342,19 +342,19 @@ private async Task VerifySuppressionDiagnosticsAsync(ImmutableArrayA collection of s describing the expected /// diagnostics for the sources. /// The verifier to use for test assertions. - private void VerifyDiagnosticResults(IEnumerable actualResults, ImmutableArray analyzers, DiagnosticResult[] expectedResults, IVerifier verifier) + private void VerifyDiagnosticResults(IEnumerable<(Project project, Diagnostic diagnostic)> actualResults, ImmutableArray analyzers, DiagnosticResult[] expectedResults, IVerifier verifier) { var matchedDiagnostics = MatchDiagnostics(actualResults.ToArray(), expectedResults); verifier.Equal(actualResults.Count(), matchedDiagnostics.Count(x => x.actual is object), $"{nameof(MatchDiagnostics)} failed to include all actual diagnostics in the result"); verifier.Equal(expectedResults.Length, matchedDiagnostics.Count(x => x.expected is object), $"{nameof(MatchDiagnostics)} failed to include all expected diagnostics in the result"); - actualResults = matchedDiagnostics.Select(x => x.actual).WhereNotNull(); + actualResults = matchedDiagnostics.Select(x => x.actual).Where(x => x is { }).Select(x => x!.Value); expectedResults = matchedDiagnostics.Where(x => x.expected is object).Select(x => x.expected.GetValueOrDefault()).ToArray(); var expectedCount = expectedResults.Length; var actualCount = actualResults.Count(); - var diagnosticsOutput = actualResults.Any() ? FormatDiagnostics(analyzers, DefaultFilePath, actualResults.ToArray()) : " NONE."; + var diagnosticsOutput = actualResults.Any() ? FormatDiagnostics(analyzers, DefaultFilePath, actualResults.Select(result => result.diagnostic).ToArray()) : " NONE."; var message = $"Mismatch between number of diagnostics returned, expected \"{expectedCount}\" actual \"{actualCount}\"\r\n\r\nDiagnostics:\r\n{diagnosticsOutput}\r\n"; verifier.Equal(expectedCount, actualCount, message); @@ -365,51 +365,51 @@ private void VerifyDiagnosticResults(IEnumerable actualResults, Immu if (!expected.HasLocation) { - message = FormatVerifierMessage(analyzers, actual, expected, "Expected a project diagnostic with no location:"); - verifier.Equal(Location.None, actual.Location, message); + message = FormatVerifierMessage(analyzers, actual.diagnostic, expected, "Expected a project diagnostic with no location:"); + verifier.Equal(Location.None, actual.diagnostic.Location, message); } else { - VerifyDiagnosticLocation(analyzers, actual, expected, actual.Location, expected.Spans[0], verifier); + VerifyDiagnosticLocation(analyzers, actual.diagnostic, expected, actual.diagnostic.Location, expected.Spans[0], verifier); if (!expected.Options.HasFlag(DiagnosticOptions.IgnoreAdditionalLocations)) { - var additionalLocations = actual.AdditionalLocations.ToArray(); + var additionalLocations = actual.diagnostic.AdditionalLocations.ToArray(); - message = FormatVerifierMessage(analyzers, actual, expected, $"Expected {expected.Spans.Length - 1} additional locations but got {additionalLocations.Length} for Diagnostic:"); + message = FormatVerifierMessage(analyzers, actual.diagnostic, expected, $"Expected {expected.Spans.Length - 1} additional locations but got {additionalLocations.Length} for Diagnostic:"); verifier.Equal(expected.Spans.Length - 1, additionalLocations.Length, message); for (var j = 0; j < additionalLocations.Length; ++j) { - VerifyDiagnosticLocation(analyzers, actual, expected, additionalLocations[j], expected.Spans[j + 1], verifier); + VerifyDiagnosticLocation(analyzers, actual.diagnostic, expected, additionalLocations[j], expected.Spans[j + 1], verifier); } } } - message = FormatVerifierMessage(analyzers, actual, expected, $"Expected diagnostic id to be \"{expected.Id}\" was \"{actual.Id}\""); - verifier.Equal(expected.Id, actual.Id, message); + message = FormatVerifierMessage(analyzers, actual.diagnostic, expected, $"Expected diagnostic id to be \"{expected.Id}\" was \"{actual.diagnostic.Id}\""); + verifier.Equal(expected.Id, actual.diagnostic.Id, message); if (!expected.Options.HasFlag(DiagnosticOptions.IgnoreSeverity)) { - message = FormatVerifierMessage(analyzers, actual, expected, $"Expected diagnostic severity to be \"{expected.Severity}\" was \"{actual.Severity}\""); - verifier.Equal(expected.Severity, actual.Severity, message); + message = FormatVerifierMessage(analyzers, actual.diagnostic, expected, $"Expected diagnostic severity to be \"{expected.Severity}\" was \"{actual.diagnostic.Severity}\""); + verifier.Equal(expected.Severity, actual.diagnostic.Severity, message); } if (expected.Message != null) { - message = FormatVerifierMessage(analyzers, actual, expected, $"Expected diagnostic message to be \"{expected.Message}\" was \"{actual.GetMessage()}\""); - verifier.Equal(expected.Message, actual.GetMessage(), message); + message = FormatVerifierMessage(analyzers, actual.diagnostic, expected, $"Expected diagnostic message to be \"{expected.Message}\" was \"{actual.diagnostic.GetMessage()}\""); + verifier.Equal(expected.Message, actual.diagnostic.GetMessage(), message); } else if (expected.MessageArguments?.Length > 0) { - message = FormatVerifierMessage(analyzers, actual, expected, $"Expected diagnostic message arguments to match"); + message = FormatVerifierMessage(analyzers, actual.diagnostic, expected, $"Expected diagnostic message arguments to match"); verifier.SequenceEqual( expected.MessageArguments.Select(argument => argument?.ToString() ?? string.Empty), - GetArguments(actual).Select(argument => argument?.ToString() ?? string.Empty), + GetArguments(actual.diagnostic).Select(argument => argument?.ToString() ?? string.Empty), StringComparer.Ordinal, message); } - DiagnosticVerifier?.Invoke(actual, expected, verifier); + DiagnosticVerifier?.Invoke(actual.diagnostic, expected, verifier); } } @@ -441,11 +441,11 @@ private void VerifyDiagnosticResults(IEnumerable actualResults, Immu /// the total number of mismatched pairs. /// /// - private ImmutableArray<(Diagnostic? actual, DiagnosticResult? expected)> MatchDiagnostics(Diagnostic[] actualResults, DiagnosticResult[] expectedResults) + private ImmutableArray<((Project project, Diagnostic diagnostic)? actual, DiagnosticResult? expected)> MatchDiagnostics((Project project, Diagnostic diagnostic)[] actualResults, DiagnosticResult[] expectedResults) { - var actualIds = actualResults.Select(result => result.Id).ToImmutableArray(); - var actualResultLocations = actualResults.Select(result => (location: result.Location.GetLineSpan(), additionalLocations: result.AdditionalLocations.Select(location => location.GetLineSpan()).ToImmutableArray())).ToImmutableArray(); - var actualArguments = actualResults.Select(actual => GetArguments(actual).Select(argument => argument?.ToString() ?? string.Empty).ToImmutableArray()).ToImmutableArray(); + var actualIds = actualResults.Select(result => result.diagnostic.Id).ToImmutableArray(); + var actualResultLocations = actualResults.Select(result => (location: result.diagnostic.Location.GetLineSpan(), additionalLocations: result.diagnostic.AdditionalLocations.Select(location => location.GetLineSpan()).ToImmutableArray())).ToImmutableArray(); + var actualArguments = actualResults.Select(actual => GetArguments(actual.diagnostic).Select(argument => argument?.ToString() ?? string.Empty).ToImmutableArray()).ToImmutableArray(); expectedResults = expectedResults.ToOrderedArray(); var expectedArguments = expectedResults.Select(expected => expected.MessageArguments?.Select(argument => argument?.ToString() ?? string.Empty).ToImmutableArray() ?? ImmutableArray.Empty).ToImmutableArray(); @@ -453,9 +453,9 @@ private void VerifyDiagnosticResults(IEnumerable actualResults, Immu // Initialize the best match to a trivial result where everything is unmatched. This will be updated if/when // better matches are found. var bestMatchCount = MatchQuality.RemainingUnmatched(actualResults.Length + expectedResults.Length); - var bestMatch = actualResults.Select(result => ((Diagnostic?)result, default(DiagnosticResult?))).Concat(expectedResults.Select(result => (default(Diagnostic?), (DiagnosticResult?)result))).ToImmutableArray(); + var bestMatch = actualResults.Select(result => (((Project project, Diagnostic diagnostic)?)result, default(DiagnosticResult?))).Concat(expectedResults.Select(result => (default((Project project, Diagnostic diagnostic)?), (DiagnosticResult?)result))).ToImmutableArray(); - var builder = ImmutableArray.CreateBuilder<(Diagnostic? actual, DiagnosticResult? expected)>(); + var builder = ImmutableArray.CreateBuilder<((Project project, Diagnostic diagnostic)? actual, DiagnosticResult? expected)>(); var usedExpected = new bool[expectedResults.Length]; // The recursive match algorithm is not optimized, so use a timeout to ensure it completes in a reasonable @@ -531,7 +531,7 @@ MatchQuality RecursiveMatch(int firstActualIndex, int remainingActualItems, int } var (lineSpan, additionalLineSpans) = actualResultLocations[firstActualIndex]; - var matchValue = GetMatchValue(actualResults[firstActualIndex], actualIds[firstActualIndex], lineSpan, additionalLineSpans, actualArguments[firstActualIndex], expectedResults[i], expectedArguments[i]); + var matchValue = GetMatchValue(actualResults[firstActualIndex].diagnostic, actualIds[firstActualIndex], lineSpan, additionalLineSpans, actualArguments[firstActualIndex], expectedResults[i], expectedArguments[i]); if (matchValue == MatchQuality.None) { continue; @@ -992,13 +992,15 @@ private static bool IsInSourceFile(DiagnosticResult result, (string filename, So /// The that the task will observe. /// A collection of s that surfaced in the source code, sorted by /// . - private async Task> GetSortedDiagnosticsAsync(EvaluatedProjectState primaryProject, ImmutableArray additionalProjects, ImmutableArray analyzers, IVerifier verifier, CancellationToken cancellationToken) + private async Task> GetSortedDiagnosticsAsync(EvaluatedProjectState primaryProject, ImmutableArray additionalProjects, ImmutableArray analyzers, IVerifier verifier, CancellationToken cancellationToken) { var solution = await GetSolutionAsync(primaryProject, additionalProjects, verifier, cancellationToken); - var additionalDiagnostics = primaryProject.AdditionalDiagnostics; - foreach (var project in additionalProjects) + var primaryProjectInSolution = solution.Projects.Single(project => project.Name == DefaultTestProjectName); + var additionalDiagnostics = primaryProject.AdditionalDiagnostics.Select(diagnostic => (primaryProjectInSolution, diagnostic)).ToImmutableArray(); + foreach (var additionalProject in additionalProjects) { - additionalDiagnostics = additionalDiagnostics.AddRange(project.AdditionalDiagnostics); + var additionalProjectInSolution = solution.Projects.Single(project => project.Name == additionalProject.Name); + additionalDiagnostics = additionalDiagnostics.AddRange(additionalProject.AdditionalDiagnostics.Select(diagnostic => (additionalProjectInSolution, diagnostic))); } return await GetSortedDiagnosticsAsync(solution, analyzers, additionalDiagnostics, CompilerDiagnostics, verifier, cancellationToken); @@ -1016,21 +1018,21 @@ private async Task> GetSortedDiagnosticsAsync(Evaluat /// The that the task will observe. /// A collection of s that surfaced in the source code, sorted by /// . - protected async Task> GetSortedDiagnosticsAsync(Solution solution, ImmutableArray analyzers, ImmutableArray additionalDiagnostics, CompilerDiagnostics compilerDiagnostics, IVerifier verifier, CancellationToken cancellationToken) + protected async Task> GetSortedDiagnosticsAsync(Solution solution, ImmutableArray analyzers, ImmutableArray<(Project project, Diagnostic diagnostic)> additionalDiagnostics, CompilerDiagnostics compilerDiagnostics, IVerifier verifier, CancellationToken cancellationToken) { if (analyzers.IsEmpty) { analyzers = ImmutableArray.Create(new EmptyDiagnosticAnalyzer()); } - var diagnostics = ImmutableArray.CreateBuilder(); + var diagnostics = ImmutableArray.CreateBuilder<(Project project, Diagnostic diagnostic)>(); foreach (var project in solution.Projects) { var compilation = await GetProjectCompilationAsync(project, verifier, cancellationToken).ConfigureAwait(false); var compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, GetAnalyzerOptions(project), cancellationToken); var allDiagnostics = await compilationWithAnalyzers.GetAllDiagnosticsAsync().ConfigureAwait(false); - diagnostics.AddRange(allDiagnostics.Where(diagnostic => !IsCompilerDiagnostic(diagnostic) || IsCompilerDiagnosticIncluded(diagnostic, compilerDiagnostics))); + diagnostics.AddRange(allDiagnostics.Where(diagnostic => !IsCompilerDiagnostic(diagnostic) || IsCompilerDiagnosticIncluded(diagnostic, compilerDiagnostics)).Select(diagnostic => (project, diagnostic))); } diagnostics.AddRange(additionalDiagnostics); @@ -1357,14 +1359,14 @@ protected virtual Workspace CreateWorkspaceImpl() /// A collection of s to be sorted. /// A collection containing the input , sorted by /// and . - private static Diagnostic[] SortDistinctDiagnostics(IEnumerable diagnostics) + private static (Project project, Diagnostic diagnostic)[] SortDistinctDiagnostics(IEnumerable<(Project project, Diagnostic diagnostic)> diagnostics) { return diagnostics - .OrderBy(d => d.Location.GetLineSpan().Path, StringComparer.Ordinal) - .ThenBy(d => d.Location.SourceSpan.Start) - .ThenBy(d => d.Location.SourceSpan.End) - .ThenBy(d => d.Id) - .ThenBy(d => GetArguments(d), LexicographicComparer.Instance).ToArray(); + .OrderBy(d => d.diagnostic.Location.GetLineSpan().Path, StringComparer.Ordinal) + .ThenBy(d => d.diagnostic.Location.SourceSpan.Start) + .ThenBy(d => d.diagnostic.Location.SourceSpan.End) + .ThenBy(d => d.diagnostic.Id) + .ThenBy(d => GetArguments(d.diagnostic), LexicographicComparer.Instance).ToArray(); } private static IReadOnlyList GetArguments(Diagnostic diagnostic) diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt index 14d5b1ccb0..42f6732ca6 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt @@ -9,7 +9,7 @@ Microsoft.CodeAnalysis.Testing.AnalyzerTest.DiagnosticVerifier.set -> Microsoft.CodeAnalysis.Testing.AnalyzerTest.DisabledDiagnostics.get -> System.Collections.Generic.List Microsoft.CodeAnalysis.Testing.AnalyzerTest.ExpectedDiagnostics.get -> System.Collections.Generic.List Microsoft.CodeAnalysis.Testing.AnalyzerTest.FormatVerifierMessage(System.Collections.Immutable.ImmutableArray analyzers, Microsoft.CodeAnalysis.Diagnostic actual, Microsoft.CodeAnalysis.Testing.DiagnosticResult expected, string message) -> string -Microsoft.CodeAnalysis.Testing.AnalyzerTest.GetSortedDiagnosticsAsync(Microsoft.CodeAnalysis.Solution solution, System.Collections.Immutable.ImmutableArray analyzers, System.Collections.Immutable.ImmutableArray additionalDiagnostics, Microsoft.CodeAnalysis.Testing.CompilerDiagnostics compilerDiagnostics, Microsoft.CodeAnalysis.Testing.IVerifier verifier, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task> +Microsoft.CodeAnalysis.Testing.AnalyzerTest.GetSortedDiagnosticsAsync(Microsoft.CodeAnalysis.Solution solution, System.Collections.Immutable.ImmutableArray analyzers, System.Collections.Immutable.ImmutableArray<(Microsoft.CodeAnalysis.Project project, Microsoft.CodeAnalysis.Diagnostic diagnostic)> additionalDiagnostics, Microsoft.CodeAnalysis.Testing.CompilerDiagnostics compilerDiagnostics, Microsoft.CodeAnalysis.Testing.IVerifier verifier, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task> Microsoft.CodeAnalysis.Testing.AnalyzerTest.MarkupOptions.get -> Microsoft.CodeAnalysis.Testing.MarkupOptions Microsoft.CodeAnalysis.Testing.AnalyzerTest.MarkupOptions.set -> void Microsoft.CodeAnalysis.Testing.AnalyzerTest.MatchDiagnosticsTimeout.get -> System.TimeSpan diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs index de2c8c122a..ff1d2c0650 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs @@ -532,12 +532,12 @@ private async Task VerifyProjectAsync(ProjectState newState, Project project, IV numberOfIterations = -numberOfIterations; } - var previousDiagnostics = ImmutableArray.Create(); + var previousDiagnostics = ImmutableArray.Create<(Project project, Diagnostic diagnostic)>(); bool done; do { - var analyzerDiagnostics = await GetSortedDiagnosticsAsync(project.Solution, analyzers, additionalDiagnostics: ImmutableArray.Empty, CompilerDiagnostics, verifier, cancellationToken).ConfigureAwait(false); + var analyzerDiagnostics = await GetSortedDiagnosticsAsync(project.Solution, analyzers, additionalDiagnostics: ImmutableArray<(Project project, Diagnostic diagnostic)>.Empty, CompilerDiagnostics, verifier, cancellationToken).ConfigureAwait(false); if (analyzerDiagnostics.Length == 0) { break; @@ -560,19 +560,19 @@ private async Task VerifyProjectAsync(ProjectState newState, Project project, IV previousDiagnostics = analyzerDiagnostics; var fixableDiagnostics = analyzerDiagnostics - .Where(diagnostic => codeFixProviders.Any(provider => provider.FixableDiagnosticIds.Contains(diagnostic.Id))) - .Where(diagnostic => project.Solution.GetDocument(diagnostic.Location.SourceTree) is object) + .Where(diagnostic => codeFixProviders.Any(provider => provider.FixableDiagnosticIds.Contains(diagnostic.diagnostic.Id))) + .Where(diagnostic => project.Solution.GetDocument(diagnostic.diagnostic.Location.SourceTree) is object) .ToImmutableArray(); if (CodeFixTestBehaviors.HasFlag(CodeFixTestBehaviors.FixOne)) { - var diagnosticToFix = TrySelectDiagnosticToFix(fixableDiagnostics); - fixableDiagnostics = diagnosticToFix is object ? ImmutableArray.Create(diagnosticToFix) : ImmutableArray.Empty; + var diagnosticToFix = TrySelectDiagnosticToFix(fixableDiagnostics.Select(x => x.diagnostic).ToImmutableArray()); + fixableDiagnostics = diagnosticToFix is object ? ImmutableArray.Create(fixableDiagnostics.Single(x => x.diagnostic == diagnosticToFix)) : ImmutableArray<(Project project, Diagnostic diagnostic)>.Empty; } done = true; var anyActions = false; - foreach (var diagnostic in fixableDiagnostics) + foreach (var (_, diagnostic) in fixableDiagnostics) { var actions = ImmutableArray.CreateBuilder(); @@ -670,12 +670,12 @@ private async Task VerifyProjectAsync(ProjectState newState, Project project, IV numberOfIterations = -numberOfIterations; } - var previousDiagnostics = ImmutableArray.Create(); + var previousDiagnostics = ImmutableArray.Create<(Project project, Diagnostic diagnostic)>(); bool done; do { - var analyzerDiagnostics = await GetSortedDiagnosticsAsync(project.Solution, analyzers, additionalDiagnostics: ImmutableArray.Empty, CompilerDiagnostics, verifier, cancellationToken).ConfigureAwait(false); + var analyzerDiagnostics = await GetSortedDiagnosticsAsync(project.Solution, analyzers, additionalDiagnostics: ImmutableArray<(Project project, Diagnostic diagnostic)>.Empty, CompilerDiagnostics, verifier, cancellationToken).ConfigureAwait(false); if (analyzerDiagnostics.Length == 0) { break; @@ -698,7 +698,7 @@ private async Task VerifyProjectAsync(ProjectState newState, Project project, IV Diagnostic? firstDiagnostic = null; CodeFixProvider? effectiveCodeFixProvider = null; string? equivalenceKey = null; - foreach (var diagnostic in analyzerDiagnostics) + foreach (var (_, diagnostic) in analyzerDiagnostics) { var actions = new List<(CodeAction, CodeFixProvider)>(); @@ -819,7 +819,7 @@ private static async Task GetSourceTextFromDocumentAsync(Document do return await formatted.GetTextAsync(cancellationToken).ConfigureAwait(false); } - private static bool AreDiagnosticsDifferent(ImmutableArray analyzerDiagnostics, ImmutableArray previousDiagnostics) + private static bool AreDiagnosticsDifferent(ImmutableArray<(Project project, Diagnostic diagnostic)> analyzerDiagnostics, ImmutableArray<(Project project, Diagnostic diagnostic)> previousDiagnostics) { if (analyzerDiagnostics.Length != previousDiagnostics.Length) { @@ -828,8 +828,9 @@ private static bool AreDiagnosticsDifferent(ImmutableArray analyzerD for (var i = 0; i < analyzerDiagnostics.Length; i++) { - if ((analyzerDiagnostics[i].Id != previousDiagnostics[i].Id) - || (analyzerDiagnostics[i].Location.SourceSpan != previousDiagnostics[i].Location.SourceSpan)) + if ((analyzerDiagnostics[i].project.Id != previousDiagnostics[i].project.Id) + || (analyzerDiagnostics[i].diagnostic.Id != previousDiagnostics[i].diagnostic.Id) + || (analyzerDiagnostics[i].diagnostic.Location.SourceSpan != previousDiagnostics[i].diagnostic.Location.SourceSpan)) { return true; } diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/TestDiagnosticProvider.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/TestDiagnosticProvider.cs index fb63c41226..07940362d5 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/TestDiagnosticProvider.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/TestDiagnosticProvider.cs @@ -13,22 +13,22 @@ namespace Microsoft.CodeAnalysis.Testing { internal sealed class TestDiagnosticProvider : FixAllContext.DiagnosticProvider { - private readonly ImmutableArray _diagnostics; + private readonly ImmutableArray<(Project project, Diagnostic diagnostic)> _diagnostics; - private TestDiagnosticProvider(ImmutableArray diagnostics) + private TestDiagnosticProvider(ImmutableArray<(Project project, Diagnostic diagnostic)> diagnostics) { _diagnostics = diagnostics; } public override Task> GetAllDiagnosticsAsync(Project project, CancellationToken cancellationToken) - => Task.FromResult>(_diagnostics); + => Task.FromResult>(_diagnostics.Where(diagnostic => diagnostic.project.Id == project.Id).Select(diagnostic => diagnostic.diagnostic)); public override Task> GetDocumentDiagnosticsAsync(Document document, CancellationToken cancellationToken) - => Task.FromResult(_diagnostics.Where(i => i.Location.GetLineSpan().Path == document.Name)); + => Task.FromResult(_diagnostics.Where(i => i.diagnostic.Location.GetLineSpan().Path == document.Name).Where(diagnostic => diagnostic.project.Id == document.Project.Id).Select(diagnostic => diagnostic.diagnostic)); public override Task> GetProjectDiagnosticsAsync(Project project, CancellationToken cancellationToken) - => Task.FromResult(_diagnostics.Where(i => !i.Location.IsInSource)); + => Task.FromResult(_diagnostics.Where(i => !i.diagnostic.Location.IsInSource).Where(diagnostic => diagnostic.project.Id == project.Id).Select(diagnostic => diagnostic.diagnostic)); - internal static TestDiagnosticProvider Create(ImmutableArray diagnostics) => new TestDiagnosticProvider(diagnostics); + internal static TestDiagnosticProvider Create(ImmutableArray<(Project project, Diagnostic diagnostic)> diagnostics) => new TestDiagnosticProvider(diagnostics); } } From 0f5e185a4ed158e4579e72732df6b74356df7846 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 21 Jun 2021 21:20:29 -0700 Subject: [PATCH 58/65] Support TrySelectDiagnosticToFix for Fix All operations --- .../CodeFixTest`1.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs index ff1d2c0650..411b8a0d8b 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs @@ -695,24 +695,35 @@ private async Task VerifyProjectAsync(ProjectState newState, Project project, IV return (project, ExceptionDispatchInfo.Capture(ex)); } + var fixableDiagnostics = analyzerDiagnostics + .Where(diagnostic => codeFixProviders.Any(provider => provider.FixableDiagnosticIds.Contains(diagnostic.diagnostic.Id))) + .Where(diagnostic => project.Solution.GetDocument(diagnostic.diagnostic.Location.SourceTree) is object) + .ToImmutableArray(); + + if (CodeFixTestBehaviors.HasFlag(CodeFixTestBehaviors.FixOne)) + { + var diagnosticToFix = TrySelectDiagnosticToFix(fixableDiagnostics.Select(x => x.diagnostic).ToImmutableArray()); + fixableDiagnostics = diagnosticToFix is object ? ImmutableArray.Create(fixableDiagnostics.Single(x => x.diagnostic == diagnosticToFix)) : ImmutableArray<(Project project, Diagnostic diagnostic)>.Empty; + } + Diagnostic? firstDiagnostic = null; CodeFixProvider? effectiveCodeFixProvider = null; string? equivalenceKey = null; - foreach (var (_, diagnostic) in analyzerDiagnostics) + foreach (var (_, diagnostic) in fixableDiagnostics) { var actions = new List<(CodeAction, CodeFixProvider)>(); + var diagnosticDocument = project.Solution.GetDocument(diagnostic.Location.SourceTree); foreach (var codeFixProvider in codeFixProviders) { - if (!codeFixProvider.FixableDiagnosticIds.Contains(diagnostic.Id) - || !(project.Solution.GetDocument(diagnostic.Location.SourceTree) is { } document)) + if (!codeFixProvider.FixableDiagnosticIds.Contains(diagnostic.Id)) { // do not pass unsupported diagnostics to a code fix provider continue; } var actionsBuilder = ImmutableArray.CreateBuilder(); - var context = new CodeFixContext(document, diagnostic, (a, d) => actionsBuilder.Add(a), cancellationToken); + var context = new CodeFixContext(diagnosticDocument, diagnostic, (a, d) => actionsBuilder.Add(a), cancellationToken); await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false); actions.AddRange(FilterCodeActions(actionsBuilder.ToImmutable()).Select(action => (action, codeFixProvider))); } From b5e84513662f79d0d13439dff1fa95b1b695090f Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Wed, 23 Jun 2021 09:51:58 -0700 Subject: [PATCH 59/65] Only require code fix for first iteration Fixes #874 --- .../CodeActionTest`1.cs | 10 ++- .../PublicAPI.Unshipped.txt | 2 +- .../CodeFixTest`1.cs | 10 ++- .../CodeRefactoringTest`1.cs | 5 +- .../CodeFixIterationTests.cs | 61 +++++++++++++++++++ .../TestAnalyzers/LiteralUnderFiveAnalyzer.cs | 6 +- .../TestFixes/IncrementFix.cs | 2 +- 7 files changed, 88 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/CodeActionTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/CodeActionTest`1.cs index 73f93a6270..e3542db494 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/CodeActionTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/CodeActionTest`1.cs @@ -110,16 +110,22 @@ protected static bool HasAnyChange(ProjectState oldState, ProjectState newState, return false; } - protected static CodeAction? TryGetCodeActionToApply(ImmutableArray actions, int? codeActionIndex, string? codeActionEquivalenceKey, Action? codeActionVerifier, IVerifier verifier) + protected static CodeAction? TryGetCodeActionToApply(int iteration, ImmutableArray actions, int? codeActionIndex, string? codeActionEquivalenceKey, Action? codeActionVerifier, IVerifier verifier) { CodeAction? result; if (codeActionIndex.HasValue && codeActionEquivalenceKey != null) { - if (actions.Length <= codeActionIndex) + var expectedAction = actions.FirstOrDefault(action => action.EquivalenceKey == codeActionEquivalenceKey); + if (expectedAction is null && iteration > 0) { + // No matching code action was found. This is acceptable if this is not the first iteration. return null; } + verifier.True( + actions.Length > codeActionIndex, + $"Expected to find a code action at index '{codeActionIndex}', but only '{actions.Length}' code actions were found."); + verifier.Equal( codeActionEquivalenceKey, actions[codeActionIndex.Value].EquivalenceKey, diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt index 42f6732ca6..f9d4cbf7d7 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt @@ -246,7 +246,7 @@ static Microsoft.CodeAnalysis.Testing.AnalyzerVerifier.VerifyAnalyzerAsync(string source, params Microsoft.CodeAnalysis.Testing.DiagnosticResult[] expected) -> System.Threading.Tasks.Task static Microsoft.CodeAnalysis.Testing.CodeActionTest.CodeActionExpected(Microsoft.CodeAnalysis.Testing.SolutionState state) -> bool static Microsoft.CodeAnalysis.Testing.CodeActionTest.HasAnyChange(Microsoft.CodeAnalysis.Testing.ProjectState oldState, Microsoft.CodeAnalysis.Testing.ProjectState newState, bool recursive) -> bool -static Microsoft.CodeAnalysis.Testing.CodeActionTest.TryGetCodeActionToApply(System.Collections.Immutable.ImmutableArray actions, int? codeActionIndex, string codeActionEquivalenceKey, System.Action codeActionVerifier, Microsoft.CodeAnalysis.Testing.IVerifier verifier) -> Microsoft.CodeAnalysis.CodeActions.CodeAction +static Microsoft.CodeAnalysis.Testing.CodeActionTest.TryGetCodeActionToApply(int iteration, System.Collections.Immutable.ImmutableArray actions, int? codeActionIndex, string codeActionEquivalenceKey, System.Action codeActionVerifier, Microsoft.CodeAnalysis.Testing.IVerifier verifier) -> Microsoft.CodeAnalysis.CodeActions.CodeAction static Microsoft.CodeAnalysis.Testing.DiagnosticResult.CompilerError(string identifier) -> Microsoft.CodeAnalysis.Testing.DiagnosticResult static Microsoft.CodeAnalysis.Testing.DiagnosticResult.CompilerWarning(string identifier) -> Microsoft.CodeAnalysis.Testing.DiagnosticResult static Microsoft.CodeAnalysis.Testing.IVerifierExtensions.EqualOrDiff(this Microsoft.CodeAnalysis.Testing.IVerifier verifier, string expected, string actual, string message = null) -> void diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs index 411b8a0d8b..0bc34d8390 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs @@ -534,9 +534,12 @@ private async Task VerifyProjectAsync(ProjectState newState, Project project, IV var previousDiagnostics = ImmutableArray.Create<(Project project, Diagnostic diagnostic)>(); + var currentIteration = -1; bool done; do { + currentIteration++; + var analyzerDiagnostics = await GetSortedDiagnosticsAsync(project.Solution, analyzers, additionalDiagnostics: ImmutableArray<(Project project, Diagnostic diagnostic)>.Empty, CompilerDiagnostics, verifier, cancellationToken).ConfigureAwait(false); if (analyzerDiagnostics.Length == 0) { @@ -590,7 +593,7 @@ private async Task VerifyProjectAsync(ProjectState newState, Project project, IV } var filteredActions = FilterCodeActions(actions.ToImmutable()); - var actionToApply = TryGetCodeActionToApply(filteredActions, codeFixIndex, codeFixEquivalenceKey, codeActionVerifier, verifier); + var actionToApply = TryGetCodeActionToApply(currentIteration, filteredActions, codeFixIndex, codeFixEquivalenceKey, codeActionVerifier, verifier); if (actionToApply != null) { anyActions = true; @@ -672,9 +675,12 @@ private async Task VerifyProjectAsync(ProjectState newState, Project project, IV var previousDiagnostics = ImmutableArray.Create<(Project project, Diagnostic diagnostic)>(); + var currentIteration = -1; bool done; do { + currentIteration++; + var analyzerDiagnostics = await GetSortedDiagnosticsAsync(project.Solution, analyzers, additionalDiagnostics: ImmutableArray<(Project project, Diagnostic diagnostic)>.Empty, CompilerDiagnostics, verifier, cancellationToken).ConfigureAwait(false); if (analyzerDiagnostics.Length == 0) { @@ -728,7 +734,7 @@ private async Task VerifyProjectAsync(ProjectState newState, Project project, IV actions.AddRange(FilterCodeActions(actionsBuilder.ToImmutable()).Select(action => (action, codeFixProvider))); } - var actionToApply = TryGetCodeActionToApply(actions.Select(a => a.Item1).ToImmutableArray(), codeFixIndex, codeFixEquivalenceKey, codeActionVerifier, verifier); + var actionToApply = TryGetCodeActionToApply(currentIteration, actions.Select(a => a.Item1).ToImmutableArray(), codeFixIndex, codeFixEquivalenceKey, codeActionVerifier, verifier); if (actionToApply != null) { firstDiagnostic = diagnostic; diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs index 80ee3581f0..4aa1ca2bbc 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing/CodeRefactoringTest`1.cs @@ -227,9 +227,12 @@ private async Task VerifyProjectAsync(ProjectState newState, Project project, IV numberOfIterations = -numberOfIterations; } + var currentIteration = -1; bool done; do { + currentIteration++; + try { verifier.True(--numberOfIterations >= -1, "The upper limit for the number of code fix iterations was exceeded"); @@ -253,7 +256,7 @@ private async Task VerifyProjectAsync(ProjectState newState, Project project, IV } var filteredActions = FilterCodeActions(actions.ToImmutable()); - var actionToApply = TryGetCodeActionToApply(filteredActions, codeActionIndex, codeActionEquivalenceKey, codeActionVerifier, verifier); + var actionToApply = TryGetCodeActionToApply(currentIteration, filteredActions, codeActionIndex, codeActionEquivalenceKey, codeActionVerifier, verifier); if (actionToApply != null) { anyActions = true; diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/CodeFixIterationTests.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/CodeFixIterationTests.cs index 5b38386b76..e506741695 100644 --- a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/CodeFixIterationTests.cs +++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/CodeFixIterationTests.cs @@ -395,6 +395,67 @@ class TestClass2 { Assert.Equal($"Context: {context}{Environment.NewLine}Expected '2' iterations but found '1' iterations.", exception.Message); } + [Fact] + [WorkItem(874, "https://github.com/dotnet/roslyn-sdk/issues/874")] + public async Task TestTwoIterationsRequiredButOneApplied() + { + var testCode = @" +class TestClass { + int field = [|3|]; +} +"; + var fixedCode = @" +class TestClass { + int field = [|4|]; +} +"; + + await new CSharpTest + { + TestCode = testCode, + FixedState = + { + Sources = { fixedCode }, + MarkupHandling = MarkupMode.Allow, + }, + CodeActionEquivalenceKey = "IncrementFix:4", + CodeActionIndex = 0, + }.RunAsync(); + } + + [Fact] + [WorkItem(874, "https://github.com/dotnet/roslyn-sdk/issues/874")] + public async Task TestTwoIterationsRequiredButNoneApplied() + { + var testCode = @" +class TestClass { + int field = [|3|]; +} +"; + var fixedCode = @" +class TestClass { + int field = [|4|]; +} +"; + + var exception = await Assert.ThrowsAsync(async () => + { + await new CSharpTest + { + TestCode = testCode, + FixedState = + { + Sources = { fixedCode }, + MarkupHandling = MarkupMode.Allow, + }, + CodeActionEquivalenceKey = "IncrementFix:3", + CodeActionIndex = 0, + }.RunAsync(); + }); + + new DefaultVerifier().EqualOrDiff($"Context: Iterative code fix application{Environment.NewLine}The code action equivalence key and index must be consistent when both are specified.", exception.Message); + } + private class CSharpTest : CSharpCodeFixTest { public int DiagnosticIndexToFix { get; set; } diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestAnalyzers/LiteralUnderFiveAnalyzer.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestAnalyzers/LiteralUnderFiveAnalyzer.cs index 281dd7808a..e852b0a6a9 100644 --- a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestAnalyzers/LiteralUnderFiveAnalyzer.cs +++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestAnalyzers/LiteralUnderFiveAnalyzer.cs @@ -14,6 +14,8 @@ namespace Microsoft.CodeAnalysis.Testing.TestAnalyzers [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] public class LiteralUnderFiveAnalyzer : DiagnosticAnalyzer { + internal const string CurrentValueProperty = nameof(CurrentValueProperty); + internal static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor("LiteralUnderFive", "title", "message", "category", DiagnosticSeverity.Warning, isEnabledByDefault: true); @@ -34,7 +36,9 @@ private void HandleLiteralOperation(OperationAnalysisContext context) && operation.ConstantValue.Value is int value && value < 5) { - context.ReportDiagnostic(Diagnostic.Create(Descriptor, operation.Syntax.GetLocation())); + var properties = ImmutableDictionary.Empty + .Add(CurrentValueProperty, value.ToString()); + context.ReportDiagnostic(Diagnostic.Create(Descriptor, operation.Syntax.GetLocation(), properties)); } } } diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestFixes/IncrementFix.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestFixes/IncrementFix.cs index dadff19f90..f7d0765e8d 100644 --- a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestFixes/IncrementFix.cs +++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestFixes/IncrementFix.cs @@ -31,7 +31,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) CodeAction.Create( "LiteralUnderFive", cancellationToken => CreateChangedDocument(context.Document, diagnostic.Location.SourceSpan, cancellationToken), - nameof(IncrementFix)), + $"{nameof(IncrementFix)}:{int.Parse(diagnostic.Properties[LiteralUnderFiveAnalyzer.CurrentValueProperty]!) + 1}"), diagnostic); } From c3008802d969ae5c7f5eceaa6977a25bccb15ec6 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 28 Jun 2021 10:22:27 -0700 Subject: [PATCH 60/65] Show differences when only end-of-line changes Fixes #876 --- .../Extensions/IVerifierExtensions.cs | 91 ++++++++++++++++++- .../VerifierExtensionsTests.cs | 82 +++++++++++++++++ 2 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/VerifierExtensionsTests.cs diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/Extensions/IVerifierExtensions.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/Extensions/IVerifierExtensions.cs index 0bffc225c2..c433339195 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/Extensions/IVerifierExtensions.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/Extensions/IVerifierExtensions.cs @@ -2,10 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; +using System.Collections.Generic; +using System.Linq; using System.Text; using DiffPlex; using DiffPlex.DiffBuilder; using DiffPlex.DiffBuilder.Model; +using DiffPlex.Model; namespace Microsoft.CodeAnalysis.Testing { @@ -14,6 +18,9 @@ namespace Microsoft.CodeAnalysis.Testing /// public static class IVerifierExtensions { + private static readonly InlineDiffBuilder s_diffWithoutLineEndings = new InlineDiffBuilder(new Differ()); + private static readonly InlineDiffBuilder s_diffWithLineEndings = new InlineDiffBuilder(new DifferWithLineEndings()); + /// /// Asserts that two strings are equal, and prints a diff between the two if they are not. /// @@ -27,14 +34,19 @@ public static void EqualOrDiff(this IVerifier verifier, string expected, string if (expected != actual) { - var diffBuilder = new InlineDiffBuilder(new Differ()); - var diff = diffBuilder.BuildDiffModel(expected, actual, ignoreWhitespace: false); + var diff = s_diffWithoutLineEndings.BuildDiffModel(expected, actual, ignoreWhitespace: false); var messageBuilder = new StringBuilder(); messageBuilder.AppendLine( string.IsNullOrEmpty(message) ? "Actual and expected values differ. Expected shown in baseline of diff:" : message); + if (!diff.Lines.Any(line => line.Type == ChangeType.Inserted || line.Type == ChangeType.Deleted)) + { + // We have a failure only caused by line ending differences; recalculate with line endings visible + diff = s_diffWithLineEndings.BuildDiffModel(expected, actual, ignoreWhitespace: false); + } + foreach (var line in diff.Lines) { switch (line.Type) @@ -56,5 +68,80 @@ public static void EqualOrDiff(this IVerifier verifier, string expected, string verifier.Fail(messageBuilder.ToString()); } } + + private class DifferWithLineEndings : IDiffer + { + private const string CarriageReturnText = ""; + private const string LineFeedText = ""; + + private static readonly char[] s_endOfLineCharacters = { '\r', '\n' }; + private static readonly Differ s_differ = new Differ(); + + public DiffResult CreateCharacterDiffs(string oldText, string newText, bool ignoreWhitespace) + => s_differ.CreateCharacterDiffs(oldText, newText, ignoreWhitespace); + + public DiffResult CreateCharacterDiffs(string oldText, string newText, bool ignoreWhitespace, bool ignoreCase) + => s_differ.CreateCharacterDiffs(oldText, newText, ignoreWhitespace, ignoreCase); + + public DiffResult CreateCustomDiffs(string oldText, string newText, bool ignoreWhiteSpace, Func chunker) + => s_differ.CreateCustomDiffs(oldText, newText, ignoreWhiteSpace, chunker); + + public DiffResult CreateCustomDiffs(string oldText, string newText, bool ignoreWhiteSpace, bool ignoreCase, Func chunker) + => s_differ.CreateCustomDiffs(oldText, newText, ignoreWhiteSpace, ignoreCase, chunker); + + public DiffResult CreateLineDiffs(string oldText, string newText, bool ignoreWhitespace) + => CreateLineDiffs(oldText, newText, ignoreWhitespace, ignoreCase: false); + + public DiffResult CreateLineDiffs(string oldText, string newText, bool ignoreWhitespace, bool ignoreCase) + { + Func chunker = s => + { + var lines = new List(); + + var nextChar = 0; + while (nextChar < s.Length) + { + var nextEol = s.IndexOfAny(s_endOfLineCharacters, nextChar); + if (nextEol == -1) + { + lines.Add(s.Substring(nextChar)); + break; + } + + var currentLine = s.Substring(nextChar, nextEol - nextChar); + + switch (s[nextEol]) + { + case '\r': + currentLine += CarriageReturnText; + if (nextEol < s.Length - 1 && s[nextEol + 1] == '\n') + { + currentLine += LineFeedText; + nextEol++; + } + + break; + + case '\n': + currentLine += LineFeedText; + break; + } + + lines.Add(currentLine); + nextChar = nextEol + 1; + } + + return lines.ToArray(); + }; + + return CreateCustomDiffs(oldText, newText, ignoreWhitespace, ignoreCase, chunker); + } + + public DiffResult CreateWordDiffs(string oldText, string newText, bool ignoreWhitespace, char[] separators) + => s_differ.CreateWordDiffs(oldText, newText, ignoreWhitespace, separators); + + public DiffResult CreateWordDiffs(string oldText, string newText, bool ignoreWhitespace, bool ignoreCase, char[] separators) + => s_differ.CreateWordDiffs(oldText, newText, ignoreWhitespace, ignoreCase, separators); + } } } diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/VerifierExtensionsTests.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/VerifierExtensionsTests.cs new file mode 100644 index 0000000000..eb850de695 --- /dev/null +++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/VerifierExtensionsTests.cs @@ -0,0 +1,82 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Xunit; + +namespace Microsoft.CodeAnalysis.Testing +{ + public class VerifierExtensionsTests + { + [Fact] + [WorkItem(876, "https://github.com/dotnet/roslyn-sdk/issues/876")] + public void VerifyContentWithMixedLineEndings1() + { + var baseline = + "Line 1\r\n" + + "Line 2\r\n" + + "Line 3\r\n" + + "Line 4\r\n" + + "Line 5\r\n" + + "Line 6\r\n"; + var modified = + "Line 1\r" + + "Line 2\r\n" + + "Line 3\n" + + "Line 4\r" + + "Line 5\r\n" + + "Line 6\n"; + + var exception = Assert.Throws(() => new DefaultVerifier().EqualOrDiff(baseline, modified)); + Assert.Equal( + $"Actual and expected values differ. Expected shown in baseline of diff:{Environment.NewLine}" + + $"-Line 1{Environment.NewLine}" + + $"+Line 1{Environment.NewLine}" + + $" Line 2{Environment.NewLine}" + + $"-Line 3{Environment.NewLine}" + + $"-Line 4{Environment.NewLine}" + + $"+Line 3{Environment.NewLine}" + + $"+Line 4{Environment.NewLine}" + + $" Line 5{Environment.NewLine}" + + $"-Line 6{Environment.NewLine}" + + $"+Line 6{Environment.NewLine}", + exception.Message); + } + + [Fact] + [WorkItem(876, "https://github.com/dotnet/roslyn-sdk/issues/876")] + public void VerifyContentWithMixedLineEnding2() + { + var baseline = + "Line 1\n" + + "Line 2\n" + + "Line 3\n" + + "Line 4\n" + + "Line 5\n" + + "Line 6\n"; + var modified = + "Line 1\r" + + "Line 2\r\n" + + "Line 3\n" + + "Line 4\r" + + "Line 5\r\n" + + "Line 6\n"; + + var exception = Assert.Throws(() => new DefaultVerifier().EqualOrDiff(baseline, modified)); + Assert.Equal( + $"Actual and expected values differ. Expected shown in baseline of diff:{Environment.NewLine}" + + $"-Line 1{Environment.NewLine}" + + $"-Line 2{Environment.NewLine}" + + $"+Line 1{Environment.NewLine}" + + $"+Line 2{Environment.NewLine}" + + $" Line 3{Environment.NewLine}" + + $"-Line 4{Environment.NewLine}" + + $"-Line 5{Environment.NewLine}" + + $"+Line 4{Environment.NewLine}" + + $"+Line 5{Environment.NewLine}" + + $" Line 6{Environment.NewLine}", + exception.Message); + } + } +} From 5b0208cadb89fa0783310a8fec2b074a9ebef5f1 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Thu, 1 Jul 2021 12:02:03 -0700 Subject: [PATCH 61/65] update versions to 1.1.1 as per https://github.com/microsoft/vs-threading/pull/875#discussion_r662456811 --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index bdaa950b9e..797e3046cb 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -3,7 +3,7 @@ 3.2.0 - 1.1.0 + 1.1.1 beta1 true From de9af89015295d30088cf95477c9079eb3c3d1b4 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Wed, 21 Jul 2021 15:44:07 -0700 Subject: [PATCH 62/65] Add ReferenceAssemblies.Net.Net60 --- .../PublicAPI.Unshipped.txt | 1 + .../ReferenceAssemblies.cs | 19 +++++++++++++++++++ .../MetadataReferenceTests.cs | 2 ++ 3 files changed, 22 insertions(+) diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt index f9d4cbf7d7..7c946dcb09 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt @@ -252,6 +252,7 @@ static Microsoft.CodeAnalysis.Testing.DiagnosticResult.CompilerWarning(string id static Microsoft.CodeAnalysis.Testing.IVerifierExtensions.EqualOrDiff(this Microsoft.CodeAnalysis.Testing.IVerifier verifier, string expected, string actual, string message = null) -> void static Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.Default.get -> Microsoft.CodeAnalysis.Testing.ReferenceAssemblies static Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.Net.Net50.get -> Microsoft.CodeAnalysis.Testing.ReferenceAssemblies +static Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.Net.Net60.get -> Microsoft.CodeAnalysis.Testing.ReferenceAssemblies static Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.NetCore.NetCoreApp10.get -> Microsoft.CodeAnalysis.Testing.ReferenceAssemblies static Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.NetCore.NetCoreApp11.get -> Microsoft.CodeAnalysis.Testing.ReferenceAssemblies static Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.NetCore.NetCoreApp20.get -> Microsoft.CodeAnalysis.Testing.ReferenceAssemblies diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/ReferenceAssemblies.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/ReferenceAssemblies.cs index 8e085d2134..2ab950247b 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/ReferenceAssemblies.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/ReferenceAssemblies.cs @@ -865,7 +865,26 @@ public static class Net Path.Combine("ref", "net5.0")); }); + private static readonly Lazy _lazyNet60 = + new Lazy(() => + { + if (!NuGetFramework.Parse("net6.0").IsPackageBased) + { + // The NuGet version provided at runtime does not recognize the 'net6.0' target framework + throw new NotSupportedException("The 'net6.0' target framework is not supported by this version of NuGet."); + } + + return new ReferenceAssemblies( + "net6.0", + new PackageIdentity( + "Microsoft.NETCore.App.Ref", + "6.0.0-preview.6.21352.12"), + Path.Combine("ref", "net6.0")); + }); + public static ReferenceAssemblies Net50 => _lazyNet50.Value; + + public static ReferenceAssemblies Net60 => _lazyNet60.Value; } public static class NetStandard diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MetadataReferenceTests.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MetadataReferenceTests.cs index 70f0a47d5a..9a5f501f39 100644 --- a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MetadataReferenceTests.cs +++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MetadataReferenceTests.cs @@ -450,6 +450,7 @@ public async Task ResolveReferenceAssemblies_Net50() [InlineData("netcoreapp3.1")] #if !(NETCOREAPP1_1 || NET46) [InlineData("net5.0")] + [InlineData("net6.0")] #endif [InlineData("netstandard1.0")] [InlineData("netstandard1.1")] @@ -500,6 +501,7 @@ internal static ReferenceAssemblies ReferenceAssembliesForTargetFramework(string "netcoreapp3.0" => ReferenceAssemblies.NetCore.NetCoreApp30, "netcoreapp3.1" => ReferenceAssemblies.NetCore.NetCoreApp31, "net5.0" => ReferenceAssemblies.Net.Net50, + "net6.0" => ReferenceAssemblies.Net.Net60, "netstandard1.0" => ReferenceAssemblies.NetStandard.NetStandard10, "netstandard1.1" => ReferenceAssemblies.NetStandard.NetStandard11, "netstandard1.2" => ReferenceAssemblies.NetStandard.NetStandard12, From 709bfd426f4077b3d65336bbb7342927bbf1c809 Mon Sep 17 00:00:00 2001 From: Richard Melito <69733336+RichardMelito@users.noreply.github.com> Date: Wed, 4 Aug 2021 08:49:21 -0600 Subject: [PATCH 63/65] Added closing slash to analyzer reference XML --- samples/CSharp/SourceGenerators/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/CSharp/SourceGenerators/README.md b/samples/CSharp/SourceGenerators/README.md index fe06c349ef..958cf03f64 100644 --- a/samples/CSharp/SourceGenerators/README.md +++ b/samples/CSharp/SourceGenerators/README.md @@ -28,7 +28,7 @@ You can add the sample generators to your own project by adding an item group co ```xml - + ``` From 6d70e6e47235fe632eca21b3a5dcb00682a6b521 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Fri, 13 Aug 2021 08:20:14 -0700 Subject: [PATCH 64/65] Update to DiffPlex 1.5.0 This version offers an IChunker interface that eliminates the need to reimplement IDiffer entirely. Since the IDiffer interface also changed for the 1.5.0 release, this change avoids errors for users who try to update this dependency in downstream projects. --- eng/Versions.props | 2 +- .../Extensions/IVerifierExtensions.cs | 90 ++----------------- 2 files changed, 8 insertions(+), 84 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index 797e3046cb..24cdd4a44a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -69,7 +69,7 @@ 16.7.30508.193 12.0.4 - 1.4.4 + 1.5.0 2.6.1 3.9.0 diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/Extensions/IVerifierExtensions.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/Extensions/IVerifierExtensions.cs index c433339195..7e0f3d551c 100644 --- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/Extensions/IVerifierExtensions.cs +++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/Extensions/IVerifierExtensions.cs @@ -2,14 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; using System.Linq; using System.Text; using DiffPlex; +using DiffPlex.Chunkers; using DiffPlex.DiffBuilder; using DiffPlex.DiffBuilder.Model; -using DiffPlex.Model; namespace Microsoft.CodeAnalysis.Testing { @@ -18,8 +16,9 @@ namespace Microsoft.CodeAnalysis.Testing /// public static class IVerifierExtensions { - private static readonly InlineDiffBuilder s_diffWithoutLineEndings = new InlineDiffBuilder(new Differ()); - private static readonly InlineDiffBuilder s_diffWithLineEndings = new InlineDiffBuilder(new DifferWithLineEndings()); + private static readonly IChunker s_lineChunker = new LineChunker(); + private static readonly IChunker s_lineEndingsPreservingChunker = new LineEndingsPreservingChunker(); + private static readonly InlineDiffBuilder s_diffBuilder = new InlineDiffBuilder(new Differ()); /// /// Asserts that two strings are equal, and prints a diff between the two if they are not. @@ -34,7 +33,7 @@ public static void EqualOrDiff(this IVerifier verifier, string expected, string if (expected != actual) { - var diff = s_diffWithoutLineEndings.BuildDiffModel(expected, actual, ignoreWhitespace: false); + var diff = s_diffBuilder.BuildDiffModel(expected, actual, ignoreWhitespace: false, ignoreCase: false, s_lineChunker); var messageBuilder = new StringBuilder(); messageBuilder.AppendLine( string.IsNullOrEmpty(message) @@ -44,7 +43,7 @@ public static void EqualOrDiff(this IVerifier verifier, string expected, string if (!diff.Lines.Any(line => line.Type == ChangeType.Inserted || line.Type == ChangeType.Deleted)) { // We have a failure only caused by line ending differences; recalculate with line endings visible - diff = s_diffWithLineEndings.BuildDiffModel(expected, actual, ignoreWhitespace: false); + diff = s_diffBuilder.BuildDiffModel(expected, actual, ignoreWhitespace: false, ignoreCase: false, s_lineEndingsPreservingChunker); } foreach (var line in diff.Lines) @@ -62,86 +61,11 @@ public static void EqualOrDiff(this IVerifier verifier, string expected, string break; } - messageBuilder.AppendLine(line.Text); + messageBuilder.AppendLine(line.Text.Replace("\r", "").Replace("\n", "")); } verifier.Fail(messageBuilder.ToString()); } } - - private class DifferWithLineEndings : IDiffer - { - private const string CarriageReturnText = ""; - private const string LineFeedText = ""; - - private static readonly char[] s_endOfLineCharacters = { '\r', '\n' }; - private static readonly Differ s_differ = new Differ(); - - public DiffResult CreateCharacterDiffs(string oldText, string newText, bool ignoreWhitespace) - => s_differ.CreateCharacterDiffs(oldText, newText, ignoreWhitespace); - - public DiffResult CreateCharacterDiffs(string oldText, string newText, bool ignoreWhitespace, bool ignoreCase) - => s_differ.CreateCharacterDiffs(oldText, newText, ignoreWhitespace, ignoreCase); - - public DiffResult CreateCustomDiffs(string oldText, string newText, bool ignoreWhiteSpace, Func chunker) - => s_differ.CreateCustomDiffs(oldText, newText, ignoreWhiteSpace, chunker); - - public DiffResult CreateCustomDiffs(string oldText, string newText, bool ignoreWhiteSpace, bool ignoreCase, Func chunker) - => s_differ.CreateCustomDiffs(oldText, newText, ignoreWhiteSpace, ignoreCase, chunker); - - public DiffResult CreateLineDiffs(string oldText, string newText, bool ignoreWhitespace) - => CreateLineDiffs(oldText, newText, ignoreWhitespace, ignoreCase: false); - - public DiffResult CreateLineDiffs(string oldText, string newText, bool ignoreWhitespace, bool ignoreCase) - { - Func chunker = s => - { - var lines = new List(); - - var nextChar = 0; - while (nextChar < s.Length) - { - var nextEol = s.IndexOfAny(s_endOfLineCharacters, nextChar); - if (nextEol == -1) - { - lines.Add(s.Substring(nextChar)); - break; - } - - var currentLine = s.Substring(nextChar, nextEol - nextChar); - - switch (s[nextEol]) - { - case '\r': - currentLine += CarriageReturnText; - if (nextEol < s.Length - 1 && s[nextEol + 1] == '\n') - { - currentLine += LineFeedText; - nextEol++; - } - - break; - - case '\n': - currentLine += LineFeedText; - break; - } - - lines.Add(currentLine); - nextChar = nextEol + 1; - } - - return lines.ToArray(); - }; - - return CreateCustomDiffs(oldText, newText, ignoreWhitespace, ignoreCase, chunker); - } - - public DiffResult CreateWordDiffs(string oldText, string newText, bool ignoreWhitespace, char[] separators) - => s_differ.CreateWordDiffs(oldText, newText, ignoreWhitespace, separators); - - public DiffResult CreateWordDiffs(string oldText, string newText, bool ignoreWhitespace, bool ignoreCase, char[] separators) - => s_differ.CreateWordDiffs(oldText, newText, ignoreWhitespace, ignoreCase, separators); - } } } From 35a163bcdb4474e9ea6053b21446bbad094fea9d Mon Sep 17 00:00:00 2001 From: Chris Sienkiewicz Date: Thu, 16 Sep 2021 11:20:45 -0700 Subject: [PATCH 65/65] Update component debugger to work for VS 2022 (#896) Update the component debugger to work in the new launch profiles format introduced in VS2022. See https://github.com/dotnet/project-system/blob/main/docs/repo/property-pages/how-to-add-a-new-launch-profile-kind.md for reference. Removes the old user control, and writing code which is now handled by the rule file (ComponentDebuggerLaunchProfile.xaml). Adds rule exporting and ProvideCodeBase so that VS can find the rule and apply it to matching projects. Tested on VS2022 using an existing launchsettings.json and confirmed projects show the new UI, and can add/remove as needed --- Roslyn-SDK.sln | 13 ++- eng/Versions.props | 5 +- .../AssemblyVersionGenerator.cs | 24 +++++ .../AssemblyVersionGenerator.csproj | 13 +++ .../ComponentDebuggerLaunchProfile.xaml | 43 ++++++++ .../ComponentDebugger/DebuggerOptions.xaml | 19 ---- .../ComponentDebugger/DebuggerOptions.xaml.cs | 14 --- .../DebuggerOptionsViewModel.cs | 61 ----------- .../LaunchSettingsManager.cs | 17 --- .../LaunchSettingsProvider.cs | 101 ------------------ .../ComponentDebugger/ProjectUtilities.cs | 28 +++++ .../Roslyn.ComponentDebugger.csproj | 18 +++- .../ComponentDebugger/RuleExporter.cs | 24 +++++ .../TargetProjectEnumProvider.cs | 67 ++++++++++++ ...ComponentDebuggerLaunchProfile.xaml.cs.xlf | 32 ++++++ ...ComponentDebuggerLaunchProfile.xaml.de.xlf | 32 ++++++ ...ComponentDebuggerLaunchProfile.xaml.es.xlf | 32 ++++++ ...ComponentDebuggerLaunchProfile.xaml.fr.xlf | 32 ++++++ ...ComponentDebuggerLaunchProfile.xaml.it.xlf | 32 ++++++ ...ComponentDebuggerLaunchProfile.xaml.ja.xlf | 32 ++++++ ...ComponentDebuggerLaunchProfile.xaml.ko.xlf | 32 ++++++ ...ComponentDebuggerLaunchProfile.xaml.pl.xlf | 32 ++++++ ...ponentDebuggerLaunchProfile.xaml.pt-BR.xlf | 32 ++++++ ...ComponentDebuggerLaunchProfile.xaml.ru.xlf | 32 ++++++ ...ComponentDebuggerLaunchProfile.xaml.tr.xlf | 32 ++++++ ...nentDebuggerLaunchProfile.xaml.zh-Hans.xlf | 32 ++++++ ...nentDebuggerLaunchProfile.xaml.zh-Hant.xlf | 32 ++++++ .../Roslyn.SDK/Properties/AssemblyInfo.cs | 1 + .../Roslyn.SDK/Roslyn.SDK.csproj | 4 +- 29 files changed, 648 insertions(+), 220 deletions(-) create mode 100644 src/VisualStudio.Roslyn.SDK/AssemblyVersionGenerator/AssemblyVersionGenerator.cs create mode 100644 src/VisualStudio.Roslyn.SDK/AssemblyVersionGenerator/AssemblyVersionGenerator.csproj create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/ComponentDebuggerLaunchProfile.xaml delete mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptions.xaml delete mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptions.xaml.cs delete mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptionsViewModel.cs delete mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/LaunchSettingsProvider.cs create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/RuleExporter.cs create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/TargetProjectEnumProvider.cs create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.cs.xlf create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.de.xlf create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.es.xlf create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.fr.xlf create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.it.xlf create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ja.xlf create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ko.xlf create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.pl.xlf create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.pt-BR.xlf create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ru.xlf create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.tr.xlf create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.zh-Hans.xlf create mode 100644 src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.zh-Hant.xlf diff --git a/Roslyn-SDK.sln b/Roslyn-SDK.sln index ef1484fb0b..ae7e94b1b3 100644 --- a/Roslyn-SDK.sln +++ b/Roslyn-SDK.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29814.53 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31706.66 MinimumVisualStudioVersion = 15.0.26124.0 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{924F7971-780C-4E70-A306-86482469502E}" EndProject @@ -191,6 +191,10 @@ Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "Microsoft.CodeAnalysis.Visu EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roslyn.ComponentDebugger", "src\VisualStudio.Roslyn.SDK\ComponentDebugger\Roslyn.ComponentDebugger.csproj", "{421DE59C-8246-4679-9D69-79F16A7187BE}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "util", "util", "{7A94E723-ADD6-48C4-BBE7-1D5B311187A8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyVersionGenerator", "src\VisualStudio.Roslyn.SDK\AssemblyVersionGenerator\AssemblyVersionGenerator.csproj", "{AB6B3C69-9F6F-461C-BFD8-D3F25B9F44AD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -545,6 +549,10 @@ Global {421DE59C-8246-4679-9D69-79F16A7187BE}.Debug|Any CPU.Build.0 = Debug|Any CPU {421DE59C-8246-4679-9D69-79F16A7187BE}.Release|Any CPU.ActiveCfg = Release|Any CPU {421DE59C-8246-4679-9D69-79F16A7187BE}.Release|Any CPU.Build.0 = Release|Any CPU + {AB6B3C69-9F6F-461C-BFD8-D3F25B9F44AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB6B3C69-9F6F-461C-BFD8-D3F25B9F44AD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB6B3C69-9F6F-461C-BFD8-D3F25B9F44AD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB6B3C69-9F6F-461C-BFD8-D3F25B9F44AD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -642,6 +650,7 @@ Global {7C3FE60E-055B-4E0C-BB85-C7E94A640074} = {9905147E-CC1F-42A0-BD27-05586C583DF7} {92BD1781-5DB4-4F72-BCCB-0D64C0790A2B} = {9905147E-CC1F-42A0-BD27-05586C583DF7} {421DE59C-8246-4679-9D69-79F16A7187BE} = {F9B73995-76C6-4056-ADA9-18342F951361} + {AB6B3C69-9F6F-461C-BFD8-D3F25B9F44AD} = {7A94E723-ADD6-48C4-BBE7-1D5B311187A8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {56695AA9-EA80-47A7-8562-E51285906C54} diff --git a/eng/Versions.props b/eng/Versions.props index 24cdd4a44a..f377a207d2 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -38,8 +38,9 @@ 16.8.30705.32 16.8.30406.65-pre 16.8.239 - 16.8.1-beta1-1008-05 - 16.8.1-beta1-1008-05 + 16.8.1-beta1-1008-05 + 16.8.1-beta1-1008-05 + 16.8.338-pre 16.9.23-alpha 16.7.9 16.7.30329.88 diff --git a/src/VisualStudio.Roslyn.SDK/AssemblyVersionGenerator/AssemblyVersionGenerator.cs b/src/VisualStudio.Roslyn.SDK/AssemblyVersionGenerator/AssemblyVersionGenerator.cs new file mode 100644 index 0000000000..84d9616380 --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/AssemblyVersionGenerator/AssemblyVersionGenerator.cs @@ -0,0 +1,24 @@ +using System; +using System.Diagnostics; +using Microsoft.CodeAnalysis; + +namespace AssemblyVersionGenerator +{ + [Generator] + public class AssemblyVersionGenerator : ISourceGenerator + { + public void Execute(GeneratorExecutionContext context) + { + context.AddSource("assemblyversion.g.cs", $@" + +internal class AssemblyVersion +{{ + public const string Version = ""{context.Compilation.Assembly.Identity.Version}""; +}}"); + } + + public void Initialize(GeneratorInitializationContext context) + { + } + } +} diff --git a/src/VisualStudio.Roslyn.SDK/AssemblyVersionGenerator/AssemblyVersionGenerator.csproj b/src/VisualStudio.Roslyn.SDK/AssemblyVersionGenerator/AssemblyVersionGenerator.csproj new file mode 100644 index 0000000000..6d0e593f4b --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/AssemblyVersionGenerator/AssemblyVersionGenerator.csproj @@ -0,0 +1,13 @@ + + + + netstandard2.0 + enable + true + + + + + + + diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/ComponentDebuggerLaunchProfile.xaml b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/ComponentDebuggerLaunchProfile.xaml new file mode 100644 index 0000000000..656b12969f --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/ComponentDebuggerLaunchProfile.xaml @@ -0,0 +1,43 @@ + + + + + DebugRoslynComponent + + + AE27A6B0-E345-4288-96DF-5EAF394EE369 + + + 3644 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptions.xaml b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptions.xaml deleted file mode 100644 index b431658e46..0000000000 --- a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptions.xaml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptions.xaml.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptions.xaml.cs deleted file mode 100644 index 56459afeba..0000000000 --- a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptions.xaml.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Roslyn.ComponentDebugger -{ - partial class DebuggerOptions - { - public DebuggerOptions() - { - InitializeComponent(); - } - } -} diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptionsViewModel.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptionsViewModel.cs deleted file mode 100644 index 180012a97e..0000000000 --- a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptionsViewModel.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.ComponentModel; -using System.Linq; -using System.Runtime.CompilerServices; - -namespace Roslyn.ComponentDebugger -{ - internal sealed class DebuggerOptionsViewModel : INotifyPropertyChanged - { - private readonly Action _indexChanged; - - private IEnumerable _projectNames = ImmutableArray.Empty; - - private int _selectedProjectIndex = -1; - - public event PropertyChangedEventHandler? PropertyChanged; - - public DebuggerOptionsViewModel(Action indexChanged) - { - _indexChanged = indexChanged; - } - - public IEnumerable ProjectNames - { - get => _projectNames; - set - { - if (!_projectNames.SequenceEqual(value)) - { - _projectNames = value; - NotifyPropertyChanged(); - } - } - } - - public int SelectedProjectIndex - { - get => _selectedProjectIndex; - set - { - if (_selectedProjectIndex != value) - { - _selectedProjectIndex = value; - NotifyPropertyChanged(); - _indexChanged?.Invoke(value); - } - } - } - - private void NotifyPropertyChanged([CallerMemberName]string propertyName = "") - { - this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - } -} diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/LaunchSettingsManager.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/LaunchSettingsManager.cs index 6d9c972364..44a5d49a20 100644 --- a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/LaunchSettingsManager.cs +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/LaunchSettingsManager.cs @@ -38,22 +38,5 @@ public LaunchSettingsManager(UnconfiguredProject owningProject, IDebugTokenRepla } return targetProject; } - - public void WriteProjectForLaunch(IWritableLaunchProfile profile, UnconfiguredProject targetProject) - { - if (profile is null) - { - throw new System.ArgumentNullException(nameof(profile)); - } - - if (targetProject is null) - { - throw new System.ArgumentNullException(nameof(targetProject)); - } - - var rootedPath = _owningProject.MakeRelative(targetProject.FullPath); - profile.OtherSettings[Constants.TargetProjectKeyName] = rootedPath; - } - } } diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/LaunchSettingsProvider.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/LaunchSettingsProvider.cs deleted file mode 100644 index 43b54a2d7f..0000000000 --- a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/LaunchSettingsProvider.cs +++ /dev/null @@ -1,101 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Immutable; -using System.ComponentModel.Composition; -using System.IO; -using System.Linq; -using System.Windows.Controls; -using Microsoft.VisualStudio.ProjectSystem; -using Microsoft.VisualStudio.ProjectSystem.Debug; -using Microsoft.VisualStudio.Utilities; -using Task = System.Threading.Tasks.Task; - -namespace Roslyn.ComponentDebugger -{ - [Export(typeof(ILaunchSettingsUIProvider))] - [AppliesTo(Constants.RoslynComponentCapability)] - public class LaunchSettingsProvider : ILaunchSettingsUIProvider - { - private readonly IProjectThreadingService _threadingService; - private readonly UnconfiguredProject _unconfiguredProject; - private readonly LaunchSettingsManager _launchSettingsManager; - private readonly DebuggerOptionsViewModel _viewModel; - - private ImmutableArray _projects; - private IWritableLaunchProfile? _launchProfile; - - [ImportingConstructor] - [Obsolete("This exported object must be obtained through the MEF export provider.", error: true)] - public LaunchSettingsProvider(IProjectThreadingService threadingService, UnconfiguredProject unconfiguredProject, LaunchSettingsManager launchSettingsManager) - { - _threadingService = threadingService; - _unconfiguredProject = unconfiguredProject; - _launchSettingsManager = launchSettingsManager; - _viewModel = new DebuggerOptionsViewModel(IndexChanged); - } - - public string CommandName { get => Constants.CommandName; } - - // https://github.com/dotnet/roslyn-sdk/issues/730 : localization - public string FriendlyName { get => "Roslyn Component"; } - - public UserControl? CustomUI { get => new DebuggerOptions() { DataContext = _viewModel }; } - - public void ProfileSelected(IWritableLaunchSettings curSettings) - { - _launchProfile = curSettings?.ActiveProfile; - _threadingService.ExecuteSynchronously(UpdateViewModelAsync); - } - - public bool ShouldEnableProperty(string propertyName) - { - // we disable all the default options for a debugger. - // in the future we might want to enable env vars and (potentially) the exe to allow - // customization of the compiler used? - return false; - } - - private async Task UpdateViewModelAsync() - { - var targetProjects = ArrayBuilder.GetInstance(); - - // get the output assembly for this project - var projectArgs = await _unconfiguredProject.GetCompilationArgumentsAsync().ConfigureAwait(false); - var targetArg = projectArgs.LastOrDefault(a => a.StartsWith("/out:", StringComparison.OrdinalIgnoreCase)); - var target = Path.GetFileName(targetArg); - - var projectService = _unconfiguredProject.Services.ProjectService; - foreach (var targetProjectUnconfigured in projectService.LoadedUnconfiguredProjects) - { - // check if the args contain the project as an analyzer ref - foreach (var arg in await targetProjectUnconfigured.GetCompilationArgumentsAsync().ConfigureAwait(false)) - { - if (arg.StartsWith("/analyzer:", StringComparison.OrdinalIgnoreCase) - && arg.EndsWith(target, StringComparison.OrdinalIgnoreCase)) - { - targetProjects.Add(targetProjectUnconfigured); - } - } - } - _projects = targetProjects.ToImmutableAndFree(); - - var launchTargetProject = await _launchSettingsManager.TryGetProjectForLaunchAsync(_launchProfile?.ToLaunchProfile()).ConfigureAwait(true); - var index = _projects.IndexOf(launchTargetProject!); - - _viewModel.ProjectNames = _projects.Select(p => Path.GetFileNameWithoutExtension(p.FullPath)); - _viewModel.SelectedProjectIndex = index; - } - - private void IndexChanged(int newIndex) - { - if (_launchProfile is object && !_projects.IsDefaultOrEmpty && newIndex >= 0 && newIndex < _projects.Length) - { - var project = _projects[newIndex]; - _launchSettingsManager.WriteProjectForLaunch(_launchProfile, project); - } - } - } -} diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/ProjectUtilities.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/ProjectUtilities.cs index b20cc31159..4c2a4a7696 100644 --- a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/ProjectUtilities.cs +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/ProjectUtilities.cs @@ -4,13 +4,41 @@ using System; using System.Collections.Immutable; +using System.IO; +using System.Linq; using System.Threading.Tasks; using Microsoft.VisualStudio.ProjectSystem; +using Microsoft.VisualStudio.Utilities; namespace Roslyn.ComponentDebugger { public static class ProjectUtilities { + public static async Task> GetComponentReferencingProjectsAsync(this UnconfiguredProject unconfiguredProject) + { + var targetProjects = ArrayBuilder.GetInstance(); + + // get the output assembly for this project + var projectArgs = await unconfiguredProject.GetCompilationArgumentsAsync().ConfigureAwait(false); + var targetArg = projectArgs.LastOrDefault(a => a.StartsWith("/out:", StringComparison.OrdinalIgnoreCase)); + var target = Path.GetFileName(targetArg); + + var projectService = unconfiguredProject.Services.ProjectService; + foreach (var targetProjectUnconfigured in projectService.LoadedUnconfiguredProjects) + { + // check if the args contain the project as an analyzer ref + foreach (var arg in await targetProjectUnconfigured.GetCompilationArgumentsAsync().ConfigureAwait(false)) + { + if (arg.StartsWith("/analyzer:", StringComparison.OrdinalIgnoreCase) + && arg.EndsWith(target, StringComparison.OrdinalIgnoreCase)) + { + targetProjects.Add(targetProjectUnconfigured); + } + } + } + return targetProjects.ToImmutableAndFree(); + } + public static Task> GetCompilationArgumentsAsync(this UnconfiguredProject project) { if (project is null) diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj index c64c4c359d..70a2846652 100644 --- a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj @@ -8,13 +8,27 @@ enable true + + + + Never + MSBuild:GenerateRuleSourceFromXaml + Designer + None + None + + + + + - - + + + diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/RuleExporter.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/RuleExporter.cs new file mode 100644 index 0000000000..38382da9fa --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/RuleExporter.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.VisualStudio.ProjectSystem; +using Microsoft.VisualStudio.ProjectSystem.Properties; + +namespace Roslyn.ComponentDebugger +{ + internal static class RuleExporter + { + /// + /// Used to export the XAML rule via MEF + /// + [ExportPropertyXamlRuleDefinition( + xamlResourceAssemblyName: "Roslyn.ComponentDebugger, Version=" + AssemblyVersion.Version + ", Culture=neutral, PublicKeyToken=31bf3856ad364e35", + xamlResourceStreamName: "XamlRuleToCode:ComponentDebuggerLaunchProfile.xaml", + context: PropertyPageContexts.Project)] + [AppliesTo(Constants.RoslynComponentCapability)] +#pragma warning disable CS0649 + public static int LaunchProfileRule; +#pragma warning restore CS0649 + } +} diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/TargetProjectEnumProvider.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/TargetProjectEnumProvider.cs new file mode 100644 index 0000000000..23582bd2ac --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/TargetProjectEnumProvider.cs @@ -0,0 +1,67 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.ComponentModel.Composition; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Build.Framework.XamlTypes; +using Microsoft.VisualStudio.ProjectSystem; +using Microsoft.VisualStudio.ProjectSystem.Properties; + +namespace Roslyn.ComponentDebugger +{ + [ExportDynamicEnumValuesProvider(nameof(TargetProjectEnumProvider))] + [AppliesTo(Constants.RoslynComponentCapability)] + public class TargetProjectEnumProvider : IDynamicEnumValuesProvider + { + private readonly UnconfiguredProject _unconfiguredProject; + private readonly LaunchSettingsManager _launchSettingsManager; + + [ImportingConstructor] + public TargetProjectEnumProvider(UnconfiguredProject unconfiguredProject, LaunchSettingsManager launchSettingsManager) + { + _unconfiguredProject = unconfiguredProject; + _launchSettingsManager = launchSettingsManager; + } + + public async Task GetProviderAsync(IList? options) + { + // get the targets for this project + var projects = await _unconfiguredProject.GetComponentReferencingProjectsAsync().ConfigureAwait(false); + + // convert to display values of friendly name + relative path + var displayValues = projects.Select(p => (Path.GetFileNameWithoutExtension(p.FullPath), _unconfiguredProject.MakeRelative(p.FullPath))).ToImmutableArray(); + + return new TargetProjectEnumValuesGenerator(displayValues); + } + + private class TargetProjectEnumValuesGenerator : IDynamicEnumValuesGenerator + { + private readonly ImmutableArray<(string display, string path)> _referencingProjects; + + public bool AllowCustomValues => false; + + public TargetProjectEnumValuesGenerator(ImmutableArray<(string display, string path)> referencingProjects) + { + _referencingProjects = referencingProjects; + } + + public Task> GetListedValuesAsync() + { + var values = _referencingProjects.Select(p => new PageEnumValue(new EnumValue() { DisplayName = p.display, Name = p.path})).Cast().ToImmutableArray(); + return Task.FromResult>(values); + } + + /// + /// The user can't add arbitrary projects from the UI, so this is unsupported + /// + public Task TryCreateEnumValueAsync(string userSuppliedValue) => Task.FromResult(null); + } + } +} diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.cs.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.cs.xlf new file mode 100644 index 0000000000..70107d3d75 --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.cs.xlf @@ -0,0 +1,32 @@ + + + + + + A project that uses this component, whose compilation will be debugged. + A project that uses this component, whose compilation will be debugged. + + + + Target Project + Target Project + + + + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + + + + Roslyn Component + Roslyn Component + + + + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + + + + + \ No newline at end of file diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.de.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.de.xlf new file mode 100644 index 0000000000..3f73ba68ae --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.de.xlf @@ -0,0 +1,32 @@ + + + + + + A project that uses this component, whose compilation will be debugged. + A project that uses this component, whose compilation will be debugged. + + + + Target Project + Target Project + + + + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + + + + Roslyn Component + Roslyn Component + + + + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + + + + + \ No newline at end of file diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.es.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.es.xlf new file mode 100644 index 0000000000..49696eefb1 --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.es.xlf @@ -0,0 +1,32 @@ + + + + + + A project that uses this component, whose compilation will be debugged. + A project that uses this component, whose compilation will be debugged. + + + + Target Project + Target Project + + + + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + + + + Roslyn Component + Roslyn Component + + + + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + + + + + \ No newline at end of file diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.fr.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.fr.xlf new file mode 100644 index 0000000000..b0ad7e720f --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.fr.xlf @@ -0,0 +1,32 @@ + + + + + + A project that uses this component, whose compilation will be debugged. + A project that uses this component, whose compilation will be debugged. + + + + Target Project + Target Project + + + + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + + + + Roslyn Component + Roslyn Component + + + + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + + + + + \ No newline at end of file diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.it.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.it.xlf new file mode 100644 index 0000000000..6e9993b18f --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.it.xlf @@ -0,0 +1,32 @@ + + + + + + A project that uses this component, whose compilation will be debugged. + A project that uses this component, whose compilation will be debugged. + + + + Target Project + Target Project + + + + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + + + + Roslyn Component + Roslyn Component + + + + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + + + + + \ No newline at end of file diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ja.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ja.xlf new file mode 100644 index 0000000000..38b0fc455c --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ja.xlf @@ -0,0 +1,32 @@ + + + + + + A project that uses this component, whose compilation will be debugged. + A project that uses this component, whose compilation will be debugged. + + + + Target Project + Target Project + + + + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + + + + Roslyn Component + Roslyn Component + + + + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + + + + + \ No newline at end of file diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ko.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ko.xlf new file mode 100644 index 0000000000..55caf820f5 --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ko.xlf @@ -0,0 +1,32 @@ + + + + + + A project that uses this component, whose compilation will be debugged. + A project that uses this component, whose compilation will be debugged. + + + + Target Project + Target Project + + + + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + + + + Roslyn Component + Roslyn Component + + + + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + + + + + \ No newline at end of file diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.pl.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.pl.xlf new file mode 100644 index 0000000000..d623a39530 --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.pl.xlf @@ -0,0 +1,32 @@ + + + + + + A project that uses this component, whose compilation will be debugged. + A project that uses this component, whose compilation will be debugged. + + + + Target Project + Target Project + + + + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + + + + Roslyn Component + Roslyn Component + + + + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + + + + + \ No newline at end of file diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.pt-BR.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.pt-BR.xlf new file mode 100644 index 0000000000..d93d99696e --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.pt-BR.xlf @@ -0,0 +1,32 @@ + + + + + + A project that uses this component, whose compilation will be debugged. + A project that uses this component, whose compilation will be debugged. + + + + Target Project + Target Project + + + + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + + + + Roslyn Component + Roslyn Component + + + + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + + + + + \ No newline at end of file diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ru.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ru.xlf new file mode 100644 index 0000000000..5890416c89 --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ru.xlf @@ -0,0 +1,32 @@ + + + + + + A project that uses this component, whose compilation will be debugged. + A project that uses this component, whose compilation will be debugged. + + + + Target Project + Target Project + + + + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + + + + Roslyn Component + Roslyn Component + + + + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + + + + + \ No newline at end of file diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.tr.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.tr.xlf new file mode 100644 index 0000000000..8c8db3e8f0 --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.tr.xlf @@ -0,0 +1,32 @@ + + + + + + A project that uses this component, whose compilation will be debugged. + A project that uses this component, whose compilation will be debugged. + + + + Target Project + Target Project + + + + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + + + + Roslyn Component + Roslyn Component + + + + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + + + + + \ No newline at end of file diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.zh-Hans.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.zh-Hans.xlf new file mode 100644 index 0000000000..1e3273ef37 --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.zh-Hans.xlf @@ -0,0 +1,32 @@ + + + + + + A project that uses this component, whose compilation will be debugged. + A project that uses this component, whose compilation will be debugged. + + + + Target Project + Target Project + + + + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + + + + Roslyn Component + Roslyn Component + + + + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + + + + + \ No newline at end of file diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.zh-Hant.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.zh-Hant.xlf new file mode 100644 index 0000000000..5720b1a0cc --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.zh-Hant.xlf @@ -0,0 +1,32 @@ + + + + + + A project that uses this component, whose compilation will be debugged. + A project that uses this component, whose compilation will be debugged. + + + + Target Project + Target Project + + + + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + Allows a user to debug a Roslyn Component by running it in the context of another projects build. + + + + Roslyn Component + Roslyn Component + + + + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list. + + + + + \ No newline at end of file diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Properties/AssemblyInfo.cs b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Properties/AssemblyInfo.cs index 6ccb8544f7..710a6f0cb6 100644 --- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Properties/AssemblyInfo.cs +++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Properties/AssemblyInfo.cs @@ -5,3 +5,4 @@ using Microsoft.VisualStudio.Shell; [assembly: ProvideBindingRedirection(CodeBase = "Roslyn.SDK.Template.Wizard.dll", OldVersionLowerBound = "1.0.0.0")] +[assembly: ProvideCodeBase(AssemblyName = "Roslyn.ComponentDebugger", CodeBase = "$PackageFolder$\\Roslyn.ComponentDebugger.dll")] diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Roslyn.SDK.csproj b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Roslyn.SDK.csproj index 370c4ea744..13601d250e 100644 --- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Roslyn.SDK.csproj +++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Roslyn.SDK.csproj @@ -122,8 +122,8 @@ Roslyn.ComponentDebugger - BuiltProjectOutputGroup%3bGetCopyToOutputDirectoryItems%3b - DebugSymbolsProjectOutputGroup%3b + BuiltProjectOutputGroup%3bGetCopyToOutputDirectoryItems + DebugSymbolsProjectOutputGroup true false