Skip to content

Commit 10ab17a

Browse files
committed
C#: Enable nullability in csharp extraction project v1
1 parent 3400c12 commit 10ab17a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+333
-278
lines changed

csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,24 @@
1010
using Semmle.Util.Logging;
1111
using Semmle.Util;
1212

13+
#nullable disable warnings
14+
1315
namespace Semmle.Extraction.CSharp
1416
{
1517
/// <summary>
1618
/// Encapsulates a C# analysis task.
1719
/// </summary>
1820
public sealed class Analyser : IDisposable
1921
{
20-
private Extraction.Extractor extractor;
21-
private CSharpCompilation compilation;
22-
private Layout layout;
22+
private Extraction.Extractor? extractor;
23+
private CSharpCompilation? compilation;
24+
private Layout? layout;
2325
private bool init;
2426
private readonly object progressMutex = new object();
2527
private int taskCount = 0;
26-
private CommonOptions options;
27-
private Entities.Compilation compilationEntity;
28-
private IDisposable compilationTrapFile;
28+
private CommonOptions? options;
29+
private Entities.Compilation? compilationEntity;
30+
private IDisposable? compilationTrapFile;
2931

3032
private readonly Stopwatch stopWatch = new Stopwatch();
3133

@@ -359,13 +361,13 @@ private void DoExtractTree(SyntaxTree tree)
359361

360362
var projectLayout = layout.LookupProjectOrNull(transformedSourcePath);
361363
var excluded = projectLayout == null;
362-
var trapPath = excluded ? "" : projectLayout.GetTrapPath(Logger, transformedSourcePath, options.TrapCompression);
364+
var trapPath = excluded ? "" : projectLayout!.GetTrapPath(Logger, transformedSourcePath, options.TrapCompression);
363365
var upToDate = false;
364366

365367
if (!excluded)
366368
{
367369
// compilation.Clone() is used to allow symbols to be garbage collected.
368-
using var trapWriter = projectLayout.CreateTrapWriter(Logger, transformedSourcePath, options.TrapCompression, discardDuplicates: false);
370+
using var trapWriter = projectLayout!.CreateTrapWriter(Logger, transformedSourcePath, options.TrapCompression, discardDuplicates: false);
369371

370372
upToDate = options.Fast && FileIsUpToDate(sourcePath, trapWriter.TrapFile);
371373

@@ -571,3 +573,5 @@ public interface IProgressMonitor
571573
void MissingSummary(int types, int namespaces);
572574
}
573575
}
576+
577+
#nullable restore warnings

csharp/extractor/Semmle.Extraction.CSharp/Comments/CommentProcessor.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public void AddComment(CommentLine comment)
2626

2727
private readonly Dictionary<Label, Key> duplicationGuardKeys = new Dictionary<Label, Key>();
2828

29-
private Key GetDuplicationGuardKey(Label label)
29+
private Key? GetDuplicationGuardKey(Label label)
3030
{
3131
if (duplicationGuardKeys.TryGetValue(label, out var duplicationGuardKey))
3232
return duplicationGuardKey;
@@ -35,7 +35,7 @@ private Key GetDuplicationGuardKey(Label label)
3535

3636
private class LocationComparer : IComparer<Location>
3737
{
38-
public int Compare(Location l1, Location l2) => CommentProcessor.Compare(l1, l2);
38+
public int Compare(Location? l1, Location? l2) => CommentProcessor.Compare(l1, l2);
3939
}
4040

4141
/// <summary>
@@ -44,7 +44,7 @@ private class LocationComparer : IComparer<Location>
4444
/// <param name="l1">First location</param>
4545
/// <param name="l2">Second location</param>
4646
/// <returns>&lt;0 if l1 before l2, &gt;0 if l1 after l2, else 0.</returns>
47-
private static int Compare(Location l1, Location l2)
47+
private static int Compare(Location? l1, Location? l2)
4848
{
4949
if (object.ReferenceEquals(l1, l2))
5050
return 0;
@@ -68,7 +68,7 @@ private static int Compare(Location l1, Location l2)
6868
/// <param name="elementLabel">The label of the element in the trap file.</param>
6969
/// <param name="duplicationGuardKey">The duplication guard key of the element, if any.</param>
7070
/// <param name="loc">The location of the element.</param>
71-
public void AddElement(Label elementLabel, Key duplicationGuardKey, Location loc)
71+
public void AddElement(Label elementLabel, Key? duplicationGuardKey, Location? loc)
7272
{
7373
if (loc != null && loc.IsInSource)
7474
elements[loc] = elementLabel;
@@ -265,7 +265,7 @@ private bool GenerateBindings(
265265
CommentBindingCallback cb
266266
)
267267
{
268-
Comments.CommentBlock block = null;
268+
Comments.CommentBlock? block = null;
269269

270270
// Iterate comments until the commentEnumerator has gone past nextElement
271271
while (nextElement == null || Compare(commentEnumerator.Current.Value.Location, nextElement.Value.Key) < 0)
@@ -350,5 +350,5 @@ public void GenerateBindings(CommentBindingCallback cb)
350350
/// <param name="duplicationGuardKey">The duplication guard key of the element, if any</param>
351351
/// <param name="commentBlock">The comment block associated with the element</param>
352352
/// <param name="binding">The relationship between the commentblock and the element</param>
353-
internal delegate void CommentBindingCallback(Label elementLabel, Key duplicationGuardKey, Comments.CommentBlock commentBlock, CommentBinding binding);
353+
internal delegate void CommentBindingCallback(Label elementLabel, Key? duplicationGuardKey, Comments.CommentBlock commentBlock, CommentBinding binding);
354354
}

csharp/extractor/Semmle.Extraction.CSharp/CompilerVersion.cs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ namespace Semmle.Extraction.CSharp
1414
public class CompilerVersion
1515
{
1616
private const string csc_rsp = "csc.rsp";
17-
private readonly string specifiedFramework = null;
17+
private readonly string? specifiedFramework = null;
1818

1919
/// <summary>
2020
/// The value specified by --compiler, or null.
2121
/// </summary>
22-
public string SpecifiedCompiler
22+
public string? SpecifiedCompiler
2323
{
2424
get;
2525
private set;
@@ -28,12 +28,20 @@ public string SpecifiedCompiler
2828
/// <summary>
2929
/// Why was the candidate exe rejected as a compiler?
3030
/// </summary>
31-
public string SkipReason
31+
public string? SkipReason
3232
{
3333
get;
3434
private set;
3535
}
3636

37+
private static readonly Dictionary<string, string> knownCompilerNames = new Dictionary<string, string>
38+
{
39+
{ "csc.exe", "Microsoft" },
40+
{ "csc2.exe", "Microsoft" },
41+
{ "csc.dll", "Microsoft" },
42+
{ "mcs.exe", "Novell" }
43+
};
44+
3745
/// <summary>
3846
/// Probes the compiler (if specified).
3947
/// </summary>
@@ -52,23 +60,21 @@ public CompilerVersion(Options options)
5260
}
5361

5462
// Reads the file details from the .exe
55-
var versionInfo = FileVersionInfo.GetVersionInfo(SpecifiedCompiler);
56-
5763
var compilerDir = Path.GetDirectoryName(SpecifiedCompiler);
58-
var knownCompilerNames = new Dictionary<string, string>
64+
if (compilerDir is null)
5965
{
60-
{ "csc.exe", "Microsoft" },
61-
{ "csc2.exe", "Microsoft" },
62-
{ "csc.dll", "Microsoft" },
63-
{ "mcs.exe", "Novell" }
64-
};
66+
SkipExtractionBecause("the compiler directory could not be retrieved");
67+
return;
68+
}
69+
6570
var mscorlibExists = File.Exists(Path.Combine(compilerDir, "mscorlib.dll"));
6671

6772
if (specifiedFramework == null && mscorlibExists)
6873
{
6974
specifiedFramework = compilerDir;
7075
}
7176

77+
var versionInfo = FileVersionInfo.GetVersionInfo(SpecifiedCompiler);
7278
if (!knownCompilerNames.TryGetValue(versionInfo.OriginalFilename, out var vendor))
7379
{
7480
SkipExtractionBecause("the compiler name is not recognised");
@@ -114,7 +120,7 @@ public bool SkipExtraction
114120
/// <summary>
115121
/// Gets additional reference directories - the compiler directory.
116122
/// </summary>
117-
public string AdditionalReferenceDirectories => SpecifiedCompiler != null ? Path.GetDirectoryName(SpecifiedCompiler) : null;
123+
public string? AdditionalReferenceDirectories => SpecifiedCompiler != null ? Path.GetDirectoryName(SpecifiedCompiler) : null;
118124

119125
/// <summary>
120126
/// Adds @csc.rsp to the argument list to mimic csc.exe.
@@ -134,6 +140,6 @@ private static bool SuppressDefaultResponseFile(IEnumerable<string> args)
134140
return args.Any(arg => new[] { "/noconfig", "-noconfig" }.Contains(arg.ToLowerInvariant()));
135141
}
136142

137-
public IEnumerable<string> ArgsWithResponse { get; }
143+
public IEnumerable<string> ArgsWithResponse { get; } = Enumerable.Empty<string>();
138144
}
139145
}

csharp/extractor/Semmle.Extraction.CSharp/Context.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public SemanticModel GetModel(SyntaxNode node)
2929
return cachedModel;
3030
}
3131

32-
private SemanticModel cachedModel;
32+
private SemanticModel? cachedModel;
3333

3434
/// <summary>
3535
/// The current compilation unit.
@@ -51,7 +51,7 @@ public Context(Extraction.Extractor e, Compilation c, TrapWriter trapWriter, IEx
5151

5252
public bool IsAssemblyScope => scope is AssemblyScope;
5353

54-
private SyntaxTree SourceTree => scope is SourceScope sc ? sc.SourceTree : null;
54+
private SyntaxTree? SourceTree => scope is SourceScope sc ? sc.SourceTree : null;
5555

5656
/// <summary>
5757
/// Whether the given symbol needs to be defined in this context.
@@ -85,7 +85,7 @@ public override Extraction.Entities.Location CreateLocation()
8585
: CreateLocation(Microsoft.CodeAnalysis.Location.Create(SourceTree, Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(0, 0)));
8686
}
8787

88-
public override Extraction.Entities.Location CreateLocation(Microsoft.CodeAnalysis.Location location)
88+
public override Extraction.Entities.Location CreateLocation(Microsoft.CodeAnalysis.Location? location)
8989
{
9090
return (location == null || location.Kind == LocationKind.None)
9191
? GeneratedLocation.Create(this)
@@ -100,13 +100,13 @@ public override Extraction.Entities.Location CreateLocation(Microsoft.CodeAnalys
100100
/// <param name="cx">Extractor context.</param>
101101
/// <param name="entity">Program entity.</param>
102102
/// <param name="l">Location of the entity.</param>
103-
public void BindComments(Entity entity, Microsoft.CodeAnalysis.Location l)
103+
public void BindComments(Entity entity, Microsoft.CodeAnalysis.Location? l)
104104
{
105105
var duplicationGuardKey = GetCurrentTagStackKey();
106106
CommentGenerator.AddElement(entity.Label, duplicationGuardKey, l);
107107
}
108108

109-
protected override bool IsEntityDuplicationGuarded(IEntity entity, [NotNullWhen(true)] out Extraction.Entities.Location loc)
109+
protected override bool IsEntityDuplicationGuarded(IEntity entity, [NotNullWhen(true)] out Extraction.Entities.Location? loc)
110110
{
111111
if (CreateLocation(entity.ReportingLocation) is Entities.NonGeneratedSourceLocation l)
112112
{

csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public override void Populate(TextWriter trapFile)
3737
{
3838
PopulateMethod(trapFile);
3939
PopulateModifiers(trapFile);
40-
ContainingType.PopulateGenerics();
40+
ContainingType!.PopulateGenerics();
4141

4242
var prop = PropertySymbol;
4343
if (prop == null)
@@ -52,12 +52,12 @@ public override void Populate(TextWriter trapFile)
5252
if (SymbolEqualityComparer.Default.Equals(Symbol, prop.GetMethod))
5353
{
5454
kind = 1;
55-
unboundAccessor = Create(Context, prop.OriginalDefinition.GetMethod);
55+
unboundAccessor = Create(Context, prop.OriginalDefinition.GetMethod!);
5656
}
5757
else if (SymbolEqualityComparer.Default.Equals(Symbol, prop.SetMethod))
5858
{
5959
kind = 2;
60-
unboundAccessor = Create(Context, prop.OriginalDefinition.SetMethod);
60+
unboundAccessor = Create(Context, prop.OriginalDefinition.SetMethod!);
6161
}
6262
else
6363
{

csharp/extractor/Semmle.Extraction.CSharp/Entities/Assembly.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ internal class Assembly : Extraction.Entities.Location
1212
private readonly string assemblyPath;
1313
private readonly IAssemblySymbol assembly;
1414

15-
private Assembly(Context cx, Microsoft.CodeAnalysis.Location init)
15+
private Assembly(Context cx, Microsoft.CodeAnalysis.Location? init)
1616
: base(cx, init)
1717
{
1818
if (init == null)
@@ -44,7 +44,7 @@ public override void Populate(TextWriter trapFile)
4444
public override int GetHashCode() =>
4545
Symbol == null ? 91187354 : Symbol.GetHashCode();
4646

47-
public override bool Equals(object obj)
47+
public override bool Equals(object? obj)
4848
{
4949
if (obj is Assembly other && other.GetType() == typeof(Assembly))
5050
return Equals(Symbol, other.Symbol);
@@ -54,11 +54,11 @@ public override bool Equals(object obj)
5454

5555
public static Extraction.Entities.Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => AssemblyConstructorFactory.Instance.CreateEntity(cx, loc, loc);
5656

57-
private class AssemblyConstructorFactory : CachedEntityFactory<Microsoft.CodeAnalysis.Location, Assembly>
57+
private class AssemblyConstructorFactory : CachedEntityFactory<Microsoft.CodeAnalysis.Location?, Assembly>
5858
{
5959
public static AssemblyConstructorFactory Instance { get; } = new AssemblyConstructorFactory();
6060

61-
public override Assembly Create(Context cx, Microsoft.CodeAnalysis.Location init) => new Assembly(cx, init);
61+
public override Assembly Create(Context cx, Microsoft.CodeAnalysis.Location? init) => new Assembly(cx, init);
6262
}
6363

6464
private static readonly object outputAssemblyCacheKey = new object();

csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ internal class Attribute : CachedEntity<AttributeData>, IExpressionParentEntity
1010
{
1111
bool IExpressionParentEntity.IsTopLevelParent => true;
1212

13-
private readonly AttributeSyntax attributeSyntax;
13+
private readonly AttributeSyntax? attributeSyntax;
1414
private readonly IEntity entity;
1515

1616
private Attribute(Context cx, AttributeData attributeData, IEntity entity)
@@ -93,7 +93,7 @@ private void ExtractArguments(TextWriter trapFile)
9393
{
9494
var expr = CreateExpressionFromArgument(
9595
namedArgument.Value,
96-
attributeSyntax?.ArgumentList.Arguments.Single(a => a.NameEquals?.Name?.Identifier.Text == namedArgument.Key).Expression,
96+
attributeSyntax?.ArgumentList?.Arguments.Single(a => a.NameEquals?.Name?.Identifier.Text == namedArgument.Key).Expression,
9797
this,
9898
childIndex++);
9999

@@ -104,7 +104,7 @@ private void ExtractArguments(TextWriter trapFile)
104104
}
105105
}
106106

107-
private Expression CreateExpressionFromArgument(TypedConstant constant, ExpressionSyntax syntax, IExpressionParentEntity parent,
107+
private Expression? CreateExpressionFromArgument(TypedConstant constant, ExpressionSyntax? syntax, IExpressionParentEntity parent,
108108
int childIndex)
109109
{
110110
return syntax is null
@@ -114,11 +114,14 @@ private Expression CreateExpressionFromArgument(TypedConstant constant, Expressi
114114

115115
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel;
116116

117-
public override Microsoft.CodeAnalysis.Location ReportingLocation => attributeSyntax?.Name.GetLocation();
117+
public override Microsoft.CodeAnalysis.Location? ReportingLocation => attributeSyntax?.Name.GetLocation();
118+
119+
private Semmle.Extraction.Entities.Location? location;
118120

119-
private Semmle.Extraction.Entities.Location location;
120121
private Semmle.Extraction.Entities.Location Location =>
121-
location ?? (location = Context.CreateLocation(attributeSyntax is null ? entity.ReportingLocation : attributeSyntax.Name.GetLocation()));
122+
location ??= Context.CreateLocation(attributeSyntax is null
123+
? entity.ReportingLocation
124+
: attributeSyntax.Name.GetLocation());
122125

123126
public override bool NeedsPopulation => true;
124127

csharp/extractor/Semmle.Extraction.CSharp/Entities/CachedEntity.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
namespace Semmle.Extraction.CSharp.Entities
22
{
3-
internal abstract class CachedEntity<T> : Extraction.CachedEntity<T>
3+
internal abstract class CachedEntity<T> : Extraction.CachedEntity<T> where T : class
44
{
55
// todo: this can be changed to an override after the .NET 5 upgrade
66
protected new Context Context => (Context)base.Context;
77

8-
protected CachedEntity(Context context, T symbol) : base(context, symbol)
8+
protected CachedEntity(Context context, T symbol)
9+
: base(context, symbol)
910
{
1011
}
1112
}

csharp/extractor/Semmle.Extraction.CSharp/Entities/CachedSymbol.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,16 @@
99

1010
namespace Semmle.Extraction.CSharp.Entities
1111
{
12-
internal abstract class CachedSymbol<T> : CachedEntity<T> where T : ISymbol
12+
internal abstract class CachedSymbol<T> : CachedEntity<T> where T : class, ISymbol
1313
{
14-
// todo: this can be changed to an override after the .NET 5 upgrade
15-
protected new Context Context => (Context)base.Context;
16-
17-
protected CachedSymbol(Context cx, T init)
14+
#nullable disable warnings
15+
protected CachedSymbol(Context cx, T? init)
1816
: base(cx, init)
1917
{
2018
}
19+
#nullable restore warnings
2120

22-
public virtual Type ContainingType => Symbol.ContainingType != null ? Type.Create(Context, Symbol.ContainingType) : null;
21+
public virtual Type? ContainingType => Symbol.ContainingType != null ? Type.Create(Context, Symbol.ContainingType) : null;
2322

2423
public void PopulateModifiers(TextWriter trapFile)
2524
{
@@ -68,12 +67,12 @@ protected void ExtractCompilerGenerated(TextWriter trapFile)
6867
/// The location which is stored in the database and is used when highlighing source code.
6968
/// It's generally short, e.g. a method name.
7069
/// </summary>
71-
public override Microsoft.CodeAnalysis.Location ReportingLocation => Symbol.Locations.FirstOrDefault();
70+
public override Microsoft.CodeAnalysis.Location? ReportingLocation => Symbol.Locations.FirstOrDefault();
7271

7372
/// <summary>
7473
/// The full text span of the entity, e.g. for binding comments.
7574
/// </summary>
76-
public virtual Microsoft.CodeAnalysis.Location FullLocation => Symbol.Locations.FirstOrDefault();
75+
public virtual Microsoft.CodeAnalysis.Location? FullLocation => Symbol.Locations.FirstOrDefault();
7776

7877
public virtual IEnumerable<Extraction.Entities.Location> Locations
7978
{
@@ -139,7 +138,7 @@ protected void PopulateMetadataHandle(TextWriter trapFile)
139138
trapFile.metadata_handle(this, Location, MetadataTokens.GetToken(handle.Value));
140139
}
141140

142-
private static System.Reflection.PropertyInfo GetPropertyInfo(object o, string name)
141+
private static System.Reflection.PropertyInfo? GetPropertyInfo(object o, string name)
143142
{
144143
return o.GetType().GetProperty(name, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetProperty);
145144
}

0 commit comments

Comments
 (0)