Skip to content

Commit

Permalink
feat: support roslyn analyzer
Browse files Browse the repository at this point in the history
Close #9
  • Loading branch information
mob-sakai committed Nov 15, 2020
1 parent 34d1a28 commit 0b06968
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 0 deletions.
51 changes: 51 additions & 0 deletions Editor/CSharpProjectModifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,58 @@ private static string OnGeneratedCSProject(string path, string content)
content = Regex.Replace(content, "(\\s+)(<LangVersion>.*</LangVersion>)([\r\n]+)", "$1$2$3$1<Nullable>" + value + "</Nullable>$3");
}

// Additional contents.
// content = Regex.Replace(content, "^</Project>", "<!-- C# Settings For Unity -->", RegexOptions.Singleline);
content = Regex.Replace(content, "[\r\n]+</Project>[\r\n]*", "\r\n<!-- C# Settings For Unity -->");
{
content += NewLine + " <ItemGroup>";
{
// Add compiler package.
if (!setting.UseDefaultCompiler)
content = AddPackage(content, setting.CompilerPackage.Name, setting.CompilerPackage.Version);

// Add analyzer packages.
foreach (var package in setting.AnalyzerPackages)
content = AddPackage(content, package.Name, package.Version);
}
content += NewLine + " </ItemGroup>";

// Add rule set files.
content += NewLine + " <PropertyGroup>";
{
// Ruleset.
var rulesets = new[] {"Assets/Default.ruleset"} // Add default rule set for project.
.Concat(string.IsNullOrEmpty(asmdefPath)
? new[] {"Assets/" + assemblyName + ".ruleset"} // Add rule set for predefined assemblies (e.g. Assembly-CSharp.dll).
: Directory.GetFiles(Path.GetDirectoryName(asmdefPath), "*.ruleset")) // Add rule sets for asmdef.
.Where(File.Exists);

foreach (var ruleset in rulesets)
content = AddRuleSet(content, ruleset);
}
content += NewLine + " </PropertyGroup>";
}
content += NewLine + "<!-- C# Settings For Unity -->" + NewLine + NewLine + "</Project>" + NewLine;

return content;
}

private static string AddPackage(string content, string name, string version)
{
content += NewLine + " <PackageReference Include=\"" + name + "\" Version=\"" + version + "\">";
content += NewLine + " <PrivateAssets>all</PrivateAssets>";
content += NewLine + " <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>";
content += NewLine + " </PackageReference>";
return content;
}

private static string AddRuleSet(string content, string ruleset)
{
if (File.Exists(ruleset))
content += NewLine + " <CodeAnalysisRuleSet>" + ruleset.Replace('/', '\\') + "</CodeAnalysisRuleSet>";
return content;
}

private static string NewLine = "\r\n";
}
}
30 changes: 30 additions & 0 deletions Editor/CscSettingsProvider.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.IO;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;

namespace Coffee.CSharpCompilerSettings
Expand All @@ -8,12 +9,30 @@ internal class CscSettingsProvider
{
private static SerializedObject serializedObject;
private static SerializedProperty s_EnableLogging;
private static SerializedProperty s_AnalyzerFilter;
private static SerializedProperty s_PredefinedAssemblies;
private static SerializedProperty s_IncludedAssemblies;
private static ReorderableList s_RoAnalyzerPackages = null;


[SettingsProvider]
private static SettingsProvider CreateSettingsProvider()
{
serializedObject = new SerializedObject(CscSettingsAsset.instance);
s_EnableLogging = serializedObject.FindProperty("m_EnableLogging");
s_AnalyzerFilter = serializedObject.FindProperty("m_AnalyzerFilter");
s_PredefinedAssemblies = s_AnalyzerFilter.FindPropertyRelative("m_PredefinedAssemblies");
s_IncludedAssemblies = s_AnalyzerFilter.FindPropertyRelative("m_IncludedAssemblies");

s_RoAnalyzerPackages = new ReorderableList(serializedObject, serializedObject.FindProperty("m_AnalyzerPackages"));
s_RoAnalyzerPackages.drawHeaderCallback = rect => EditorGUI.PrefixLabel(rect, GUIUtility.GetControlID(FocusType.Passive), new GUIContent("Analyzer Packages"));
s_RoAnalyzerPackages.elementHeight = NugetPackageDrawer.Height;
s_RoAnalyzerPackages.drawElementCallback = (rect, index, active, focused) =>
{
var sp = s_RoAnalyzerPackages.serializedProperty.GetArrayElementAtIndex(index);
EditorGUI.PropertyField(rect, sp, GUIContent.none);
};

var keywords = SettingsProvider.GetSearchKeywordsFromSerializedObject(serializedObject);
return new SettingsProvider("Project/C# Compiler", SettingsScope.Project)
{
Expand All @@ -28,7 +47,18 @@ private static void OnGUI(string searchContext)
InspectorGUI.DrawCompilerPackage(serializedObject);
EditorGUILayout.Space();

EditorGUILayout.LabelField("Analyzer", EditorStyles.boldLabel);
using (new GUILayout.HorizontalScope())
{
GUILayout.Space(20);
using (new GUILayout.VerticalScope())
{
NugetPackageCatalog.CurrentCategory = NugetPackage.CategoryType.Analyzer;
s_RoAnalyzerPackages.DoLayoutList();
EditorGUILayout.PropertyField(s_IncludedAssemblies);
GUILayout.Space(-16);
EditorGUILayout.PropertyField(s_PredefinedAssemblies);
}
}

EditorGUILayout.Space();
Expand Down
25 changes: 25 additions & 0 deletions Plugins/CSharpCompilerSettings/AnalyzerInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.IO;

namespace Coffee.CSharpCompilerSettings
{
internal struct AnalyzerInfo
{
public string PackageId { get; }
public string[] DllFiles { get; }

private AnalyzerInfo(string packageId, string[] dllFiles)
{
PackageId = packageId;
DllFiles = dllFiles;
}

public static AnalyzerInfo GetInstalledInfo(string packageId)
{
var path = Utils.InstallNugetPackage(packageId);
if (string.IsNullOrEmpty(path)) return new AnalyzerInfo(packageId, new string[0]);

var dir = Utils.PathCombine(path, "analyzers", "dotnet", "cs");
return new AnalyzerInfo(packageId, Directory.GetFiles(dir, "*.dll"));
}
}
}
11 changes: 11 additions & 0 deletions Plugins/CSharpCompilerSettings/AnalyzerInfo.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions Plugins/CSharpCompilerSettings/Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,27 @@ private static void ChangeCompilerProcess(object compiler, object scriptAssembly
foreach (var d in modifiedDefines)
text += "\n/define:" + d;

// Setup analyzer.
foreach (var package in setting.AnalyzerPackages)
{
var analyzerInfo = AnalyzerInfo.GetInstalledInfo(package.PackageId);
foreach (var dll in analyzerInfo.DllFiles)
text += string.Format("\n/analyzer:\"{0}\"", dll);
}

// Ruleset.
var rulesets = new[] {"Assets/Default.ruleset"}
.Concat(string.IsNullOrEmpty(originPath)
? new[] {"Assets/" + assemblyName + ".ruleset"}
: Directory.GetFiles(originPath, "*.ruleset"))
.Where(File.Exists);

foreach (var ruleset in rulesets)
text += string.Format("\n/ruleset:\"{0}\"", ruleset);




// Replace NewLine and save.
text = Regex.Replace(text, "\n", Environment.NewLine);
File.WriteAllText(responseFile, text);
Expand Down Expand Up @@ -258,6 +279,8 @@ static Core()
if (!settings || settings.UseDefaultCompiler) return;
CompilerInfo.GetInstalledInfo(settings.CompilerPackage.PackageId);

foreach (var package in settings.AnalyzerPackages)
AnalyzerInfo.GetInstalledInfo(package.PackageId);

// If Unity 2020.2 or newer, request re-compilation.
var version = Application.unityVersion.Split('.');
Expand Down
21 changes: 21 additions & 0 deletions Plugins/CSharpCompilerSettings/CscSettingsAsset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,23 @@ public override string ToString()
}
}

[Serializable]
public struct AnalyzerFilter
{
[Tooltip("Include predefined assemblies (e.g. Assembly-CSharp.dll)")]
[SerializeField] private bool m_PredefinedAssemblies;

[Tooltip("Include assemblies filter. Separate multiple values with ';'. Prefix '!' to exclude (e.g. 'Assets/;!Packages/')")]
[Split(';')]
[SerializeField] private string m_IncludedAssemblies;

public AnalyzerFilter(bool predefinedAssemblies, string includedAssemblies)
{
m_PredefinedAssemblies = predefinedAssemblies;
m_IncludedAssemblies = includedAssemblies;
}
}

public class SplitAttribute : PropertyAttribute
{
public char separater { get; }
Expand All @@ -91,6 +108,8 @@ internal class CscSettingsAsset : ScriptableObject, ISerializationCallbackReceiv
[SerializeField] private bool m_EnableNullable = false;
[SerializeField] private Nullable m_Nullable = Nullable.Disable;
[SerializeField] private NugetPackage m_CompilerPackage = new NugetPackage("Microsoft.Net.Compilers", "3.5.0", NugetPackage.CategoryType.Compiler);
[SerializeField] private NugetPackage[] m_AnalyzerPackages = new NugetPackage[0];
[SerializeField] private AnalyzerFilter m_AnalyzerFilter = new AnalyzerFilter(true, "Assets/;!Packages/");

[Tooltip(
"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;...'")]
Expand All @@ -112,6 +131,8 @@ private static CscSettingsAsset CreateFromProjectSettings()
public bool UseDefaultCompiler => m_CompilerType == CompilerType.BuiltIn;
public bool ShouldToRecompile => m_CompilerType == CompilerType.CustomPackage || !string.IsNullOrEmpty(m_ModifySymbols);
public Nullable Nullable => m_Nullable;
public NugetPackage[] AnalyzerPackages => m_AnalyzerPackages;
public AnalyzerFilter AnalyzerFilter => m_AnalyzerFilter;

public string LanguageVersion
{
Expand Down
1 change: 1 addition & 0 deletions Plugins/CSharpCompilerSettings/Dev/rsp
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@
"${PLUGIN_SOURCE}/RuntimeInfo.cs"
"${PLUGIN_SOURCE}/Utils.cs"
"${PLUGIN_SOURCE}/Logger.cs"
"${PLUGIN_SOURCE}/AnalyzerInfo.cs"

0 comments on commit 0b06968

Please sign in to comment.