├── InferNull
├── Properties
│ └── .gitignore
├── AppDomainExtensions.cs
├── App.config
├── InferNull.csproj
├── ExportProviderExtensions.cs
├── ProcessRunner.cs
└── Program.cs
├── global.json
├── .github
├── img
│ ├── FlowState.png
│ ├── GenericCall.png
│ ├── GenericType.png
│ └── SimpleClass.png
└── workflows
│ └── dotnet.yml
├── .gitattributes
├── NullabilityInference
├── Statistics.cs
├── NullabilityInference.csproj
├── CallbackOnDispose.cs
├── SimpleTypeParameter.cs
├── NullType.cs
├── MaximumFlow.cs
├── NullabilityEdge.cs
├── AccessPath.cs
├── AllNullableSyntaxRewriter.cs
├── NullabilityNode.cs
├── FlowState.cs
├── TypeWithNode.cs
├── GraphVizGraph.cs
├── InferredNullabilitySyntaxRewriter.cs
├── System.Diagnostics.CodeAnalysis
│ └── NullableAttributes.cs
├── GraphBuildingSyntaxVisitor.cs
├── ExtensionMethods.cs
└── NullCheckingEngine.cs
├── LICENSE
├── NullabilityInference.Tests
├── Tests.csproj
├── NullabilityTestHelper.cs
└── FlowTests.cs
├── azure-pipelines.yml
├── NullabilityInference.sln
├── .editorconfig
├── .gitignore
└── README.md
/InferNull/Properties/.gitignore:
--------------------------------------------------------------------------------
1 | /launchSettings.json
2 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "3.1"
4 | }
5 | }
--------------------------------------------------------------------------------
/.github/img/FlowState.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/icsharpcode/NullabilityInference/HEAD/.github/img/FlowState.png
--------------------------------------------------------------------------------
/.github/img/GenericCall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/icsharpcode/NullabilityInference/HEAD/.github/img/GenericCall.png
--------------------------------------------------------------------------------
/.github/img/GenericType.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/icsharpcode/NullabilityInference/HEAD/.github/img/GenericType.png
--------------------------------------------------------------------------------
/.github/img/SimpleClass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/icsharpcode/NullabilityInference/HEAD/.github/img/SimpleClass.png
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text eol=crlf
2 | *.dll binary
3 | *.png binary
4 | *.jpeg binary
5 | *.jpg binary
6 | *.gif binary
7 | *.ttf binary
8 | *.exe binary
9 | *.eot binary
10 | *.woff binary
11 | *.woff2 binary
12 |
13 | CHANGELOG.md text merge=union
--------------------------------------------------------------------------------
/NullabilityInference/Statistics.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace ICSharpCode.NullabilityInference
6 | {
7 | public struct Statistics
8 | {
9 | public int NullableCount;
10 | public int NonNullCount;
11 | public int NotNullWhenCount;
12 |
13 | internal void Update(in Statistics s)
14 | {
15 | this.NullableCount += s.NullableCount;
16 | this.NonNullCount += s.NonNullCount;
17 | this.NotNullWhenCount += s.NotNullWhenCount;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/NullabilityInference/NullabilityInference.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | ICSharpCode.NullabilityInference
6 | ICSharpCode.NullabilityInference
7 | 8.0
8 | enable
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/NullabilityInference/CallbackOnDispose.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 |
4 | namespace ICSharpCode.NullabilityInference
5 | {
6 | ///
7 | /// Invokes an action when it is disposed.
8 | ///
9 | ///
10 | /// This class ensures the callback is invoked at most once,
11 | /// even when Dispose is called on multiple threads.
12 | ///
13 | public sealed class CallbackOnDispose : IDisposable
14 | {
15 | private Action? action;
16 |
17 | public CallbackOnDispose(Action action)
18 | {
19 | this.action = action ?? throw new ArgumentNullException(nameof(action));
20 | }
21 |
22 | public void Dispose()
23 | {
24 | Action? a = Interlocked.Exchange(ref action, null);
25 | a?.Invoke();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/NullabilityInference/SimpleTypeParameter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using Microsoft.CodeAnalysis;
5 |
6 | namespace ICSharpCode.NullabilityInference
7 | {
8 | ///
9 | /// Used for ExtensionMethods.FullTypeParameters()
10 | ///
11 | internal struct SimpleTypeParameter
12 | {
13 | ///
14 | /// If symbol != null, wraps a real type parameter.
15 | /// If symbol == null, this is a fake type parameter for an anonymous type.
16 | ///
17 | private ITypeParameterSymbol? symbol;
18 |
19 | public SimpleTypeParameter(ITypeParameterSymbol symbol)
20 | {
21 | this.symbol = symbol;
22 | }
23 |
24 | public VarianceKind Variance => symbol?.Variance ?? VarianceKind.None;
25 | public bool HasNotNullConstraint => symbol?.HasNotNullConstraint ?? false;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/InferNull/AppDomainExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 |
4 | namespace InferNull
5 | {
6 | internal static class AppDomainExtensions
7 | {
8 | public static void UseVersionAgnosticAssemblyResolution(this AppDomain appDomain) => appDomain.AssemblyResolve += LoadAnyVersion;
9 |
10 | private static Assembly? LoadAnyVersion(object? sender, ResolveEventArgs? args)
11 | {
12 | if (args?.Name == null) return null;
13 | var requestedAssemblyName = new AssemblyName(args.Name);
14 | if (requestedAssemblyName.Version != null && requestedAssemblyName.Name != null) {
15 | try {
16 | return Assembly.Load(new AssemblyName(requestedAssemblyName.Name) { CultureName = requestedAssemblyName.CultureName });
17 | } catch (Exception) {
18 | return null; //Give other handlers a chance
19 | }
20 | }
21 | return null;
22 |
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 AlphaSierraPapa for the ILSpy team
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NullabilityInference.Tests/Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net472
4 | Library
5 | ICSharpCode.NullabilityInference.Tests
6 | ICSharpCode.NullabilityInference.Tests
7 | false
8 | 8.0
9 | $(NoWarn);1998
10 | true
11 | true
12 | true
13 |
14 |
15 |
16 |
17 | all
18 | runtime; build; native; contentfiles; analyzers; buildtransitive
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet.yml:
--------------------------------------------------------------------------------
1 | name: .NET
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: windows-latest
13 | strategy:
14 | matrix:
15 | Configuration: [ Debug, Release]
16 | env:
17 | StagingDirectory: buildartifacts
18 |
19 | steps:
20 | - run: mkdir -p $env:StagingDirectory
21 | - uses: actions/checkout@v2
22 | - name: Setup .NET
23 | uses: actions/setup-dotnet@v1
24 | with:
25 | dotnet-version: 3.1.x
26 | - name: Restore dependencies
27 | run: dotnet restore
28 | - name: Build
29 | run: dotnet build --no-restore -c ${{ matrix.Configuration }}
30 | - name: Test
31 | run: dotnet test --no-build --verbosity normal -c ${{ matrix.Configuration }}
32 | - name: Zip
33 | run: 7z a -tzip $env:StagingDirectory\InferNull_${{ matrix.Configuration }}.zip .\InferNull\bin\${{ matrix.Configuration }}\*
34 | - name: Upload
35 | uses: actions/upload-artifact@v2
36 | with:
37 | name: InferNull (${{ matrix.configuration }}) ${{ github.run_number }}
38 | path: ${{ env.StagingDirectory }}\InferNull_${{ matrix.Configuration }}.zip
39 | if-no-files-found: error
40 |
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | trigger:
2 | - master
3 |
4 | pr:
5 | - master
6 |
7 | pool:
8 | vmImage: 'windows-latest'
9 |
10 | strategy:
11 | matrix:
12 | Config_Release:
13 | buildConfiguration: 'Release'
14 | Config_Debug:
15 | buildConfiguration: 'Debug'
16 |
17 | variables:
18 | solution: '**/*.sln'
19 | buildPlatform: 'Any CPU'
20 |
21 | steps:
22 | - task: NuGetToolInstaller@1
23 |
24 | - task: NuGetCommand@2
25 | inputs:
26 | restoreSolution: '$(solution)'
27 |
28 | - task: VSBuild@1
29 | inputs:
30 | solution: '$(solution)'
31 | platform: '$(buildPlatform)'
32 | configuration: '$(buildConfiguration)'
33 |
34 | - task: VSTest@2
35 | inputs:
36 | platform: '$(buildPlatform)'
37 | configuration: '$(buildConfiguration)'
38 |
39 | - task: CopyFiles@2
40 | displayName: Copy InferNull $(buildConfiguration)
41 | inputs:
42 | sourceFolder: '$(Build.SourcesDirectory)/InferNull/bin/$(buildConfiguration)'
43 | contents: '**'
44 | targetFolder: $(Build.ArtifactStagingDirectory)/$(buildConfiguration)
45 | condition: succeeded()
46 |
47 | - task: PublishPipelineArtifact@1
48 | displayName: Publish $(buildConfiguration)
49 | inputs:
50 | targetPath: $(Build.ArtifactStagingDirectory)/$(buildConfiguration)
51 | artifactName: InferNull - $(buildConfiguration) $(Build.BuildId)
52 |
--------------------------------------------------------------------------------
/InferNull/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/NullabilityInference/NullType.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Daniel Grunwald
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this
4 | // software and associated documentation files (the "Software"), to deal in the Software
5 | // without restriction, including without limitation the rights to use, copy, modify, merge,
6 | // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7 | // to whom the Software is furnished to do so, subject to the following conditions:
8 | //
9 | // The above copyright notice and this permission notice shall be included in all copies or
10 | // substantial portions of the Software.
11 | //
12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17 | // DEALINGS IN THE SOFTWARE.
18 |
19 | namespace ICSharpCode.NullabilityInference
20 | {
21 | public enum NullType
22 | {
23 | ///
24 | /// Let the static null checker automatically infer whether this type is nullable.
25 | ///
26 | Infer = 0,
27 | ///
28 | /// Declares the type as non-nullable.
29 | ///
30 | NonNull = 1,
31 | ///
32 | /// Declares the type as nullable.
33 | ///
34 | Nullable = 2,
35 | ///
36 | /// Declares the type as oblivious.
37 | ///
38 | Oblivious = 3
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/InferNull/InferNull.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net472
6 | InferNull
7 | InferNull
8 | infernull
9 | 0.1.0.0
10 | 0.1.0.0
11 | true
12 | 8.0
13 | enable
14 | false
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/NullabilityInference.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30114.105
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InferNull", "InferNull\InferNull.csproj", "{60A5F778-F837-493E-A549-CC85BEA75A50}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NullabilityInference", "NullabilityInference\NullabilityInference.csproj", "{61EBF036-9D1F-451A-8A02-5B301125DF34}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BC69B7DB-0F9E-4605-87E8-AF373FA5318D}"
11 | ProjectSection(SolutionItems) = preProject
12 | .editorconfig = .editorconfig
13 | EndProjectSection
14 | EndProject
15 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "NullabilityInference.Tests\Tests.csproj", "{9EF15FAD-17F1-4D16-B5D0-86653A3567FF}"
16 | EndProject
17 | Global
18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
19 | Debug|Any CPU = Debug|Any CPU
20 | Release|Any CPU = Release|Any CPU
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {60A5F778-F837-493E-A549-CC85BEA75A50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {60A5F778-F837-493E-A549-CC85BEA75A50}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {60A5F778-F837-493E-A549-CC85BEA75A50}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 | {60A5F778-F837-493E-A549-CC85BEA75A50}.Release|Any CPU.Build.0 = Release|Any CPU
27 | {61EBF036-9D1F-451A-8A02-5B301125DF34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 | {61EBF036-9D1F-451A-8A02-5B301125DF34}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 | {61EBF036-9D1F-451A-8A02-5B301125DF34}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 | {61EBF036-9D1F-451A-8A02-5B301125DF34}.Release|Any CPU.Build.0 = Release|Any CPU
31 | {9EF15FAD-17F1-4D16-B5D0-86653A3567FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 | {9EF15FAD-17F1-4D16-B5D0-86653A3567FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 | {9EF15FAD-17F1-4D16-B5D0-86653A3567FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
34 | {9EF15FAD-17F1-4D16-B5D0-86653A3567FF}.Release|Any CPU.Build.0 = Release|Any CPU
35 | EndGlobalSection
36 | GlobalSection(SolutionProperties) = preSolution
37 | HideSolutionNode = FALSE
38 | EndGlobalSection
39 | GlobalSection(ExtensibilityGlobals) = postSolution
40 | SolutionGuid = {4D725FEF-3650-48ED-AF74-42775ACF8934}
41 | EndGlobalSection
42 | EndGlobal
43 |
--------------------------------------------------------------------------------
/NullabilityInference/MaximumFlow.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Daniel Grunwald
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this
4 | // software and associated documentation files (the "Software"), to deal in the Software
5 | // without restriction, including without limitation the rights to use, copy, modify, merge,
6 | // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7 | // to whom the Software is furnished to do so, subject to the following conditions:
8 | //
9 | // The above copyright notice and this permission notice shall be included in all copies or
10 | // substantial portions of the Software.
11 | //
12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17 | // DEALINGS IN THE SOFTWARE.
18 |
19 | using System;
20 | using System.Collections.Generic;
21 | using System.Diagnostics;
22 | using System.Threading;
23 |
24 | namespace ICSharpCode.NullabilityInference
25 | {
26 | ///
27 | /// Implements the Ford-Fulkerson algorithm for maximum flow.
28 | ///
29 | internal static class MaximumFlow
30 | {
31 | public static int Compute(IEnumerable allNodes, NullabilityNode source, NullabilityNode sink, CancellationToken cancellationToken)
32 | {
33 | Debug.Assert(source != sink);
34 | int maxFlow = 0;
35 | ResetVisited(allNodes);
36 | while (AddFlow(sink, source)) {
37 | cancellationToken.ThrowIfCancellationRequested();
38 | maxFlow += 1;
39 | ResetVisited(allNodes);
40 | }
41 | return maxFlow;
42 | }
43 |
44 | private static bool AddFlow(NullabilityNode node, NullabilityNode source)
45 | {
46 | if (node.Visited)
47 | return false;
48 | node.Visited = true;
49 | if (node == source)
50 | return true;
51 | var predecessors = node.ResidualGraphPredecessors;
52 | for (int i = 0; i < predecessors.Count; i++) {
53 | var prevNode = predecessors[i];
54 | if (AddFlow(prevNode, source)) {
55 | // Remove the edge from the residual graph
56 | predecessors.SwapRemoveAt(i);
57 | // and instead add the reverse edge
58 | prevNode.ResidualGraphPredecessors.Add(node);
59 | return true;
60 | }
61 | }
62 | return false;
63 | }
64 |
65 | private static void ResetVisited(IEnumerable allTypes)
66 | {
67 | foreach (NullabilityNode node in allTypes)
68 | node.Visited = false;
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/NullabilityInference/NullabilityEdge.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020 Daniel Grunwald
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this
4 | // software and associated documentation files (the "Software"), to deal in the Software
5 | // without restriction, including without limitation the rights to use, copy, modify, merge,
6 | // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7 | // to whom the Software is furnished to do so, subject to the following conditions:
8 | //
9 | // The above copyright notice and this permission notice shall be included in all copies or
10 | // substantial portions of the Software.
11 | //
12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17 | // DEALINGS IN THE SOFTWARE.
18 |
19 | using System;
20 | using System.Diagnostics;
21 | using Microsoft.CodeAnalysis;
22 |
23 | namespace ICSharpCode.NullabilityInference
24 | {
25 | ///
26 | /// An edge in the graph of nullability nodes.
27 | ///
28 | /// An edge represents the constraint "if source is nullable, then target is nullable"
29 | /// (source is assignable to target).
30 | ///
31 | [DebuggerDisplay("{Source} -> {Target}")]
32 | internal sealed class NullabilityEdge
33 | {
34 | public NullabilityNode Source { get; }
35 | public NullabilityNode Target { get; }
36 |
37 | internal readonly EdgeLabel Label;
38 | public bool IsError => Source.NullType == NullType.Nullable && Target.NullType == NullType.NonNull;
39 |
40 | ///
41 | /// Represents the subtype relation "subType <: superType".
42 | /// This means that values of type subType can be assigned to variables of type superType.
43 | ///
44 | public NullabilityEdge(NullabilityNode source, NullabilityNode target, EdgeLabel label)
45 | {
46 | this.Source = source ?? throw new ArgumentNullException(nameof(source));
47 | this.Target = target ?? throw new ArgumentNullException(nameof(target));
48 | this.Label = label;
49 | }
50 | }
51 |
52 | internal readonly struct EdgeLabel
53 | {
54 | private readonly string text;
55 | internal readonly Location? location;
56 |
57 | public EdgeLabel(string text)
58 | {
59 | this.text = text;
60 | this.location = null;
61 | }
62 |
63 | public EdgeLabel(string text, Location? location)
64 | {
65 | this.text = text;
66 | this.location = location;
67 | }
68 |
69 | internal EdgeLabel(string text, SyntaxNode? syntaxForLocation)
70 | : this(text, syntaxForLocation?.GetLocation())
71 | {
72 | }
73 |
74 | internal EdgeLabel(string text, IOperation? operation)
75 | : this(text, operation?.Syntax)
76 | {
77 | }
78 |
79 | public override string ToString()
80 | {
81 | if (location == null)
82 | return text;
83 | else
84 | return text + " at " + location.StartPosToString();
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/InferNull/ExportProviderExtensions.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Composition;
8 | using System.Composition.Hosting.Core;
9 | using System.Linq;
10 | using System.Reflection;
11 | using Microsoft.VisualStudio.Composition;
12 |
13 | namespace InferNull.FromRoslynSdk
14 | {
15 | internal static class ExportProviderExtensions
16 | {
17 | public static CompositionContext AsCompositionContext(this ExportProvider exportProvider)
18 | {
19 | return new CompositionContextShim(exportProvider);
20 | }
21 |
22 | private class CompositionContextShim : CompositionContext
23 | {
24 | private readonly ExportProvider _exportProvider;
25 |
26 | public CompositionContextShim(ExportProvider exportProvider)
27 | {
28 | _exportProvider = exportProvider;
29 | }
30 |
31 | public override bool TryGetExport(CompositionContract contract, out object export)
32 | {
33 | var importMany = contract.MetadataConstraints.Contains(new KeyValuePair("IsImportMany", true));
34 | var (contractType, metadataType) = GetContractType(contract.ContractType, importMany);
35 |
36 | if (metadataType != null) {
37 | var methodInfo = (from method in _exportProvider.GetType().GetTypeInfo().GetMethods()
38 | where method.Name == nameof(ExportProvider.GetExports)
39 | where method.IsGenericMethod && method.GetGenericArguments().Length == 2
40 | where method.GetParameters().Length == 1 && method.GetParameters()[0].ParameterType == typeof(string)
41 | select method).Single();
42 | var parameterizedMethod = methodInfo.MakeGenericMethod(contractType, metadataType);
43 | export = parameterizedMethod.Invoke(_exportProvider, new[] { contract.ContractName });
44 | } else {
45 | var methodInfo = (from method in _exportProvider.GetType().GetTypeInfo().GetMethods()
46 | where method.Name == nameof(ExportProvider.GetExports)
47 | where method.IsGenericMethod && method.GetGenericArguments().Length == 1
48 | where method.GetParameters().Length == 1 && method.GetParameters()[0].ParameterType == typeof(string)
49 | select method).Single();
50 | var parameterizedMethod = methodInfo.MakeGenericMethod(contractType);
51 | export = parameterizedMethod.Invoke(_exportProvider, new[] { contract.ContractName });
52 | }
53 |
54 | return true;
55 | }
56 |
57 | private (Type exportType, Type? metadataType) GetContractType(Type contractType, bool importMany)
58 | {
59 | if (importMany && contractType.IsConstructedGenericType) {
60 | if (contractType.GetGenericTypeDefinition() == typeof(IList<>)
61 | || contractType.GetGenericTypeDefinition() == typeof(ICollection<>)
62 | || contractType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) {
63 | contractType = contractType.GenericTypeArguments[0];
64 | }
65 | }
66 |
67 | if (contractType.IsConstructedGenericType) {
68 | if (contractType.GetGenericTypeDefinition() == typeof(Lazy<>)) {
69 | return (contractType.GenericTypeArguments[0], null);
70 | } else if (contractType.GetGenericTypeDefinition() == typeof(Lazy<,>)) {
71 | return (contractType.GenericTypeArguments[0], contractType.GenericTypeArguments[1]);
72 | } else {
73 | throw new NotSupportedException();
74 | }
75 | }
76 |
77 | throw new NotSupportedException();
78 | }
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/InferNull/ProcessRunner.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Runtime.InteropServices;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using Microsoft.Win32.SafeHandles;
9 |
10 | namespace InferNull
11 | {
12 | internal static class ProcessRunner
13 | {
14 | /// Process is started from this information
15 | /// Defaults to Console.Out
16 | /// Defaults to Console.Error
17 | internal static async Task GetExitCodeAsync(this ProcessStartInfo psi, TextWriter? stdOut = null, TextWriter? stdErr = null)
18 | {
19 | stdOut ??= Console.Out;
20 | stdErr ??= Console.Error;
21 | psi.UseShellExecute = false;
22 | psi.RedirectStandardError = true;
23 | psi.RedirectStandardOutput = true;
24 | using var process = new Process() { StartInfo = psi };
25 | var stdOutComplete = new TaskCompletionSource