diff --git a/eng/tools/RepoTasks/CreateFrameworkListFile.cs b/eng/tools/RepoTasks/CreateFrameworkListFile.cs
index 0ac46a87c12a..8005f81f65fe 100644
--- a/eng/tools/RepoTasks/CreateFrameworkListFile.cs
+++ b/eng/tools/RepoTasks/CreateFrameworkListFile.cs
@@ -57,12 +57,35 @@ public override bool Execute()
(f.Filename.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) || f.IsNative))
.OrderBy(f => f.Filename, StringComparer.Ordinal))
{
- var element = new XElement(
- "File",
- new XAttribute("Type", f.IsNative ? "Native" : "Managed"),
- new XAttribute(
- "Path",
- Path.Combine(f.PackagePath, f.Filename).Replace('\\', '/')));
+ string path = Path.Combine(f.PackagePath, f.Filename).Replace('\\', '/');
+ string type = f.IsNative ? "Native" : "Managed";
+ var element = new XElement("File", new XAttribute("Path", path));
+
+ if (path.StartsWith("analyzers/", StringComparison.Ordinal))
+ {
+ type = "Analyzer";
+
+ if (path.EndsWith(".resources.dll", StringComparison.Ordinal))
+ {
+ // omit analyzer resources
+ continue;
+ }
+
+ var pathParts = path.Split('/');
+
+ if (pathParts.Length < 3 || !pathParts[1].Equals("dotnet", StringComparison.Ordinal) || pathParts.Length > 4)
+ {
+ Log.LogError($"Unexpected analyzer path format {path}. Expected 'analyzers/dotnet(/language)/analyzer.dll");
+ }
+
+ // Check if we have enough parts for language directory and include it
+ if (pathParts.Length > 3)
+ {
+ element.Add(new XAttribute("Language", pathParts[2]));
+ }
+ }
+
+ element.Add(new XAttribute("Type", type));
if (f.AssemblyName != null)
{
diff --git a/src/Framework/App.Ref/src/Microsoft.AspNetCore.App.Ref.csproj b/src/Framework/App.Ref/src/Microsoft.AspNetCore.App.Ref.csproj
index ebb7fe041e60..43eba091547f 100644
--- a/src/Framework/App.Ref/src/Microsoft.AspNetCore.App.Ref.csproj
+++ b/src/Framework/App.Ref/src/Microsoft.AspNetCore.App.Ref.csproj
@@ -164,6 +164,9 @@ This package is an internal implementation of the .NET Core SDK and is not meant
Include="@(AspNetCoreReferenceAssemblyPath->WithMetadataValue('ExternallyResolved', 'true')->'%(RootDir)%(Directory)%(Filename).xml')"
Condition="Exists('%(RootDir)%(Directory)%(Filename).xml')" />
+ <_AnalyzerContent Include="$(PkgMicrosoft_AspNetCore_Internal_Transport)\$(AnalyzersPackagePath)**\*.*" />
+
+
diff --git a/src/Framework/Directory.Build.props b/src/Framework/Directory.Build.props
index 11d96a6864b7..4533e3e5e1be 100644
--- a/src/Framework/Directory.Build.props
+++ b/src/Framework/Directory.Build.props
@@ -3,6 +3,7 @@
data/
+ analyzers/
PlatformManifest.txt
$(ArtifactsObjDir)$(PlatformManifestFileName)
diff --git a/src/Framework/test/TargetingPackTests.cs b/src/Framework/test/TargetingPackTests.cs
index 5f34153949c5..99b43ca08ee3 100644
--- a/src/Framework/test/TargetingPackTests.cs
+++ b/src/Framework/test/TargetingPackTests.cs
@@ -200,7 +200,7 @@ public void AssembliesAreReferenceAssemblies()
return;
}
- IEnumerable dlls = Directory.GetFiles(_targetingPackRoot, "*.dll", SearchOption.AllDirectories);
+ IEnumerable dlls = Directory.GetFiles(Path.Combine(_targetingPackRoot, "ref"), "*.dll", SearchOption.AllDirectories);
Assert.NotEmpty(dlls);
Assert.All(dlls, path =>
@@ -312,32 +312,48 @@ public void FrameworkListListsContainsCorrectEntries()
var frameworkListDoc = XDocument.Load(frameworkListPath);
var frameworkListEntries = frameworkListDoc.Root.Descendants();
+ var managedEntries = frameworkListEntries.Where(i => i.Attribute("Type").Value.Equals("Managed", StringComparison.Ordinal));
+ var analyzerEntries = frameworkListEntries.Where(i => i.Attribute("Type").Value.Equals("Analyzer", StringComparison.Ordinal));
- _output.WriteLine("==== file contents ====");
- _output.WriteLine(string.Join('\n', frameworkListEntries.Select(i => i.Attribute("AssemblyName").Value).OrderBy(i => i)));
- _output.WriteLine("==== expected assemblies ====");
- _output.WriteLine(string.Join('\n', expectedAssemblies.OrderBy(i => i)));
-
- var actualAssemblies = frameworkListEntries
- .Select(i =>
- {
- var fileName = i.Attribute("AssemblyName").Value;
- return fileName.EndsWith(".dll", StringComparison.Ordinal)
- ? fileName.Substring(0, fileName.Length - 4)
- : fileName;
- })
- .ToHashSet();
+ var analyzersDir = Path.Combine(_targetingPackRoot, "analyzers");
+ var expectedAnalyzers = Directory.Exists(analyzersDir) ?
+ Directory.GetFiles(analyzersDir, "*.dll", SearchOption.AllDirectories)
+ .Select(p => Path.GetFileNameWithoutExtension(p))
+ .Where(f => !f.EndsWith(".resources", StringComparison.OrdinalIgnoreCase))
+ .ToHashSet() :
+ new HashSet();
- var missing = expectedAssemblies.Except(actualAssemblies);
- var unexpected = actualAssemblies.Except(expectedAssemblies);
-
- _output.WriteLine("==== missing assemblies from the framework list ====");
- _output.WriteLine(string.Join('\n', missing));
- _output.WriteLine("==== unexpected assemblies in the framework list ====");
- _output.WriteLine(string.Join('\n', unexpected));
+ CompareFrameworkElements(expectedAssemblies, managedEntries, "managed");
+ CompareFrameworkElements(expectedAnalyzers, analyzerEntries, "analyzer");
- Assert.Empty(missing);
- Assert.Empty(unexpected);
+ void CompareFrameworkElements(HashSet expectedAssemblyNames, IEnumerable actualElements, string type)
+ {
+ _output.WriteLine($"==== file contents ({type}) ====");
+ _output.WriteLine(string.Join('\n', actualElements.Select(i => i.Attribute("AssemblyName").Value).OrderBy(i => i)));
+ _output.WriteLine($"==== expected {type} assemblies ====");
+ _output.WriteLine(string.Join('\n', expectedAssemblyNames.OrderBy(i => i)));
+
+ var actualAssemblyNames = managedEntries
+ .Select(i =>
+ {
+ var fileName = i.Attribute("AssemblyName").Value;
+ return fileName.EndsWith(".dll", StringComparison.Ordinal)
+ ? fileName.Substring(0, fileName.Length - 4)
+ : fileName;
+ })
+ .ToHashSet();
+
+ var missing = actualAssemblyNames.Except(actualAssemblyNames);
+ var unexpected = actualAssemblyNames.Except(expectedAssemblies);
+
+ _output.WriteLine($"==== missing {type} assemblies from the framework list ====");
+ _output.WriteLine(string.Join('\n', missing));
+ _output.WriteLine($"==== unexpected {type} assemblies in the framework list ====");
+ _output.WriteLine(string.Join('\n', unexpected));
+
+ Assert.Empty(missing);
+ Assert.Empty(unexpected);
+ }
Assert.All(frameworkListEntries, i =>
{
@@ -370,7 +386,7 @@ public void FrameworkListListsContainsCorrectPaths()
ZipArchive archive = ZipFile.OpenRead(targetingPackPath);
var actualPaths = archive.Entries
- .Where(i => i.FullName.EndsWith(".dll", StringComparison.Ordinal))
+ .Where(i => i.FullName.EndsWith(".dll", StringComparison.Ordinal) && !i.FullName.EndsWith(".resources.dll", StringComparison.Ordinal))
.Select(i => i.FullName).ToHashSet();
var expectedPaths = frameworkListEntries.Select(i => i.Attribute("Path").Value).ToHashSet();
@@ -391,5 +407,38 @@ public void FrameworkListListsContainsCorrectPaths()
Assert.Empty(missing);
Assert.Empty(unexpected);
}
+
+ [Fact]
+ public void FrameworkListListsContainsAnalyzerLanguage()
+ {
+ if (!_isTargetingPackBuilding || string.IsNullOrEmpty(Environment.GetEnvironmentVariable("helix")))
+ {
+ return;
+ }
+
+ var frameworkListPath = Path.Combine(_targetingPackRoot, "data", "FrameworkList.xml");
+
+ AssertEx.FileExists(frameworkListPath);
+
+ var frameworkListDoc = XDocument.Load(frameworkListPath);
+ var frameworkListEntries = frameworkListDoc.Root.Descendants();
+
+ var analyzerEntries = frameworkListEntries.Where(i => i.Attribute("Type").Value.Equals("Analyzer", StringComparison.Ordinal));
+
+ Assert.All(analyzerEntries, analyzerEntry =>
+ {
+ var actualLanguage = analyzerEntry.Attribute("Language")?.Value;
+ var assemblyPath = analyzerEntry.Attribute("Path").Value;
+
+ string expectedLanguage = Path.GetFileName(Path.GetDirectoryName(assemblyPath));
+
+ if (expectedLanguage.Equals("dotnet", StringComparison.OrdinalIgnoreCase))
+ {
+ expectedLanguage = null;
+ }
+
+ Assert.Equal(expectedLanguage, actualLanguage);
+ });
+ }
}
}