Merge branch 'main' into napalys/ES2023-array-protype-with

This commit is contained in:
Napalys Klicius 2024-11-18 08:25:09 +01:00 коммит произвёл GitHub
Родитель 1304ab7065 63bc1ef69f
Коммит a23850940f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
93 изменённых файлов: 629 добавлений и 904 удалений

Просмотреть файл

@ -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>&lt;0 if l1 before l2, &gt;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`. */