Skip to content

Commit cad1086

Browse files
committed
enable nullable
1 parent fd083a3 commit cad1086

File tree

6 files changed

+237
-24
lines changed

6 files changed

+237
-24
lines changed

Directory.Build.props

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,8 @@
1010
<DebugType>embedded</DebugType>
1111
</PropertyGroup>
1212

13+
<ItemGroup>
14+
<Compile Include="$(MSBuildThisFileDirectory)src\NullableAttribute.cs" />
15+
</ItemGroup>
16+
1317
</Project>

src/IxMilia.Config.Test/ConfigWriterTests.cs

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace IxMilia.Config.Test
66
{
77
public class ConfigWriterTests
88
{
9-
private void AssertWritten(IDictionary<string, string> dict, string expected, string existingText = null)
9+
private void AssertWritten(IDictionary<string, string> dict, string expected, string? existingText = null)
1010
{
1111
existingText = existingText ?? string.Empty;
1212
var existingLines = existingText.Trim().Split('\n').Select(line => line.TrimEnd('\r')).ToArray();
@@ -161,22 +161,6 @@ public void DontWriteMultipleBlankLinesTest()
161161
");
162162
}
163163

164-
[Fact]
165-
public void NullPropertiesAreNoteWritten()
166-
{
167-
var dict = new Dictionary<string, string>()
168-
{
169-
{ "key1", "value1" },
170-
{ "key2", null },
171-
{ "key3", "value3" },
172-
};
173-
174-
AssertWritten(dict, @"
175-
key1 = value1
176-
key3 = value3
177-
");
178-
}
179-
180164
[Fact]
181165
public void NewSettingInGroupDoesNotCauseBlankLineToBeWritten()
182166
{

src/IxMilia.Config.Test/IxMilia.Config.Test.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
55
<TargetFramework>net8.0</TargetFramework>
6+
<LangVersion>12</LangVersion>
7+
<Nullable>enable</Nullable>
68
</PropertyGroup>
79

810
<ItemGroup>

src/IxMilia.Config/ConfigExtensions.cs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ public static string WriteConfig(this IDictionary<string, string> dictionary, pa
134134
}
135135

136136
// remove blank lines within the same section
137-
string lastSectionName = null;
137+
string? lastSectionName = null;
138138
for (int i = 0; i < lines.Count; i++)
139139
{
140140
var line = lines[i];
@@ -189,13 +189,13 @@ private static Tuple<string, string> GetPrefixAndKey(string fullKey)
189189
return Tuple.Create(prefix, key);
190190
}
191191

192-
private static KeyValuePair<string, string> GetKeyValuePair(string line)
192+
private static KeyValuePair<string, string?> GetKeyValuePair(string line)
193193
{
194194
var parts = line.Split(Separator, 2);
195195
var key = parts[0].Trim();
196196
var value = parts.Length == 2 ? parts[1].Trim() : null;
197197
var parsedValue = ParseString(value);
198-
return new KeyValuePair<string, string>(key, parsedValue);
198+
return new KeyValuePair<string, string?>(key, parsedValue);
199199
}
200200

201201
private static string MakeFullKey(Tuple<string, string> key)
@@ -216,7 +216,7 @@ private static string MakeLine(string key, string value)
216216
return string.Concat(key, " = ", escapedValue);
217217
}
218218

219-
internal static string ParseString(string value)
219+
internal static string? ParseString(string? value)
220220
{
221221
if (value == null || value.Length == 1)
222222
{
@@ -282,7 +282,7 @@ internal static string ParseString(string value)
282282
return sb.ToString();
283283
}
284284

285-
internal static string EscapeString(string value)
285+
internal static string? EscapeString(string? value)
286286
{
287287
if (value == null)
288288
{
@@ -342,8 +342,23 @@ private KeyPrefixComparer()
342342
{
343343
}
344344

345-
public int Compare(Tuple<string, string> left, Tuple<string, string> right)
345+
public int Compare(Tuple<string, string>? left, Tuple<string, string>? right)
346346
{
347+
if (left is null && right is null)
348+
{
349+
return 0;
350+
}
351+
352+
if (left is null)
353+
{
354+
return -1;
355+
}
356+
357+
if (right is null)
358+
{
359+
return 1;
360+
}
361+
347362
// split into parts before comparing, and only compare the number of prefix parts that exist
348363
var partsLeft = left.Item1.Split('.');
349364
var partsRight = right.Item1.Split('.');

src/IxMilia.Config/IxMilia.Config.csproj

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,25 @@
55
<Copyright>Copyright 2018</Copyright>
66
<AssemblyTitle>IxMilia.Config</AssemblyTitle>
77
<Authors>IxMilia</Authors>
8-
<TargetFramework>netstandard2.0</TargetFramework>
8+
<TargetFrameworks>net8.0;netstandard2.0</TargetFrameworks>
99
<AssemblyName>IxMilia.Config</AssemblyName>
1010
<PackageId>IxMilia.Config</PackageId>
1111
<PackageTags>config;INI</PackageTags>
1212
<PackageProjectUrl>https://github.com/ixmilia/config</PackageProjectUrl>
1313
<PackageLicenseExpression>MIT</PackageLicenseExpression>
14+
<LangVersion>12</LangVersion>
15+
<Nullable>enable</Nullable>
1416

1517
<!-- SourceLink settings -->
1618
<PublishRepositoryUrl>true</PublishRepositoryUrl>
1719
<EmbedUntrackedSources>true</EmbedUntrackedSources>
1820
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
1921
</PropertyGroup>
2022

23+
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
24+
<NoWarn>$(NoWarn);nullable</NoWarn>
25+
</PropertyGroup>
26+
2127
<ItemGroup>
2228
<InternalsVisibleTo Include="IxMilia.Config.Test" />
2329
</ItemGroup>

src/NullableAttribute.cs

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
// Original code: https://github.com/dotnet/runtime/blob/419e949d258ecee4c40a460fb09c66d974229623/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs
2+
3+
#define INTERNAL_NULLABLE_ATTRIBUTES
4+
#if NETSTANDARD2_0
5+
6+
// Licensed to the .NET Foundation under one or more agreements.
7+
// The .NET Foundation licenses this file to you under the MIT license.
8+
// See the LICENSE file in the project root for more information.
9+
10+
namespace System.Diagnostics.CodeAnalysis
11+
{
12+
/// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary>
13+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
14+
#if INTERNAL_NULLABLE_ATTRIBUTES
15+
internal
16+
#else
17+
public
18+
#endif
19+
sealed class AllowNullAttribute : Attribute { }
20+
21+
/// <summary>Specifies that null is disallowed as an input even if the corresponding type allows it.</summary>
22+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
23+
#if INTERNAL_NULLABLE_ATTRIBUTES
24+
internal
25+
#else
26+
public
27+
#endif
28+
sealed class DisallowNullAttribute : Attribute { }
29+
30+
/// <summary>Specifies that an output may be null even if the corresponding type disallows it.</summary>
31+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
32+
#if INTERNAL_NULLABLE_ATTRIBUTES
33+
internal
34+
#else
35+
public
36+
#endif
37+
sealed class MaybeNullAttribute : Attribute { }
38+
39+
/// <summary>Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns.</summary>
40+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
41+
#if INTERNAL_NULLABLE_ATTRIBUTES
42+
internal
43+
#else
44+
public
45+
#endif
46+
sealed class NotNullAttribute : Attribute { }
47+
48+
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter may be null even if the corresponding type disallows it.</summary>
49+
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
50+
#if INTERNAL_NULLABLE_ATTRIBUTES
51+
internal
52+
#else
53+
public
54+
#endif
55+
sealed class MaybeNullWhenAttribute : Attribute
56+
{
57+
/// <summary>Initializes the attribute with the specified return value condition.</summary>
58+
/// <param name="returnValue">
59+
/// The return value condition. If the method returns this value, the associated parameter may be null.
60+
/// </param>
61+
public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
62+
63+
/// <summary>Gets the return value condition.</summary>
64+
public bool ReturnValue { get; }
65+
}
66+
67+
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
68+
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
69+
#if INTERNAL_NULLABLE_ATTRIBUTES
70+
internal
71+
#else
72+
public
73+
#endif
74+
sealed class NotNullWhenAttribute : Attribute
75+
{
76+
/// <summary>Initializes the attribute with the specified return value condition.</summary>
77+
/// <param name="returnValue">
78+
/// The return value condition. If the method returns this value, the associated parameter will not be null.
79+
/// </param>
80+
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
81+
82+
/// <summary>Gets the return value condition.</summary>
83+
public bool ReturnValue { get; }
84+
}
85+
86+
/// <summary>Specifies that the output will be non-null if the named parameter is non-null.</summary>
87+
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
88+
#if INTERNAL_NULLABLE_ATTRIBUTES
89+
internal
90+
#else
91+
public
92+
#endif
93+
sealed class NotNullIfNotNullAttribute : Attribute
94+
{
95+
/// <summary>Initializes the attribute with the associated parameter name.</summary>
96+
/// <param name="parameterName">
97+
/// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null.
98+
/// </param>
99+
public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName;
100+
101+
/// <summary>Gets the associated parameter name.</summary>
102+
public string ParameterName { get; }
103+
}
104+
105+
/// <summary>Applied to a method that will never return under any circumstance.</summary>
106+
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
107+
#if INTERNAL_NULLABLE_ATTRIBUTES
108+
internal
109+
#else
110+
public
111+
#endif
112+
sealed class DoesNotReturnAttribute : Attribute { }
113+
114+
/// <summary>Specifies that the method will not return if the associated Boolean parameter is passed the specified value.</summary>
115+
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
116+
#if INTERNAL_NULLABLE_ATTRIBUTES
117+
internal
118+
#else
119+
public
120+
#endif
121+
sealed class DoesNotReturnIfAttribute : Attribute
122+
{
123+
/// <summary>Initializes the attribute with the specified parameter value.</summary>
124+
/// <param name="parameterValue">
125+
/// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to
126+
/// the associated parameter matches this value.
127+
/// </param>
128+
public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;
129+
130+
/// <summary>Gets the condition parameter value.</summary>
131+
public bool ParameterValue { get; }
132+
}
133+
134+
/// <summary>Specifies that the method or property will ensure that the listed field and property members have not-null values.</summary>
135+
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
136+
#if INTERNAL_NULLABLE_ATTRIBUTES
137+
internal
138+
#else
139+
public
140+
#endif
141+
sealed class MemberNotNullAttribute : Attribute
142+
{
143+
/// <summary>Initializes the attribute with a field or property member.</summary>
144+
/// <param name="member">
145+
/// The field or property member that is promised to be not-null.
146+
/// </param>
147+
public MemberNotNullAttribute(string member) => Members = new[] { member };
148+
149+
/// <summary>Initializes the attribute with the list of field and property members.</summary>
150+
/// <param name="members">
151+
/// The list of field and property members that are promised to be not-null.
152+
/// </param>
153+
public MemberNotNullAttribute(params string[] members) => Members = members;
154+
155+
/// <summary>Gets field or property member names.</summary>
156+
public string[] Members { get; }
157+
}
158+
159+
/// <summary>Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition.</summary>
160+
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
161+
#if INTERNAL_NULLABLE_ATTRIBUTES
162+
internal
163+
#else
164+
public
165+
#endif
166+
sealed class MemberNotNullWhenAttribute : Attribute
167+
{
168+
/// <summary>Initializes the attribute with the specified return value condition and a field or property member.</summary>
169+
/// <param name="returnValue">
170+
/// The return value condition. If the method returns this value, the associated parameter will not be null.
171+
/// </param>
172+
/// <param name="member">
173+
/// The field or property member that is promised to be not-null.
174+
/// </param>
175+
public MemberNotNullWhenAttribute(bool returnValue, string member)
176+
{
177+
ReturnValue = returnValue;
178+
Members = new[] { member };
179+
}
180+
181+
/// <summary>Initializes the attribute with the specified return value condition and list of field and property members.</summary>
182+
/// <param name="returnValue">
183+
/// The return value condition. If the method returns this value, the associated parameter will not be null.
184+
/// </param>
185+
/// <param name="members">
186+
/// The list of field and property members that are promised to be not-null.
187+
/// </param>
188+
public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
189+
{
190+
ReturnValue = returnValue;
191+
Members = members;
192+
}
193+
194+
/// <summary>Gets the return value condition.</summary>
195+
public bool ReturnValue { get; }
196+
197+
/// <summary>Gets field or property member names.</summary>
198+
public string[] Members { get; }
199+
}
200+
}
201+
202+
#endif

0 commit comments

Comments
 (0)