зеркало из https://github.com/github/codeql.git
Merge branch 'main' into napalys/ES2023-array-protype-with
This commit is contained in:
Коммит
a23850940f
|
@ -4,8 +4,6 @@ VisualStudioVersion = 15.0.27130.2036
|
|||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Util", "extractor\Semmle.Util\Semmle.Util.csproj", "{CDD7AD69-0FD8-40F0-A9DA-F1077A2A85D6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction", "extractor\Semmle.Extraction\Semmle.Extraction.csproj", "{81EAAD75-4BE1-44E4-91DF-20778216DB64}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp", "extractor\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj", "{C4D62DA0-B64B-440B-86DC-AB52318CB8BF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp.DependencyFetching", "extractor\Semmle.Extraction.CSharp.DependencyFetching\Semmle.Extraction.CSharp.DependencyFetching.csproj", "{541D1AC5-E42C-4AB2-A1A4-C2355CE2A2EF}"
|
||||
|
|
|
@ -14,7 +14,7 @@ codeql_csharp_library(
|
|||
nowarn = ["CA1822"],
|
||||
visibility = ["//csharp:__subpackages__"],
|
||||
deps = [
|
||||
"//csharp/extractor/Semmle.Extraction",
|
||||
"//csharp/extractor/Semmle.Extraction.CSharp",
|
||||
"//csharp/extractor/Semmle.Util",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
|||
internal class NugetExeWrapper : IDisposable
|
||||
{
|
||||
private readonly string? nugetExe;
|
||||
private readonly Util.Logging.ILogger logger;
|
||||
private readonly Semmle.Util.Logging.ILogger logger;
|
||||
|
||||
public int PackageCount => fileProvider.PackagesConfigs.Count;
|
||||
|
||||
|
@ -33,7 +33,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
|||
/// <summary>
|
||||
/// Create the package manager for a specified source tree.
|
||||
/// </summary>
|
||||
public NugetExeWrapper(FileProvider fileProvider, TemporaryDirectory packageDirectory, Util.Logging.ILogger logger)
|
||||
public NugetExeWrapper(FileProvider fileProvider, TemporaryDirectory packageDirectory, Semmle.Util.Logging.ILogger logger)
|
||||
{
|
||||
this.fileProvider = fileProvider;
|
||||
this.packageDirectory = packageDirectory;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj" />
|
||||
|
||||
<InternalsVisibleTo Include="Semmle.Extraction.Tests" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -6,17 +6,18 @@ load(
|
|||
codeql_csharp_library(
|
||||
name = "Semmle.Extraction.CSharp",
|
||||
srcs = glob([
|
||||
"CodeAnalysisExtensions/**/*.cs",
|
||||
"Comments/**/*.cs",
|
||||
"Entities/**/*.cs",
|
||||
"Extractor/**/*.cs",
|
||||
"Kinds/**/*.cs",
|
||||
"Populators/**/*.cs",
|
||||
"Trap/**/*.cs",
|
||||
"*.cs",
|
||||
]),
|
||||
allow_unsafe_blocks = True,
|
||||
visibility = ["//csharp:__subpackages__"],
|
||||
deps = [
|
||||
"//csharp/extractor/Semmle.Extraction",
|
||||
"//csharp/extractor/Semmle.Extraction.CSharp.Util",
|
||||
"//csharp/extractor/Semmle.Util",
|
||||
"@paket.main//basic.compilerlog.util",
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// A factory for creating cached entities.
|
||||
/// </summary>
|
||||
internal abstract class CachedEntityFactory<TInit, TEntity>
|
||||
: Extraction.CachedEntityFactory<TInit, TEntity> where TEntity : CachedEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the entity, but does not generate any trap code.
|
||||
/// </summary>
|
||||
public sealed override TEntity Create(Extraction.Context cx, TInit init)
|
||||
{
|
||||
return Create((Context)cx, init);
|
||||
}
|
||||
|
||||
public abstract TEntity Create(Context cx, TInit init);
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
public static class LocationExtensions
|
||||
{
|
|
@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Comments
|
|||
|
||||
public IEnumerable<CommentLine> CommentLines => lines;
|
||||
|
||||
public Location Location { get; private set; }
|
||||
public Microsoft.CodeAnalysis.Location Location { get; private set; }
|
||||
|
||||
public CommentBlock(CommentLine firstLine)
|
||||
{
|
||||
|
@ -49,7 +49,7 @@ namespace Semmle.Extraction.CSharp.Comments
|
|||
{
|
||||
Location = !lines.Any()
|
||||
? line.Location
|
||||
: Location.Create(
|
||||
: Microsoft.CodeAnalysis.Location.Create(
|
||||
line.Location.SourceTree!,
|
||||
new TextSpan(Location.SourceSpan.Start, line.Location.SourceSpan.End - Location.SourceSpan.Start));
|
||||
|
||||
|
|
|
@ -19,10 +19,10 @@ namespace Semmle.Extraction.CSharp
|
|||
}
|
||||
|
||||
// Comments sorted by location.
|
||||
private readonly SortedDictionary<Location, CommentLine> comments = new SortedDictionary<Location, CommentLine>(new LocationComparer());
|
||||
private readonly SortedDictionary<Microsoft.CodeAnalysis.Location, CommentLine> comments = new SortedDictionary<Microsoft.CodeAnalysis.Location, CommentLine>(new LocationComparer());
|
||||
|
||||
// Program elements sorted by location.
|
||||
private readonly SortedDictionary<Location, Label> elements = new SortedDictionary<Location, Label>(new LocationComparer());
|
||||
private readonly SortedDictionary<Microsoft.CodeAnalysis.Location, Label> elements = new SortedDictionary<Microsoft.CodeAnalysis.Location, Label>(new LocationComparer());
|
||||
|
||||
private readonly Dictionary<Label, Key> duplicationGuardKeys = new Dictionary<Label, Key>();
|
||||
|
||||
|
@ -33,9 +33,9 @@ namespace Semmle.Extraction.CSharp
|
|||
return null;
|
||||
}
|
||||
|
||||
private class LocationComparer : IComparer<Location>
|
||||
private class LocationComparer : IComparer<Microsoft.CodeAnalysis.Location>
|
||||
{
|
||||
public int Compare(Location? l1, Location? l2) => CommentProcessor.Compare(l1, l2);
|
||||
public int Compare(Microsoft.CodeAnalysis.Location? l1, Microsoft.CodeAnalysis.Location? l2) => CommentProcessor.Compare(l1, l2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -44,7 +44,7 @@ namespace Semmle.Extraction.CSharp
|
|||
/// <param name="l1">First location</param>
|
||||
/// <param name="l2">Second location</param>
|
||||
/// <returns><0 if l1 before l2, >0 if l1 after l2, else 0.</returns>
|
||||
private static int Compare(Location? l1, Location? l2)
|
||||
private static int Compare(Microsoft.CodeAnalysis.Location? l1, Microsoft.CodeAnalysis.Location? l2)
|
||||
{
|
||||
if (object.ReferenceEquals(l1, l2))
|
||||
return 0;
|
||||
|
@ -68,7 +68,7 @@ namespace Semmle.Extraction.CSharp
|
|||
/// <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, Microsoft.CodeAnalysis.Location? loc)
|
||||
{
|
||||
if (loc is not null && loc.IsInSource)
|
||||
elements[loc] = elementLabel;
|
||||
|
@ -78,7 +78,7 @@ namespace Semmle.Extraction.CSharp
|
|||
|
||||
// Ensure that commentBlock and element refer to the same file
|
||||
// which can happen when processing multiple files.
|
||||
private static void EnsureSameFile(Comments.CommentBlock commentBlock, ref KeyValuePair<Location, Label>? element)
|
||||
private static void EnsureSameFile(Comments.CommentBlock commentBlock, ref KeyValuePair<Microsoft.CodeAnalysis.Location, Label>? element)
|
||||
{
|
||||
if (element is not null && element.Value.Key.SourceTree != commentBlock.Location.SourceTree)
|
||||
element = null;
|
||||
|
@ -96,9 +96,9 @@ namespace Semmle.Extraction.CSharp
|
|||
/// <param name="callback">Output binding information.</param>
|
||||
private void GenerateBindings(
|
||||
Comments.CommentBlock commentBlock,
|
||||
KeyValuePair<Location, Label>? previousElement,
|
||||
KeyValuePair<Location, Label>? nextElement,
|
||||
KeyValuePair<Location, Label>? parentElement,
|
||||
KeyValuePair<Microsoft.CodeAnalysis.Location, Label>? previousElement,
|
||||
KeyValuePair<Microsoft.CodeAnalysis.Location, Label>? nextElement,
|
||||
KeyValuePair<Microsoft.CodeAnalysis.Location, Label>? parentElement,
|
||||
CommentBindingCallback callback
|
||||
)
|
||||
{
|
||||
|
@ -125,7 +125,7 @@ namespace Semmle.Extraction.CSharp
|
|||
}
|
||||
|
||||
// Heuristic to decide which is the "best" element associated with the comment.
|
||||
KeyValuePair<Location, Label>? bestElement;
|
||||
KeyValuePair<Microsoft.CodeAnalysis.Location, Label>? bestElement;
|
||||
|
||||
if (previousElement is not null && previousElement.Value.Key.EndLine() == commentBlock.Location.StartLine())
|
||||
{
|
||||
|
@ -180,14 +180,14 @@ namespace Semmle.Extraction.CSharp
|
|||
private class ElementStack
|
||||
{
|
||||
// Invariant: the top of the stack must be contained by items below it.
|
||||
private readonly Stack<KeyValuePair<Location, Label>> elementStack = new Stack<KeyValuePair<Location, Label>>();
|
||||
private readonly Stack<KeyValuePair<Microsoft.CodeAnalysis.Location, Label>> elementStack = new();
|
||||
|
||||
/// <summary>
|
||||
/// Add a new element to the stack.
|
||||
/// </summary>
|
||||
/// The stack is maintained.
|
||||
/// <param name="value">The new element to push.</param>
|
||||
public void Push(KeyValuePair<Location, Label> value)
|
||||
public void Push(KeyValuePair<Microsoft.CodeAnalysis.Location, Label> value)
|
||||
{
|
||||
// Maintain the invariant by popping existing elements
|
||||
while (elementStack.Count > 0 && !elementStack.Peek().Key.Contains(value.Key))
|
||||
|
@ -201,7 +201,7 @@ namespace Semmle.Extraction.CSharp
|
|||
/// </summary>
|
||||
/// <param name="l">The location of the comment.</param>
|
||||
/// <returns>An element completely containing l, or null if none found.</returns>
|
||||
public KeyValuePair<Location, Label>? FindParent(Location l) =>
|
||||
public KeyValuePair<Microsoft.CodeAnalysis.Location, Label>? FindParent(Microsoft.CodeAnalysis.Location l) =>
|
||||
elementStack.Where(v => v.Key.Contains(l)).FirstOrNull();
|
||||
|
||||
/// <summary>
|
||||
|
@ -209,7 +209,7 @@ namespace Semmle.Extraction.CSharp
|
|||
/// </summary>
|
||||
/// <param name="l">The location of the comment.</param>
|
||||
/// <returns>The element before l, or null.</returns>
|
||||
public KeyValuePair<Location, Label>? FindBefore(Location l)
|
||||
public KeyValuePair<Microsoft.CodeAnalysis.Location, Label>? FindBefore(Microsoft.CodeAnalysis.Location l)
|
||||
{
|
||||
return elementStack
|
||||
.Where(v => v.Key.SourceSpan.End < l.SourceSpan.Start)
|
||||
|
@ -222,7 +222,7 @@ namespace Semmle.Extraction.CSharp
|
|||
/// <param name="comment">The location of the comment.</param>
|
||||
/// <param name="next">The next element.</param>
|
||||
/// <returns>The next element.</returns>
|
||||
public KeyValuePair<Location, Label>? FindAfter(Location comment, KeyValuePair<Location, Label>? next)
|
||||
public KeyValuePair<Microsoft.CodeAnalysis.Location, Label>? FindAfter(Microsoft.CodeAnalysis.Location comment, KeyValuePair<Microsoft.CodeAnalysis.Location, Label>? next)
|
||||
{
|
||||
var p = FindParent(comment);
|
||||
return next.HasValue && p.HasValue && p.Value.Key.Before(next.Value.Key) ? null : next;
|
||||
|
@ -233,7 +233,7 @@ namespace Semmle.Extraction.CSharp
|
|||
private void GenerateBindings(
|
||||
Comments.CommentBlock block,
|
||||
ElementStack elementStack,
|
||||
KeyValuePair<Location, Label>? nextElement,
|
||||
KeyValuePair<Microsoft.CodeAnalysis.Location, Label>? nextElement,
|
||||
CommentBindingCallback cb
|
||||
)
|
||||
{
|
||||
|
@ -259,8 +259,8 @@ namespace Semmle.Extraction.CSharp
|
|||
/// <param name="cb">Where to send the results.</param>
|
||||
/// <returns>true if there are more comments to process, false otherwise.</returns>
|
||||
private bool GenerateBindings(
|
||||
IEnumerator<KeyValuePair<Location, CommentLine>> commentEnumerator,
|
||||
KeyValuePair<Location, Label>? nextElement,
|
||||
IEnumerator<KeyValuePair<Microsoft.CodeAnalysis.Location, CommentLine>> commentEnumerator,
|
||||
KeyValuePair<Microsoft.CodeAnalysis.Location, Label>? nextElement,
|
||||
ElementStack elementStack,
|
||||
CommentBindingCallback cb
|
||||
)
|
||||
|
@ -319,8 +319,8 @@ namespace Semmle.Extraction.CSharp
|
|||
|
||||
var elementStack = new ElementStack();
|
||||
|
||||
using IEnumerator<KeyValuePair<Location, Label>> elementEnumerator = elements.GetEnumerator();
|
||||
using IEnumerator<KeyValuePair<Location, CommentLine>> commentEnumerator = comments.GetEnumerator();
|
||||
using IEnumerator<KeyValuePair<Microsoft.CodeAnalysis.Location, Label>> elementEnumerator = elements.GetEnumerator();
|
||||
using IEnumerator<KeyValuePair<Microsoft.CodeAnalysis.Location, CommentLine>> commentEnumerator = comments.GetEnumerator();
|
||||
if (!commentEnumerator.MoveNext())
|
||||
{
|
||||
// There are no comments to process.
|
||||
|
|
|
@ -3,10 +3,8 @@ using Microsoft.CodeAnalysis;
|
|||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
internal class Assembly : Extraction.Entities.Location
|
||||
internal class Assembly : Location
|
||||
{
|
||||
public override Context Context => (Context)base.Context;
|
||||
|
||||
private readonly string assemblyPath;
|
||||
private readonly IAssemblySymbol assembly;
|
||||
private readonly bool isOutputAssembly;
|
||||
|
@ -56,7 +54,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
return false;
|
||||
}
|
||||
|
||||
public static Extraction.Entities.Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => AssemblyConstructorFactory.Instance.CreateEntity(cx, loc, loc);
|
||||
public static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => AssemblyConstructorFactory.Instance.CreateEntity(cx, loc, loc);
|
||||
|
||||
private class AssemblyConstructorFactory : CachedEntityFactory<Microsoft.CodeAnalysis.Location?, Assembly>
|
||||
{
|
||||
|
|
|
@ -151,9 +151,9 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
|
||||
public override Microsoft.CodeAnalysis.Location? ReportingLocation => attributeSyntax?.Name.GetLocation();
|
||||
|
||||
private Semmle.Extraction.Entities.Location? location;
|
||||
private Location? location;
|
||||
|
||||
private Semmle.Extraction.Entities.Location Location =>
|
||||
private Location Location =>
|
||||
location ??= Context.CreateLocation(attributeSyntax is null
|
||||
? entity.ReportingLocation
|
||||
: attributeSyntax.Name.GetLocation());
|
||||
|
|
|
@ -2,7 +2,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A cached entity.
|
|
@ -1,9 +1,9 @@
|
|||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// A factory for creating cached entities.
|
||||
/// </summary>
|
||||
public abstract class CachedEntityFactory<TInit, TEntity> where TEntity : CachedEntity
|
||||
public abstract class CachedEntityFactory<TInit, TEntity> where TEntity : Entities.CachedEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the entity, but does not generate any trap code.
|
|
@ -1,6 +1,6 @@
|
|||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
public static class CachedEntityFactoryExtensions
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ namespace Semmle.Extraction
|
|||
/// <param name="init">The initializer for the entity.</param>
|
||||
/// <returns>The entity.</returns>
|
||||
public static TEntity CreateEntity<TInit, TEntity>(this CachedEntityFactory<TInit, TEntity> factory, Context cx, object cacheKey, TInit init)
|
||||
where TEntity : CachedEntity => cx.CreateEntity(factory, cacheKey, init);
|
||||
where TEntity : Entities.CachedEntity => cx.CreateEntity(factory, cacheKey, init);
|
||||
|
||||
/// <summary>
|
||||
/// Creates and populates a new entity from an `ISymbol`, or returns the existing one
|
||||
|
@ -30,6 +30,6 @@ namespace Semmle.Extraction
|
|||
/// <returns>The entity.</returns>
|
||||
public static TEntity CreateEntityFromSymbol<TSymbol, TEntity>(this CachedEntityFactory<TSymbol, TEntity> factory, Context cx, TSymbol init)
|
||||
where TSymbol : ISymbol
|
||||
where TEntity : CachedEntity => cx.CreateEntityFromSymbol(factory, init);
|
||||
where TEntity : Entities.CachedEntity => cx.CreateEntityFromSymbol(factory, init);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
|
@ -89,7 +87,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
/// </summary>
|
||||
public virtual Microsoft.CodeAnalysis.Location? FullLocation => Symbol.Locations.BestOrDefault();
|
||||
|
||||
public virtual IEnumerable<Extraction.Entities.Location> Locations
|
||||
public virtual IEnumerable<Location> Locations
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -143,6 +141,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
|
||||
public override bool NeedsPopulation => Context.Defines(Symbol);
|
||||
|
||||
public Extraction.Entities.Location Location => Context.CreateLocation(ReportingLocation);
|
||||
public Location Location => Context.CreateLocation(ReportingLocation);
|
||||
}
|
||||
}
|
|
@ -2,11 +2,11 @@ using System;
|
|||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
public abstract class Entity : IEntity
|
||||
{
|
||||
public virtual Context Context { get; }
|
||||
public Context Context { get; }
|
||||
|
||||
protected Entity(Context context)
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An entity which has a default "*" ID assigned to it.
|
|
@ -1,7 +1,7 @@
|
|||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Any program entity which has a corresponding label in the trap file.
|
|
@ -1,4 +1,4 @@
|
|||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
public abstract class LabelledEntity : Entity
|
||||
{
|
|
@ -1,4 +1,4 @@
|
|||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
public abstract class UnlabelledEntity : Entity
|
||||
{
|
|
@ -1,12 +0,0 @@
|
|||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
internal abstract class CachedEntity<T> : Extraction.CachedEntity<T> where T : notnull
|
||||
{
|
||||
public override Context Context => (Context)base.Context;
|
||||
|
||||
protected CachedEntity(Context context, T symbol)
|
||||
: base(context, symbol)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using System.IO;
|
||||
using Semmle.Extraction.Entities;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
|
|
|
@ -3,7 +3,6 @@ using System.Collections.Concurrent;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Semmle.Extraction.Entities;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
|
|
|
@ -116,7 +116,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
}
|
||||
}
|
||||
|
||||
private void ExtractSourceInitializer(TextWriter trapFile, ITypeSymbol? type, IMethodSymbol? symbol, ArgumentListSyntax arguments, Location location)
|
||||
private void ExtractSourceInitializer(TextWriter trapFile, ITypeSymbol? type, IMethodSymbol? symbol, ArgumentListSyntax arguments, Microsoft.CodeAnalysis.Location location)
|
||||
{
|
||||
var initInfo = new ExpressionInfo(Context,
|
||||
AnnotatedTypeSymbol.CreateNotAnnotated(type),
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
{
|
||||
private readonly IExpressionInfo info;
|
||||
public AnnotatedTypeSymbol? Type { get; private set; }
|
||||
public Extraction.Entities.Location Location { get; }
|
||||
public Location Location { get; }
|
||||
public ExprKind Kind { get; }
|
||||
|
||||
internal Expression(IExpressionInfo info, bool shouldPopulate = true)
|
||||
|
@ -62,7 +62,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
type.PopulateGenerics();
|
||||
}
|
||||
|
||||
public override Location? ReportingLocation => Location.Symbol;
|
||||
public override Microsoft.CodeAnalysis.Location? ReportingLocation => Location.Symbol;
|
||||
|
||||
internal void SetType(ITypeSymbol? type)
|
||||
{
|
||||
|
@ -138,7 +138,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
/// Creates a generated expression from a typed constant.
|
||||
/// </summary>
|
||||
public static Expression? CreateGenerated(Context cx, TypedConstant constant, IExpressionParentEntity parent,
|
||||
int childIndex, Extraction.Entities.Location location)
|
||||
int childIndex, Location location)
|
||||
{
|
||||
if (constant.IsNull ||
|
||||
constant.Type is null)
|
||||
|
@ -176,7 +176,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
/// Creates a generated expression for a default argument value.
|
||||
/// </summary>
|
||||
public static Expression? CreateGenerated(Context cx, IParameterSymbol parameter, IExpressionParentEntity parent,
|
||||
int childIndex, Extraction.Entities.Location location)
|
||||
int childIndex, Location location)
|
||||
{
|
||||
if (!parameter.HasExplicitDefaultValue ||
|
||||
parameter.Type is IErrorTypeSymbol)
|
||||
|
@ -315,7 +315,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
|
||||
/// <summary>
|
||||
/// Given `b` in `a?.b.c`, return `(a?.b, a?.b)`.
|
||||
///
|
||||
///
|
||||
/// Given `c` in `a?.b?.c.d`, return `(b?.c, a?.b?.c)`.
|
||||
/// </summary>
|
||||
/// <param name="node">A MemberBindingExpression.</param>
|
||||
|
|
|
@ -10,14 +10,14 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
{
|
||||
public Context Context { get; }
|
||||
public AnnotatedTypeSymbol? Type { get; }
|
||||
public Extraction.Entities.Location Location { get; }
|
||||
public Location Location { get; }
|
||||
public ExprKind Kind { get; }
|
||||
public IExpressionParentEntity Parent { get; }
|
||||
public int Child { get; }
|
||||
public bool IsCompilerGenerated { get; }
|
||||
public string? ExprValue { get; }
|
||||
|
||||
public ExpressionInfo(Context cx, AnnotatedTypeSymbol? type, Extraction.Entities.Location location, ExprKind kind,
|
||||
public ExpressionInfo(Context cx, AnnotatedTypeSymbol? type, Location location, ExprKind kind,
|
||||
IExpressionParentEntity parent, int child, bool isCompilerGenerated, string? value)
|
||||
{
|
||||
Context = cx;
|
||||
|
|
|
@ -115,9 +115,9 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
}
|
||||
}
|
||||
|
||||
private Extraction.Entities.Location? cachedLocation;
|
||||
private Location? cachedLocation;
|
||||
|
||||
public Extraction.Entities.Location Location
|
||||
public Location Location
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
|||
|
||||
public static Expression Create(ExpressionNodeInfo info) => new NormalArrayCreation(info).TryPopulate();
|
||||
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, IEnumerable<TypedConstant> items, Semmle.Extraction.Entities.Location location)
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, IEnumerable<TypedConstant> items, Location location)
|
||||
{
|
||||
var info = new ExpressionInfo(
|
||||
cx,
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
|||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => Syntax.GetLocation();
|
||||
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, object? value, Action<Expression, int> createChild, Extraction.Entities.Location location)
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, object? value, Action<Expression, int> createChild, Location location)
|
||||
{
|
||||
var info = new ExpressionInfo(
|
||||
cx,
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
|||
TypeAccess.Create(Context, Syntax.Type, this, 0);
|
||||
}
|
||||
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Extraction.Entities.Location location, string? value)
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Location location, string? value)
|
||||
{
|
||||
var info = new ExpressionInfo(
|
||||
cx,
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
|||
/// Creates a new generated expression with an implicit conversion added.
|
||||
/// </summary>
|
||||
public static Expression CreateGeneratedConversion(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object value,
|
||||
Extraction.Entities.Location location)
|
||||
Location location)
|
||||
{
|
||||
ExpressionInfo create(ExprKind kind, string? v) =>
|
||||
new ExpressionInfo(
|
||||
|
@ -85,7 +85,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
|||
/// Creates a new generated cast expression.
|
||||
/// </summary>
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object value,
|
||||
Extraction.Entities.Location location)
|
||||
Location location)
|
||||
{
|
||||
var info = new ExpressionInfo(cx,
|
||||
AnnotatedTypeSymbol.CreateNotAnnotated(type),
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
|||
}
|
||||
}
|
||||
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int index, Extraction.Entities.Location location)
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int index, Location location)
|
||||
{
|
||||
var info = new ExpressionInfo(
|
||||
cx,
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
|||
return GetExprKind(type, info.Node, info.Location, info.Context);
|
||||
}
|
||||
|
||||
private static ExprKind GetExprKind(ITypeSymbol? type, ExpressionSyntax? expr, Extraction.Entities.Location loc, Context context)
|
||||
private static ExprKind GetExprKind(ITypeSymbol? type, ExpressionSyntax? expr, Location loc, Context context)
|
||||
{
|
||||
switch (type?.SpecialType)
|
||||
{
|
||||
|
@ -87,7 +87,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
|||
}
|
||||
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object? value,
|
||||
Extraction.Entities.Location location)
|
||||
Location location)
|
||||
{
|
||||
var kind = value is null ? ExprKind.NULL_LITERAL : GetExprKind(type, null, location, cx);
|
||||
var info = new ExpressionInfo(
|
||||
|
@ -103,7 +103,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
|||
return new Expression(info);
|
||||
}
|
||||
|
||||
public static Expression CreateGeneratedNullLiteral(Context cx, IExpressionParentEntity parent, int childIndex, Extraction.Entities.Location location)
|
||||
public static Expression CreateGeneratedNullLiteral(Context cx, IExpressionParentEntity parent, int childIndex, Location location)
|
||||
{
|
||||
var info = new ExpressionInfo(
|
||||
cx,
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
|||
// The `type` symbol must be a System.DateTime type and the value must be a System.DateTime object.
|
||||
// The expression that is being created is a call to the System.DateTime(long) constructor, where
|
||||
// the number of ticks from the `value` object is used as the argument to the constructor call.
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object? value, Extraction.Entities.Location location)
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object? value, Location location)
|
||||
{
|
||||
var constructorSymbol = GetDateTimeConstructor(type) ?? throw new InternalError("Could not find symbol for System.DateTime(long)");
|
||||
var expr = new DateTimeObjectCreation(constructorSymbol, new ExpressionInfo(
|
||||
|
@ -68,4 +68,4 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
|||
return expr.TryPopulate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
|||
{
|
||||
private This(IExpressionInfo info) : base(info) { }
|
||||
|
||||
public static This CreateImplicit(Context cx, ITypeSymbol @class, Extraction.Entities.Location loc, IExpressionParentEntity parent, int child) =>
|
||||
public static This CreateImplicit(Context cx, ITypeSymbol @class, Location loc, IExpressionParentEntity parent, int child) =>
|
||||
new This(new ExpressionInfo(cx, AnnotatedTypeSymbol.CreateNotAnnotated(@class), loc, Kinds.ExprKind.THIS_ACCESS, parent, child, isCompilerGenerated: true, null));
|
||||
|
||||
public static This CreateExplicit(ExpressionNodeInfo info) => new This(info.SetKind(ExprKind.THIS_ACCESS));
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
|||
|
||||
public static Expression Create(ExpressionNodeInfo info) => new TypeAccess(info).TryPopulate();
|
||||
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, Extraction.Entities.Location location)
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, Location location)
|
||||
{
|
||||
var typeAccessInfo = new ExpressionInfo(
|
||||
cx,
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
|||
TypeAccess.Create(Context, Syntax.Type, this, TypeAccessIndex);
|
||||
}
|
||||
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, Extraction.Entities.Location location)
|
||||
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, Location location)
|
||||
{
|
||||
var info = new ExpressionInfo(
|
||||
cx,
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
|||
{
|
||||
private VariableDeclaration(IExpressionInfo info) : base(info) { }
|
||||
|
||||
public static VariableDeclaration Create(Context cx, ISymbol symbol, AnnotatedTypeSymbol? type, TypeSyntax? optionalSyntax, Extraction.Entities.Location exprLocation, bool isVar, IExpressionParentEntity parent, int child)
|
||||
public static VariableDeclaration Create(Context cx, ISymbol symbol, AnnotatedTypeSymbol? type, TypeSyntax? optionalSyntax, Location exprLocation, bool isVar, IExpressionParentEntity parent, int child)
|
||||
{
|
||||
var ret = new VariableDeclaration(new ExpressionInfo(cx, type, exprLocation, ExprKind.LOCAL_VAR_DECL, parent, child, isCompilerGenerated: false, null));
|
||||
cx.Try(null, null, () =>
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.IO;
|
|||
using System.Threading;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Extraction.Entities
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
internal class ExtractionMessage : FreshEntity
|
||||
{
|
||||
|
@ -40,7 +40,7 @@ namespace Semmle.Extraction.Entities
|
|||
if (val == limit + 1)
|
||||
{
|
||||
Context.ExtractionContext.Logger.LogWarning($"Stopped logging extractor messages after reaching {limit}");
|
||||
_ = new ExtractionMessage(Context, new Message($"Stopped logging extractor messages after reaching {limit}", null, null, null, Util.Logging.Severity.Warning), bypassLimit: true);
|
||||
_ = new ExtractionMessage(Context, new Message($"Stopped logging extractor messages after reaching {limit}", null, null, null, Semmle.Util.Logging.Severity.Warning), bypassLimit: true);
|
||||
}
|
||||
return;
|
||||
}
|
|
@ -4,7 +4,6 @@ using System.Linq;
|
|||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.CSharp.Entities.Expressions;
|
||||
using Semmle.Extraction.Entities;
|
||||
using Semmle.Extraction.Kinds;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
|
@ -105,7 +104,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
}
|
||||
}
|
||||
|
||||
private Expression AddInitializerAssignment(TextWriter trapFile, ExpressionSyntax initializer, Extraction.Entities.Location loc,
|
||||
private Expression AddInitializerAssignment(TextWriter trapFile, ExpressionSyntax initializer, Location loc,
|
||||
string? constValue, ref int child)
|
||||
{
|
||||
var type = Symbol.GetAnnotatedType();
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
internal abstract class FreshEntity : Extraction.FreshEntity
|
||||
{
|
||||
public override Context Context => (Context)base.Context;
|
||||
|
||||
protected FreshEntity(Context cx)
|
||||
: base(cx)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
/// <summary>
|
||||
/// The location of the expression.
|
||||
/// </summary>
|
||||
Extraction.Entities.Location Location { get; }
|
||||
Location Location { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The kind of the expression.
|
||||
|
|
|
@ -6,21 +6,36 @@ using Semmle.Util;
|
|||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
internal class File : Extraction.Entities.File
|
||||
public class File : CachedEntity<string>
|
||||
{
|
||||
public override Context Context => (Context)base.Context;
|
||||
protected readonly string originalPath;
|
||||
private readonly Lazy<PathTransformer.ITransformedPath> transformedPathLazy;
|
||||
protected PathTransformer.ITransformedPath TransformedPath => transformedPathLazy.Value;
|
||||
public override Microsoft.CodeAnalysis.Location? ReportingLocation => null;
|
||||
|
||||
public override bool NeedsPopulation => true;
|
||||
|
||||
protected File(Context cx, string path)
|
||||
: base(cx, path)
|
||||
{
|
||||
originalPath = path;
|
||||
var adjustedPath = BinaryLogExtractionContext.GetAdjustedPath(Context.ExtractionContext, originalPath) ?? path;
|
||||
transformedPathLazy = new Lazy<PathTransformer.ITransformedPath>(() => Context.ExtractionContext.PathTransformer.Transform(adjustedPath));
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(TransformedPath.DatabaseId);
|
||||
trapFile.Write(";sourcefile");
|
||||
}
|
||||
|
||||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
{
|
||||
trapFile.files(this, TransformedPath.Value);
|
||||
|
||||
if (TransformedPath.ParentDirectory is PathTransformer.ITransformedPath dir)
|
||||
trapFile.containerparent(Extraction.Entities.Folder.Create(Context, dir), this);
|
||||
trapFile.containerparent(Folder.Create(Context, dir), this);
|
||||
|
||||
var trees = Context.Compilation.SyntaxTrees.Where(t => t.FilePath == originalPath);
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.Entities
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
public sealed class Folder : CachedEntity<PathTransformer.ITransformedPath>
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.Entities
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
internal class GeneratedFile : File
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.Entities
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
public class GeneratedLocation : SourceLocation
|
||||
{
|
|
@ -1,4 +1,4 @@
|
|||
namespace Semmle.Extraction.Entities
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
#nullable disable warnings
|
||||
public abstract class Location : CachedEntity<Microsoft.CodeAnalysis.Location?>
|
|
@ -1,22 +1,18 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
internal class NonGeneratedSourceLocation : Extraction.Entities.SourceLocation
|
||||
internal class NonGeneratedSourceLocation : SourceLocation
|
||||
{
|
||||
public override Context Context => (Context)base.Context;
|
||||
|
||||
protected NonGeneratedSourceLocation(Context cx, Location init)
|
||||
protected NonGeneratedSourceLocation(Context cx, Microsoft.CodeAnalysis.Location init)
|
||||
: base(cx, init)
|
||||
{
|
||||
Position = init.GetLineSpan();
|
||||
FileEntity = File.Create(Context, Position.Path);
|
||||
}
|
||||
|
||||
public static NonGeneratedSourceLocation Create(Context cx, Location loc) => SourceLocationFactory.Instance.CreateEntity(cx, loc, loc);
|
||||
public static NonGeneratedSourceLocation Create(Context cx, Microsoft.CodeAnalysis.Location loc) => SourceLocationFactory.Instance.CreateEntity(cx, loc, loc);
|
||||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
{
|
||||
|
@ -28,7 +24,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
if (mapped.HasMappedPath && mapped.IsValid)
|
||||
{
|
||||
var path = Context.TryAdjustRelativeMappedFilePath(mapped.Path, Position.Path);
|
||||
var mappedLoc = Create(Context, Location.Create(path, default, mapped.Span));
|
||||
var mappedLoc = Create(Context, Microsoft.CodeAnalysis.Location.Create(path, default, mapped.Span));
|
||||
|
||||
trapFile.locations_mapped(this, mappedLoc);
|
||||
}
|
||||
|
@ -58,11 +54,11 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
trapFile.Write(Position.Span.End.Character);
|
||||
}
|
||||
|
||||
private class SourceLocationFactory : CachedEntityFactory<Location, NonGeneratedSourceLocation>
|
||||
private class SourceLocationFactory : CachedEntityFactory<Microsoft.CodeAnalysis.Location, NonGeneratedSourceLocation>
|
||||
{
|
||||
public static SourceLocationFactory Instance { get; } = new SourceLocationFactory();
|
||||
|
||||
public override NonGeneratedSourceLocation Create(Context cx, Location init) => new NonGeneratedSourceLocation(cx, init);
|
||||
public override NonGeneratedSourceLocation Create(Context cx, Microsoft.CodeAnalysis.Location init) => new NonGeneratedSourceLocation(cx, init);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
namespace Semmle.Extraction.Entities
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
public abstract class SourceLocation : Location
|
||||
{
|
|
@ -290,7 +290,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
|
||||
public Method OriginalDefinition => Create(Context, Symbol.OriginalDefinition);
|
||||
|
||||
public override Location? FullLocation => ReportingLocation;
|
||||
public override Microsoft.CodeAnalysis.Location? FullLocation => ReportingLocation;
|
||||
|
||||
public override bool IsSourceDeclaration => Symbol.IsSourceDeclaration();
|
||||
|
||||
|
|
|
@ -3,12 +3,12 @@ using Microsoft.CodeAnalysis;
|
|||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
internal class Modifier : Extraction.CachedEntity<string>
|
||||
internal class Modifier : CachedEntity<string>
|
||||
{
|
||||
private Modifier(Context cx, string init)
|
||||
: base(cx, init) { }
|
||||
|
||||
public override Location? ReportingLocation => null;
|
||||
public override Microsoft.CodeAnalysis.Location? ReportingLocation => null;
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
private Namespace(Context cx, INamespaceSymbol init)
|
||||
: base(cx, init) { }
|
||||
|
||||
public override Location? ReportingLocation => null;
|
||||
public override Microsoft.CodeAnalysis.Location? ReportingLocation => null;
|
||||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
{
|
||||
|
|
|
@ -4,7 +4,6 @@ using System.Linq;
|
|||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.CSharp.Populators;
|
||||
using Semmle.Extraction.Entities;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System.IO;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Semmle.Extraction.CSharp.Populators;
|
||||
using Semmle.Extraction.Entities;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System.IO;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.Entities;
|
||||
using Semmle.Extraction.Kinds;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities.Statements
|
||||
|
|
|
@ -101,7 +101,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
|
||||
public override IEnumerable<Type> TypeMentions => TypeArguments;
|
||||
|
||||
public override IEnumerable<Extraction.Entities.Location> Locations
|
||||
public override IEnumerable<Location> Locations
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
|
@ -102,7 +102,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
{
|
||||
}
|
||||
|
||||
public override Location ReportingLocation => throw new System.NotImplementedException();
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => throw new System.NotImplementedException();
|
||||
|
||||
public override bool NeedsPopulation => true;
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
}
|
||||
}
|
||||
|
||||
public override Location? ReportingLocation => null;
|
||||
public override Microsoft.CodeAnalysis.Location? ReportingLocation => null;
|
||||
|
||||
public static TypeParameterConstraints Create(Context cx, TypeParameter p) =>
|
||||
TypeParameterConstraintsFactory.Instance.CreateEntity(cx, (typeof(TypeParameterConstraints), p), p);
|
||||
|
@ -62,4 +62,3 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// The scope of symbols in an assembly.
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
|||
using Microsoft.CodeAnalysis;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
public class BinaryLogExtractionContext : ExtractionContext
|
||||
{
|
|
@ -2,7 +2,7 @@ using System;
|
|||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the parsed state of the command line arguments.
|
|
@ -2,8 +2,9 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Semmle.Extraction.Entities;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
|
@ -11,8 +12,453 @@ namespace Semmle.Extraction.CSharp
|
|||
/// State that needs to be available throughout the extraction process.
|
||||
/// There is one Context object per trap output file.
|
||||
/// </summary>
|
||||
internal class Context : Extraction.Context
|
||||
public class Context
|
||||
{
|
||||
/// <summary>
|
||||
/// Access various extraction functions, e.g. logger, trap writer.
|
||||
/// </summary>
|
||||
public ExtractionContext ExtractionContext { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Access to the trap file.
|
||||
/// </summary>
|
||||
public TrapWriter TrapWriter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds if assembly information should be prefixed to TRAP labels.
|
||||
/// </summary>
|
||||
public bool ShouldAddAssemblyTrapPrefix { get; }
|
||||
|
||||
public IList<object> TrapStackSuffix { get; } = new List<object>();
|
||||
|
||||
private int GetNewId() => TrapWriter.IdCounter++;
|
||||
|
||||
// A recursion guard against writing to the trap file whilst writing an id to the trap file.
|
||||
private bool writingLabel = false;
|
||||
|
||||
private readonly Queue<IEntity> labelQueue = [];
|
||||
|
||||
protected void DefineLabel(IEntity entity)
|
||||
{
|
||||
if (writingLabel)
|
||||
{
|
||||
// Don't define a label whilst writing a label.
|
||||
labelQueue.Enqueue(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
writingLabel = true;
|
||||
entity.DefineLabel(TrapWriter.Writer);
|
||||
}
|
||||
finally
|
||||
{
|
||||
writingLabel = false;
|
||||
if (labelQueue.Any())
|
||||
{
|
||||
DefineLabel(labelQueue.Dequeue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG_LABELS
|
||||
private void CheckEntityHasUniqueLabel(string id, CachedEntity entity)
|
||||
{
|
||||
if (idLabelCache.ContainsKey(id))
|
||||
{
|
||||
this.Extractor.Message(new Message("Label collision for " + id, entity.Label.ToString(), CreateLocation(entity.ReportingLocation), "", Severity.Warning));
|
||||
}
|
||||
else
|
||||
{
|
||||
idLabelCache[id] = entity;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
protected Label GetNewLabel() => new Label(GetNewId());
|
||||
|
||||
internal TEntity CreateEntity<TInit, TEntity>(CachedEntityFactory<TInit, TEntity> factory, object cacheKey, TInit init)
|
||||
where TEntity : Entities.CachedEntity =>
|
||||
cacheKey is ISymbol s ? CreateEntity(factory, s, init, symbolEntityCache) : CreateEntity(factory, cacheKey, init, objectEntityCache);
|
||||
|
||||
internal TEntity CreateEntityFromSymbol<TSymbol, TEntity>(CachedEntityFactory<TSymbol, TEntity> factory, TSymbol init)
|
||||
where TSymbol : ISymbol
|
||||
where TEntity : Entities.CachedEntity => CreateEntity(factory, init, init, symbolEntityCache);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates and populates a new entity, or returns the existing one from the cache.
|
||||
/// </summary>
|
||||
/// <param name="factory">The entity factory.</param>
|
||||
/// <param name="cacheKey">The key used for caching.</param>
|
||||
/// <param name="init">The initializer for the entity.</param>
|
||||
/// <param name="dictionary">The dictionary to use for caching.</param>
|
||||
/// <returns>The new/existing entity.</returns>
|
||||
private TEntity CreateEntity<TInit, TCacheKey, TEntity>(CachedEntityFactory<TInit, TEntity> factory, TCacheKey cacheKey, TInit init, IDictionary<TCacheKey, Entities.CachedEntity> dictionary)
|
||||
where TCacheKey : notnull
|
||||
where TEntity : Entities.CachedEntity
|
||||
{
|
||||
if (dictionary.TryGetValue(cacheKey, out var cached))
|
||||
return (TEntity)cached;
|
||||
|
||||
using (StackGuard)
|
||||
{
|
||||
var label = GetNewLabel();
|
||||
var entity = factory.Create(this, init);
|
||||
entity.Label = label;
|
||||
|
||||
dictionary[cacheKey] = entity;
|
||||
|
||||
DefineLabel(entity);
|
||||
if (entity.NeedsPopulation)
|
||||
Populate(init as ISymbol, entity);
|
||||
|
||||
#if DEBUG_LABELS
|
||||
using var id = new EscapingTextWriter();
|
||||
entity.WriteQuotedId(id);
|
||||
CheckEntityHasUniqueLabel(id.ToString(), entity);
|
||||
#endif
|
||||
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a fresh label with ID "*", and set it on the
|
||||
/// supplied <paramref name="entity"/> object.
|
||||
/// </summary>
|
||||
internal void AddFreshLabel(Entity entity)
|
||||
{
|
||||
entity.Label = GetNewLabel();
|
||||
entity.DefineFreshLabel(TrapWriter.Writer);
|
||||
}
|
||||
|
||||
#if DEBUG_LABELS
|
||||
private readonly Dictionary<string, CachedEntity> idLabelCache = new Dictionary<string, CachedEntity>();
|
||||
#endif
|
||||
|
||||
private readonly IDictionary<object, Entities.CachedEntity> objectEntityCache = new Dictionary<object, Entities.CachedEntity>();
|
||||
private readonly IDictionary<ISymbol, Entities.CachedEntity> symbolEntityCache = new Dictionary<ISymbol, Entities.CachedEntity>(10000, SymbolEqualityComparer.Default);
|
||||
|
||||
/// <summary>
|
||||
/// Queue of items to populate later.
|
||||
/// The only reason for this is so that the call stack does not
|
||||
/// grow indefinitely, causing a potential stack overflow.
|
||||
/// </summary>
|
||||
private readonly Queue<Action> populateQueue = new Queue<Action>();
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue the given action to be performed later.
|
||||
/// </summary>
|
||||
/// <param name="toRun">The action to run.</param>
|
||||
public void PopulateLater(Action a, bool preserveDuplicationKey = true)
|
||||
{
|
||||
var key = preserveDuplicationKey ? GetCurrentTagStackKey() : null;
|
||||
if (key is not null)
|
||||
{
|
||||
// If we are currently executing with a duplication guard, then the same
|
||||
// guard must be used for the deferred action
|
||||
populateQueue.Enqueue(() => WithDuplicationGuard(key, a));
|
||||
}
|
||||
else
|
||||
{
|
||||
populateQueue.Enqueue(a);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the main populate loop until there's nothing left to populate.
|
||||
/// </summary>
|
||||
public void PopulateAll()
|
||||
{
|
||||
while (populateQueue.Any())
|
||||
{
|
||||
try
|
||||
{
|
||||
populateQueue.Dequeue()();
|
||||
}
|
||||
catch (InternalError ex)
|
||||
{
|
||||
ExtractionError(new Message(ex.Text, ex.EntityText, CreateLocation(ex.Location), ex.StackTrace));
|
||||
}
|
||||
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
ExtractionError($"Uncaught exception. {ex.Message}", null, CreateLocation(), ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int currentRecursiveDepth = 0;
|
||||
private const int maxRecursiveDepth = 150;
|
||||
|
||||
private void EnterScope()
|
||||
{
|
||||
if (currentRecursiveDepth >= maxRecursiveDepth)
|
||||
throw new StackOverflowException($"Maximum nesting depth of {maxRecursiveDepth} exceeded");
|
||||
++currentRecursiveDepth;
|
||||
}
|
||||
|
||||
private void ExitScope()
|
||||
{
|
||||
--currentRecursiveDepth;
|
||||
}
|
||||
|
||||
public IDisposable StackGuard => new ScopeGuard(this);
|
||||
|
||||
private sealed class ScopeGuard : IDisposable
|
||||
{
|
||||
private readonly Context cx;
|
||||
|
||||
public ScopeGuard(Context c)
|
||||
{
|
||||
cx = c;
|
||||
cx.EnterScope();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
cx.ExitScope();
|
||||
}
|
||||
}
|
||||
|
||||
private class PushEmitter : ITrapEmitter
|
||||
{
|
||||
private readonly Key key;
|
||||
|
||||
public PushEmitter(Key key)
|
||||
{
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public void EmitTrap(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(".push ");
|
||||
key.AppendTo(trapFile);
|
||||
trapFile.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
private class PopEmitter : ITrapEmitter
|
||||
{
|
||||
public void EmitTrap(TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteLine(".pop");
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Stack<Key> tagStack = new Stack<Key>();
|
||||
|
||||
/// <summary>
|
||||
/// Populates an entity, handling the tag stack appropriately
|
||||
/// </summary>
|
||||
/// <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>
|
||||
private void Populate(ISymbol? optionalSymbol, Entities.CachedEntity entity)
|
||||
{
|
||||
if (writingLabel)
|
||||
{
|
||||
// Don't write tuples etc if we're currently defining a label
|
||||
PopulateLater(() => Populate(optionalSymbol, entity));
|
||||
return;
|
||||
}
|
||||
|
||||
bool duplicationGuard, deferred;
|
||||
|
||||
if (ExtractionContext.Mode is ExtractorMode.Standalone)
|
||||
{
|
||||
duplicationGuard = false;
|
||||
deferred = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (entity.TrapStackBehaviour)
|
||||
{
|
||||
case TrapStackBehaviour.NeedsLabel:
|
||||
if (!tagStack.Any())
|
||||
ExtractionError("TagStack unexpectedly empty", optionalSymbol, entity);
|
||||
duplicationGuard = false;
|
||||
deferred = false;
|
||||
break;
|
||||
case TrapStackBehaviour.NoLabel:
|
||||
duplicationGuard = false;
|
||||
deferred = tagStack.Any();
|
||||
break;
|
||||
case TrapStackBehaviour.OptionalLabel:
|
||||
duplicationGuard = false;
|
||||
deferred = false;
|
||||
break;
|
||||
case TrapStackBehaviour.PushesLabel:
|
||||
duplicationGuard = true;
|
||||
deferred = tagStack.Any();
|
||||
break;
|
||||
default:
|
||||
throw new InternalError("Unexpected TrapStackBehaviour");
|
||||
}
|
||||
}
|
||||
|
||||
var a = duplicationGuard && IsEntityDuplicationGuarded(entity, out var loc)
|
||||
? (() =>
|
||||
{
|
||||
var args = new object[TrapStackSuffix.Count + 2];
|
||||
args[0] = entity;
|
||||
args[1] = loc;
|
||||
for (var i = 0; i < TrapStackSuffix.Count; i++)
|
||||
{
|
||||
args[i + 2] = TrapStackSuffix[i];
|
||||
}
|
||||
WithDuplicationGuard(new Key(args), () => entity.Populate(TrapWriter.Writer));
|
||||
})
|
||||
: (Action)(() => this.Try(null, optionalSymbol, () => entity.Populate(TrapWriter.Writer)));
|
||||
|
||||
if (deferred)
|
||||
populateQueue.Enqueue(a);
|
||||
else
|
||||
a();
|
||||
}
|
||||
|
||||
protected Key? GetCurrentTagStackKey() => tagStack.Count > 0
|
||||
? tagStack.Peek()
|
||||
: null;
|
||||
|
||||
/// <summary>
|
||||
/// Log an extraction error.
|
||||
/// </summary>
|
||||
/// <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 null.</param>
|
||||
/// <param name="severity">The severity of the error.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log an extraction error.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
private void ExtractionError(string message, ISymbol? optionalSymbol, Entity optionalEntity)
|
||||
{
|
||||
if (!(optionalSymbol is null))
|
||||
{
|
||||
ExtractionError(message, optionalSymbol.ToDisplayString(), CreateLocation(optionalSymbol.Locations.BestOrDefault()));
|
||||
}
|
||||
else if (!(optionalEntity is null))
|
||||
{
|
||||
ExtractionError(message, optionalEntity.Label.ToString(), CreateLocation(optionalEntity.ReportingLocation));
|
||||
}
|
||||
else
|
||||
{
|
||||
ExtractionError(message, null, CreateLocation());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log an extraction message.
|
||||
/// </summary>
|
||||
/// <param name="msg">The message to log.</param>
|
||||
private void ExtractionError(Message msg)
|
||||
{
|
||||
_ = new Entities.ExtractionMessage(this, msg);
|
||||
ExtractionContext.Message(msg);
|
||||
}
|
||||
|
||||
private void ExtractionError(InternalError error)
|
||||
{
|
||||
ExtractionError(new Message(error.Message, error.EntityText, CreateLocation(error.Location), error.StackTrace, Severity.Error));
|
||||
}
|
||||
|
||||
private void ReportError(InternalError error)
|
||||
{
|
||||
if (!ExtractionContext.Mode.HasFlag(ExtractorMode.Standalone))
|
||||
throw error;
|
||||
|
||||
ExtractionError(error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signal an error in the program model.
|
||||
/// </summary>
|
||||
/// <param name="node">The syntax node causing the failure.</param>
|
||||
/// <param name="msg">The error message.</param>
|
||||
public void ModelError(SyntaxNode node, string msg)
|
||||
{
|
||||
ReportError(new InternalError(node, msg));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signal an error in the program model.
|
||||
/// </summary>
|
||||
/// <param name="symbol">Symbol causing the error.</param>
|
||||
/// <param name="msg">The error message.</param>
|
||||
public void ModelError(ISymbol symbol, string msg)
|
||||
{
|
||||
ReportError(new InternalError(symbol, msg));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signal an error in the program model.
|
||||
/// </summary>
|
||||
/// <param name="loc">The location of the error.</param>
|
||||
/// <param name="msg">The error message.</param>
|
||||
public void ModelError(CSharp.Entities.Location loc, string msg)
|
||||
{
|
||||
ReportError(new InternalError(loc.ReportingLocation, msg));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signal an error in the program model.
|
||||
/// </summary>
|
||||
/// <param name="msg">The error message.</param>
|
||||
public void ModelError(string msg)
|
||||
{
|
||||
ReportError(new InternalError(msg));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries the supplied action <paramref name="a"/>, and logs an uncaught
|
||||
/// exception error if the action fails.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
public void Try(SyntaxNode? node, ISymbol? symbol, Action a)
|
||||
{
|
||||
try
|
||||
{
|
||||
a();
|
||||
}
|
||||
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
Message message;
|
||||
|
||||
if (node is not null)
|
||||
{
|
||||
message = Message.Create(this, ex.Message, node, ex.StackTrace);
|
||||
}
|
||||
else if (symbol is not null)
|
||||
{
|
||||
message = Message.Create(this, ex.Message, symbol, ex.StackTrace);
|
||||
}
|
||||
else if (ex is InternalError ie)
|
||||
{
|
||||
message = new Message(ie.Text, ie.EntityText, CreateLocation(ie.Location), ex.StackTrace);
|
||||
}
|
||||
else
|
||||
{
|
||||
message = new Message($"Uncaught exception. {ex.Message}", null, CreateLocation(), ex.StackTrace);
|
||||
}
|
||||
|
||||
ExtractionError(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The program database provided by Roslyn.
|
||||
/// There's one per syntax tree, which makes things awkward.
|
||||
|
@ -77,9 +523,11 @@ namespace Semmle.Extraction.CSharp
|
|||
|
||||
internal CommentProcessor CommentGenerator { get; } = new CommentProcessor();
|
||||
|
||||
public Context(ExtractionContext extractionContext, Compilation c, TrapWriter trapWriter, IExtractionScope scope, bool addAssemblyTrapPrefix)
|
||||
: base(extractionContext, trapWriter, addAssemblyTrapPrefix)
|
||||
public Context(ExtractionContext extractionContext, Compilation c, TrapWriter trapWriter, IExtractionScope scope, bool shouldAddAssemblyTrapPrefix = false)
|
||||
{
|
||||
ExtractionContext = extractionContext;
|
||||
TrapWriter = trapWriter;
|
||||
ShouldAddAssemblyTrapPrefix = shouldAddAssemblyTrapPrefix;
|
||||
Compilation = c;
|
||||
this.scope = scope;
|
||||
}
|
||||
|
@ -102,7 +550,11 @@ namespace Semmle.Extraction.CSharp
|
|||
!SymbolEqualityComparer.Default.Equals(symbol, symbol.OriginalDefinition) ||
|
||||
scope.InScope(symbol);
|
||||
|
||||
public override void WithDuplicationGuard(Key key, Action a)
|
||||
/// <summary>
|
||||
/// Runs the given action <paramref name="a"/>, guarding for trap duplication
|
||||
/// based on key <paramref name="key"/>.
|
||||
/// </summary>
|
||||
public void WithDuplicationGuard(Key key, Action a)
|
||||
{
|
||||
if (IsAssemblyScope)
|
||||
{
|
||||
|
@ -113,21 +565,31 @@ namespace Semmle.Extraction.CSharp
|
|||
}
|
||||
else
|
||||
{
|
||||
base.WithDuplicationGuard(key, a);
|
||||
tagStack.Push(key);
|
||||
TrapWriter.Emit(new PushEmitter(key));
|
||||
try
|
||||
{
|
||||
a();
|
||||
}
|
||||
finally
|
||||
{
|
||||
TrapWriter.Emit(new PopEmitter());
|
||||
tagStack.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override Extraction.Entities.Location CreateLocation()
|
||||
public Entities.Location CreateLocation()
|
||||
{
|
||||
return SourceTree is null
|
||||
? GeneratedLocation.Create(this)
|
||||
? Entities.GeneratedLocation.Create(this)
|
||||
: CreateLocation(Microsoft.CodeAnalysis.Location.Create(SourceTree, Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(0, 0)));
|
||||
}
|
||||
|
||||
public override Extraction.Entities.Location CreateLocation(Microsoft.CodeAnalysis.Location? location)
|
||||
public Entities.Location CreateLocation(Microsoft.CodeAnalysis.Location? location)
|
||||
{
|
||||
return (location is null || location.Kind == LocationKind.None)
|
||||
? GeneratedLocation.Create(this)
|
||||
? Entities.GeneratedLocation.Create(this)
|
||||
: location.IsInSource
|
||||
? Entities.NonGeneratedSourceLocation.Create(this, location)
|
||||
: Entities.Assembly.Create(this, location);
|
||||
|
@ -145,7 +607,7 @@ namespace Semmle.Extraction.CSharp
|
|||
CommentGenerator.AddElement(entity.Label, duplicationGuardKey, l);
|
||||
}
|
||||
|
||||
protected override bool IsEntityDuplicationGuarded(IEntity entity, [NotNullWhen(true)] out Extraction.Entities.Location? loc)
|
||||
private bool IsEntityDuplicationGuarded(IEntity entity, [NotNullWhen(true)] out Entities.Location? loc)
|
||||
{
|
||||
if (CreateLocation(entity.ReportingLocation) is Entities.NonGeneratedSourceLocation l)
|
||||
{
|
||||
|
@ -169,7 +631,7 @@ namespace Semmle.Extraction.CSharp
|
|||
/// </summary>
|
||||
/// <param name="entity">The entity to extract.</param>
|
||||
/// <returns>True only on the first call for a particular entity.</returns>
|
||||
internal bool ExtractGenerics(CachedEntity entity)
|
||||
internal bool ExtractGenerics(CSharp.Entities.CachedEntity entity)
|
||||
{
|
||||
if (extractedGenerics.Contains(entity.Label))
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Xml;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a .csproj file and reads information from it.
|
|
@ -2,7 +2,7 @@ using System.Collections.Generic;
|
|||
using Semmle.Util.Logging;
|
||||
using CompilationInfo = (string key, string value);
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of the main extractor state.
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// The mode in which a file is extracted.
|
|
@ -6,7 +6,7 @@ using System.Text;
|
|||
using System.Text.RegularExpressions;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
public sealed class InvalidFilePatternException : Exception
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines which entities belong in the trap file
|
|
@ -1,9 +1,8 @@
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Encapsulates information for a log message.
|
|
@ -5,7 +5,7 @@ using System.IO;
|
|||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// A class for interpreting path transformers specified using the environment
|
|
@ -2,7 +2,7 @@
|
|||
using Microsoft.CodeAnalysis;
|
||||
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
|
||||
/// <summary>
|
|
@ -5,7 +5,7 @@ using System.Text;
|
|||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
public interface ITrapEmitter
|
||||
{
|
|
@ -1,8 +1,7 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception thrown whenever extraction encounters something unexpected.
|
|
@ -1,7 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp.Util\Semmle.Extraction.CSharp.Util.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Text;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// A `TextWriter` object that wraps another `TextWriter` object, and which
|
|
@ -1,52 +1,13 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// An ID. Either a fresh ID (`*`), a key, or a label (https://semmle.com/wiki/display/IN/TRAP+Files):
|
||||
///
|
||||
/// ```
|
||||
/// id ::= '*' | key | label
|
||||
/// ```
|
||||
/// </summary>
|
||||
public interface IId
|
||||
{
|
||||
/// <summary>
|
||||
/// Appends this ID to the supplied trap builder.
|
||||
/// </summary>
|
||||
void AppendTo(TextWriter trapFile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A fresh ID (`*`).
|
||||
/// </summary>
|
||||
public class FreshId : IId
|
||||
{
|
||||
private FreshId() { }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the singleton <see cref="FreshId"/> instance.
|
||||
/// </summary>
|
||||
public static IId Instance { get; } = new FreshId();
|
||||
|
||||
public override string ToString() => "*";
|
||||
|
||||
public override bool Equals(object? obj) => obj?.GetType() == GetType();
|
||||
|
||||
public override int GetHashCode() => 0;
|
||||
|
||||
public void AppendTo(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write('*');
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A key. Either a simple key, e.g. `@"bool A.M();method"`, or a compound key, e.g.
|
||||
/// `@"{0} {1}.M();method"` where `0` and `1` are both labels.
|
||||
/// </summary>
|
||||
public class Key : IId
|
||||
public class Key
|
||||
{
|
||||
private readonly StringWriter trapBuilder = new StringWriter();
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
public static class TrapExtensions
|
||||
{
|
|
@ -1,4 +1,4 @@
|
|||
namespace Semmle.Extraction
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// How an entity behaves with respect to .push and .pop
|
|
@ -3,7 +3,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|||
using Semmle.Util;
|
||||
using Semmle.Extraction.CSharp.Entities;
|
||||
using Semmle.Extraction.CSharp.Entities.Expressions;
|
||||
using Semmle.Extraction.Entities;
|
||||
using Semmle.Extraction.Kinds;
|
||||
|
||||
namespace Semmle.Extraction.CSharp
|
||||
|
@ -17,7 +16,22 @@ namespace Semmle.Extraction.CSharp
|
|||
/// </remarks>
|
||||
internal static class Tuples
|
||||
{
|
||||
internal static void assemblies(this System.IO.TextWriter trapFile, Assembly assembly, Extraction.Entities.File file, string identifier, string name, string version) =>
|
||||
public static void containerparent(this TextWriter trapFile, Folder parent, IEntity child) =>
|
||||
trapFile.WriteTuple("containerparent", parent, child);
|
||||
|
||||
internal static void extractor_messages(this TextWriter trapFile, ExtractionMessage error, Semmle.Util.Logging.Severity severity, string errorMessage, string entityText, Location location, string stackTrace) =>
|
||||
trapFile.WriteTuple("extractor_messages", error, (int)severity, "C# extractor", errorMessage, entityText, location, stackTrace);
|
||||
|
||||
public static void files(this TextWriter trapFile, Entities.File file, string fullName) =>
|
||||
trapFile.WriteTuple("files", file, fullName);
|
||||
|
||||
internal static void folders(this TextWriter trapFile, Folder folder, string path) =>
|
||||
trapFile.WriteTuple("folders", folder, path);
|
||||
|
||||
public static void locations_default(this TextWriter trapFile, SourceLocation label, Entities.File file, int startLine, int startCol, int endLine, int endCol) =>
|
||||
trapFile.WriteTuple("locations_default", label, file, startLine, startCol, endLine, endCol);
|
||||
|
||||
internal static void assemblies(this TextWriter trapFile, Assembly assembly, Entities.File file, string identifier, string name, string version) =>
|
||||
trapFile.WriteTuple("assemblies", assembly, file, identifier, name, version);
|
||||
|
||||
internal static void accessor_location(this TextWriter trapFile, Accessor accessorKey, Location location) =>
|
||||
|
@ -74,10 +88,10 @@ namespace Semmle.Extraction.CSharp
|
|||
internal static void compilation_info(this TextWriter trapFile, Compilation compilation, string infoKey, string infoValue) =>
|
||||
trapFile.WriteTuple("compilation_info", compilation, infoKey, infoValue);
|
||||
|
||||
internal static void compilation_compiling_files(this TextWriter trapFile, Compilation compilation, int index, Extraction.Entities.File file) =>
|
||||
internal static void compilation_compiling_files(this TextWriter trapFile, Compilation compilation, int index, Entities.File file) =>
|
||||
trapFile.WriteTuple("compilation_compiling_files", compilation, index, file);
|
||||
|
||||
internal static void compilation_referencing_files(this TextWriter trapFile, Compilation compilation, int index, Extraction.Entities.File file) =>
|
||||
internal static void compilation_referencing_files(this TextWriter trapFile, Compilation compilation, int index, Entities.File file) =>
|
||||
trapFile.WriteTuple("compilation_referencing_files", compilation, index, file);
|
||||
|
||||
internal static void compilation_finished(this TextWriter trapFile, Compilation compilation, float cpuSeconds, float elapsedSeconds) =>
|
||||
|
@ -398,7 +412,7 @@ namespace Semmle.Extraction.CSharp
|
|||
internal static void pragma_warning_error_codes(this TextWriter trapFile, PragmaWarningDirective pragma, string errorCode, int child) =>
|
||||
trapFile.WriteTuple("pragma_warning_error_codes", pragma, errorCode, child);
|
||||
|
||||
internal static void pragma_checksums(this TextWriter trapFile, PragmaChecksumDirective pragma, Extraction.Entities.File file, string guid, string bytes) =>
|
||||
internal static void pragma_checksums(this TextWriter trapFile, PragmaChecksumDirective pragma, Entities.File file, string guid, string bytes) =>
|
||||
trapFile.WriteTuple("pragma_checksums", pragma, file, guid, bytes);
|
||||
|
||||
internal static void directive_defines(this TextWriter trapFile, DefineDirective directive, string name) =>
|
||||
|
@ -422,7 +436,7 @@ namespace Semmle.Extraction.CSharp
|
|||
internal static void directive_line_value(this TextWriter trapFile, LineDirective directive, int line) =>
|
||||
trapFile.WriteTuple("directive_line_value", directive, line);
|
||||
|
||||
internal static void directive_line_file<T>(this TextWriter trapFile, LineOrSpanDirective<T> directive, Extraction.Entities.File file) where T : LineOrSpanDirectiveTriviaSyntax =>
|
||||
internal static void directive_line_file<T>(this TextWriter trapFile, LineOrSpanDirective<T> directive, Entities.File file) where T : LineOrSpanDirectiveTriviaSyntax =>
|
||||
trapFile.WriteTuple("directive_line_file", directive, file);
|
||||
|
||||
internal static void directive_line_offset(this TextWriter trapFile, LineSpanDirective directive, int offset) =>
|
|
@ -9,7 +9,6 @@ codeql_xunit_test(
|
|||
"*.cs",
|
||||
]),
|
||||
deps = [
|
||||
"//csharp/extractor/Semmle.Extraction",
|
||||
"//csharp/extractor/Semmle.Extraction.CSharp",
|
||||
"//csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching",
|
||||
"//csharp/extractor/Semmle.Extraction.CSharp.Standalone:bin/Semmle.Extraction.CSharp.Standalone",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Xunit;
|
||||
using Semmle.Extraction.CSharp;
|
||||
|
||||
namespace Semmle.Extraction.Tests
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.IO;
|
|||
using System.Text.RegularExpressions;
|
||||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
using Semmle.Extraction.CSharp;
|
||||
|
||||
namespace Semmle.Extraction.Tests
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Xunit;
|
||||
using Semmle.Util;
|
||||
using Semmle.Extraction.CSharp;
|
||||
|
||||
namespace Semmle.Extraction.Tests
|
||||
{
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
<ProjectReference Include="..\Semmle.Extraction.CSharp.StubGenerator\Semmle.Extraction.CSharp.StubGenerator.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp.Standalone\Semmle.Extraction.CSharp.Standalone.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\..\.paket\Paket.Restore.targets" />
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
load(
|
||||
"//misc/bazel:csharp.bzl",
|
||||
"codeql_csharp_library",
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "debug_build",
|
||||
values = {
|
||||
"compilation_mode": "dbg",
|
||||
},
|
||||
)
|
||||
|
||||
codeql_csharp_library(
|
||||
name = "Semmle.Extraction",
|
||||
srcs = glob([
|
||||
"Entities/**/*.cs",
|
||||
"Extractor/**/*.cs",
|
||||
"*.cs",
|
||||
]),
|
||||
# enable via -c dbg on the bazel command line/in .bazelrc.local
|
||||
defines = select({
|
||||
":debug_build": [
|
||||
"TRACE",
|
||||
"DEBUG",
|
||||
"DEBUG_LABELS",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
internals_visible_to = ["Semmle.Extraction.CSharp"],
|
||||
visibility = ["//csharp:__subpackages__"],
|
||||
deps = [
|
||||
"//csharp/extractor/Semmle.Util",
|
||||
"@paket.main//microsoft.build",
|
||||
"@paket.main//microsoft.codeanalysis",
|
||||
],
|
||||
)
|
|
@ -1,500 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Semmle.Util.Logging;
|
||||
using Semmle.Extraction.Entities;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
{
|
||||
/// <summary>
|
||||
/// State that needs to be available throughout the extraction process.
|
||||
/// There is one Context object per trap output file.
|
||||
/// </summary>
|
||||
public class Context
|
||||
{
|
||||
/// <summary>
|
||||
/// Access various extraction functions, e.g. logger, trap writer.
|
||||
/// </summary>
|
||||
public ExtractionContext ExtractionContext { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Access to the trap file.
|
||||
/// </summary>
|
||||
public TrapWriter TrapWriter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds if assembly information should be prefixed to TRAP labels.
|
||||
/// </summary>
|
||||
public bool ShouldAddAssemblyTrapPrefix { get; }
|
||||
|
||||
public IList<object> TrapStackSuffix { get; } = new List<object>();
|
||||
|
||||
private int GetNewId() => TrapWriter.IdCounter++;
|
||||
|
||||
// A recursion guard against writing to the trap file whilst writing an id to the trap file.
|
||||
private bool writingLabel = false;
|
||||
|
||||
private readonly Queue<IEntity> labelQueue = [];
|
||||
|
||||
protected void DefineLabel(IEntity entity)
|
||||
{
|
||||
if (writingLabel)
|
||||
{
|
||||
// Don't define a label whilst writing a label.
|
||||
labelQueue.Enqueue(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
writingLabel = true;
|
||||
entity.DefineLabel(TrapWriter.Writer);
|
||||
}
|
||||
finally
|
||||
{
|
||||
writingLabel = false;
|
||||
if (labelQueue.Any())
|
||||
{
|
||||
DefineLabel(labelQueue.Dequeue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG_LABELS
|
||||
private void CheckEntityHasUniqueLabel(string id, CachedEntity entity)
|
||||
{
|
||||
if (idLabelCache.ContainsKey(id))
|
||||
{
|
||||
this.Extractor.Message(new Message("Label collision for " + id, entity.Label.ToString(), CreateLocation(entity.ReportingLocation), "", Severity.Warning));
|
||||
}
|
||||
else
|
||||
{
|
||||
idLabelCache[id] = entity;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
protected Label GetNewLabel() => new Label(GetNewId());
|
||||
|
||||
internal TEntity CreateEntity<TInit, TEntity>(CachedEntityFactory<TInit, TEntity> factory, object cacheKey, TInit init)
|
||||
where TEntity : CachedEntity =>
|
||||
cacheKey is ISymbol s ? CreateEntity(factory, s, init, symbolEntityCache) : CreateEntity(factory, cacheKey, init, objectEntityCache);
|
||||
|
||||
internal TEntity CreateEntityFromSymbol<TSymbol, TEntity>(CachedEntityFactory<TSymbol, TEntity> factory, TSymbol init)
|
||||
where TSymbol : ISymbol
|
||||
where TEntity : CachedEntity => CreateEntity(factory, init, init, symbolEntityCache);
|
||||
|
||||
/// <summary>
|
||||
/// Creates and populates a new entity, or returns the existing one from the cache.
|
||||
/// </summary>
|
||||
/// <param name="factory">The entity factory.</param>
|
||||
/// <param name="cacheKey">The key used for caching.</param>
|
||||
/// <param name="init">The initializer for the entity.</param>
|
||||
/// <param name="dictionary">The dictionary to use for caching.</param>
|
||||
/// <returns>The new/existing entity.</returns>
|
||||
private TEntity CreateEntity<TInit, TCacheKey, TEntity>(CachedEntityFactory<TInit, TEntity> factory, TCacheKey cacheKey, TInit init, IDictionary<TCacheKey, CachedEntity> dictionary)
|
||||
where TCacheKey : notnull
|
||||
where TEntity : CachedEntity
|
||||
{
|
||||
if (dictionary.TryGetValue(cacheKey, out var cached))
|
||||
return (TEntity)cached;
|
||||
|
||||
using (StackGuard)
|
||||
{
|
||||
var label = GetNewLabel();
|
||||
var entity = factory.Create(this, init);
|
||||
entity.Label = label;
|
||||
|
||||
dictionary[cacheKey] = entity;
|
||||
|
||||
DefineLabel(entity);
|
||||
if (entity.NeedsPopulation)
|
||||
Populate(init as ISymbol, entity);
|
||||
|
||||
#if DEBUG_LABELS
|
||||
using var id = new EscapingTextWriter();
|
||||
entity.WriteQuotedId(id);
|
||||
CheckEntityHasUniqueLabel(id.ToString(), entity);
|
||||
#endif
|
||||
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a fresh label with ID "*", and set it on the
|
||||
/// supplied <paramref name="entity"/> object.
|
||||
/// </summary>
|
||||
internal void AddFreshLabel(Entity entity)
|
||||
{
|
||||
entity.Label = GetNewLabel();
|
||||
entity.DefineFreshLabel(TrapWriter.Writer);
|
||||
}
|
||||
|
||||
#if DEBUG_LABELS
|
||||
private readonly Dictionary<string, CachedEntity> idLabelCache = new Dictionary<string, CachedEntity>();
|
||||
#endif
|
||||
|
||||
private readonly IDictionary<object, CachedEntity> objectEntityCache = new Dictionary<object, CachedEntity>();
|
||||
private readonly IDictionary<ISymbol, CachedEntity> symbolEntityCache = new Dictionary<ISymbol, CachedEntity>(10000, SymbolEqualityComparer.Default);
|
||||
|
||||
/// <summary>
|
||||
/// Queue of items to populate later.
|
||||
/// The only reason for this is so that the call stack does not
|
||||
/// grow indefinitely, causing a potential stack overflow.
|
||||
/// </summary>
|
||||
private readonly Queue<Action> populateQueue = new Queue<Action>();
|
||||
|
||||
/// <summary>
|
||||
/// Enqueue the given action to be performed later.
|
||||
/// </summary>
|
||||
/// <param name="toRun">The action to run.</param>
|
||||
public void PopulateLater(Action a, bool preserveDuplicationKey = true)
|
||||
{
|
||||
var key = preserveDuplicationKey ? GetCurrentTagStackKey() : null;
|
||||
if (key is not null)
|
||||
{
|
||||
// If we are currently executing with a duplication guard, then the same
|
||||
// guard must be used for the deferred action
|
||||
populateQueue.Enqueue(() => WithDuplicationGuard(key, a));
|
||||
}
|
||||
else
|
||||
{
|
||||
populateQueue.Enqueue(a);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the main populate loop until there's nothing left to populate.
|
||||
/// </summary>
|
||||
public void PopulateAll()
|
||||
{
|
||||
while (populateQueue.Any())
|
||||
{
|
||||
try
|
||||
{
|
||||
populateQueue.Dequeue()();
|
||||
}
|
||||
catch (InternalError ex)
|
||||
{
|
||||
ExtractionError(new Message(ex.Text, ex.EntityText, CreateLocation(ex.Location), ex.StackTrace));
|
||||
}
|
||||
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
ExtractionError($"Uncaught exception. {ex.Message}", null, CreateLocation(), ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Context(ExtractionContext extractionContext, TrapWriter trapWriter, bool shouldAddAssemblyTrapPrefix = false)
|
||||
{
|
||||
ExtractionContext = extractionContext;
|
||||
TrapWriter = trapWriter;
|
||||
ShouldAddAssemblyTrapPrefix = shouldAddAssemblyTrapPrefix;
|
||||
}
|
||||
|
||||
private int currentRecursiveDepth = 0;
|
||||
private const int maxRecursiveDepth = 150;
|
||||
|
||||
private void EnterScope()
|
||||
{
|
||||
if (currentRecursiveDepth >= maxRecursiveDepth)
|
||||
throw new StackOverflowException($"Maximum nesting depth of {maxRecursiveDepth} exceeded");
|
||||
++currentRecursiveDepth;
|
||||
}
|
||||
|
||||
private void ExitScope()
|
||||
{
|
||||
--currentRecursiveDepth;
|
||||
}
|
||||
|
||||
public IDisposable StackGuard => new ScopeGuard(this);
|
||||
|
||||
private sealed class ScopeGuard : IDisposable
|
||||
{
|
||||
private readonly Context cx;
|
||||
|
||||
public ScopeGuard(Context c)
|
||||
{
|
||||
cx = c;
|
||||
cx.EnterScope();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
cx.ExitScope();
|
||||
}
|
||||
}
|
||||
|
||||
private class PushEmitter : ITrapEmitter
|
||||
{
|
||||
private readonly Key key;
|
||||
|
||||
public PushEmitter(Key key)
|
||||
{
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public void EmitTrap(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(".push ");
|
||||
key.AppendTo(trapFile);
|
||||
trapFile.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
private class PopEmitter : ITrapEmitter
|
||||
{
|
||||
public void EmitTrap(TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteLine(".pop");
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Stack<Key> tagStack = new Stack<Key>();
|
||||
|
||||
/// <summary>
|
||||
/// Populates an entity, handling the tag stack appropriately
|
||||
/// </summary>
|
||||
/// <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>
|
||||
private void Populate(ISymbol? optionalSymbol, CachedEntity entity)
|
||||
{
|
||||
if (writingLabel)
|
||||
{
|
||||
// Don't write tuples etc if we're currently defining a label
|
||||
PopulateLater(() => Populate(optionalSymbol, entity));
|
||||
return;
|
||||
}
|
||||
|
||||
bool duplicationGuard, deferred;
|
||||
|
||||
if (ExtractionContext.Mode is ExtractorMode.Standalone)
|
||||
{
|
||||
duplicationGuard = false;
|
||||
deferred = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (entity.TrapStackBehaviour)
|
||||
{
|
||||
case TrapStackBehaviour.NeedsLabel:
|
||||
if (!tagStack.Any())
|
||||
ExtractionError("TagStack unexpectedly empty", optionalSymbol, entity);
|
||||
duplicationGuard = false;
|
||||
deferred = false;
|
||||
break;
|
||||
case TrapStackBehaviour.NoLabel:
|
||||
duplicationGuard = false;
|
||||
deferred = tagStack.Any();
|
||||
break;
|
||||
case TrapStackBehaviour.OptionalLabel:
|
||||
duplicationGuard = false;
|
||||
deferred = false;
|
||||
break;
|
||||
case TrapStackBehaviour.PushesLabel:
|
||||
duplicationGuard = true;
|
||||
deferred = duplicationGuard && tagStack.Any();
|
||||
break;
|
||||
default:
|
||||
throw new InternalError("Unexpected TrapStackBehaviour");
|
||||
}
|
||||
}
|
||||
|
||||
var a = duplicationGuard && IsEntityDuplicationGuarded(entity, out var loc)
|
||||
? (() =>
|
||||
{
|
||||
var args = new object[TrapStackSuffix.Count + 2];
|
||||
args[0] = entity;
|
||||
args[1] = loc;
|
||||
for (var i = 0; i < TrapStackSuffix.Count; i++)
|
||||
{
|
||||
args[i + 2] = TrapStackSuffix[i];
|
||||
}
|
||||
WithDuplicationGuard(new Key(args), () => entity.Populate(TrapWriter.Writer));
|
||||
})
|
||||
: (Action)(() => this.Try(null, optionalSymbol, () => entity.Populate(TrapWriter.Writer)));
|
||||
|
||||
if (deferred)
|
||||
populateQueue.Enqueue(a);
|
||||
else
|
||||
a();
|
||||
}
|
||||
|
||||
protected virtual bool IsEntityDuplicationGuarded(IEntity entity, [NotNullWhen(returnValue: true)] out Entities.Location? loc)
|
||||
{
|
||||
loc = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the given action <paramref name="a"/>, guarding for trap duplication
|
||||
/// based on key <paramref name="key"/>.
|
||||
/// </summary>
|
||||
public virtual void WithDuplicationGuard(Key key, Action a)
|
||||
{
|
||||
tagStack.Push(key);
|
||||
TrapWriter.Emit(new PushEmitter(key));
|
||||
try
|
||||
{
|
||||
a();
|
||||
}
|
||||
finally
|
||||
{
|
||||
TrapWriter.Emit(new PopEmitter());
|
||||
tagStack.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
protected Key? GetCurrentTagStackKey() => tagStack.Count > 0
|
||||
? tagStack.Peek()
|
||||
: null;
|
||||
|
||||
/// <summary>
|
||||
/// Log an extraction error.
|
||||
/// </summary>
|
||||
/// <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 null.</param>
|
||||
/// <param name="severity">The severity of the error.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log an extraction error.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
private void ExtractionError(string message, ISymbol? optionalSymbol, Entity optionalEntity)
|
||||
{
|
||||
if (!(optionalSymbol is null))
|
||||
{
|
||||
ExtractionError(message, optionalSymbol.ToDisplayString(), CreateLocation(optionalSymbol.Locations.BestOrDefault()));
|
||||
}
|
||||
else if (!(optionalEntity is null))
|
||||
{
|
||||
ExtractionError(message, optionalEntity.Label.ToString(), CreateLocation(optionalEntity.ReportingLocation));
|
||||
}
|
||||
else
|
||||
{
|
||||
ExtractionError(message, null, CreateLocation());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log an extraction message.
|
||||
/// </summary>
|
||||
/// <param name="msg">The message to log.</param>
|
||||
private void ExtractionError(Message msg)
|
||||
{
|
||||
new ExtractionMessage(this, msg);
|
||||
ExtractionContext.Message(msg);
|
||||
}
|
||||
|
||||
private void ExtractionError(InternalError error)
|
||||
{
|
||||
ExtractionError(new Message(error.Message, error.EntityText, CreateLocation(error.Location), error.StackTrace, Severity.Error));
|
||||
}
|
||||
|
||||
private void ReportError(InternalError error)
|
||||
{
|
||||
if (!ExtractionContext.Mode.HasFlag(ExtractorMode.Standalone))
|
||||
throw error;
|
||||
|
||||
ExtractionError(error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signal an error in the program model.
|
||||
/// </summary>
|
||||
/// <param name="node">The syntax node causing the failure.</param>
|
||||
/// <param name="msg">The error message.</param>
|
||||
public void ModelError(SyntaxNode node, string msg)
|
||||
{
|
||||
ReportError(new InternalError(node, msg));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signal an error in the program model.
|
||||
/// </summary>
|
||||
/// <param name="symbol">Symbol causing the error.</param>
|
||||
/// <param name="msg">The error message.</param>
|
||||
public void ModelError(ISymbol symbol, string msg)
|
||||
{
|
||||
ReportError(new InternalError(symbol, msg));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signal an error in the program model.
|
||||
/// </summary>
|
||||
/// <param name="loc">The location of the error.</param>
|
||||
/// <param name="msg">The error message.</param>
|
||||
public void ModelError(Entities.Location loc, string msg)
|
||||
{
|
||||
ReportError(new InternalError(loc.ReportingLocation, msg));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signal an error in the program model.
|
||||
/// </summary>
|
||||
/// <param name="msg">The error message.</param>
|
||||
public void ModelError(string msg)
|
||||
{
|
||||
ReportError(new InternalError(msg));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries the supplied action <paramref name="a"/>, and logs an uncaught
|
||||
/// exception error if the action fails.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
public void Try(SyntaxNode? node, ISymbol? symbol, Action a)
|
||||
{
|
||||
try
|
||||
{
|
||||
a();
|
||||
}
|
||||
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
Message message;
|
||||
|
||||
if (node is not null)
|
||||
{
|
||||
message = Message.Create(this, ex.Message, node, ex.StackTrace);
|
||||
}
|
||||
else if (symbol is not null)
|
||||
{
|
||||
message = Message.Create(this, ex.Message, symbol, ex.StackTrace);
|
||||
}
|
||||
else if (ex is InternalError ie)
|
||||
{
|
||||
message = new Message(ie.Text, ie.EntityText, CreateLocation(ie.Location), ex.StackTrace);
|
||||
}
|
||||
else
|
||||
{
|
||||
message = new Message($"Uncaught exception. {ex.Message}", null, CreateLocation(), ex.StackTrace);
|
||||
}
|
||||
|
||||
ExtractionError(message);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Entities.Location CreateLocation() =>
|
||||
GeneratedLocation.Create(this);
|
||||
|
||||
public virtual Entities.Location CreateLocation(Microsoft.CodeAnalysis.Location? location) =>
|
||||
CreateLocation();
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Semmle.Extraction.Entities
|
||||
{
|
||||
public abstract class File : CachedEntity<string>
|
||||
{
|
||||
protected File(Context cx, string path)
|
||||
: base(cx, path)
|
||||
{
|
||||
originalPath = path;
|
||||
var adjustedPath = BinaryLogExtractionContext.GetAdjustedPath(Context.ExtractionContext, originalPath) ?? path;
|
||||
transformedPathLazy = new Lazy<PathTransformer.ITransformedPath>(() => Context.ExtractionContext.PathTransformer.Transform(adjustedPath));
|
||||
}
|
||||
|
||||
protected readonly string originalPath;
|
||||
private readonly Lazy<PathTransformer.ITransformedPath> transformedPathLazy;
|
||||
protected PathTransformer.ITransformedPath TransformedPath => transformedPathLazy.Value;
|
||||
|
||||
public override bool NeedsPopulation => true;
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(TransformedPath.DatabaseId);
|
||||
trapFile.Write(";sourcefile");
|
||||
}
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location? ReportingLocation => null;
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<CodeAnalysisRuleSet>Semmle.Extraction.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
|
||||
<InternalsVisibleTo Include="Semmle.Extraction.CSharp" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\..\.paket\Paket.Restore.targets" />
|
||||
</Project>
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RuleSet Name="Microsoft Managed Recommended Rules" Description="These rules focus on the most critical problems in your code, including potential security holes, application crashes, and other important logic and design errors. It is recommended to include this rule set in any custom rule set you create for your projects." ToolsVersion="10.0">
|
||||
<Localization ResourceAssembly="Microsoft.VisualStudio.CodeAnalysis.RuleSets.Strings.dll" ResourceBaseName="Microsoft.VisualStudio.CodeAnalysis.RuleSets.Strings.Localized">
|
||||
<Name Resource="MinimumRecommendedRules_Name" />
|
||||
<Description Resource="MinimumRecommendedRules_Description" />
|
||||
</Localization>
|
||||
|
||||
<Rules AnalyzerId="Microsoft.CodeAnalysis.CSharp.Analyzers" RuleNamespace="Microsoft.CodeAnalysis.CSharp.Analyzers">
|
||||
<Rule Id="RS1022" Action="None" />
|
||||
</Rules>
|
||||
<Rules AnalyzerId="Microsoft.CodeAnalysis.Analyzers" RuleNamespace="Microsoft.CodeAnalysis.Analyzers" />
|
||||
</RuleSet>
|
|
@ -1,36 +0,0 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
{
|
||||
/// <summary>
|
||||
/// A tuple represents a string of the form "a(b,c,d)".
|
||||
/// </summary>
|
||||
public struct Tuple : ITrapEmitter
|
||||
{
|
||||
private readonly string name;
|
||||
private readonly object[] args;
|
||||
|
||||
public Tuple(string name, params object[] args)
|
||||
{
|
||||
this.name = name;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a unique string for this tuple.
|
||||
/// </summary>
|
||||
/// <param name="trapFile">The trap file to write to.</param>
|
||||
public void EmitTrap(TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteTuple(name, args);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
// Only implemented for debugging purposes
|
||||
using var writer = new StringWriter();
|
||||
EmitTrap(writer);
|
||||
return writer.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
using Semmle.Extraction.Entities;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
{
|
||||
/// <summary>
|
||||
/// Methods for creating DB tuples.
|
||||
/// </summary>
|
||||
public static class Tuples
|
||||
{
|
||||
public static void containerparent(this System.IO.TextWriter trapFile, Folder parent, IEntity child)
|
||||
{
|
||||
trapFile.WriteTuple("containerparent", parent, child);
|
||||
}
|
||||
|
||||
internal static void extractor_messages(this System.IO.TextWriter trapFile, ExtractionMessage error, Semmle.Util.Logging.Severity severity, string errorMessage, string entityText, Location location, string stackTrace)
|
||||
{
|
||||
trapFile.WriteTuple("extractor_messages", error, (int)severity, "C# extractor", errorMessage, entityText, location, stackTrace);
|
||||
}
|
||||
|
||||
public static void files(this System.IO.TextWriter trapFile, File file, string fullName)
|
||||
{
|
||||
trapFile.WriteTuple("files", file, fullName);
|
||||
}
|
||||
|
||||
internal static void folders(this System.IO.TextWriter trapFile, Folder folder, string path)
|
||||
{
|
||||
trapFile.WriteTuple("folders", folder, path);
|
||||
}
|
||||
|
||||
public static void locations_default(this System.IO.TextWriter trapFile, SourceLocation label, Entities.File file, int startLine, int startCol, int endLine, int endCol)
|
||||
{
|
||||
trapFile.WriteTuple("locations_default", label, file, startLine, startCol, endLine, endCol);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
Microsoft.Build
|
||||
Microsoft.CodeAnalysis
|
|
@ -71,10 +71,6 @@ class AverageExpr extends PotentiallyRedundantExpr, AddExpr {
|
|||
this.getLeftOperand().getKind() = this.getRightOperand().getKind()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate operands(Expr left, Expr right) {
|
||||
left = this.getLeftOperand() and right = this.getRightOperand()
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the hash of `nd`, which is the `i`th operand of `red`. */
|
||||
|
|
Загрузка…
Ссылка в новой задаче