From 9b190dba8ac686b0ec8573282da4c60d4752907c Mon Sep 17 00:00:00 2001 From: neuecc Date: Tue, 28 Feb 2017 23:48:04 +0900 Subject: [PATCH] working analyzer --- MessagePack.sln | 30 + nuget/MessagePack.ImmutableCollection.nuspec | 6 +- nuget/MessagePack.ReactiveProperty.nuspec | 6 +- nuget/MessagePack.UnityShims.nuspec | 6 +- nuget/MessagePack.nuspec | 5 +- sandbox/Sandbox/Generated.cs | 78 +-- sandbox/SharedData/Class1.cs | 8 +- .../MessagePack.Analyzer.Vsix.csproj | 90 +++ .../source.extension.vsixmanifest | 22 + .../MessagePack.Analyzer/CodeFixProvider.cs | 88 +++ .../ConfigurationLoader.cs | 50 ++ .../DiagnosticAnalyzer.cs | 427 +++++++++++++ .../DiagnosticsReportContext.cs | 41 ++ .../MessagePack.Analyzer.csproj | 113 ++++ .../Properties/AssemblyInfo.cs | 31 + .../MessagePack.Analyzer/RoslynExtensions.cs | 132 ++++ .../MessagePack.Analyzer/TinyJsonReader.cs | 594 ++++++++++++++++++ .../MessagePack.Analyzer/packages.config | 12 + .../MessagePack.Analyzer/tools/install.ps1 | 58 ++ .../MessagePack.Analyzer/tools/uninstall.ps1 | 65 ++ 20 files changed, 1789 insertions(+), 73 deletions(-) create mode 100644 src/MessagePack.Analyzer/MessagePack.Analyzer.Vsix/MessagePack.Analyzer.Vsix.csproj create mode 100644 src/MessagePack.Analyzer/MessagePack.Analyzer.Vsix/source.extension.vsixmanifest create mode 100644 src/MessagePack.Analyzer/MessagePack.Analyzer/CodeFixProvider.cs create mode 100644 src/MessagePack.Analyzer/MessagePack.Analyzer/ConfigurationLoader.cs create mode 100644 src/MessagePack.Analyzer/MessagePack.Analyzer/DiagnosticAnalyzer.cs create mode 100644 src/MessagePack.Analyzer/MessagePack.Analyzer/DiagnosticsReportContext.cs create mode 100644 src/MessagePack.Analyzer/MessagePack.Analyzer/MessagePack.Analyzer.csproj create mode 100644 src/MessagePack.Analyzer/MessagePack.Analyzer/Properties/AssemblyInfo.cs create mode 100644 src/MessagePack.Analyzer/MessagePack.Analyzer/RoslynExtensions.cs create mode 100644 src/MessagePack.Analyzer/MessagePack.Analyzer/TinyJsonReader.cs create mode 100644 src/MessagePack.Analyzer/MessagePack.Analyzer/packages.config create mode 100644 src/MessagePack.Analyzer/MessagePack.Analyzer/tools/install.ps1 create mode 100644 src/MessagePack.Analyzer/MessagePack.Analyzer/tools/uninstall.ps1 diff --git a/MessagePack.sln b/MessagePack.sln index 4aee9a09..9d640fa8 100644 --- a/MessagePack.sln +++ b/MessagePack.sln @@ -40,6 +40,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessagePack.ReactivePropert EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MessagePack.ImmutableCollection", "src\MessagePack.ImmutableCollection\MessagePack.ImmutableCollection.csproj", "{E066F547-7261-4561-AEFC-E64DBFD874F8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessagePack.Analyzer", "src\MessagePack.Analyzer\MessagePack.Analyzer\MessagePack.Analyzer.csproj", "{900E3D34-3091-4841-AA71-5D610797BC25}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessagePack.Analyzer.Vsix", "src\MessagePack.Analyzer\MessagePack.Analyzer.Vsix\MessagePack.Analyzer.Vsix.csproj", "{32CCBE3D-DBEC-416C-8F07-225F8B34B71A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -158,6 +162,30 @@ Global {E066F547-7261-4561-AEFC-E64DBFD874F8}.Release|x64.Build.0 = Release|x64 {E066F547-7261-4561-AEFC-E64DBFD874F8}.Release|x86.ActiveCfg = Release|x86 {E066F547-7261-4561-AEFC-E64DBFD874F8}.Release|x86.Build.0 = Release|x86 + {900E3D34-3091-4841-AA71-5D610797BC25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {900E3D34-3091-4841-AA71-5D610797BC25}.Debug|Any CPU.Build.0 = Debug|Any CPU + {900E3D34-3091-4841-AA71-5D610797BC25}.Debug|x64.ActiveCfg = Debug|Any CPU + {900E3D34-3091-4841-AA71-5D610797BC25}.Debug|x64.Build.0 = Debug|Any CPU + {900E3D34-3091-4841-AA71-5D610797BC25}.Debug|x86.ActiveCfg = Debug|Any CPU + {900E3D34-3091-4841-AA71-5D610797BC25}.Debug|x86.Build.0 = Debug|Any CPU + {900E3D34-3091-4841-AA71-5D610797BC25}.Release|Any CPU.ActiveCfg = Release|Any CPU + {900E3D34-3091-4841-AA71-5D610797BC25}.Release|Any CPU.Build.0 = Release|Any CPU + {900E3D34-3091-4841-AA71-5D610797BC25}.Release|x64.ActiveCfg = Release|Any CPU + {900E3D34-3091-4841-AA71-5D610797BC25}.Release|x64.Build.0 = Release|Any CPU + {900E3D34-3091-4841-AA71-5D610797BC25}.Release|x86.ActiveCfg = Release|Any CPU + {900E3D34-3091-4841-AA71-5D610797BC25}.Release|x86.Build.0 = Release|Any CPU + {32CCBE3D-DBEC-416C-8F07-225F8B34B71A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {32CCBE3D-DBEC-416C-8F07-225F8B34B71A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {32CCBE3D-DBEC-416C-8F07-225F8B34B71A}.Debug|x64.ActiveCfg = Debug|Any CPU + {32CCBE3D-DBEC-416C-8F07-225F8B34B71A}.Debug|x64.Build.0 = Debug|Any CPU + {32CCBE3D-DBEC-416C-8F07-225F8B34B71A}.Debug|x86.ActiveCfg = Debug|Any CPU + {32CCBE3D-DBEC-416C-8F07-225F8B34B71A}.Debug|x86.Build.0 = Debug|Any CPU + {32CCBE3D-DBEC-416C-8F07-225F8B34B71A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {32CCBE3D-DBEC-416C-8F07-225F8B34B71A}.Release|Any CPU.Build.0 = Release|Any CPU + {32CCBE3D-DBEC-416C-8F07-225F8B34B71A}.Release|x64.ActiveCfg = Release|Any CPU + {32CCBE3D-DBEC-416C-8F07-225F8B34B71A}.Release|x64.Build.0 = Release|Any CPU + {32CCBE3D-DBEC-416C-8F07-225F8B34B71A}.Release|x86.ActiveCfg = Release|Any CPU + {32CCBE3D-DBEC-416C-8F07-225F8B34B71A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -172,5 +200,7 @@ Global {C01E1407-7FEC-4C1D-B0B4-74D95A317AA6} = {86309CF6-0054-4CE3-BFD3-CA0AA7DB17BC} {166A16C0-B89F-41AF-956A-235C6CA62C25} = {86309CF6-0054-4CE3-BFD3-CA0AA7DB17BC} {E066F547-7261-4561-AEFC-E64DBFD874F8} = {86309CF6-0054-4CE3-BFD3-CA0AA7DB17BC} + {900E3D34-3091-4841-AA71-5D610797BC25} = {86309CF6-0054-4CE3-BFD3-CA0AA7DB17BC} + {32CCBE3D-DBEC-416C-8F07-225F8B34B71A} = {86309CF6-0054-4CE3-BFD3-CA0AA7DB17BC} EndGlobalSection EndGlobal diff --git a/nuget/MessagePack.ImmutableCollection.nuspec b/nuget/MessagePack.ImmutableCollection.nuspec index 52722e93..8dcaa999 100644 --- a/nuget/MessagePack.ImmutableCollection.nuspec +++ b/nuget/MessagePack.ImmutableCollection.nuspec @@ -2,7 +2,7 @@ MessagePack.ImmutableCollection - 0.2.0-beta + 0.3.0-beta MessagePack for C# Extension Support for ImmutableCollection neuecc neuecc @@ -17,11 +17,11 @@ - + - + diff --git a/nuget/MessagePack.ReactiveProperty.nuspec b/nuget/MessagePack.ReactiveProperty.nuspec index e19464db..aa1668c0 100644 --- a/nuget/MessagePack.ReactiveProperty.nuspec +++ b/nuget/MessagePack.ReactiveProperty.nuspec @@ -2,7 +2,7 @@ MessagePack.ReactiveProperty - 0.2.0-beta + 0.3.0-beta MessagePack for C# Extension Support for ReactiveProperty neuecc neuecc @@ -17,11 +17,11 @@ - + - + diff --git a/nuget/MessagePack.UnityShims.nuspec b/nuget/MessagePack.UnityShims.nuspec index a96b909b..bc0f0533 100644 --- a/nuget/MessagePack.UnityShims.nuspec +++ b/nuget/MessagePack.UnityShims.nuspec @@ -2,7 +2,7 @@ MessagePack.Unity - 0.2.0-beta + 0.3.0-beta MessagePack for C# Extension Support for Unity(add pseudo Vector type and fast Vectory[] extension formatter) neuecc neuecc @@ -17,10 +17,10 @@ - + - + diff --git a/nuget/MessagePack.nuspec b/nuget/MessagePack.nuspec index 8e318ea4..93637430 100644 --- a/nuget/MessagePack.nuspec +++ b/nuget/MessagePack.nuspec @@ -2,7 +2,7 @@ MessagePack - 0.2.3-beta + 0.3.0-beta MessagePack for C# neuecc neuecc @@ -33,7 +33,6 @@ - - + \ No newline at end of file diff --git a/sandbox/Sandbox/Generated.cs b/sandbox/Sandbox/Generated.cs index fd598fe9..e8fb2dd1 100644 --- a/sandbox/Sandbox/Generated.cs +++ b/sandbox/Sandbox/Generated.cs @@ -355,21 +355,13 @@ namespace MessagePack.Formatters.SharedData public IIVersioningUnionFormatter() { - this.typeToKeyAndJumpMap = new Dictionary>(5, global::MessagePack.Internal.RuntimeTypeHandleEqualityComparer.Default) + this.typeToKeyAndJumpMap = new Dictionary>(1, global::MessagePack.Internal.RuntimeTypeHandleEqualityComparer.Default) { { typeof(global::SharedData.MySubUnion1).TypeHandle, new KeyValuePair(0, 0) }, - { typeof(global::SharedData.MySubUnion2).TypeHandle, new KeyValuePair(1, 1) }, - { typeof(global::SharedData.MySubUnion3).TypeHandle, new KeyValuePair(2, 2) }, - { typeof(global::SharedData.MySubUnion4).TypeHandle, new KeyValuePair(3, 3) }, - { typeof(global::SharedData.VersioningUnion).TypeHandle, new KeyValuePair(4, 4) }, }; - this.keyToJumpMap = new Dictionary(5) + this.keyToJumpMap = new Dictionary(1) { { 0, 0 }, - { 1, 1 }, - { 2, 2 }, - { 3, 3 }, - { 4, 4 }, }; } @@ -386,18 +378,6 @@ namespace MessagePack.Formatters.SharedData case 0: offset += formatterResolver.GetFormatterWithVerify().Serialize(ref bytes, offset, (global::SharedData.MySubUnion1)value, formatterResolver); break; - case 1: - offset += formatterResolver.GetFormatterWithVerify().Serialize(ref bytes, offset, (global::SharedData.MySubUnion2)value, formatterResolver); - break; - case 2: - offset += formatterResolver.GetFormatterWithVerify().Serialize(ref bytes, offset, (global::SharedData.MySubUnion3)value, formatterResolver); - break; - case 3: - offset += formatterResolver.GetFormatterWithVerify().Serialize(ref bytes, offset, (global::SharedData.MySubUnion4)value, formatterResolver); - break; - case 4: - offset += formatterResolver.GetFormatterWithVerify().Serialize(ref bytes, offset, (global::SharedData.VersioningUnion)value, formatterResolver); - break; default: break; } @@ -434,22 +414,6 @@ namespace MessagePack.Formatters.SharedData result = (global::SharedData.IIVersioningUnion)formatterResolver.GetFormatterWithVerify().Deserialize(bytes, offset, formatterResolver, out readSize); offset += readSize; break; - case 1: - result = (global::SharedData.IIVersioningUnion)formatterResolver.GetFormatterWithVerify().Deserialize(bytes, offset, formatterResolver, out readSize); - offset += readSize; - break; - case 2: - result = (global::SharedData.IIVersioningUnion)formatterResolver.GetFormatterWithVerify().Deserialize(bytes, offset, formatterResolver, out readSize); - offset += readSize; - break; - case 3: - result = (global::SharedData.IIVersioningUnion)formatterResolver.GetFormatterWithVerify().Deserialize(bytes, offset, formatterResolver, out readSize); - offset += readSize; - break; - case 4: - result = (global::SharedData.IIVersioningUnion)formatterResolver.GetFormatterWithVerify().Deserialize(bytes, offset, formatterResolver, out readSize); - offset += readSize; - break; default: offset += MessagePackBinary.ReadNext(bytes, offset); break; @@ -482,7 +446,7 @@ namespace MessagePack.Formatters.SharedData } var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 2); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 3); offset += MessagePackBinary.WriteInt32(ref bytes, offset, value.Prop1); offset += MessagePackBinary.WriteString(ref bytes, offset, value.Prop2); offset += MessagePackBinary.WriteInt32(ref bytes, offset, value.Prop3); @@ -637,7 +601,7 @@ namespace MessagePack.Formatters.SharedData { var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 2); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 3); offset += MessagePackBinary.WriteInt32(ref bytes, offset, value.X); offset += MessagePackBinary.WriteInt32(ref bytes, offset, value.Y); offset += MessagePackBinary.WriteBytes(ref bytes, offset, value.BytesSpecial); @@ -782,7 +746,7 @@ namespace MessagePack.Formatters.SharedData } var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 6); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 7); offset += MessagePackBinary.WriteInt32(ref bytes, offset, value.Prop1); offset += formatterResolver.GetFormatterWithVerify().Serialize(ref bytes, offset, value.Prop2, formatterResolver); offset += MessagePackBinary.WriteString(ref bytes, offset, value.Prop3); @@ -869,7 +833,7 @@ namespace MessagePack.Formatters.SharedData { var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 1); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 2); offset += MessagePackBinary.WriteSingle(ref bytes, offset, value.X); offset += MessagePackBinary.WriteSingle(ref bytes, offset, value.Y); return offset - startOffset; @@ -927,7 +891,7 @@ namespace MessagePack.Formatters.SharedData } var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 0); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 1); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); return offset - startOffset; } @@ -973,7 +937,7 @@ namespace MessagePack.Formatters.SharedData { var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 0); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 1); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); return offset - startOffset; } @@ -1022,7 +986,7 @@ namespace MessagePack.Formatters.SharedData } var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 5); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 6); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); @@ -1092,7 +1056,7 @@ namespace MessagePack.Formatters.SharedData } var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 7); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 8); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); @@ -1169,7 +1133,7 @@ namespace MessagePack.Formatters.SharedData } var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 3); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 4); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); @@ -1227,7 +1191,7 @@ namespace MessagePack.Formatters.SharedData } var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 1); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 2); offset += formatterResolver.GetFormatterWithVerify().Serialize(ref bytes, offset, value.MyProperty1, formatterResolver); offset += MessagePackBinary.WriteInt32(ref bytes, offset, value.After); return offset - startOffset; @@ -1288,7 +1252,7 @@ namespace MessagePack.Formatters.SharedData } var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 1); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 2); offset += formatterResolver.GetFormatterWithVerify().Serialize(ref bytes, offset, value.MyProperty1, formatterResolver); offset += MessagePackBinary.WriteInt32(ref bytes, offset, value.After); return offset - startOffset; @@ -1349,7 +1313,7 @@ namespace MessagePack.Formatters.SharedData } var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 1); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 2); offset += formatterResolver.GetFormatterWithVerify().Serialize(ref bytes, offset, value.MyProperty1, formatterResolver); offset += MessagePackBinary.WriteInt32(ref bytes, offset, value.After); return offset - startOffset; @@ -1411,7 +1375,7 @@ namespace MessagePack.Formatters.SharedData value.OnBeforeSerialize(); var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 0); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 1); offset += MessagePackBinary.WriteInt32(ref bytes, offset, value.X); return offset - startOffset; } @@ -1468,7 +1432,7 @@ namespace MessagePack.Formatters.SharedData ((IMessagePackSerializationCallbackReceiver)value).OnBeforeSerialize(); var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 0); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 1); offset += MessagePackBinary.WriteInt32(ref bytes, offset, value.X); return offset - startOffset; } @@ -1670,7 +1634,7 @@ namespace MessagePack.Formatters.SharedData } var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 3); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 4); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); @@ -1724,7 +1688,7 @@ namespace MessagePack.Formatters.SharedData { var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 5); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 6); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); @@ -1783,7 +1747,7 @@ namespace MessagePack.Formatters.SharedData } var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 2); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 3); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += MessagePackBinary.WriteInt32(ref bytes, offset, value.Three); @@ -1836,7 +1800,7 @@ namespace MessagePack.Formatters.SharedData { var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 7); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 8); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); @@ -1897,7 +1861,7 @@ namespace MessagePack.Formatters.SharedData } var startOffset = offset; - offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 7); + offset += global::MessagePack.MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref bytes, offset, 8); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); offset += global::MessagePack.MessagePackBinary.WriteNil(ref bytes, offset); diff --git a/sandbox/SharedData/Class1.cs b/sandbox/SharedData/Class1.cs index a74e26bf..16a1c480 100644 --- a/sandbox/SharedData/Class1.cs +++ b/sandbox/SharedData/Class1.cs @@ -302,10 +302,10 @@ namespace SharedData } [Union(0, typeof(MySubUnion1))] - [Union(1, typeof(MySubUnion2))] - [Union(2, typeof(MySubUnion3))] - [Union(3, typeof(MySubUnion4))] - [Union(4, typeof(VersioningUnion))] + //[Union(1, typeof(MySubUnion2))] + //[Union(2, typeof(MySubUnion3))] + //[Union(3, typeof(MySubUnion4))] + //[Union(4, typeof(VersioningUnion))] public interface IIVersioningUnion { diff --git a/src/MessagePack.Analyzer/MessagePack.Analyzer.Vsix/MessagePack.Analyzer.Vsix.csproj b/src/MessagePack.Analyzer/MessagePack.Analyzer.Vsix/MessagePack.Analyzer.Vsix.csproj new file mode 100644 index 00000000..d9a588cc --- /dev/null +++ b/src/MessagePack.Analyzer/MessagePack.Analyzer.Vsix/MessagePack.Analyzer.Vsix.csproj @@ -0,0 +1,90 @@ + + + + + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + 14.0 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + + Debug + AnyCPU + AnyCPU + 2.0 + {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {32CCBE3D-DBEC-416C-8F07-225F8B34B71A} + Library + Properties + MessagePack.Analyzer.Vsix + MessagePack.Analyzer.Vsix + v4.5 + false + false + false + false + false + false + Roslyn + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + Program + $(DevEnvDir)devenv.exe + /rootsuffix Roslyn + + + + Designer + + + + + {900E3D34-3091-4841-AA71-5D610797BC25} + MessagePack.Analyzer + + + + + False + .NET Framework 3.5 SP1 + false + + + + + \ No newline at end of file diff --git a/src/MessagePack.Analyzer/MessagePack.Analyzer.Vsix/source.extension.vsixmanifest b/src/MessagePack.Analyzer/MessagePack.Analyzer.Vsix/source.extension.vsixmanifest new file mode 100644 index 00000000..06f40f67 --- /dev/null +++ b/src/MessagePack.Analyzer/MessagePack.Analyzer.Vsix/source.extension.vsixmanifest @@ -0,0 +1,22 @@ + + + + + MessagePack.Analyzer + This is a sample diagnostic extension for the .NET Compiler Platform ("Roslyn"). + + + + + + + + + + + + + + + + diff --git a/src/MessagePack.Analyzer/MessagePack.Analyzer/CodeFixProvider.cs b/src/MessagePack.Analyzer/MessagePack.Analyzer/CodeFixProvider.cs new file mode 100644 index 00000000..a6835900 --- /dev/null +++ b/src/MessagePack.Analyzer/MessagePack.Analyzer/CodeFixProvider.cs @@ -0,0 +1,88 @@ +//using Microsoft.CodeAnalysis; +//using Microsoft.CodeAnalysis.CodeActions; +//using Microsoft.CodeAnalysis.CodeFixes; +//using Microsoft.CodeAnalysis.CSharp; +//using Microsoft.CodeAnalysis.CSharp.Syntax; +//using Microsoft.CodeAnalysis.Editing; +//using System.Collections.Immutable; +//using System.Composition; +//using System.Linq; +//using System.Threading; +//using System.Threading.Tasks; + +//namespace ZeroFormatter.Analyzer +//{ +// [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(ZeroFormatterCodeFixProvider)), Shared] +// public class ZeroFormatterCodeFixProvider : CodeFixProvider +// { +// public sealed override ImmutableArray FixableDiagnosticIds +// { +// get +// { +// return ImmutableArray.Create( +// ZeroFormatterAnalyzer.PublicPropertyNeedsIndex.Id, +// ZeroFormatterAnalyzer.PublicPropertyMustBeVirtual.Id +// ); +// } +// } + +// public sealed override FixAllProvider GetFixAllProvider() +// { +// return WellKnownFixAllProviders.BatchFixer; +// } + +// public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) +// { +// var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false) as CompilationUnitSyntax; +// var model = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); + +// var targetNode = root.FindNode(context.Span); +// var property = targetNode as PropertyDeclarationSyntax; +// if (property == null) return; + +// var targetType = model.GetDeclaredSymbol(property)?.ContainingType; +// if (targetType == null) return; +// if (!targetType.GetAllMembers().OfType().Any()) return; + +// var action = CodeAction.Create("Add IndexAttribute and Set 'virtual'", c => AddIndexAttributeAndSetVirtual(context.Document, targetType, c)); + +// context.RegisterCodeFix(action, context.Diagnostics.First()); // use single. +// } + +// static async Task AddIndexAttributeAndSetVirtual(Document document, INamedTypeSymbol type, CancellationToken cancellationToken) +// { +// var editor = await DocumentEditor.CreateAsync(document); + +// var targets = type.GetAllMembers().OfType() +// .Where(x => x.GetAttributes().FindAttributeShortName(ZeroFormatterAnalyzer.IgnoreShortName) == null) +// .Where(x => !x.IsStatic) +// .Where(x => x.ExplicitInterfaceImplementations.Length == 0) +// .ToArray(); + +// var startOrder = targets +// .Select(x => x.GetAttributes().FindAttributeShortName(ZeroFormatterAnalyzer.IndexAttributeShortName)) +// .Where(x => x != null) +// .Select(x => x.ConstructorArguments[0]) +// .Where(x => !x.IsNull) +// .Select(x => (int)x.Value) +// .DefaultIfEmpty(-1) // if empty, start from zero. +// .Max() + 1; + +// foreach (var item in targets) +// { +// var node = await item.DeclaringSyntaxReferences[0].GetSyntaxAsync(); +// editor.SetModifiers(node, DeclarationModifiers.Virtual); // force virtual + +// var attr = item.GetAttributes().FindAttributeShortName(ZeroFormatterAnalyzer.IndexAttributeShortName); +// if (attr != null) continue; // already tagged Index. + +// var attribute = RoslynExtensions.ParseAttributeList($"[Index({startOrder++})]"); + +// editor.AddAttribute(node, attribute); +// } + +// var newDocument = editor.GetChangedDocument(); +// return newDocument; +// } +// } +//} \ No newline at end of file diff --git a/src/MessagePack.Analyzer/MessagePack.Analyzer/ConfigurationLoader.cs b/src/MessagePack.Analyzer/MessagePack.Analyzer/ConfigurationLoader.cs new file mode 100644 index 00000000..1c37a26b --- /dev/null +++ b/src/MessagePack.Analyzer/MessagePack.Analyzer/ConfigurationLoader.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using System.IO; + +namespace MessagePack.Analyzer +{ + public static class ConfigurationLoader + { + static readonly string[] Empty = new string[0]; + + public static System.Collections.Generic.IReadOnlyList GetAdditionalAllowTypes(this AnalyzerOptions option) + { + var config = option.AdditionalFiles.FirstOrDefault(x => System.IO.Path.GetFileName(x.Path).Equals("MessagePackAnalyzer.json", StringComparison.OrdinalIgnoreCase)); + if (config != null) + { + try + { + var l = new List(); + var raw = config.GetText().ToString(); + using (var sr = new StringReader(raw)) + using (var tr = new TinyJsonReader(sr)) + { + while (tr.Read()) + { + if (tr.TokenType == TinyJsonToken.String) + { + l.Add(tr.Value as string); + } + } + } + + return l; + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine("Can't load MessagePackAnalyzer.json:" + ex.ToString()); + return Empty; + } + } + else + { + return Empty; + } + } + } +} \ No newline at end of file diff --git a/src/MessagePack.Analyzer/MessagePack.Analyzer/DiagnosticAnalyzer.cs b/src/MessagePack.Analyzer/MessagePack.Analyzer/DiagnosticAnalyzer.cs new file mode 100644 index 00000000..39f0dac9 --- /dev/null +++ b/src/MessagePack.Analyzer/MessagePack.Analyzer/DiagnosticAnalyzer.cs @@ -0,0 +1,427 @@ +//using System; +//using System.Collections.Generic; +//using System.Collections.Immutable; +//using System.Linq; +//using System.Threading; +//using Microsoft.CodeAnalysis; +//using Microsoft.CodeAnalysis.CSharp; +//using Microsoft.CodeAnalysis.CSharp.Syntax; +//using Microsoft.CodeAnalysis.Diagnostics; + +//namespace MessagePack.Analyzer +//{ +// [DiagnosticAnalyzer(LanguageNames.CSharp)] +// public class MessagePackAnalyzer : DiagnosticAnalyzer +// { +// const string DiagnosticIdBase = "MessagePackAnalyzerAnalyzer"; + +// internal const string Title = "Lint of MessagePack Type."; +// internal const string Category = "Usage"; + +// internal const string MessagePackObjectAttributeShortName = "MessagePackObjectAttribute"; +// internal const string KeyAttributeShortName = "KeyAttribute"; +// internal const string IgnoreShortName = "IgnoreAttribute"; +// internal const string UnionAttributeShortName = "UnionAttribute"; + +// internal static readonly DiagnosticDescriptor TypeMustBeMessagePackObject = new DiagnosticDescriptor( +// id: DiagnosticIdBase + "_" + nameof(TypeMustBeMessagePackObject), title: Title, category: Category, +// messageFormat: "Type must be marked with MessagePackObjectAttribute. {0}.", // type.Name +// description: "Type must be marked with MessagePackObjectAttribute.", +// defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); + +// internal static readonly DiagnosticDescriptor PublicMemberNeedsKey = new DiagnosticDescriptor( +// id: DiagnosticIdBase + "_" + nameof(PublicMemberNeedsKey), title: Title, category: Category, +// messageFormat: "Public member must be marked with KeyAttribute or IgnoreAttribute. {0}.{1}.", // type.Name + "." + item.Name +// description: "Public member must be marked with KeyAttribute or IgnoreAttribute.", +// defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); + +// internal static readonly DiagnosticDescriptor KeyAttributeDuplicate = new DiagnosticDescriptor( +// id: DiagnosticIdBase + "_" + nameof(KeyAttributeDuplicate), title: Title, category: Category, +// messageFormat: "KeyAttribute is not allow duplicate number or name. {0}.{1}, Index:{2}", // type.Name, item.Name index.Index +// description: "KeyAttribute is not allow duplicate number or name.", +// defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); + +// static readonly ImmutableArray supportedDiagnostics = ImmutableArray.Create( +// TypeMustBeMessagePackObject, +// PublicMemberNeedsKey, +// KeyAttributeDuplicate +// ); + +// public override ImmutableArray SupportedDiagnostics +// { +// get +// { +// return supportedDiagnostics; +// } +// } + +// public override void Initialize(AnalysisContext context) +// { +// context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.InterfaceDeclaration); +// } + +// static void Analyze(SyntaxNodeAnalysisContext context) +// { +// var model = context.SemanticModel; + +// var typeDeclaration = context.Node as TypeDeclarationSyntax; +// if (typeDeclaration == null) return; + +// var declaredSymbol = model.GetDeclaredSymbol(typeDeclaration); +// if (declaredSymbol == null) return; + +// var reportContext = new DiagnosticsReportContext(context); + +// var collector = new TypeCollector(reportContext, model.Compilation); +// collector.CollectCore(declaredSymbol); +// reportContext.ReportAll(); +// } +// } + +// public class ReferenceSymbols +// { +// public readonly INamedTypeSymbol Task; +// public readonly INamedTypeSymbol TaskOfT; +// public readonly INamedTypeSymbol MessagePackObjectAttribnute; +// public readonly INamedTypeSymbol UnionAttribute; +// public readonly INamedTypeSymbol SerializationConstructorAttribute; +// public readonly INamedTypeSymbol KeyAttribnute; +// public readonly INamedTypeSymbol IgnoreAttribnute; +// public readonly INamedTypeSymbol IMessagePackSerializationCallbackReceiver; + +// public ReferenceSymbols(Compilation compilation) +// { +// TaskOfT = compilation.GetTypeByMetadataName("System.Threading.Tasks.Task`1"); +// Task = compilation.GetTypeByMetadataName("System.Threading.Tasks.Task"); +// MessagePackObjectAttribnute = compilation.GetTypeByMetadataName("MessagePack.MessagePackObjectAttribute"); +// UnionAttribute = compilation.GetTypeByMetadataName("MessagePack.UnionAttribute"); +// SerializationConstructorAttribute = compilation.GetTypeByMetadataName("MessagePack.SerializationConstructorAttribute"); +// KeyAttribnute = compilation.GetTypeByMetadataName("MessagePack.KeyAttribute"); +// IgnoreAttribnute = compilation.GetTypeByMetadataName("MessagePack.IgnoreAttribute"); +// IMessagePackSerializationCallbackReceiver = compilation.GetTypeByMetadataName("MessagePack.IMessagePackSerializationCallbackReceiver"); +// } +// } + +// internal class TypeCollector +// { +// static readonly SymbolDisplayFormat binaryWriteFormat = new SymbolDisplayFormat( +// genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, +// miscellaneousOptions: SymbolDisplayMiscellaneousOptions.ExpandNullable, +// typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameOnly); + +// static readonly SymbolDisplayFormat shortTypeNameFormat = new SymbolDisplayFormat( +// typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes); + +// readonly ReferenceSymbols typeReferences; +// readonly INamedTypeSymbol[] targetTypes; +// readonly HashSet embeddedTypes = new HashSet(new string[] +// { +// "short", +// "int", +// "long", +// "ushort", +// "uint", +// "ulong", +// "float", +// "double", +// "bool", +// "byte", +// "sbyte", +// "decimal", +// "char", +// "System.Guid", +// "System.TimeSpan", +// "System.DateTime", +// "System.DateTimeOffset", +// }); + +// readonly Dictionary knownGenericTypes = new Dictionary +// { +// {"System.Collections.Generic.List<>", "global::MessagePack.Formatters.ListFormatter" }, +// {"System.Collections.Generic.LinkedList<>", "global::MessagePack.Formatters.LinkedListFormatter"}, +// {"System.Collections.Generic.Queue<>", "global::MessagePack.Formatters.QeueueFormatter"}, +// {"System.Collections.Generic.Stack<>", "global::MessagePack.Formatters.StackFormatter"}, +// {"System.Collections.Generic.HashSet<>", "global::MessagePack.Formatters.HashSetFormatter"}, +// {"System.Collections.ObjectModel.ReadOnlyCollection<>", "global::MessagePack.Formatters.ReadOnlyCollectionFormatter"}, +// {"System.Collections.Generic.IList<>", "global::MessagePack.Formatters.InterfaceListFormatter"}, +// {"System.Collections.Generic.ICollection<>", "global::MessagePack.Formatters.InterfaceCollectionFormatter"}, +// {"System.Collections.Generic.IEnumerable<>", "global::MessagePack.Formatters.InterfaceEnumerableFormatter"}, +// {"System.Collections.Generic.Dictionary<,>", "global::MessagePack.Formatters.DictionaryFormatter"}, +// {"System.Collections.Generic.IDictionary<,>", "global::MessagePack.Formatters.InterfaceDictionaryFormatter"}, +// {"System.Collections.Generic.SortedDictionary<,>", "global::MessagePack.Formatters.SortedDictionaryFormatter"}, +// {"System.Collections.Generic.SortedList<,>", "global::MessagePack.Formatters.SortedListFormatter"}, +// {"System.Linq.ILookup<,>", "global::MessagePack.Formatters.InterfaceLookupFormatter"}, +// {"System.Linq.IGrouping<,>", "global::MessagePack.Formatters.InterfaceGroupingFormatter"}, +// {"System.Collections.ObjectModel.ObservableCollection<>", "global::MessagePack.Formatters.ObservableCollectionFormatter"}, +// {"System.Collections.ObjectModel.ReadOnlyObservableCollection<>", "global::MessagePack.Formatters.ReadOnlyObservableCollectionFormatter" }, +// {"System.Collections.Generic.IReadOnlyList<>", "global::MessagePack.Formatters.InterfaceReadOnlyListFormatter"}, +// {"System.Collections.Generic.IReadOnlyCollection<>", "global::MessagePack.Formatters.InterfaceReadOnlyCollectionFormatter"}, +// {"System.Collections.Generic.ISet<>", "global::MessagePack.Formatters.InterfaceSetFormatter"}, +// {"System.Collections.Concurrent.ConcurrentBag<>", "global::MessagePack.Formatters.ConcurrentBagFormatter"}, +// {"System.Collections.Concurrent.ConcurrentQueue<>", "global::MessagePack.Formatters.ConcurrentQueueFormatter"}, +// {"System.Collections.Concurrent.ConcurrentStack<>", "global::MessagePack.Formatters.ConcurrentStackFormatter"}, +// {"System.Collections.ObjectModel.ReadOnlyDictionary<,>", "global::MessagePack.Formatters.ReadOnlyDictionaryFormatter"}, +// {"System.Collections.Generic.IReadOnlyDictionary<,>", "global::MessagePack.Formatters.InterfaceReadOnlyDictionaryFormatter"}, +// {"System.Collections.Concurrent.ConcurrentDictionary<,>", "global::MessagePack.Formatters.ConcurrentDictionaryFormatter"}, +// {"System.Lazy<>", "global::MessagePack.Formatters.LazyFormatter"}, +// {"System.Threading.Tasks<>", "global::MessagePack.Formatters.TaskValueFormatter"}, + +// {"System.Tuple<>", "global::MessagePack.Formatters.TupleFormatter"}, +// {"System.Tuple<,>", "global::MessagePack.Formatters.TupleFormatter"}, +// {"System.Tuple<,,>", "global::MessagePack.Formatters.TupleFormatter"}, +// {"System.Tuple<,,,>", "global::MessagePack.Formatters.TupleFormatter"}, +// {"System.Tuple<,,,,>", "global::MessagePack.Formatters.TupleFormatter"}, +// {"System.Tuple<,,,,,>", "global::MessagePack.Formatters.TupleFormatter"}, +// {"System.Tuple<,,,,,,>", "global::MessagePack.Formatters.TupleFormatter"}, +// {"System.Tuple<,,,,,,,>", "global::MessagePack.Formatters.TupleFormatter"}, + +// {"System.ValueTuple<>", "global::MessagePack.Formatters.ValueTupleFormatter"}, +// {"System.ValueTuple<,>", "global::MessagePack.Formatters.ValueTupleFormatter"}, +// {"System.ValueTuple<,,>", "global::MessagePack.Formatters.ValueTupleFormatter"}, +// {"System.ValueTuple<,,,>", "global::MessagePack.Formatters.ValueTupleFormatter"}, +// {"System.ValueTuple<,,,,>", "global::MessagePack.Formatters.ValueTupleFormatter"}, +// {"System.ValueTuple<,,,,,>", "global::MessagePack.Formatters.ValueTupleFormatter"}, +// {"System.ValueTuple<,,,,,,>", "global::MessagePack.Formatters.ValueTupleFormatter"}, +// {"System.ValueTuple<,,,,,,,>", "global::MessagePack.Formatters.ValueTupleFormatter"}, + +// {"System.Collections.Generic.KeyValuePair<,>", "global::MessagePack.Formatters.KeyValuePairFormatter"}, +// {"System.Threading.Tasks.ValueTask<>", "global::MessagePack.Formatters.KeyValuePairFormatter"}, +// {"System.ArraySegment<>", "global::MessagePack.Formatters.ArraySegmentFormatter"}, + +// // extensions + +// {"System.Collections.Immutable.ImmutableArray<>", "global::MessagePack.ImmutableCollection.ImmutableArrayFormatter"}, +// {"System.Collections.Immutable.ImmutableList<>", "global::MessagePack.ImmutableCollection.ImmutableListFormatter"}, +// {"System.Collections.Immutable.ImmutableDictionary<,>", "global::MessagePack.ImmutableCollection.ImmutableDictionaryFormatter"}, +// {"System.Collections.Immutable.ImmutableHashSet<>", "global::MessagePack.ImmutableCollection.ImmutableHashSetFormatter"}, +// {"System.Collections.Immutable.ImmutableSortedDictionary<,>", "global::MessagePack.ImmutableCollection.ImmutableSortedDictionaryFormatter"}, +// {"System.Collections.Immutable.ImmutableSortedSet<>", "global::MessagePack.ImmutableCollection.ImmutableSortedSetFormatter"}, +// {"System.Collections.Immutable.ImmutableQueue<>", "global::MessagePack.ImmutableCollection.ImmutableQueueFormatter"}, +// {"System.Collections.Immutable.ImmutableStack<>", "global::MessagePack.ImmutableCollection.ImmutableStackFormatter"}, +// {"System.Collections.Immutable.IImmutableList<>", "global::MessagePack.ImmutableCollection.InterfaceImmutableListFormatter"}, +// {"System.Collections.Immutable.IImmutableDictionary<,>", "global::MessagePack.ImmutableCollection.InterfaceImmutableDictionaryFormatter"}, +// {"System.Collections.Immutable.IImmutableQueue<>", "global::MessagePack.ImmutableCollection.InterfaceImmutableQueueFormatter"}, +// {"System.Collections.Immutable.IImmutableSet<>", "global::MessagePack.ImmutableCollection.InterfaceImmutableSetFormatter"}, +// {"System.Collections.Immutable.IImmutableStack<>", "global::MessagePack.ImmutableCollection.InterfaceImmutableStackFormatter"}, + +// {"Reactive.Bindings.ReactiveProperty<>", "global::MessagePack.ReactivePropertyExtension.ReactivePropertyFormatter"}, +// {"Reactive.Bindings.IReactiveProperty<>", "global::MessagePack.ReactivePropertyExtension.InterfaceReactivePropertyFormatter"}, +// {"Reactive.Bindings.IReadOnlyReactiveProperty<>", "global::MessagePack.ReactivePropertyExtension.InterfaceReadOnlyReactivePropertyFormatter"}, +// {"Reactive.Bindings.ReactiveCollection<>", "global::MessagePack.ReactivePropertyExtension.ReactiveCollectionFormatter"}, +// }; + +// // visitor workspace: +// HashSet alreadyCollected; + +// public DiagnosticsReportContext ReportContext { get; set; } + +// public TypeCollector(DiagnosticsReportContext reportContext, Compilation compilation) +// { +// this.typeReferences = new ReferenceSymbols(compilation); +// this.ReportContext = reportContext; +// } + +// // Gate of recursive collect +// public void CollectCore(ITypeSymbol typeSymbol) +// { +// var type = typeSymbol as INamedTypeSymbol; + +// if (type == null) +// { +// return; +// } + +// if (!alreadyCollected.Add(typeSymbol)) +// { +// return; +// } + +// if (embeddedTypes.Contains(type.ToString())) +// { +// return; +// } + +// if (ReportContext.AdditionalAllowTypes.Contains(type.ToDisplayString())) +// { +// return; +// } + + +// if (type.TypeKind == TypeKind.Enum) +// { +// return; +// } + +// if (type.IsGenericType) +// { +// foreach (var item in type.TypeArguments) +// { +// CollectCore(item); +// } +// return; +// } + +// if (type.TypeKind == TypeKind.Array) +// { +// var array = type as IArrayTypeSymbol; +// var t = array.ElementType; +// CollectCore(t); +// return; +// } + +// if (type.Locations[0].IsInMetadata) +// { +// return; +// } + +// if (type.TypeKind == TypeKind.Interface) +// { +// return; +// } + +// // only do object:) +// CollectObject(type); +// return; +// } + + +// void CollectObject(INamedTypeSymbol type) +// { +// var isClass = !type.IsValueType; + +// var contractAttr = type.GetAttributes().FirstOrDefault(x => x.AttributeClass == typeReferences.MessagePackObjectAttribnute); +// if (contractAttr == null) +// { +// ReportContext.Add(Diagnostic.Create(MessagePackAnalyzer.TypeMustBeMessagePackObject, type.Locations[0], type.Name)); +// } + +// var isIntKey = true; +// var intMemebers = new HashSet(); +// var stringMembers = new HashSet(); + +// if ((bool)contractAttr.ConstructorArguments[0].Value) +// { +// // Opt-out: All public members are serialize target except [Ignore] member. +// isIntKey = false; + +// foreach (var item in type.GetAllMembers().OfType()) +// { +// if (item.GetAttributes().Any(x => x.AttributeClass == typeReferences.IgnoreAttribnute)) continue; + +// var IsReadable = (item.GetMethod != null) && item.GetMethod.DeclaredAccessibility == Accessibility.Public && !item.IsStatic; +// var IsWritable = (item.SetMethod != null) && item.SetMethod.DeclaredAccessibility == Accessibility.Public && !item.IsStatic; + +// if (!IsReadable && !IsWritable) continue; + +// stringMembers.Add(item.Name); +// CollectCore(item.Type); // recursive collect +// } +// foreach (var item in type.GetAllMembers().OfType()) +// { +// if (item.GetAttributes().Any(x => x.AttributeClass == typeReferences.IgnoreAttribnute)) continue; + +// var IsReadable = item.DeclaredAccessibility == Accessibility.Public && !item.IsStatic; +// var IsWritable = item.DeclaredAccessibility == Accessibility.Public && !item.IsReadOnly && !item.IsStatic; + +// if (!IsReadable && !IsWritable) continue; + +// stringMembers.Add(item.Name); +// CollectCore(item.Type); // recursive collect +// } +// } +// else +// { +// // Opt-in: Only KeyAttribute members +// var searchFirst = true; + +// foreach (var item in type.GetAllMembers().OfType()) +// { +// if (item.GetAttributes().Any(x => x.AttributeClass == typeReferences.IgnoreAttribnute)) continue; + +// var key = item.GetAttributes().FirstOrDefault(x => x.AttributeClass == typeReferences.KeyAttribnute)?.ConstructorArguments[0]; +// if (key == null) continue; + +// var intKey = (key.Value.Value is int) ? (int)key.Value.Value : (int?)null; +// var stringKey = (key.Value.Value is string) ? (string)key.Value.Value : (string)null; +// if (intKey == null && stringKey == null) throw new MessagePackGeneratorResolveFailedException("both IntKey and StringKey are null." + " type: " + type.Name + " member:" + item.Name); + +// if (searchFirst) +// { +// searchFirst = false; +// isIntKey = intKey != null; +// } +// else +// { +// if ((isIntKey && intKey == null) || (!isIntKey && stringKey == null)) +// { +// throw new MessagePackGeneratorResolveFailedException("all members key type must be same." + " type: " + type.Name + " member:" + item.Name); +// } +// } + +// var IsReadable = (item.GetMethod != null) && item.GetMethod.DeclaredAccessibility == Accessibility.Public && !item.IsStatic; +// var IsWritable = (item.SetMethod != null) && item.SetMethod.DeclaredAccessibility == Accessibility.Public && !item.IsStatic; +// var Name = item.Name; +// if (!IsReadable && !IsWritable) continue; + +// if (isIntKey) +// { +// if (intMemebers.Contains((int)intKey)) throw new MessagePackGeneratorResolveFailedException("key is duplicated, all members key must be unique." + " type: " + type.Name + " member:" + item.Name); + +// intMemebers.Add((int)intKey); +// } +// else +// { +// if (stringMembers.Contains((string)stringKey)) throw new MessagePackGeneratorResolveFailedException("key is duplicated, all members key must be unique." + " type: " + type.Name + " member:" + item.Name); + +// stringMembers.Add((string)stringKey); +// } + +// CollectCore(item.Type); // recursive collect +// } + +// foreach (var item in type.GetAllMembers().OfType()) +// { +// var key = item.GetAttributes().FirstOrDefault(x => x.AttributeClass == typeReferences.KeyAttribnute)?.ConstructorArguments[0]; +// if (key == null) continue; + +// var intKey = (key.Value.Value is int) ? (int)key.Value.Value : (int?)null; +// var stringKey = (key.Value.Value is string) ? (string)key.Value.Value : (string)null; +// if (intKey == null && stringKey == null) throw new MessagePackGeneratorResolveFailedException("both IntKey and StringKey are null." + " type: " + type.Name + " member:" + item.Name); + +// if (searchFirst) +// { +// searchFirst = false; +// isIntKey = intKey != null; +// } +// else +// { +// if ((isIntKey && intKey == null) || (!isIntKey && stringKey == null)) +// { +// throw new MessagePackGeneratorResolveFailedException("all members key type must be same." + " type: " + type.Name + " member:" + item.Name); +// } +// } + +// var IsReadable = item.DeclaredAccessibility == Accessibility.Public && !item.IsStatic; +// var IsWritable = item.DeclaredAccessibility == Accessibility.Public && !item.IsReadOnly && !item.IsStatic; +// var Name = item.Name; +// if (!IsReadable && !IsWritable) continue; + +// if (isIntKey) +// { +// if (intMemebers.Contains((int)intKey)) throw new MessagePackGeneratorResolveFailedException("key is duplicated, all members key must be unique." + " type: " + type.Name + " member:" + item.Name); + +// intMemebers.Add((int)intKey); +// } +// else +// { +// if (stringMembers.Contains((string)stringKey)) throw new MessagePackGeneratorResolveFailedException("key is duplicated, all members key must be unique." + " type: " + type.Name + " member:" + item.Name); + +// stringMembers.Add((string)stringKey); +// } + +// CollectCore(item.Type); // recursive collect +// } +// } +// } +// } +//} diff --git a/src/MessagePack.Analyzer/MessagePack.Analyzer/DiagnosticsReportContext.cs b/src/MessagePack.Analyzer/MessagePack.Analyzer/DiagnosticsReportContext.cs new file mode 100644 index 00000000..80f4052f --- /dev/null +++ b/src/MessagePack.Analyzer/MessagePack.Analyzer/DiagnosticsReportContext.cs @@ -0,0 +1,41 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Diagnostics; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MessagePack.Analyzer +{ + // Store multiple errors. + internal class DiagnosticsReportContext + { + readonly List diagnostics = new List(); + readonly SyntaxNodeAnalysisContext context; + + public IReadOnlyList Diagnostics => diagnostics; + + public IReadOnlyList AdditionalAllowTypes { get; } + + public DiagnosticsReportContext(SyntaxNodeAnalysisContext context) + { + this.context = context; + this.AdditionalAllowTypes = this.context.Options.GetAdditionalAllowTypes(); + } + + public void Add(Diagnostic diagnostic) + { + diagnostics.Add(diagnostic); + } + + public void ReportAll() + { + foreach (var item in diagnostics) + { + context.ReportDiagnostic(item); + } + } + } +} \ No newline at end of file diff --git a/src/MessagePack.Analyzer/MessagePack.Analyzer/MessagePack.Analyzer.csproj b/src/MessagePack.Analyzer/MessagePack.Analyzer/MessagePack.Analyzer.csproj new file mode 100644 index 00000000..cebee105 --- /dev/null +++ b/src/MessagePack.Analyzer/MessagePack.Analyzer/MessagePack.Analyzer.csproj @@ -0,0 +1,113 @@ + + + + + + 11.0 + Debug + AnyCPU + AnyCPU + {900E3D34-3091-4841-AA71-5D610797BC25} + Library + Properties + MessagePack.Analyzer + MessagePack.Analyzer + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + v4.5 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + + + + + + + ..\..\..\packages\Microsoft.CodeAnalysis.Common.1.0.1\lib\portable-net45+win8\Microsoft.CodeAnalysis.dll + False + + + ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.1.0.1\lib\portable-net45+win8\Microsoft.CodeAnalysis.CSharp.dll + False + + + ..\..\..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.1.0.1\lib\portable-net45+win8\Microsoft.CodeAnalysis.CSharp.Workspaces.dll + False + + + ..\..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.0.1\lib\portable-net45+win8\Microsoft.CodeAnalysis.Workspaces.dll + False + + + ..\..\..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + False + + + ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll + False + + + ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll + False + + + ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll + False + + + ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll + False + + + ..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll + False + + + ..\..\..\packages\System.Reflection.Metadata.1.0.21\lib\portable-net45+win8\System.Reflection.Metadata.dll + False + + + + + + + + + + + + \ No newline at end of file diff --git a/src/MessagePack.Analyzer/MessagePack.Analyzer/Properties/AssemblyInfo.cs b/src/MessagePack.Analyzer/MessagePack.Analyzer/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..c5647e2e --- /dev/null +++ b/src/MessagePack.Analyzer/MessagePack.Analyzer/Properties/AssemblyInfo.cs @@ -0,0 +1,31 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MessagePack.Analyzer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MessagePack.Analyzer")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/MessagePack.Analyzer/MessagePack.Analyzer/RoslynExtensions.cs b/src/MessagePack.Analyzer/MessagePack.Analyzer/RoslynExtensions.cs new file mode 100644 index 00000000..c1898844 --- /dev/null +++ b/src/MessagePack.Analyzer/MessagePack.Analyzer/RoslynExtensions.cs @@ -0,0 +1,132 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace MessagePack.Analyzer +{ + // Utility and Extension methods for Roslyn + internal static class RoslynExtensions + { + public static IEnumerable GetNamedTypeSymbols(this Compilation compilation) + { + foreach (var syntaxTree in compilation.SyntaxTrees) + { + var semModel = compilation.GetSemanticModel(syntaxTree); + + foreach (var item in syntaxTree.GetRoot() + .DescendantNodes() + .Select(x => semModel.GetDeclaredSymbol(x)) + .Where(x => x != null)) + { + var namedType = item as INamedTypeSymbol; + if (namedType != null) + { + yield return namedType; + } + } + } + } + + public static IEnumerable EnumerateBaseType(this ITypeSymbol symbol) + { + var t = symbol.BaseType; + while (t != null) + { + yield return t; + t = t.BaseType; + } + } + + public static AttributeData FindAttribute(this IEnumerable attributeDataList, string typeName) + { + return attributeDataList + .Where(x => x.AttributeClass.ToDisplayString() == typeName) + .FirstOrDefault(); + } + + public static AttributeData FindAttributeShortName(this IEnumerable attributeDataList, string typeName) + { + return attributeDataList + .Where(x => x.AttributeClass.Name == typeName) + .FirstOrDefault(); + } + + public static AttributeData FindAttributeIncludeBasePropertyShortName(this IPropertySymbol property, string typeName) + { + do + { + var data = FindAttributeShortName(property.GetAttributes(), typeName); + if (data != null) return data; + property = property.OverriddenProperty; + } while (property != null); + + return null; + } + + public static AttributeSyntax FindAttribute(this BaseTypeDeclarationSyntax typeDeclaration, SemanticModel model, string typeName) + { + return typeDeclaration.AttributeLists + .SelectMany(x => x.Attributes) + .Where(x => model.GetTypeInfo(x).Type?.ToDisplayString() == typeName) + .FirstOrDefault(); + } + + public static INamedTypeSymbol FindBaseTargetType(this ITypeSymbol symbol, string typeName) + { + return symbol.EnumerateBaseType() + .Where(x => x.OriginalDefinition?.ToDisplayString() == typeName) + .FirstOrDefault(); + } + + public static object GetSingleNamedArgumentValue(this AttributeData attribute, string key) + { + foreach (var item in attribute.NamedArguments) + { + if (item.Key == key) + { + return item.Value.Value; + } + } + + return null; + } + + public static bool IsNullable(this INamedTypeSymbol symbol) + { + if (symbol.IsGenericType) + { + if (symbol.ConstructUnboundGenericType().ToDisplayString() == "T?") + { + return true; + } + } + return false; + } + + public static IEnumerable GetAllMembers(this ITypeSymbol symbol) + { + var t = symbol; + while (t != null) + { + foreach (var item in t.GetMembers()) + { + yield return item; + } + t = t.BaseType; + } + } + + public static IEnumerable GetAllInterfaceMembers(this ITypeSymbol symbol) + { + return symbol.GetMembers() + .Concat(symbol.AllInterfaces.SelectMany(x => x.GetMembers())); + } + } +} diff --git a/src/MessagePack.Analyzer/MessagePack.Analyzer/TinyJsonReader.cs b/src/MessagePack.Analyzer/MessagePack.Analyzer/TinyJsonReader.cs new file mode 100644 index 00000000..fcec2137 --- /dev/null +++ b/src/MessagePack.Analyzer/MessagePack.Analyzer/TinyJsonReader.cs @@ -0,0 +1,594 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; + +// TinyJson is handmade Json reader/writer library. +// It no needs JSON.NET dependency. + +namespace MessagePack.Analyzer +{ + public class TinyJsonException : Exception + { + public TinyJsonException(string message) : base(message) + { + + } + } + + public class KnownTypeSerializer + { + readonly Dictionary> serializers = new Dictionary>(); + readonly Dictionary> deserializers = new Dictionary>(); + + public static KnownTypeSerializer Default = new KnownTypeSerializer(); + + public KnownTypeSerializer() + { + serializers.Add(typeof(DateTime), x => ((DateTime)x).ToString("o")); + deserializers.Add(typeof(DateTime), x => DateTime.Parse(x)); + serializers.Add(typeof(DateTimeOffset), x => ((DateTimeOffset)x).ToString("o")); + deserializers.Add(typeof(DateTimeOffset), x => DateTimeOffset.Parse(x)); + serializers.Add(typeof(Uri), x => ((Uri)x).ToString()); + deserializers.Add(typeof(Uri), x => new Uri(x)); + serializers.Add(typeof(Guid), x => ((Guid)x).ToString()); + deserializers.Add(typeof(Guid), x => new Guid(x)); + } + + public bool Contains(Type type) + { + return serializers.ContainsKey(type); + } + + public void Register(Type type, Func serializer, Func deserializer) + { + serializers[type] = serializer; + deserializers[type] = deserializer; + } + + public bool TrySerialize(Type type, object obj, out string result) + { + Func serializer; + if (type != null && serializers.TryGetValue(type, out serializer)) + { + result = serializer(obj); + return true; + } + else + { + result = null; + return false; + } + } + + public bool TryDeserialize(Type type, string json, out object result) + { + Func deserializer; + if (type != null && deserializers.TryGetValue(type, out deserializer)) + { + result = deserializer(json); + return true; + } + else + { + result = null; + return false; + } + } + } + + public enum TinyJsonToken + { + None, + StartObject, // { + EndObject, // } + StartArray, // [ + EndArray, // ] + Number, // -0~9 + String, // "___" + True, // true + False, // false + Null, // null + } + + public class TinyJsonReader : IDisposable + { + readonly TextReader reader; + readonly bool disposeInnerReader; + + public TinyJsonToken TokenType { get; private set; } + public object Value { get; private set; } + + public TinyJsonReader(TextReader reader, bool disposeInnerReader = true) + { + this.reader = reader; + this.disposeInnerReader = disposeInnerReader; + } + + public bool Read() + { + ReadNextToken(); + ReadValue(); + return TokenType != TinyJsonToken.None; + } + + public void Dispose() + { + if (reader != null && disposeInnerReader) + { + reader.Dispose(); + } + TokenType = TinyJsonToken.None; + Value = null; + } + + void SkipWhiteSpace() + { + var c = reader.Peek(); + while (c != -1 && Char.IsWhiteSpace((char)c)) + { + reader.Read(); + c = reader.Peek(); + } + } + + char ReadChar() + { + return (char)reader.Read(); + } + + static bool IsWordBreak(char c) + { + switch (c) + { + case ' ': + case '{': + case '}': + case '[': + case ']': + case ',': + case ':': + case '\"': + return true; + default: + return false; + } + } + + void ReadNextToken() + { + SkipWhiteSpace(); + + var intChar = reader.Peek(); + if (intChar == -1) + { + TokenType = TinyJsonToken.None; + return; + } + + var c = (char)intChar; + switch (c) + { + case '{': + TokenType = TinyJsonToken.StartObject; + return; + case '}': + TokenType = TinyJsonToken.EndObject; + return; + case '[': + TokenType = TinyJsonToken.StartArray; + return; + case ']': + TokenType = TinyJsonToken.EndArray; + return; + case '"': + TokenType = TinyJsonToken.String; + return; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + TokenType = TinyJsonToken.Number; + return; + case 't': + TokenType = TinyJsonToken.True; + return; + case 'f': + TokenType = TinyJsonToken.False; + return; + case 'n': + TokenType = TinyJsonToken.Null; + return; + case ',': + case ':': + reader.Read(); + ReadNextToken(); + return; + default: + throw new TinyJsonException("Invalid String:" + c); + } + } + + void ReadValue() + { + Value = null; + + switch (TokenType) + { + case TinyJsonToken.None: + break; + case TinyJsonToken.StartObject: + case TinyJsonToken.EndObject: + case TinyJsonToken.StartArray: + case TinyJsonToken.EndArray: + reader.Read(); + break; + case TinyJsonToken.Number: + ReadNumber(); + break; + case TinyJsonToken.String: + ReadString(); + break; + case TinyJsonToken.True: + if (ReadChar() != 't') throw new TinyJsonException("Invalid Token"); + if (ReadChar() != 'r') throw new TinyJsonException("Invalid Token"); + if (ReadChar() != 'u') throw new TinyJsonException("Invalid Token"); + if (ReadChar() != 'e') throw new TinyJsonException("Invalid Token"); + Value = true; + break; + case TinyJsonToken.False: + if (ReadChar() != 'f') throw new TinyJsonException("Invalid Token"); + if (ReadChar() != 'a') throw new TinyJsonException("Invalid Token"); + if (ReadChar() != 'l') throw new TinyJsonException("Invalid Token"); + if (ReadChar() != 's') throw new TinyJsonException("Invalid Token"); + if (ReadChar() != 'e') throw new TinyJsonException("Invalid Token"); + Value = false; + break; + case TinyJsonToken.Null: + if (ReadChar() != 'n') throw new TinyJsonException("Invalid Token"); + if (ReadChar() != 'u') throw new TinyJsonException("Invalid Token"); + if (ReadChar() != 'l') throw new TinyJsonException("Invalid Token"); + if (ReadChar() != 'l') throw new TinyJsonException("Invalid Token"); + Value = null; + break; + default: + throw new ArgumentException("InvalidTokenState:" + TokenType); + } + } + + void ReadNumber() + { + var numberWord = new StringBuilder(); + + var isDouble = false; + var intChar = reader.Peek(); + while (intChar != -1 && !IsWordBreak((char)intChar)) + { + var c = ReadChar(); + numberWord.Append(c); + if (c == '.') isDouble = true; + intChar = reader.Peek(); + } + + var number = numberWord.ToString(); + if (isDouble) + { + double parsedDouble; + Double.TryParse(number, out parsedDouble); + Value = parsedDouble; + } + else + { + long parsedInt; + if (Int64.TryParse(number, out parsedInt)) + { + Value = parsedInt; + return; + } + + ulong parsedULong; + if (ulong.TryParse(number, out parsedULong)) + { + Value = parsedULong; + return; + } + + Decimal parsedDecimal; + if (decimal.TryParse(number, out parsedDecimal)) + { + Value = parsedDecimal; + return; + } + } + } + + void ReadString() + { + reader.Read(); // skip ["] + + var sb = new StringBuilder(); + while (true) + { + if (reader.Peek() == -1) throw new TinyJsonException("Invalid Json String"); + + var c = ReadChar(); + switch (c) + { + case '"': // endtoken + goto END; + case '\\': // escape character + if (reader.Peek() == -1) throw new TinyJsonException("Invalid Json String"); + + c = ReadChar(); + switch (c) + { + case '"': + case '\\': + case '/': + sb.Append(c); + break; + case 'b': + sb.Append('\b'); + break; + case 'f': + sb.Append('\f'); + break; + case 'n': + sb.Append('\n'); + break; + case 'r': + sb.Append('\r'); + break; + case 't': + sb.Append('\t'); + break; + case 'u': + var hex = new char[4]; + hex[0] = ReadChar(); + hex[1] = ReadChar(); + hex[2] = ReadChar(); + hex[3] = ReadChar(); + sb.Append((char)Convert.ToInt32(new string(hex), 16)); + break; + } + break; + default: // string + sb.Append(c); + break; + } + } + + END: + Value = sb.ToString(); + } + } + + public class TinyJsonWriter : IDisposable + { + enum WritingState + { + Value, ArrayStart, ObjectStart, Array, Object, ObjectPropertyName + } + + readonly TextWriter writer; + readonly Stack state; + readonly bool disposeInnerWriter; + + public TinyJsonWriter(TextWriter writer, bool disposeInnerWriter = true) + { + this.writer = writer; + this.disposeInnerWriter = disposeInnerWriter; + this.state = new Stack(); + state.Push(WritingState.Value); + } + + public void WriteStartObject() + { + WritePrefix(); + writer.Write('{'); + state.Push(WritingState.ObjectStart); + } + + public void WriteEndObject() + { + writer.Write('}'); + state.Pop(); + } + + public void WriteStartArray() + { + WritePrefix(); + writer.Write('['); + state.Push(WritingState.ArrayStart); + } + + public void WriteEndArray() + { + writer.Write(']'); + state.Pop(); + } + + public void WritePropertyName(string name) + { + WritePrefix(); + state.Push(WritingState.ObjectPropertyName); + WriteString(name); + } + + public void WriteValue(object obj) + { + WriteValue(obj, KnownTypeSerializer.Default); + } + + public void WriteValue(object obj, KnownTypeSerializer serializer) + { + WritePrefix(); + + // write value + if (obj == null) + { + writer.Write("null"); + } + else if (obj is string) + { + WriteString((string)obj); + } + else if (obj is bool) + { + writer.Write(((bool)obj) ? "true" : "false"); + } + else + { + var t = obj.GetType(); + if (t.GetTypeInfo().IsEnum) + { + var eValue = Convert.ChangeType(obj, Enum.GetUnderlyingType(t)); + writer.Write(eValue); // Enum as WriteNumber + return; + } + + if (t == typeof(sbyte)) + { + writer.Write((sbyte)obj); + } + else if (t == typeof(byte)) + { + writer.Write((byte)obj); + } + else if (t == typeof(Int16)) + { + writer.Write((Int16)obj); + } + else if (t == typeof(UInt16)) + { + writer.Write((UInt16)obj); + } + else if (t == typeof(Int32)) + { + writer.Write((Int32)obj); + } + else if (t == typeof(UInt32)) + { + writer.Write((UInt32)obj); + } + else if (t == typeof(Int64)) + { + writer.Write((Int64)obj); + } + else if (t == typeof(UInt64)) + { + writer.Write((UInt64)obj); + } + else if (t == typeof(Single)) + { + writer.Write((Single)obj); + } + else if (t == typeof(Double)) + { + writer.Write((Double)obj); + } + else if (t == typeof(Decimal)) + { + writer.Write((Decimal)obj); + } + else + { + string result; + if (serializer.TrySerialize(t, obj, out result)) + { + WriteString(result); + } + else + { + WriteString(obj.ToString()); + } + } + } + } + + void WritePrefix() + { + // write prefix by state + var currentState = state.Peek(); + switch (currentState) + { + case WritingState.Value: + break; + case WritingState.ArrayStart: + state.Pop(); + state.Push(WritingState.Array); + break; + case WritingState.ObjectStart: + state.Pop(); + state.Push(WritingState.Object); + break; + case WritingState.Array: + case WritingState.Object: + writer.Write(','); + break; + case WritingState.ObjectPropertyName: + state.Pop(); + writer.Write(':'); + break; + default: + break; + } + } + + void WriteString(string o) + { + writer.Write('\"'); + + for (int i = 0; i < o.Length; i++) + { + var c = o[i]; + switch (c) + { + case '"': + writer.Write("\\\""); + break; + case '\\': + writer.Write("\\\\"); + break; + case '\b': + writer.Write("\\b"); + break; + case '\f': + writer.Write("\\f"); + break; + case '\n': + writer.Write("\\n"); + break; + case '\r': + writer.Write("\\r"); + break; + case '\t': + writer.Write("\\t"); + break; + default: + writer.Write(c); + break; + } + } + + writer.Write('\"'); + } + + public void Dispose() + { + if (writer != null && disposeInnerWriter) + { + writer.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/src/MessagePack.Analyzer/MessagePack.Analyzer/packages.config b/src/MessagePack.Analyzer/MessagePack.Analyzer/packages.config new file mode 100644 index 00000000..dcb01dd2 --- /dev/null +++ b/src/MessagePack.Analyzer/MessagePack.Analyzer/packages.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/MessagePack.Analyzer/MessagePack.Analyzer/tools/install.ps1 b/src/MessagePack.Analyzer/MessagePack.Analyzer/tools/install.ps1 new file mode 100644 index 00000000..9e3fbbf4 --- /dev/null +++ b/src/MessagePack.Analyzer/MessagePack.Analyzer/tools/install.ps1 @@ -0,0 +1,58 @@ +param($installPath, $toolsPath, $package, $project) + +if($project.Object.SupportsPackageDependencyResolution) +{ + if($project.Object.SupportsPackageDependencyResolution()) + { + # Do not install analyzers via install.ps1, instead let the project system handle it. + return + } +} + +$analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve + +foreach($analyzersPath in $analyzersPaths) +{ + if (Test-Path $analyzersPath) + { + # Install the language agnostic analyzers. + foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) + { + if($project.Object.AnalyzerReferences) + { + $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) + } + } + } +} + +# $project.Type gives the language name like (C# or VB.NET) +$languageFolder = "" +if($project.Type -eq "C#") +{ + $languageFolder = "cs" +} +if($project.Type -eq "VB.NET") +{ + $languageFolder = "vb" +} +if($languageFolder -eq "") +{ + return +} + +foreach($analyzersPath in $analyzersPaths) +{ + # Install language specific analyzers. + $languageAnalyzersPath = join-path $analyzersPath $languageFolder + if (Test-Path $languageAnalyzersPath) + { + foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) + { + if($project.Object.AnalyzerReferences) + { + $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) + } + } + } +} \ No newline at end of file diff --git a/src/MessagePack.Analyzer/MessagePack.Analyzer/tools/uninstall.ps1 b/src/MessagePack.Analyzer/MessagePack.Analyzer/tools/uninstall.ps1 new file mode 100644 index 00000000..7d9c8cc1 --- /dev/null +++ b/src/MessagePack.Analyzer/MessagePack.Analyzer/tools/uninstall.ps1 @@ -0,0 +1,65 @@ +param($installPath, $toolsPath, $package, $project) + +if($project.Object.SupportsPackageDependencyResolution) +{ + if($project.Object.SupportsPackageDependencyResolution()) + { + # Do not uninstall analyzers via uninstall.ps1, instead let the project system handle it. + return + } +} + +$analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve + +foreach($analyzersPath in $analyzersPaths) +{ + # Uninstall the language agnostic analyzers. + if (Test-Path $analyzersPath) + { + foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) + { + if($project.Object.AnalyzerReferences) + { + $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) + } + } + } +} + +# $project.Type gives the language name like (C# or VB.NET) +$languageFolder = "" +if($project.Type -eq "C#") +{ + $languageFolder = "cs" +} +if($project.Type -eq "VB.NET") +{ + $languageFolder = "vb" +} +if($languageFolder -eq "") +{ + return +} + +foreach($analyzersPath in $analyzersPaths) +{ + # Uninstall language specific analyzers. + $languageAnalyzersPath = join-path $analyzersPath $languageFolder + if (Test-Path $languageAnalyzersPath) + { + foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) + { + if($project.Object.AnalyzerReferences) + { + try + { + $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) + } + catch + { + + } + } + } + } +} \ No newline at end of file