Skip to content

Commit 0b06968

Browse files
committed
feat: support roslyn analyzer
Close #9
1 parent 34d1a28 commit 0b06968

File tree

7 files changed

+162
-0
lines changed

7 files changed

+162
-0
lines changed

Editor/CSharpProjectModifier.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,58 @@ private static string OnGeneratedCSProject(string path, string content)
4141
content = Regex.Replace(content, "(\\s+)(<LangVersion>.*</LangVersion>)([\r\n]+)", "$1$2$3$1<Nullable>" + value + "</Nullable>$3");
4242
}
4343

44+
// Additional contents.
45+
// content = Regex.Replace(content, "^</Project>", "<!-- C# Settings For Unity -->", RegexOptions.Singleline);
46+
content = Regex.Replace(content, "[\r\n]+</Project>[\r\n]*", "\r\n<!-- C# Settings For Unity -->");
47+
{
48+
content += NewLine + " <ItemGroup>";
49+
{
50+
// Add compiler package.
51+
if (!setting.UseDefaultCompiler)
52+
content = AddPackage(content, setting.CompilerPackage.Name, setting.CompilerPackage.Version);
53+
54+
// Add analyzer packages.
55+
foreach (var package in setting.AnalyzerPackages)
56+
content = AddPackage(content, package.Name, package.Version);
57+
}
58+
content += NewLine + " </ItemGroup>";
59+
60+
// Add rule set files.
61+
content += NewLine + " <PropertyGroup>";
62+
{
63+
// Ruleset.
64+
var rulesets = new[] {"Assets/Default.ruleset"} // Add default rule set for project.
65+
.Concat(string.IsNullOrEmpty(asmdefPath)
66+
? new[] {"Assets/" + assemblyName + ".ruleset"} // Add rule set for predefined assemblies (e.g. Assembly-CSharp.dll).
67+
: Directory.GetFiles(Path.GetDirectoryName(asmdefPath), "*.ruleset")) // Add rule sets for asmdef.
68+
.Where(File.Exists);
69+
70+
foreach (var ruleset in rulesets)
71+
content = AddRuleSet(content, ruleset);
72+
}
73+
content += NewLine + " </PropertyGroup>";
74+
}
75+
content += NewLine + "<!-- C# Settings For Unity -->" + NewLine + NewLine + "</Project>" + NewLine;
76+
4477
return content;
4578
}
79+
80+
private static string AddPackage(string content, string name, string version)
81+
{
82+
content += NewLine + " <PackageReference Include=\"" + name + "\" Version=\"" + version + "\">";
83+
content += NewLine + " <PrivateAssets>all</PrivateAssets>";
84+
content += NewLine + " <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>";
85+
content += NewLine + " </PackageReference>";
86+
return content;
87+
}
88+
89+
private static string AddRuleSet(string content, string ruleset)
90+
{
91+
if (File.Exists(ruleset))
92+
content += NewLine + " <CodeAnalysisRuleSet>" + ruleset.Replace('/', '\\') + "</CodeAnalysisRuleSet>";
93+
return content;
94+
}
95+
96+
private static string NewLine = "\r\n";
4697
}
4798
}

Editor/CscSettingsProvider.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.IO;
22
using UnityEditor;
3+
using UnityEditorInternal;
34
using UnityEngine;
45

56
namespace Coffee.CSharpCompilerSettings
@@ -8,12 +9,30 @@ internal class CscSettingsProvider
89
{
910
private static SerializedObject serializedObject;
1011
private static SerializedProperty s_EnableLogging;
12+
private static SerializedProperty s_AnalyzerFilter;
13+
private static SerializedProperty s_PredefinedAssemblies;
14+
private static SerializedProperty s_IncludedAssemblies;
15+
private static ReorderableList s_RoAnalyzerPackages = null;
16+
1117

1218
[SettingsProvider]
1319
private static SettingsProvider CreateSettingsProvider()
1420
{
1521
serializedObject = new SerializedObject(CscSettingsAsset.instance);
1622
s_EnableLogging = serializedObject.FindProperty("m_EnableLogging");
23+
s_AnalyzerFilter = serializedObject.FindProperty("m_AnalyzerFilter");
24+
s_PredefinedAssemblies = s_AnalyzerFilter.FindPropertyRelative("m_PredefinedAssemblies");
25+
s_IncludedAssemblies = s_AnalyzerFilter.FindPropertyRelative("m_IncludedAssemblies");
26+
27+
s_RoAnalyzerPackages = new ReorderableList(serializedObject, serializedObject.FindProperty("m_AnalyzerPackages"));
28+
s_RoAnalyzerPackages.drawHeaderCallback = rect => EditorGUI.PrefixLabel(rect, GUIUtility.GetControlID(FocusType.Passive), new GUIContent("Analyzer Packages"));
29+
s_RoAnalyzerPackages.elementHeight = NugetPackageDrawer.Height;
30+
s_RoAnalyzerPackages.drawElementCallback = (rect, index, active, focused) =>
31+
{
32+
var sp = s_RoAnalyzerPackages.serializedProperty.GetArrayElementAtIndex(index);
33+
EditorGUI.PropertyField(rect, sp, GUIContent.none);
34+
};
35+
1736
var keywords = SettingsProvider.GetSearchKeywordsFromSerializedObject(serializedObject);
1837
return new SettingsProvider("Project/C# Compiler", SettingsScope.Project)
1938
{
@@ -28,7 +47,18 @@ private static void OnGUI(string searchContext)
2847
InspectorGUI.DrawCompilerPackage(serializedObject);
2948
EditorGUILayout.Space();
3049

50+
EditorGUILayout.LabelField("Analyzer", EditorStyles.boldLabel);
51+
using (new GUILayout.HorizontalScope())
3152
{
53+
GUILayout.Space(20);
54+
using (new GUILayout.VerticalScope())
55+
{
56+
NugetPackageCatalog.CurrentCategory = NugetPackage.CategoryType.Analyzer;
57+
s_RoAnalyzerPackages.DoLayoutList();
58+
EditorGUILayout.PropertyField(s_IncludedAssemblies);
59+
GUILayout.Space(-16);
60+
EditorGUILayout.PropertyField(s_PredefinedAssemblies);
61+
}
3262
}
3363

3464
EditorGUILayout.Space();
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System.IO;
2+
3+
namespace Coffee.CSharpCompilerSettings
4+
{
5+
internal struct AnalyzerInfo
6+
{
7+
public string PackageId { get; }
8+
public string[] DllFiles { get; }
9+
10+
private AnalyzerInfo(string packageId, string[] dllFiles)
11+
{
12+
PackageId = packageId;
13+
DllFiles = dllFiles;
14+
}
15+
16+
public static AnalyzerInfo GetInstalledInfo(string packageId)
17+
{
18+
var path = Utils.InstallNugetPackage(packageId);
19+
if (string.IsNullOrEmpty(path)) return new AnalyzerInfo(packageId, new string[0]);
20+
21+
var dir = Utils.PathCombine(path, "analyzers", "dotnet", "cs");
22+
return new AnalyzerInfo(packageId, Directory.GetFiles(dir, "*.dll"));
23+
}
24+
}
25+
}

Plugins/CSharpCompilerSettings/AnalyzerInfo.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Plugins/CSharpCompilerSettings/Core.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,27 @@ private static void ChangeCompilerProcess(object compiler, object scriptAssembly
137137
foreach (var d in modifiedDefines)
138138
text += "\n/define:" + d;
139139

140+
// Setup analyzer.
141+
foreach (var package in setting.AnalyzerPackages)
142+
{
143+
var analyzerInfo = AnalyzerInfo.GetInstalledInfo(package.PackageId);
144+
foreach (var dll in analyzerInfo.DllFiles)
145+
text += string.Format("\n/analyzer:\"{0}\"", dll);
146+
}
147+
148+
// Ruleset.
149+
var rulesets = new[] {"Assets/Default.ruleset"}
150+
.Concat(string.IsNullOrEmpty(originPath)
151+
? new[] {"Assets/" + assemblyName + ".ruleset"}
152+
: Directory.GetFiles(originPath, "*.ruleset"))
153+
.Where(File.Exists);
154+
155+
foreach (var ruleset in rulesets)
156+
text += string.Format("\n/ruleset:\"{0}\"", ruleset);
157+
158+
159+
160+
140161
// Replace NewLine and save.
141162
text = Regex.Replace(text, "\n", Environment.NewLine);
142163
File.WriteAllText(responseFile, text);
@@ -258,6 +279,8 @@ static Core()
258279
if (!settings || settings.UseDefaultCompiler) return;
259280
CompilerInfo.GetInstalledInfo(settings.CompilerPackage.PackageId);
260281

282+
foreach (var package in settings.AnalyzerPackages)
283+
AnalyzerInfo.GetInstalledInfo(package.PackageId);
261284

262285
// If Unity 2020.2 or newer, request re-compilation.
263286
var version = Application.unityVersion.Split('.');

Plugins/CSharpCompilerSettings/CscSettingsAsset.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,23 @@ public override string ToString()
6767
}
6868
}
6969

70+
[Serializable]
71+
public struct AnalyzerFilter
72+
{
73+
[Tooltip("Include predefined assemblies (e.g. Assembly-CSharp.dll)")]
74+
[SerializeField] private bool m_PredefinedAssemblies;
75+
76+
[Tooltip("Include assemblies filter. Separate multiple values with ';'. Prefix '!' to exclude (e.g. 'Assets/;!Packages/')")]
77+
[Split(';')]
78+
[SerializeField] private string m_IncludedAssemblies;
79+
80+
public AnalyzerFilter(bool predefinedAssemblies, string includedAssemblies)
81+
{
82+
m_PredefinedAssemblies = predefinedAssemblies;
83+
m_IncludedAssemblies = includedAssemblies;
84+
}
85+
}
86+
7087
public class SplitAttribute : PropertyAttribute
7188
{
7289
public char separater { get; }
@@ -91,6 +108,8 @@ internal class CscSettingsAsset : ScriptableObject, ISerializationCallbackReceiv
91108
[SerializeField] private bool m_EnableNullable = false;
92109
[SerializeField] private Nullable m_Nullable = Nullable.Disable;
93110
[SerializeField] private NugetPackage m_CompilerPackage = new NugetPackage("Microsoft.Net.Compilers", "3.5.0", NugetPackage.CategoryType.Compiler);
111+
[SerializeField] private NugetPackage[] m_AnalyzerPackages = new NugetPackage[0];
112+
[SerializeField] private AnalyzerFilter m_AnalyzerFilter = new AnalyzerFilter(true, "Assets/;!Packages/");
94113

95114
[Tooltip(
96115
"When compiling this assembly, add or remove specific symbols separated with semicolons (;) or commas (,).\nSymbols starting with '!' will be removed.\n\ne.g. 'SYMBOL_TO_ADD;!SYMBOL_TO_REMOVE;...'")]
@@ -112,6 +131,8 @@ private static CscSettingsAsset CreateFromProjectSettings()
112131
public bool UseDefaultCompiler => m_CompilerType == CompilerType.BuiltIn;
113132
public bool ShouldToRecompile => m_CompilerType == CompilerType.CustomPackage || !string.IsNullOrEmpty(m_ModifySymbols);
114133
public Nullable Nullable => m_Nullable;
134+
public NugetPackage[] AnalyzerPackages => m_AnalyzerPackages;
135+
public AnalyzerFilter AnalyzerFilter => m_AnalyzerFilter;
115136

116137
public string LanguageVersion
117138
{

Plugins/CSharpCompilerSettings/Dev/rsp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@
2424
"${PLUGIN_SOURCE}/RuntimeInfo.cs"
2525
"${PLUGIN_SOURCE}/Utils.cs"
2626
"${PLUGIN_SOURCE}/Logger.cs"
27+
"${PLUGIN_SOURCE}/AnalyzerInfo.cs"

0 commit comments

Comments
 (0)