Skip to content

Commit c2c4142

Browse files
authored
Merge pull request github#3306 from calumgrant/cs/extraction-nullability
C#: Enable nullability in Semmle.Extraction project
2 parents c54f8d8 + 313c9ac commit c2c4142

File tree

24 files changed

+174
-126
lines changed

24 files changed

+174
-126
lines changed

csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ bool IBuildActions.FileExists(string file)
4444
public IDictionary<string, string> RunProcessOut = new Dictionary<string, string>();
4545
public IDictionary<string, string> RunProcessWorkingDirectory = new Dictionary<string, string>();
4646

47-
int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary<string, string> env, out IList<string> stdOut)
47+
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env, out IList<string> stdOut)
4848
{
4949
var pattern = cmd + " " + args;
5050
RunProcessIn.Add(pattern);
@@ -60,7 +60,7 @@ int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, I
6060
throw new ArgumentException("Missing RunProcess " + pattern);
6161
}
6262

63-
int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary<string, string> env)
63+
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env)
6464
{
6565
var pattern = cmd + " " + args;
6666
RunProcessIn.Add(pattern);
@@ -90,16 +90,16 @@ bool IBuildActions.DirectoryExists(string dir)
9090
throw new ArgumentException("Missing DirectoryExists " + dir);
9191
}
9292

93-
public IDictionary<string, string> GetEnvironmentVariable = new Dictionary<string, string>();
93+
public IDictionary<string, string?> GetEnvironmentVariable = new Dictionary<string, string?>();
9494

95-
string IBuildActions.GetEnvironmentVariable(string name)
95+
string? IBuildActions.GetEnvironmentVariable(string name)
9696
{
9797
if (GetEnvironmentVariable.TryGetValue(name, out var ret))
9898
return ret;
9999
throw new ArgumentException("Missing GetEnvironmentVariable " + name);
100100
}
101101

102-
public string GetCurrentDirectory;
102+
public string GetCurrentDirectory = "";
103103

104104
string IBuildActions.GetCurrentDirectory()
105105
{
@@ -334,10 +334,10 @@ public void TestTry()
334334
}
335335

336336
Autobuilder CreateAutoBuilder(string lgtmLanguage, bool isWindows,
337-
string buildless = null, string solution = null, string buildCommand = null, string ignoreErrors = null,
338-
string msBuildArguments = null, string msBuildPlatform = null, string msBuildConfiguration = null, string msBuildTarget = null,
339-
string dotnetArguments = null, string dotnetVersion = null, string vsToolsVersion = null,
340-
string nugetRestore = null, string allSolutions = null,
337+
string? buildless = null, string? solution = null, string? buildCommand = null, string? ignoreErrors = null,
338+
string? msBuildArguments = null, string? msBuildPlatform = null, string? msBuildConfiguration = null, string? msBuildTarget = null,
339+
string? dotnetArguments = null, string? dotnetVersion = null, string? vsToolsVersion = null,
340+
string? nugetRestore = null, string? allSolutions = null,
341341
string cwd = @"C:\Project")
342342
{
343343
Actions.GetEnvironmentVariable["CODEQL_AUTOBUILDER_CSHARP_NO_INDEXING"] = "false";

csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<TargetFramework>netcoreapp3.0</TargetFramework>
66
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
77
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
8+
<Nullable>enable</Nullable>
89
</PropertyGroup>
910

1011
<ItemGroup>

csharp/autobuilder/Semmle.Autobuild/BuildScript.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class BuildCommand : BuildScript
6161
/// <param name="silent">Whether this command should run silently.</param>
6262
/// <param name="workingDirectory">The working directory (<code>null</code> for current directory).</param>
6363
/// <param name="environment">Additional environment variables.</param>
64-
public BuildCommand(string exe, string argumentsOpt, bool silent, string? workingDirectory = null, IDictionary<string, string>? environment = null)
64+
public BuildCommand(string exe, string? argumentsOpt, bool silent, string? workingDirectory = null, IDictionary<string, string>? environment = null)
6565
{
6666
this.exe = exe;
6767
this.arguments = argumentsOpt ?? "";
@@ -183,7 +183,7 @@ public override int Run(IBuildActions actions, Action<string, bool> startCallbac
183183
/// <param name="silent">Whether the executable should run silently.</param>
184184
/// <param name="workingDirectory">The working directory (<code>null</code> for current directory).</param>
185185
/// <param name="environment">Additional environment variables.</param>
186-
public static BuildScript Create(string exe, string argumentsOpt, bool silent, string? workingDirectory, IDictionary<string, string>? environment) =>
186+
public static BuildScript Create(string exe, string? argumentsOpt, bool silent, string? workingDirectory, IDictionary<string, string>? environment) =>
187187
new BuildCommand(exe, argumentsOpt, silent, workingDirectory, environment);
188188

189189
/// <summary>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ public override bool Equals(object obj)
202202
return obj != null && obj.GetType() == typeof(VarargsType);
203203
}
204204

205-
public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateEntity(cx, null);
205+
public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateNullableEntity(cx, null);
206206

207207
class VarargsTypeFactory : ICachedEntityFactory<string, VarargsType>
208208
{

csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public override bool Equals(object obj)
2727
return obj != null && obj.GetType() == typeof(NullType);
2828
}
2929

30-
public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateEntity(cx, null), NullableAnnotation.None);
30+
public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateNullableEntity(cx, null), NullableAnnotation.None);
3131

3232
class NullTypeFactory : ICachedEntityFactory<ITypeSymbol, NullType>
3333
{

csharp/extractor/Semmle.Extraction/CommentProcessing.cs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ public void AddComment(ICommentLine 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
{
31-
Key duplicationGuardKey;
32-
if (duplicationGuardKeys.TryGetValue(label, out duplicationGuardKey))
31+
if (duplicationGuardKeys.TryGetValue(label, out var duplicationGuardKey))
3332
return duplicationGuardKey;
3433
return null;
3534
}
@@ -60,7 +59,7 @@ static int Compare(Location l1, Location l2)
6059
/// <param name="elementLabel">The label of the element in the trap file.</param>
6160
/// <param name="duplicationGuardKey">The duplication guard key of the element, if any.</param>
6261
/// <param name="loc">The location of the element.</param>
63-
public void AddElement(Label elementLabel, Key duplicationGuardKey, Location loc)
62+
public void AddElement(Label elementLabel, Key? duplicationGuardKey, Location loc)
6463
{
6564
if (loc != null && loc.IsInSource)
6665
elements[loc] = elementLabel;
@@ -257,19 +256,24 @@ bool GenerateBindings(
257256
CommentBindingCallback cb
258257
)
259258
{
260-
CommentBlock block = new CommentBlock();
259+
CommentBlock? block = null;
261260

262261
// Iterate comments until the commentEnumerator has gone past nextElement
263262
while (nextElement == null || Compare(commentEnumerator.Current.Value.Location, nextElement.Value.Key) < 0)
264263
{
264+
if(block is null)
265+
block = new CommentBlock(commentEnumerator.Current.Value);
266+
265267
if (!block.CombinesWith(commentEnumerator.Current.Value))
266268
{
267269
// Start of a new block, so generate the bindings for the old block first.
268270
GenerateBindings(block, elementStack, nextElement, cb);
269-
block = new CommentBlock();
271+
block = new CommentBlock(commentEnumerator.Current.Value);
272+
}
273+
else
274+
{
275+
block.AddCommentLine(commentEnumerator.Current.Value);
270276
}
271-
272-
block.AddCommentLine(commentEnumerator.Current.Value);
273277

274278
// Get the next comment.
275279
if (!commentEnumerator.MoveNext())
@@ -280,7 +284,9 @@ CommentBindingCallback cb
280284
}
281285
}
282286

283-
GenerateBindings(block, elementStack, nextElement, cb);
287+
if(!(block is null))
288+
GenerateBindings(block, elementStack, nextElement, cb);
289+
284290
return true;
285291
}
286292

@@ -332,12 +338,18 @@ public void GenerateBindings(CommentBindingCallback cb)
332338

333339
class CommentBlock : ICommentBlock
334340
{
335-
private readonly List<ICommentLine> lines = new List<ICommentLine>();
341+
private readonly List<ICommentLine> lines;
336342

337343
public IEnumerable<ICommentLine> CommentLines => lines;
338344

339345
public Location Location { get; private set; }
340346

347+
public CommentBlock(ICommentLine firstLine)
348+
{
349+
lines = new List<ICommentLine> { firstLine };
350+
Location = firstLine.Location;
351+
}
352+
341353
/// <summary>
342354
/// Determine whether commentlines should be merged.
343355
/// </summary>

csharp/extractor/Semmle.Extraction/Comments.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public interface ICommentBlock
7474
/// <param name="duplicationGuardKey">The duplication guard key of the element, if any</param>
7575
/// <param name="commentBlock">The comment block associated with the element</param>
7676
/// <param name="binding">The relationship between the commentblock and the element</param>
77-
public delegate void CommentBindingCallback(Label elementLabel, Key duplicationGuardKey, ICommentBlock commentBlock, CommentBinding binding);
77+
public delegate void CommentBindingCallback(Label elementLabel, Key? duplicationGuardKey, ICommentBlock commentBlock, CommentBinding binding);
7878

7979
/// <summary>
8080
/// Computes the binding information between comments and program elements.
@@ -88,7 +88,7 @@ public interface ICommentGenerator
8888
/// <param name="elementLabel">Label of the element.</param>
8989
/// <param name="duplicationGuardKey">The duplication guard key of the element, if any.</param>
9090
/// <param name="location">Location of the element.</param>
91-
void AddElement(Label elementLabel, Key duplicationGuardKey, Location location);
91+
void AddElement(Label elementLabel, Key? duplicationGuardKey, Location location);
9292

9393
/// <summary>
9494
/// Registers a line of comment.

csharp/extractor/Semmle.Extraction/Context.cs

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public SemanticModel GetModel(SyntaxNode node)
3434
return cachedModel;
3535
}
3636

37-
private SemanticModel cachedModel;
37+
private SemanticModel? cachedModel;
3838

3939
/// <summary>
4040
/// Access to the trap file.
@@ -49,7 +49,31 @@ public SemanticModel GetModel(SyntaxNode node)
4949
/// <param name="factory">The entity factory.</param>
5050
/// <param name="init">The initializer for the entity.</param>
5151
/// <returns>The new/existing entity.</returns>
52-
public Entity CreateEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity
52+
public Entity CreateEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity where Type:struct
53+
{
54+
return CreateNonNullEntity(factory, init);
55+
}
56+
57+
/// <summary>
58+
/// Creates a new entity using the factory.
59+
/// </summary>
60+
/// <param name="factory">The entity factory.</param>
61+
/// <param name="init">The initializer for the entity.</param>
62+
/// <returns>The new/existing entity.</returns>
63+
public Entity CreateNullableEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity
64+
{
65+
return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init);
66+
}
67+
68+
/// <summary>
69+
/// Creates a new entity using the factory.
70+
/// </summary>
71+
/// <param name="factory">The entity factory.</param>
72+
/// <param name="init">The initializer for the entity.</param>
73+
/// <returns>The new/existing entity.</returns>
74+
public Entity CreateEntityFromSymbol<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init)
75+
where Entity : ICachedEntity
76+
where Type: ISymbol
5377
{
5478
return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init);
5579
}
@@ -135,8 +159,11 @@ private void CheckEntityHasUniqueLabel(string id, ICachedEntity entity)
135159

136160
public Label GetNewLabel() => new Label(GetNewId());
137161

138-
private Entity CreateNonNullEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity
162+
public Entity CreateNonNullEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init)
163+
where Entity : ICachedEntity
139164
{
165+
if (init is null) throw new ArgumentException("Unexpected null value", nameof(init));
166+
140167
if (objectEntityCache.TryGetValue(init, out var cached))
141168
return (Entity)cached;
142169

@@ -360,7 +387,7 @@ public void EmitTrap(TextWriter trapFile)
360387
/// <param name="optionalSymbol">Symbol for reporting errors.</param>
361388
/// <param name="entity">The entity to populate.</param>
362389
/// <exception cref="InternalError">Thrown on invalid trap stack behaviour.</exception>
363-
public void Populate(ISymbol optionalSymbol, ICachedEntity entity)
390+
public void Populate(ISymbol? optionalSymbol, ICachedEntity entity)
364391
{
365392
if (WritingLabel)
366393
{
@@ -453,9 +480,9 @@ public void BindComments(IEntity entity, Microsoft.CodeAnalysis.Location l)
453480
/// <param name="message">The error message.</param>
454481
/// <param name="entityText">A textual representation of the failed entity.</param>
455482
/// <param name="location">The location of the error.</param>
456-
/// <param name="stackTrace">An optional stack trace of the error, or an empty string.</param>
483+
/// <param name="stackTrace">An optional stack trace of the error, or null.</param>
457484
/// <param name="severity">The severity of the error.</param>
458-
public void ExtractionError(string message, string entityText, Entities.Location location, string stackTrace = "", Severity severity = Severity.Error)
485+
public void ExtractionError(string message, string entityText, Entities.Location location, string? stackTrace = null, Severity severity = Severity.Error)
459486
{
460487
var msg = new Message(message, entityText, location, stackTrace, severity);
461488
ExtractionError(msg);
@@ -467,7 +494,7 @@ public void ExtractionError(string message, string entityText, Entities.Location
467494
/// <param name="message">The text of the message.</param>
468495
/// <param name="optionalSymbol">The symbol of the error, or null.</param>
469496
/// <param name="optionalEntity">The entity of the error, or null.</param>
470-
public void ExtractionError(string message, ISymbol optionalSymbol, IEntity optionalEntity)
497+
public void ExtractionError(string message, ISymbol? optionalSymbol, IEntity optionalEntity)
471498
{
472499
if (!(optionalSymbol is null))
473500
{
@@ -539,7 +566,7 @@ static public void ModelError(this Context cx, string msg)
539566
/// <param name="node">Optional syntax node for error reporting.</param>
540567
/// <param name="symbol">Optional symbol for error reporting.</param>
541568
/// <param name="a">The action to perform.</param>
542-
static public void Try(this Context context, SyntaxNode node, ISymbol symbol, Action a)
569+
static public void Try(this Context context, SyntaxNode? node, ISymbol? symbol, Action a)
543570
{
544571
try
545572
{

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ public class Assembly : Location
88
readonly string assemblyPath;
99
readonly IAssemblySymbol assembly;
1010

11-
Assembly(Context cx, Microsoft.CodeAnalysis.Location init)
11+
Assembly(Context cx, Microsoft.CodeAnalysis.Location? init)
1212
: base(cx, init)
1313
{
1414
if (init == null)
@@ -19,7 +19,7 @@ public class Assembly : Location
1919
}
2020
else
2121
{
22-
assembly = symbol.MetadataModule.ContainingAssembly;
22+
assembly = init.MetadataModule.ContainingAssembly;
2323
var identity = assembly.Identity;
2424
var idString = identity.Name + " " + identity.Version;
2525
assemblyPath = cx.Extractor.GetAssemblyFile(idString);
@@ -30,7 +30,7 @@ public override void Populate(TextWriter trapFile)
3030
{
3131
if (assemblyPath != null)
3232
{
33-
trapFile.assemblies(this, File.Create(Context, assemblyPath), assembly.ToString(),
33+
trapFile.assemblies(this, File.Create(Context, assemblyPath), assembly.ToString() ?? "",
3434
assembly.Identity.Name, assembly.Identity.Version.ToString());
3535
}
3636
}
@@ -41,7 +41,7 @@ public override void Populate(TextWriter trapFile)
4141
public override int GetHashCode() =>
4242
symbol == null ? 91187354 : symbol.GetHashCode();
4343

44-
public override bool Equals(object obj)
44+
public override bool Equals(object? obj)
4545
{
4646
var other = obj as Assembly;
4747
if (other == null || other.GetType() != typeof(Assembly))
@@ -50,20 +50,20 @@ public override bool Equals(object obj)
5050
return Equals(symbol, other.symbol);
5151
}
5252

53-
public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => AssemblyConstructorFactory.Instance.CreateEntity(cx, loc);
53+
public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location? loc) => AssemblyConstructorFactory.Instance.CreateNullableEntity(cx, loc);
5454

55-
class AssemblyConstructorFactory : ICachedEntityFactory<Microsoft.CodeAnalysis.Location, Assembly>
55+
class AssemblyConstructorFactory : ICachedEntityFactory<Microsoft.CodeAnalysis.Location?, Assembly>
5656
{
5757
public static readonly AssemblyConstructorFactory Instance = new AssemblyConstructorFactory();
5858

59-
public Assembly Create(Context cx, Microsoft.CodeAnalysis.Location init) => new Assembly(cx, init);
59+
public Assembly Create(Context cx, Microsoft.CodeAnalysis.Location? init) => new Assembly(cx, init);
6060
}
6161

6262
public static Location CreateOutputAssembly(Context cx)
6363
{
6464
if (cx.Extractor.OutputPath == null)
6565
throw new InternalError("Attempting to create the output assembly in standalone extraction mode");
66-
return AssemblyConstructorFactory.Instance.CreateEntity(cx, null);
66+
return AssemblyConstructorFactory.Instance.CreateNullableEntity(cx, null);
6767
}
6868

6969
public override void WriteId(System.IO.TextWriter trapFile)

csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public ExtractionMessage(Context cx, Message msg) : base(cx)
1414

1515
protected override void Populate(TextWriter trapFile)
1616
{
17-
trapFile.extractor_messages(this, msg.Severity, "C# extractor", msg.Text, msg.EntityText, msg.Location, msg.StackTrace);
17+
trapFile.extractor_messages(this, msg.Severity, "C# extractor", msg.Text, msg.EntityText, msg.Location ?? GeneratedLocation.Create(cx), msg.StackTrace);
1818
}
1919

2020
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;

0 commit comments

Comments
 (0)