mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
C#: Enable nullability for Semmle.Extraction project. Some refactoring required.
This commit is contained in:
@@ -202,7 +202,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
return obj != null && obj.GetType() == typeof(VarargsType);
|
||||
}
|
||||
|
||||
public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateEntity(cx, null);
|
||||
public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateNullableEntity(cx, null);
|
||||
|
||||
class VarargsTypeFactory : ICachedEntityFactory<string, VarargsType>
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
return obj != null && obj.GetType() == typeof(NullType);
|
||||
}
|
||||
|
||||
public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateEntity(cx, null), NullableAnnotation.None);
|
||||
public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateNullableEntity(cx, null), NullableAnnotation.None);
|
||||
|
||||
class NullTypeFactory : ICachedEntityFactory<ITypeSymbol, NullType>
|
||||
{
|
||||
|
||||
@@ -26,10 +26,9 @@ namespace Semmle.Extraction.CommentProcessing
|
||||
|
||||
private readonly Dictionary<Label, Key> duplicationGuardKeys = new Dictionary<Label, Key>();
|
||||
|
||||
private Key GetDuplicationGuardKey(Label label)
|
||||
private Key? GetDuplicationGuardKey(Label label)
|
||||
{
|
||||
Key duplicationGuardKey;
|
||||
if (duplicationGuardKeys.TryGetValue(label, out duplicationGuardKey))
|
||||
if (duplicationGuardKeys.TryGetValue(label, out var duplicationGuardKey))
|
||||
return duplicationGuardKey;
|
||||
return null;
|
||||
}
|
||||
@@ -60,7 +59,7 @@ namespace Semmle.Extraction.CommentProcessing
|
||||
/// <param name="elementLabel">The label of the element in the trap file.</param>
|
||||
/// <param name="duplicationGuardKey">The duplication guard key of the element, if any.</param>
|
||||
/// <param name="loc">The location of the element.</param>
|
||||
public void AddElement(Label elementLabel, Key duplicationGuardKey, Location loc)
|
||||
public void AddElement(Label elementLabel, Key? duplicationGuardKey, Location loc)
|
||||
{
|
||||
if (loc != null && loc.IsInSource)
|
||||
elements[loc] = elementLabel;
|
||||
@@ -257,19 +256,24 @@ namespace Semmle.Extraction.CommentProcessing
|
||||
CommentBindingCallback cb
|
||||
)
|
||||
{
|
||||
CommentBlock block = new CommentBlock();
|
||||
CommentBlock? block = null;
|
||||
|
||||
// Iterate comments until the commentEnumerator has gone past nextElement
|
||||
while (nextElement == null || Compare(commentEnumerator.Current.Value.Location, nextElement.Value.Key) < 0)
|
||||
{
|
||||
if(block is null)
|
||||
block = new CommentBlock(commentEnumerator.Current.Value);
|
||||
|
||||
if (!block.CombinesWith(commentEnumerator.Current.Value))
|
||||
{
|
||||
// Start of a new block, so generate the bindings for the old block first.
|
||||
GenerateBindings(block, elementStack, nextElement, cb);
|
||||
block = new CommentBlock();
|
||||
block = new CommentBlock(commentEnumerator.Current.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
block.AddCommentLine(commentEnumerator.Current.Value);
|
||||
}
|
||||
|
||||
block.AddCommentLine(commentEnumerator.Current.Value);
|
||||
|
||||
// Get the next comment.
|
||||
if (!commentEnumerator.MoveNext())
|
||||
@@ -280,7 +284,9 @@ namespace Semmle.Extraction.CommentProcessing
|
||||
}
|
||||
}
|
||||
|
||||
GenerateBindings(block, elementStack, nextElement, cb);
|
||||
if(!(block is null))
|
||||
GenerateBindings(block, elementStack, nextElement, cb);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -332,12 +338,18 @@ namespace Semmle.Extraction.CommentProcessing
|
||||
|
||||
class CommentBlock : ICommentBlock
|
||||
{
|
||||
private readonly List<ICommentLine> lines = new List<ICommentLine>();
|
||||
private readonly List<ICommentLine> lines;
|
||||
|
||||
public IEnumerable<ICommentLine> CommentLines => lines;
|
||||
|
||||
public Location Location { get; private set; }
|
||||
|
||||
public CommentBlock(ICommentLine firstLine)
|
||||
{
|
||||
lines = new List<ICommentLine> { firstLine };
|
||||
Location = firstLine.Location;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine whether commentlines should be merged.
|
||||
/// </summary>
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace Semmle.Extraction.CommentProcessing
|
||||
/// <param name="duplicationGuardKey">The duplication guard key of the element, if any</param>
|
||||
/// <param name="commentBlock">The comment block associated with the element</param>
|
||||
/// <param name="binding">The relationship between the commentblock and the element</param>
|
||||
public delegate void CommentBindingCallback(Label elementLabel, Key duplicationGuardKey, ICommentBlock commentBlock, CommentBinding binding);
|
||||
public delegate void CommentBindingCallback(Label elementLabel, Key? duplicationGuardKey, ICommentBlock commentBlock, CommentBinding binding);
|
||||
|
||||
/// <summary>
|
||||
/// Computes the binding information between comments and program elements.
|
||||
@@ -88,7 +88,7 @@ namespace Semmle.Extraction.CommentProcessing
|
||||
/// <param name="elementLabel">Label of the element.</param>
|
||||
/// <param name="duplicationGuardKey">The duplication guard key of the element, if any.</param>
|
||||
/// <param name="location">Location of the element.</param>
|
||||
void AddElement(Label elementLabel, Key duplicationGuardKey, Location location);
|
||||
void AddElement(Label elementLabel, Key? duplicationGuardKey, Location location);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a line of comment.
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Semmle.Extraction
|
||||
return cachedModel;
|
||||
}
|
||||
|
||||
private SemanticModel cachedModel;
|
||||
private SemanticModel? cachedModel;
|
||||
|
||||
/// <summary>
|
||||
/// Access to the trap file.
|
||||
@@ -49,7 +49,31 @@ namespace Semmle.Extraction
|
||||
/// <param name="factory">The entity factory.</param>
|
||||
/// <param name="init">The initializer for the entity.</param>
|
||||
/// <returns>The new/existing entity.</returns>
|
||||
public Entity CreateEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity
|
||||
public Entity CreateEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity where Type:struct
|
||||
{
|
||||
return CreateNonNullEntity(factory, init);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new entity using the factory.
|
||||
/// </summary>
|
||||
/// <param name="factory">The entity factory.</param>
|
||||
/// <param name="init">The initializer for the entity.</param>
|
||||
/// <returns>The new/existing entity.</returns>
|
||||
public Entity CreateNullableEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity
|
||||
{
|
||||
return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new entity using the factory.
|
||||
/// </summary>
|
||||
/// <param name="factory">The entity factory.</param>
|
||||
/// <param name="init">The initializer for the entity.</param>
|
||||
/// <returns>The new/existing entity.</returns>
|
||||
public Entity CreateEntityFromSymbol<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init)
|
||||
where Entity : ICachedEntity
|
||||
where Type: ISymbol
|
||||
{
|
||||
return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init);
|
||||
}
|
||||
@@ -135,10 +159,13 @@ namespace Semmle.Extraction
|
||||
|
||||
public Label GetNewLabel() => new Label(GetNewId());
|
||||
|
||||
private Entity CreateNonNullEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity
|
||||
public Entity CreateNonNullEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init)
|
||||
where Entity : ICachedEntity
|
||||
{
|
||||
if (init is null) throw new ArgumentException("Unexpected null value", nameof(init));
|
||||
|
||||
if (objectEntityCache.TryGetValue(init, out var cached))
|
||||
return (Entity)cached;
|
||||
return (Entity)cached!;
|
||||
|
||||
using (StackGuard)
|
||||
{
|
||||
@@ -360,7 +387,7 @@ namespace Semmle.Extraction
|
||||
/// <param name="optionalSymbol">Symbol for reporting errors.</param>
|
||||
/// <param name="entity">The entity to populate.</param>
|
||||
/// <exception cref="InternalError">Thrown on invalid trap stack behaviour.</exception>
|
||||
public void Populate(ISymbol optionalSymbol, ICachedEntity entity)
|
||||
public void Populate(ISymbol? optionalSymbol, ICachedEntity entity)
|
||||
{
|
||||
if (WritingLabel)
|
||||
{
|
||||
@@ -453,9 +480,9 @@ namespace Semmle.Extraction
|
||||
/// <param name="message">The error message.</param>
|
||||
/// <param name="entityText">A textual representation of the failed entity.</param>
|
||||
/// <param name="location">The location of the error.</param>
|
||||
/// <param name="stackTrace">An optional stack trace of the error, or an empty string.</param>
|
||||
/// <param name="stackTrace">An optional stack trace of the error, or null.</param>
|
||||
/// <param name="severity">The severity of the error.</param>
|
||||
public void ExtractionError(string message, string entityText, Entities.Location location, string stackTrace = "", Severity severity = Severity.Error)
|
||||
public void ExtractionError(string message, string entityText, Entities.Location location, string? stackTrace = null, Severity severity = Severity.Error)
|
||||
{
|
||||
var msg = new Message(message, entityText, location, stackTrace, severity);
|
||||
ExtractionError(msg);
|
||||
@@ -467,7 +494,7 @@ namespace Semmle.Extraction
|
||||
/// <param name="message">The text of the message.</param>
|
||||
/// <param name="optionalSymbol">The symbol of the error, or null.</param>
|
||||
/// <param name="optionalEntity">The entity of the error, or null.</param>
|
||||
public void ExtractionError(string message, ISymbol optionalSymbol, IEntity optionalEntity)
|
||||
public void ExtractionError(string message, ISymbol? optionalSymbol, IEntity optionalEntity)
|
||||
{
|
||||
if (!(optionalSymbol is null))
|
||||
{
|
||||
@@ -539,7 +566,7 @@ namespace Semmle.Extraction
|
||||
/// <param name="node">Optional syntax node for error reporting.</param>
|
||||
/// <param name="symbol">Optional symbol for error reporting.</param>
|
||||
/// <param name="a">The action to perform.</param>
|
||||
static public void Try(this Context context, SyntaxNode node, ISymbol symbol, Action a)
|
||||
static public void Try(this Context context, SyntaxNode? node, ISymbol? symbol, Action a)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Semmle.Extraction.Entities
|
||||
readonly string assemblyPath;
|
||||
readonly IAssemblySymbol assembly;
|
||||
|
||||
Assembly(Context cx, Microsoft.CodeAnalysis.Location init)
|
||||
Assembly(Context cx, Microsoft.CodeAnalysis.Location? init)
|
||||
: base(cx, init)
|
||||
{
|
||||
if (init == null)
|
||||
@@ -19,7 +19,7 @@ namespace Semmle.Extraction.Entities
|
||||
}
|
||||
else
|
||||
{
|
||||
assembly = symbol.MetadataModule.ContainingAssembly;
|
||||
assembly = init.MetadataModule.ContainingAssembly;
|
||||
var identity = assembly.Identity;
|
||||
var idString = identity.Name + " " + identity.Version;
|
||||
assemblyPath = cx.Extractor.GetAssemblyFile(idString);
|
||||
@@ -30,7 +30,7 @@ namespace Semmle.Extraction.Entities
|
||||
{
|
||||
if (assemblyPath != null)
|
||||
{
|
||||
trapFile.assemblies(this, File.Create(Context, assemblyPath), assembly.ToString(),
|
||||
trapFile.assemblies(this, File.Create(Context, assemblyPath), assembly.ToString() ?? "",
|
||||
assembly.Identity.Name, assembly.Identity.Version.ToString());
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ namespace Semmle.Extraction.Entities
|
||||
public override int GetHashCode() =>
|
||||
symbol == null ? 91187354 : symbol.GetHashCode();
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
var other = obj as Assembly;
|
||||
if (other == null || other.GetType() != typeof(Assembly))
|
||||
@@ -50,20 +50,20 @@ namespace Semmle.Extraction.Entities
|
||||
return Equals(symbol, other.symbol);
|
||||
}
|
||||
|
||||
public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => AssemblyConstructorFactory.Instance.CreateEntity(cx, loc);
|
||||
public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location? loc) => AssemblyConstructorFactory.Instance.CreateNullableEntity(cx, loc);
|
||||
|
||||
class AssemblyConstructorFactory : ICachedEntityFactory<Microsoft.CodeAnalysis.Location, Assembly>
|
||||
class AssemblyConstructorFactory : ICachedEntityFactory<Microsoft.CodeAnalysis.Location?, Assembly>
|
||||
{
|
||||
public static readonly AssemblyConstructorFactory Instance = new AssemblyConstructorFactory();
|
||||
|
||||
public Assembly Create(Context cx, Microsoft.CodeAnalysis.Location init) => new Assembly(cx, init);
|
||||
public Assembly Create(Context cx, Microsoft.CodeAnalysis.Location? init) => new Assembly(cx, init);
|
||||
}
|
||||
|
||||
public static Location CreateOutputAssembly(Context cx)
|
||||
{
|
||||
if (cx.Extractor.OutputPath == null)
|
||||
throw new InternalError("Attempting to create the output assembly in standalone extraction mode");
|
||||
return AssemblyConstructorFactory.Instance.CreateEntity(cx, null);
|
||||
return AssemblyConstructorFactory.Instance.CreateNullableEntity(cx, null);
|
||||
}
|
||||
|
||||
public override void WriteId(System.IO.TextWriter trapFile)
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Semmle.Extraction.Entities
|
||||
|
||||
protected override void Populate(TextWriter trapFile)
|
||||
{
|
||||
trapFile.extractor_messages(this, msg.Severity, "C# extractor", msg.Text, msg.EntityText, msg.Location, msg.StackTrace);
|
||||
trapFile.extractor_messages(this, msg.Severity, "C# extractor", msg.Text, msg.EntityText, msg.Location ?? GeneratedLocation.Create(cx), msg.StackTrace);
|
||||
}
|
||||
|
||||
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
|
||||
|
||||
@@ -50,12 +50,12 @@ namespace Semmle.Extraction.Entities
|
||||
Where(t => t.FilePath == Path).
|
||||
Select(tree => tree.GetText()))
|
||||
{
|
||||
var rawText = text.ToString();
|
||||
var rawText = text.ToString() ?? "";
|
||||
var lineCounts = LineCounter.ComputeLineCounts(rawText);
|
||||
if (rawText.Length > 0 && rawText[rawText.Length - 1] != '\n') lineCounts.Total++;
|
||||
|
||||
trapFile.numlines(this, lineCounts);
|
||||
Context.TrapWriter.Archive(fi.FullName, text.Encoding);
|
||||
Context.TrapWriter.Archive(fi.FullName, text.Encoding ?? System.Text.Encoding.Default);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,17 +111,17 @@ namespace Semmle.Extraction.Entities
|
||||
}
|
||||
|
||||
public static GeneratedFile Create(Context cx) =>
|
||||
GeneratedFileFactory.Instance.CreateEntity(cx, null);
|
||||
GeneratedFileFactory.Instance.CreateNullableEntity(cx, null);
|
||||
|
||||
class GeneratedFileFactory : ICachedEntityFactory<string, GeneratedFile>
|
||||
class GeneratedFileFactory : ICachedEntityFactory<string?, GeneratedFile>
|
||||
{
|
||||
public static readonly GeneratedFileFactory Instance = new GeneratedFileFactory();
|
||||
|
||||
public GeneratedFile Create(Context cx, string init) => new GeneratedFile(cx);
|
||||
public GeneratedFile Create(Context cx, string? init) => new GeneratedFile(cx);
|
||||
}
|
||||
}
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => null;
|
||||
public override Microsoft.CodeAnalysis.Location? ReportingLocation => null;
|
||||
|
||||
class FileFactory : ICachedEntityFactory<string, File>
|
||||
{
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Semmle.Extraction.Entities
|
||||
public static Folder Create(Context cx, DirectoryInfo folder) =>
|
||||
FolderFactory.Instance.CreateEntity2(cx, folder);
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => null;
|
||||
public override Microsoft.CodeAnalysis.Location? ReportingLocation => null;
|
||||
|
||||
class FolderFactory : ICachedEntityFactory<DirectoryInfo, Folder>
|
||||
{
|
||||
@@ -58,7 +58,7 @@ namespace Semmle.Extraction.Entities
|
||||
|
||||
public override int GetHashCode() => Path.GetHashCode();
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Folder folder && folder.Path == Path;
|
||||
}
|
||||
|
||||
@@ -26,15 +26,15 @@ namespace Semmle.Extraction.Entities
|
||||
|
||||
public override int GetHashCode() => 98732567;
|
||||
|
||||
public override bool Equals(object obj) => obj != null && obj.GetType() == typeof(GeneratedLocation);
|
||||
public override bool Equals(object? obj) => obj != null && obj.GetType() == typeof(GeneratedLocation);
|
||||
|
||||
public static GeneratedLocation Create(Context cx) => GeneratedLocationFactory.Instance.CreateEntity(cx, null);
|
||||
public static GeneratedLocation Create(Context cx) => GeneratedLocationFactory.Instance.CreateNullableEntity(cx, null);
|
||||
|
||||
class GeneratedLocationFactory : ICachedEntityFactory<string, GeneratedLocation>
|
||||
class GeneratedLocationFactory : ICachedEntityFactory<string?, GeneratedLocation>
|
||||
{
|
||||
public static GeneratedLocationFactory Instance = new GeneratedLocationFactory();
|
||||
|
||||
public GeneratedLocation Create(Context cx, string init) => new GeneratedLocation(cx);
|
||||
public GeneratedLocation Create(Context cx, string? init) => new GeneratedLocation(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
|
||||
namespace Semmle.Extraction.Entities
|
||||
{
|
||||
public abstract class Location : CachedEntity<Microsoft.CodeAnalysis.Location>
|
||||
public abstract class Location : CachedEntity<Microsoft.CodeAnalysis.Location?>
|
||||
{
|
||||
public Location(Context cx, Microsoft.CodeAnalysis.Location init)
|
||||
public Location(Context cx, Microsoft.CodeAnalysis.Location? init)
|
||||
: base(cx, init) { }
|
||||
|
||||
public static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) =>
|
||||
public static Location Create(Context cx, Microsoft.CodeAnalysis.Location? loc) =>
|
||||
(loc == null || loc.Kind == Microsoft.CodeAnalysis.LocationKind.None) ? GeneratedLocation.Create(cx)
|
||||
: loc.IsInSource ? SourceLocation.Create(cx, loc)
|
||||
: loc.IsInSource ? NonGeneratedSourceLocation.Create(cx, loc)
|
||||
: Assembly.Create(cx, loc);
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => symbol;
|
||||
public override Microsoft.CodeAnalysis.Location? ReportingLocation => symbol;
|
||||
|
||||
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel;
|
||||
}
|
||||
@@ -24,7 +24,7 @@ namespace Semmle.Extraction.Entities
|
||||
/// <param name="cx">The extraction context.</param>
|
||||
/// <param name="location">The CodeAnalysis location.</param>
|
||||
/// <returns>The Location entity.</returns>
|
||||
public static Location Create(this Context cx, Microsoft.CodeAnalysis.Location location) =>
|
||||
public static Location Create(this Context cx, Microsoft.CodeAnalysis.Location? location) =>
|
||||
Location.Create(cx, location);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +1,64 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction.Entities
|
||||
{
|
||||
public class SourceLocation : Location
|
||||
{
|
||||
protected SourceLocation(Context cx, Microsoft.CodeAnalysis.Location init)
|
||||
: base(cx, init) { }
|
||||
public abstract class SourceLocation : Location {
|
||||
protected SourceLocation(Context cx, Microsoft.CodeAnalysis.Location? init) : base(cx, init)
|
||||
{
|
||||
}
|
||||
|
||||
public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => SourceLocationFactory.Instance.CreateEntity(cx, loc);
|
||||
public override bool NeedsPopulation => true;
|
||||
}
|
||||
|
||||
public class NonGeneratedSourceLocation : SourceLocation
|
||||
{
|
||||
protected NonGeneratedSourceLocation(Context cx, Microsoft.CodeAnalysis.Location? init)
|
||||
: base(cx, init)
|
||||
{
|
||||
if (init is null) throw new ArgumentException("Location may not be null", nameof(init));
|
||||
Position = init.GetLineSpan();
|
||||
FileEntity = File.Create(Context, Position.Path);
|
||||
}
|
||||
|
||||
public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location? loc) => SourceLocationFactory.Instance.CreateNullableEntity(cx, loc);
|
||||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
{
|
||||
Position = symbol.GetLineSpan();
|
||||
FileEntity = File.Create(Context, Position.Path);
|
||||
trapFile.locations_default(this, FileEntity, Position.Span.Start.Line + 1, Position.Span.Start.Character + 1,
|
||||
Position.Span.End.Line + 1, Position.Span.End.Character);
|
||||
}
|
||||
|
||||
public override bool NeedsPopulation => true;
|
||||
|
||||
public FileLinePositionSpan Position
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public File FileEntity
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public override void WriteId(System.IO.TextWriter trapFile)
|
||||
{
|
||||
FileLinePositionSpan l = symbol.GetLineSpan();
|
||||
FileEntity = Entities.File.Create(Context, l.Path);
|
||||
trapFile.Write("loc,");
|
||||
trapFile.WriteSubId(FileEntity);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(l.Span.Start.Line + 1);
|
||||
trapFile.Write(Position.Span.Start.Line + 1);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(l.Span.Start.Character + 1);
|
||||
trapFile.Write(Position.Span.Start.Character + 1);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(l.Span.End.Line + 1);
|
||||
trapFile.Write(Position.Span.End.Line + 1);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(l.Span.End.Character);
|
||||
trapFile.Write(Position.Span.End.Character);
|
||||
}
|
||||
|
||||
class SourceLocationFactory : ICachedEntityFactory<Microsoft.CodeAnalysis.Location, SourceLocation>
|
||||
class SourceLocationFactory : ICachedEntityFactory<Microsoft.CodeAnalysis.Location?, SourceLocation>
|
||||
{
|
||||
public static readonly SourceLocationFactory Instance = new SourceLocationFactory();
|
||||
|
||||
public SourceLocation Create(Context cx, Microsoft.CodeAnalysis.Location init) => new SourceLocation(cx, init);
|
||||
public SourceLocation Create(Context cx, Microsoft.CodeAnalysis.Location? init) => new NonGeneratedSourceLocation(cx, init);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Semmle.Extraction
|
||||
/// <summary>
|
||||
/// The location for reporting purposes.
|
||||
/// </summary>
|
||||
Location ReportingLocation { get; }
|
||||
Location? ReportingLocation { get; }
|
||||
|
||||
/// <summary>
|
||||
/// How the entity handles .push and .pop.
|
||||
@@ -92,7 +92,7 @@ namespace Semmle.Extraction
|
||||
|
||||
bool NeedsPopulation { get; }
|
||||
|
||||
object UnderlyingObject { get; }
|
||||
object? UnderlyingObject { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -127,8 +127,11 @@ namespace Semmle.Extraction
|
||||
/// <param name="factory">The factory used to construct the entity.</param>
|
||||
/// <param name="init">The initializer for the entity, which may not be null.</param>
|
||||
/// <returns>The entity.</returns>
|
||||
public static Entity CreateEntity<Type, Entity>(this ICachedEntityFactory<Type, Entity> factory, Context cx, Type init)
|
||||
where Entity : ICachedEntity => cx.CreateEntity(factory, init);
|
||||
public static Entity CreateEntity<Type, Entity>(this ICachedEntityFactory<Type, Entity> factory, Context cx, Type init) where Type : notnull
|
||||
where Entity : ICachedEntity => cx.CreateNonNullEntity(factory, init);
|
||||
|
||||
public static Entity CreateNullableEntity<Type, Entity>(this ICachedEntityFactory<Type, Entity> factory, Context cx, Type init)
|
||||
where Entity : ICachedEntity => cx.CreateNullableEntity(factory, init);
|
||||
|
||||
/// <summary>
|
||||
/// Creates and populates a new entity, but uses a different cache.
|
||||
@@ -153,7 +156,7 @@ namespace Semmle.Extraction
|
||||
catch(Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
trapFile.WriteLine("\"");
|
||||
extractor.Message(new Message("Unhandled exception generating id", entity.ToString(), null, ex.StackTrace.ToString()));
|
||||
extractor.Message(new Message("Unhandled exception generating id", entity.ToString() ?? "", null, ex.StackTrace));
|
||||
}
|
||||
trapFile.WriteLine();
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Semmle.Extraction
|
||||
|
||||
public override string ToString() => Label.ToString();
|
||||
|
||||
public virtual Microsoft.CodeAnalysis.Location ReportingLocation => null;
|
||||
public virtual Microsoft.CodeAnalysis.Location? ReportingLocation => null;
|
||||
|
||||
public abstract TrapStackBehaviour TrapStackBehaviour { get; }
|
||||
}
|
||||
|
||||
@@ -34,7 +34,12 @@ namespace Semmle.Extraction
|
||||
|
||||
public override string ToString() => "*";
|
||||
|
||||
public override bool Equals(object obj) => obj.GetType() == GetType();
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
// Expand logic to allow for nullability control flow analysis
|
||||
if (obj is null) return false;
|
||||
return obj.GetType() == GetType();
|
||||
}
|
||||
|
||||
public override int GetHashCode() => 0;
|
||||
|
||||
@@ -87,9 +92,9 @@ namespace Semmle.Extraction
|
||||
return TrapBuilder.ToString();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj.GetType() != GetType())
|
||||
if (obj is null || obj.GetType() != GetType())
|
||||
return false;
|
||||
var id = (Key)obj;
|
||||
return TrapBuilder.ToString() == id.TrapBuilder.ToString();
|
||||
@@ -133,8 +138,9 @@ namespace Semmle.Extraction
|
||||
|
||||
public static bool operator !=(Label l1, Label l2) => l1.Value != l2.Value;
|
||||
|
||||
public override bool Equals(object other)
|
||||
public override bool Equals(object? other)
|
||||
{
|
||||
if (other is null) return false;
|
||||
return GetType() == other.GetType() && ((Label)other).Value == Value;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Semmle.Extraction
|
||||
public InternalError(ISymbol symbol, string msg)
|
||||
{
|
||||
Text = msg;
|
||||
EntityText = symbol.ToString();
|
||||
EntityText = symbol.ToString() ?? "";
|
||||
Location = symbol.Locations.FirstOrDefault();
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Semmle.Extraction
|
||||
Location = null;
|
||||
}
|
||||
|
||||
public Location Location { get; }
|
||||
public Location? Location { get; }
|
||||
public string Text { get; }
|
||||
public string EntityText { get; }
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Semmle.Extraction
|
||||
/// <summary>
|
||||
/// List of blocks in the layout file.
|
||||
/// </summary>
|
||||
List<LayoutBlock> blocks;
|
||||
readonly List<LayoutBlock> blocks;
|
||||
|
||||
/// <summary>
|
||||
/// A subproject in the layout file.
|
||||
@@ -36,14 +36,14 @@ namespace Semmle.Extraction
|
||||
/// <summary>
|
||||
/// The trap folder, or null for current directory.
|
||||
/// </summary>
|
||||
public readonly string TRAP_FOLDER;
|
||||
public readonly string? TRAP_FOLDER;
|
||||
|
||||
/// <summary>
|
||||
/// The source archive, or null to skip.
|
||||
/// </summary>
|
||||
public readonly string SOURCE_ARCHIVE;
|
||||
public readonly string? SOURCE_ARCHIVE;
|
||||
|
||||
public SubProject(string traps, string archive)
|
||||
public SubProject(string? traps, string? archive)
|
||||
{
|
||||
TRAP_FOLDER = traps;
|
||||
SOURCE_ARCHIVE = archive;
|
||||
@@ -73,7 +73,7 @@ namespace Semmle.Extraction
|
||||
/// </summary>
|
||||
/// <param name="sourceFile">The file to look up.</param>
|
||||
/// <returns>The relevant subproject, or null if not found.</returns>
|
||||
public SubProject LookupProjectOrNull(string sourceFile)
|
||||
public SubProject? LookupProjectOrNull(string sourceFile)
|
||||
{
|
||||
if (!useLayoutFile) return DefaultProject;
|
||||
|
||||
@@ -113,13 +113,14 @@ namespace Semmle.Extraction
|
||||
/// <param name="archive">Directory for source archive, or null for layout/no archive.</param>
|
||||
/// <param name="layout">Path of layout file, or null for no layout.</param>
|
||||
/// <exception cref="InvalidLayoutException">Failed to read layout file.</exception>
|
||||
public Layout(string traps, string archive, string layout)
|
||||
public Layout(string? traps, string? archive, string? layout)
|
||||
{
|
||||
useLayoutFile = string.IsNullOrEmpty(traps) && !string.IsNullOrEmpty(layout);
|
||||
blocks = new List<LayoutBlock>();
|
||||
|
||||
if (useLayoutFile)
|
||||
{
|
||||
ReadLayoutFile(layout);
|
||||
ReadLayoutFile(layout!);
|
||||
DefaultProject = blocks[0].Directories;
|
||||
}
|
||||
else
|
||||
@@ -141,15 +142,12 @@ namespace Semmle.Extraction
|
||||
{
|
||||
var lines = File.ReadAllLines(layout);
|
||||
|
||||
blocks = new List<LayoutBlock>();
|
||||
|
||||
int i = 0;
|
||||
while (!lines[i].StartsWith("#"))
|
||||
i++;
|
||||
while (i < lines.Length)
|
||||
{
|
||||
LayoutBlock block = new LayoutBlock();
|
||||
i = block.Read(lines, i);
|
||||
LayoutBlock block = new LayoutBlock(lines, ref i);
|
||||
blocks.Add(block);
|
||||
}
|
||||
|
||||
@@ -197,9 +195,9 @@ namespace Semmle.Extraction
|
||||
|
||||
private readonly List<Condition> conditions = new List<Condition>();
|
||||
|
||||
public Layout.SubProject Directories;
|
||||
public readonly Layout.SubProject Directories;
|
||||
|
||||
string ReadVariable(string name, string line)
|
||||
string? ReadVariable(string name, string line)
|
||||
{
|
||||
string prefix = name + "=";
|
||||
if (!line.StartsWith(prefix))
|
||||
@@ -207,23 +205,22 @@ namespace Semmle.Extraction
|
||||
return line.Substring(prefix.Length).Trim();
|
||||
}
|
||||
|
||||
public int Read(string[] lines, int start)
|
||||
public LayoutBlock(string[] lines, ref int i)
|
||||
{
|
||||
// first line: #name
|
||||
int i = start + 1;
|
||||
var TRAP_FOLDER = ReadVariable("TRAP_FOLDER", lines[i++]);
|
||||
i++;
|
||||
string? TRAP_FOLDER = ReadVariable("TRAP_FOLDER", lines[i++]);
|
||||
// Don't care about ODASA_DB.
|
||||
ReadVariable("ODASA_DB", lines[i++]);
|
||||
var SOURCE_ARCHIVE = ReadVariable("SOURCE_ARCHIVE", lines[i++]);
|
||||
string? SOURCE_ARCHIVE = ReadVariable("SOURCE_ARCHIVE", lines[i++]);
|
||||
|
||||
Directories = new Extraction.Layout.SubProject(TRAP_FOLDER, SOURCE_ARCHIVE);
|
||||
Directories = new Layout.SubProject(TRAP_FOLDER, SOURCE_ARCHIVE);
|
||||
// Don't care about ODASA_BUILD_ERROR_DIR.
|
||||
ReadVariable("ODASA_BUILD_ERROR_DIR", lines[i++]);
|
||||
while (i < lines.Length && !lines[i].StartsWith("#"))
|
||||
{
|
||||
conditions.Add(new Condition(lines[i++]));
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public bool Matches(string path)
|
||||
|
||||
@@ -15,23 +15,23 @@ namespace Semmle.Extraction
|
||||
public readonly string Text;
|
||||
public readonly string StackTrace;
|
||||
public readonly string EntityText;
|
||||
public readonly Entities.Location Location;
|
||||
public readonly Entities.Location? Location;
|
||||
|
||||
public Message(string text, string entityText, Entities.Location location, string stackTrace="", Severity severity = Severity.Error)
|
||||
public Message(string text, string entityText, Entities.Location? location, string? stackTrace = null, Severity severity = Severity.Error)
|
||||
{
|
||||
Severity = severity;
|
||||
Text = text;
|
||||
StackTrace = stackTrace;
|
||||
StackTrace = stackTrace ?? "";
|
||||
EntityText = entityText;
|
||||
Location = location;
|
||||
}
|
||||
|
||||
public static Message Create(Context cx, string text, ISymbol symbol, string stackTrace= "", Severity severity = Severity.Error)
|
||||
public static Message Create(Context cx, string text, ISymbol symbol, string? stackTrace = null, Severity severity = Severity.Error)
|
||||
{
|
||||
return new Message(text, symbol.ToString(), Entities.Location.Create(cx, symbol.Locations.FirstOrDefault()), stackTrace, severity);
|
||||
return new Message(text, symbol.ToString() ?? "", Entities.Location.Create(cx, symbol.Locations.FirstOrDefault()), stackTrace, severity);
|
||||
}
|
||||
|
||||
public static Message Create(Context cx, string text, SyntaxNode node, string stackTrace = "", Severity severity = Severity.Error)
|
||||
public static Message Create(Context cx, string text, SyntaxNode node, string? stackTrace = null, Severity severity = Severity.Error)
|
||||
{
|
||||
return new Message(text, node.ToString(), Entities.Location.Create(cx, node.GetLocation()), stackTrace, severity);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<CodeAnalysisRuleSet>Semmle.Extraction.ruleset</CodeAnalysisRuleSet>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Semmle.Extraction
|
||||
|
||||
public Label Label { get; set; }
|
||||
|
||||
public abstract Microsoft.CodeAnalysis.Location ReportingLocation { get; }
|
||||
public abstract Microsoft.CodeAnalysis.Location? ReportingLocation { get; }
|
||||
|
||||
public override string ToString() => Label.ToString();
|
||||
|
||||
@@ -39,15 +39,15 @@ namespace Semmle.Extraction
|
||||
|
||||
public Context Context
|
||||
{
|
||||
get; private set;
|
||||
get;
|
||||
}
|
||||
|
||||
public Initializer symbol
|
||||
{
|
||||
get; private set;
|
||||
get;
|
||||
}
|
||||
|
||||
object ICachedEntity.UnderlyingObject => symbol;
|
||||
object? ICachedEntity.UnderlyingObject => symbol;
|
||||
|
||||
public Initializer UnderlyingObject => symbol;
|
||||
|
||||
@@ -75,9 +75,9 @@ namespace Semmle.Extraction
|
||||
Context.WithDuplicationGuard(key, a);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => symbol.GetHashCode();
|
||||
public override int GetHashCode() => symbol is null ? 0 : symbol.GetHashCode();
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
var other = obj as CachedEntity<Initializer>;
|
||||
return other?.GetType() == GetType() && Equals(other.symbol, symbol);
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Semmle.Extraction
|
||||
/// <summary>
|
||||
/// The location of the src_archive directory.
|
||||
/// </summary>
|
||||
private readonly string archive;
|
||||
private readonly string? archive;
|
||||
private static readonly Encoding UTF8 = new UTF8Encoding(false);
|
||||
|
||||
private readonly bool discardDuplicates;
|
||||
@@ -45,7 +45,7 @@ namespace Semmle.Extraction
|
||||
|
||||
readonly CompressionMode TrapCompression;
|
||||
|
||||
public TrapWriter(ILogger logger, string outputfile, string trap, string archive, bool discardDuplicates, CompressionMode trapCompression)
|
||||
public TrapWriter(ILogger logger, string outputfile, string? trap, string? archive, bool discardDuplicates, CompressionMode trapCompression)
|
||||
{
|
||||
Logger = logger;
|
||||
TrapCompression = trapCompression;
|
||||
@@ -101,7 +101,7 @@ namespace Semmle.Extraction
|
||||
/// The output filename of the trap.
|
||||
/// </summary>
|
||||
public readonly string TrapFile;
|
||||
string tmpFile; // The temporary file which is moved to trapFile once written.
|
||||
string tmpFile = ""; // The temporary file which is moved to trapFile once written.
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified input file to the source archive. It may end up in either the normal or long path area
|
||||
@@ -236,7 +236,7 @@ namespace Semmle.Extraction
|
||||
}
|
||||
}
|
||||
|
||||
public static string NestPaths(ILogger logger, string outerpath, string innerpath, InnerPathComputation innerPathComputation)
|
||||
public static string NestPaths(ILogger logger, string? outerpath, string innerpath, InnerPathComputation innerPathComputation)
|
||||
{
|
||||
string nested = innerpath;
|
||||
if (!string.IsNullOrEmpty(outerpath))
|
||||
@@ -276,7 +276,7 @@ namespace Semmle.Extraction
|
||||
}
|
||||
}
|
||||
|
||||
public static string TrapPath(ILogger logger, string folder, string filename, TrapWriter.CompressionMode trapCompression)
|
||||
public static string TrapPath(ILogger logger, string? folder, string filename, TrapWriter.CompressionMode trapCompression)
|
||||
{
|
||||
filename = $"{Path.GetFullPath(filename)}.trap{TrapExtension(trapCompression)}";
|
||||
if (string.IsNullOrEmpty(folder))
|
||||
|
||||
Reference in New Issue
Block a user