зеркало из https://github.com/github/codeql.git
Merge pull request #15794 from michaelnebel/csharp/removecil
C#: Delete the CIL extractor.
This commit is contained in:
Коммит
50851210ea
|
@ -268,6 +268,5 @@ csharp_style_var_elsewhere = true:suggestion
|
|||
#
|
||||
|
||||
[extractor/Semmle.Extraction/Tuples.cs,
|
||||
extractor/Semmle.Extraction.CSharp/Tuples.cs,
|
||||
extractor/Semmle.Extraction.CIL/Tuples.cs]
|
||||
extractor/Semmle.Extraction.CSharp/Tuples.cs]
|
||||
dotnet_naming_rule.members_should_be_pascal_case.severity = none
|
|
@ -8,8 +8,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction", "extrac
|
|||
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.CIL", "extractor\Semmle.Extraction.CIL\Semmle.Extraction.CIL.csproj", "{399A1579-68F0-40F4-9A23-F241BA697F9C}"
|
||||
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}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp.Standalone", "extractor\Semmle.Extraction.CSharp.Standalone\Semmle.Extraction.CSharp.Standalone.csproj", "{D00E7D25-0FA0-48EC-B048-CD60CE1B30D8}"
|
||||
|
@ -18,8 +16,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp.St
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp.Util", "extractor\Semmle.Extraction.CSharp.Util\Semmle.Extraction.CSharp.Util.csproj", "{998A0D4C-8BFC-4513-A28D-4816AFB89882}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CIL.Driver", "extractor\Semmle.Extraction.CIL.Driver\Semmle.Extraction.CIL.Driver.csproj", "{EFA400B3-C1CE-446F-A4E2-8B44E61EF47C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp.Driver", "extractor\Semmle.Extraction.CSharp.Driver\Semmle.Extraction.CSharp.Driver.csproj", "{C36453BF-0C82-448A-B15D-26947503A2D3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.Tests", "extractor\Semmle.Extraction.Tests\Semmle.Extraction.Tests.csproj", "{CD8D3F90-AD2E-4BB5-8E82-B94AA293864A}"
|
||||
|
|
|
@ -47,13 +47,6 @@ options:
|
|||
the code (for example if it uses inaccessible dependencies).
|
||||
type: string
|
||||
pattern: "^(false|true)$"
|
||||
cil:
|
||||
title: Whether to enable CIL extraction.
|
||||
description: >
|
||||
A value indicating, whether CIL extraction should be enabled.
|
||||
The default is 'true'.
|
||||
type: string
|
||||
pattern: "^(false|true)$"
|
||||
logging:
|
||||
title: Options pertaining to logging.
|
||||
type: object
|
||||
|
|
|
@ -1,250 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.Runtime.InteropServices;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Driver
|
||||
{
|
||||
/// <summary>
|
||||
/// Information about a single assembly.
|
||||
/// In particular, provides references between assemblies.
|
||||
/// </summary>
|
||||
internal class AssemblyInfo
|
||||
{
|
||||
public override string ToString() => Filename;
|
||||
|
||||
private static AssemblyName CreateAssemblyName(MetadataReader mdReader, StringHandle name, System.Version version, StringHandle culture)
|
||||
{
|
||||
var cultureString = mdReader.GetString(culture);
|
||||
|
||||
var assemblyName = new AssemblyName()
|
||||
{
|
||||
Name = mdReader.GetString(name),
|
||||
Version = version
|
||||
};
|
||||
|
||||
if (cultureString != "neutral")
|
||||
assemblyName.CultureInfo = CultureInfo.GetCultureInfo(cultureString);
|
||||
|
||||
return assemblyName;
|
||||
}
|
||||
|
||||
private static AssemblyName CreateAssemblyName(MetadataReader mdReader, AssemblyReference ar)
|
||||
{
|
||||
var an = CreateAssemblyName(mdReader, ar.Name, ar.Version, ar.Culture);
|
||||
if (!ar.PublicKeyOrToken.IsNil)
|
||||
an.SetPublicKeyToken(mdReader.GetBlobBytes(ar.PublicKeyOrToken));
|
||||
return an;
|
||||
}
|
||||
|
||||
private static AssemblyName CreateAssemblyName(MetadataReader mdReader, AssemblyDefinition ad)
|
||||
{
|
||||
var an = CreateAssemblyName(mdReader, ad.Name, ad.Version, ad.Culture);
|
||||
if (!ad.PublicKey.IsNil)
|
||||
an.SetPublicKey(mdReader.GetBlobBytes(ad.PublicKey));
|
||||
return an;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AssemblyInfo"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">Path of the assembly.</param>
|
||||
/// <exception cref="Semmle.Extraction.CIL.Driver.InvalidAssemblyException">
|
||||
/// Thrown when the input file is not a valid assembly.
|
||||
/// </exception>
|
||||
public AssemblyInfo(string path)
|
||||
{
|
||||
Filename = path;
|
||||
|
||||
// Attempt to open the file and see if it's a valid assembly.
|
||||
using var stream = File.OpenRead(path);
|
||||
using var peReader = new PEReader(stream);
|
||||
try
|
||||
{
|
||||
if (!peReader.HasMetadata)
|
||||
throw new InvalidAssemblyException();
|
||||
|
||||
var mdReader = peReader.GetMetadataReader();
|
||||
|
||||
if (!mdReader.IsAssembly)
|
||||
throw new InvalidAssemblyException();
|
||||
|
||||
// Get our own assembly name
|
||||
Name = CreateAssemblyName(mdReader, mdReader.GetAssemblyDefinition());
|
||||
|
||||
References = mdReader.AssemblyReferences
|
||||
.Select(r => mdReader.GetAssemblyReference(r))
|
||||
.Select(ar => CreateAssemblyName(mdReader, ar))
|
||||
.ToArray();
|
||||
}
|
||||
catch (System.BadImageFormatException)
|
||||
{
|
||||
// This failed on one of the Roslyn tests that includes
|
||||
// a deliberately malformed assembly.
|
||||
// In this case, we just skip the extraction of this assembly.
|
||||
throw new InvalidAssemblyException();
|
||||
}
|
||||
}
|
||||
|
||||
public AssemblyName Name { get; }
|
||||
public string Filename { get; }
|
||||
public bool Extract { get; set; }
|
||||
public AssemblyName[] References { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to manage a collection of assemblies.
|
||||
/// Resolves references between assemblies and determines which
|
||||
/// additional assemblies need to be extracted.
|
||||
/// </summary>
|
||||
internal class AssemblyList
|
||||
{
|
||||
private class AssemblyNameComparer : IEqualityComparer<AssemblyName>
|
||||
{
|
||||
bool IEqualityComparer<AssemblyName>.Equals(AssemblyName? x, AssemblyName? y) =>
|
||||
object.ReferenceEquals(x, y) ||
|
||||
x?.Name == y?.Name && x?.Version == y?.Version;
|
||||
|
||||
int IEqualityComparer<AssemblyName>.GetHashCode(AssemblyName obj) =>
|
||||
(obj.Name, obj.Version).GetHashCode();
|
||||
}
|
||||
|
||||
private readonly Dictionary<AssemblyName, AssemblyInfo> assembliesRead = new Dictionary<AssemblyName, AssemblyInfo>(new AssemblyNameComparer());
|
||||
|
||||
public void AddFile(string assemblyPath, bool extractAll)
|
||||
{
|
||||
if (!filesAnalyzed.Contains(assemblyPath))
|
||||
{
|
||||
filesAnalyzed.Add(assemblyPath);
|
||||
try
|
||||
{
|
||||
var info = new AssemblyInfo(assemblyPath)
|
||||
{
|
||||
Extract = extractAll
|
||||
};
|
||||
if (!assembliesRead.ContainsKey(info.Name))
|
||||
assembliesRead.Add(info.Name, info);
|
||||
}
|
||||
catch (InvalidAssemblyException)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<AssemblyInfo> AssembliesToExtract => assembliesRead.Values.Where(info => info.Extract);
|
||||
|
||||
private IEnumerable<AssemblyName> AssembliesToReference => AssembliesToExtract.SelectMany(info => info.References);
|
||||
|
||||
public void ResolveReferences()
|
||||
{
|
||||
var assembliesToReference = new Stack<AssemblyName>(AssembliesToReference);
|
||||
|
||||
while (assembliesToReference.Any())
|
||||
{
|
||||
var item = assembliesToReference.Pop();
|
||||
if (assembliesRead.TryGetValue(item, out var info))
|
||||
{
|
||||
if (!info.Extract)
|
||||
{
|
||||
info.Extract = true;
|
||||
foreach (var reference in info.References)
|
||||
assembliesToReference.Push(reference);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MissingReferences.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly HashSet<string> filesAnalyzed = new HashSet<string>();
|
||||
public HashSet<AssemblyName> MissingReferences { get; } = new HashSet<AssemblyName>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the command line and collates a list of DLLs/EXEs to extract.
|
||||
/// </summary>
|
||||
internal class ExtractorOptions : CommonOptions
|
||||
{
|
||||
private readonly AssemblyList assemblyList = new AssemblyList();
|
||||
|
||||
public ExtractorOptions(string[] args)
|
||||
{
|
||||
this.ParseArguments(args.Append("--pdb").ToArray());
|
||||
|
||||
AddFrameworkDirectories(false);
|
||||
|
||||
assemblyList.ResolveReferences();
|
||||
AssembliesToExtract = assemblyList.AssembliesToExtract.ToArray();
|
||||
}
|
||||
|
||||
public void AddDirectory(string directory, bool extractAll)
|
||||
{
|
||||
foreach (var file in
|
||||
Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories).
|
||||
Concat(Directory.EnumerateFiles(directory, "*.exe", SearchOption.AllDirectories)))
|
||||
{
|
||||
assemblyList.AddFile(file, extractAll);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddFrameworkDirectories(bool extractAll)
|
||||
{
|
||||
AddDirectory(RuntimeEnvironment.GetRuntimeDirectory(), extractAll);
|
||||
}
|
||||
|
||||
private void AddFileOrDirectory(string path)
|
||||
{
|
||||
path = Path.GetFullPath(path);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
assemblyList.AddFile(path, true);
|
||||
var directory = Path.GetDirectoryName(path);
|
||||
if (directory is null)
|
||||
{
|
||||
throw new InternalError($"Directory of path '{path}' is null");
|
||||
}
|
||||
AddDirectory(directory, false);
|
||||
}
|
||||
else if (Directory.Exists(path))
|
||||
{
|
||||
AddDirectory(path, true);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<AssemblyInfo> AssembliesToExtract { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the assemblies that were referenced but were not available to be
|
||||
/// extracted. This is not an error, it just means that the database is not
|
||||
/// as complete as it could be.
|
||||
/// </summary>
|
||||
public IEnumerable<AssemblyName> MissingReferences => assemblyList.MissingReferences;
|
||||
|
||||
public override bool HandleFlag(string flag, bool value)
|
||||
{
|
||||
switch (flag)
|
||||
{
|
||||
case "dotnet":
|
||||
if (value)
|
||||
AddFrameworkDirectories(true);
|
||||
return true;
|
||||
default:
|
||||
return base.HandleFlag(flag, value);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool HandleArgument(string argument)
|
||||
{
|
||||
AddFileOrDirectory(argument);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void InvalidArgument(string argument) { }
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Driver
|
||||
{
|
||||
public class InvalidAssemblyException : Exception
|
||||
{ }
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Driver
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
private static void DisplayHelp()
|
||||
{
|
||||
Console.WriteLine("CIL command line extractor");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Usage: Semmle.Extraction.CIL.Driver.exe [options] path ...");
|
||||
Console.WriteLine(" --verbose Turn on verbose output");
|
||||
Console.WriteLine(" --dotnet Extract the .Net Framework");
|
||||
Console.WriteLine(" --nocache Overwrite existing trap files");
|
||||
Console.WriteLine(" --no-pdb Do not extract PDB files");
|
||||
Console.WriteLine(" path A directory/dll/exe to analyze");
|
||||
}
|
||||
|
||||
private static void ExtractAssembly(string assemblyPath, ILogger logger, CommonOptions options)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
Analyser.ExtractCIL(assemblyPath, logger, options, out _, out _);
|
||||
sw.Stop();
|
||||
logger.Log(Severity.Info, " {0} ({1})", assemblyPath, sw.Elapsed);
|
||||
}
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
if (args.Length == 0)
|
||||
{
|
||||
DisplayHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
var options = new ExtractorOptions(args);
|
||||
using ILogger logger = new ConsoleLogger(options.Verbosity, logThreadId: false);
|
||||
|
||||
var actions = options.AssembliesToExtract
|
||||
.Select(asm => asm.Filename)
|
||||
.Select<string, Action>(filename => () => ExtractAssembly(filename, logger, options))
|
||||
.ToArray();
|
||||
|
||||
foreach (var missingRef in options.MissingReferences)
|
||||
logger.LogInfo(" Missing assembly " + missingRef);
|
||||
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var piOptions = new ParallelOptions
|
||||
{
|
||||
MaxDegreeOfParallelism = options.Threads
|
||||
};
|
||||
|
||||
Parallel.Invoke(piOptions, actions);
|
||||
|
||||
sw.Stop();
|
||||
logger.Log(Severity.Info, "Extraction completed in {0}", sw.Elapsed);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Semmle.Extraction.CIL.Driver")]
|
||||
[assembly: AssemblyDescription("Semmle CIL extractor")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Semmle Ltd")]
|
||||
[assembly: AssemblyProduct("Semmle.Extraction.CIL.Driver")]
|
||||
[assembly: AssemblyCopyright("Copyright © Semmle 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("5642ae68-9c26-43c9-bd3c-49923dddf02d")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -1,23 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Extraction.CIL.Driver</AssemblyName>
|
||||
<RootNamespace>Semmle.Extraction.CIL.Driver</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CIL\Semmle.Extraction.CIL.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,52 +0,0 @@
|
|||
using System;
|
||||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
using Semmle.Extraction.CIL.Entities;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
public static class Analyser
|
||||
{
|
||||
private static void ExtractCIL(TracingExtractor extractor, TrapWriter trapWriter, bool extractPdbs)
|
||||
{
|
||||
using var cilContext = new Context(extractor, trapWriter, extractor.OutputPath, extractPdbs);
|
||||
cilContext.Populate(new Assembly(cilContext));
|
||||
cilContext.PopulateAll();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Main entry point to the CIL extractor.
|
||||
/// Call this to extract a given assembly.
|
||||
/// </summary>
|
||||
/// <param name="layout">The trap layout.</param>
|
||||
/// <param name="assemblyPath">The full path of the assembly to extract.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="nocache">True to overwrite existing trap file.</param>
|
||||
/// <param name="extractPdbs">Whether to extract PDBs.</param>
|
||||
/// <param name="trapFile">The path of the trap file.</param>
|
||||
/// <param name="extracted">Whether the file was extracted (false=cached).</param>
|
||||
public static void ExtractCIL(string assemblyPath, ILogger logger, CommonOptions options, out string trapFile, out bool extracted)
|
||||
{
|
||||
trapFile = "";
|
||||
extracted = false;
|
||||
try
|
||||
{
|
||||
var canonicalPathCache = CanonicalPathCache.Create(logger, 1000);
|
||||
var pathTransformer = new PathTransformer(canonicalPathCache);
|
||||
var extractor = new TracingExtractor(assemblyPath, logger, pathTransformer, options);
|
||||
var transformedAssemblyPath = pathTransformer.Transform(assemblyPath);
|
||||
using var trapWriter = transformedAssemblyPath.WithSuffix(".cil").CreateTrapWriter(logger, options.TrapCompression, discardDuplicates: true);
|
||||
trapFile = trapWriter.TrapFile;
|
||||
if (!options.Cache || !System.IO.File.Exists(trapFile))
|
||||
{
|
||||
ExtractCIL(extractor, trapWriter, options.PDB);
|
||||
extracted = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
logger.LogError(string.Format("Exception extracting {0}: {1}", assemblyPath, ex));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// A factory and a cache for mapping source entities to target entities.
|
||||
/// Could be considered as a memoizer.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSrc">The type of the source.</typeparam>
|
||||
/// <typeparam name="TTarget">The type of the generated object.</typeparam>
|
||||
public class CachedFunction<TSrc, TTarget> where TSrc : notnull
|
||||
{
|
||||
private readonly Func<TSrc, TTarget> generator;
|
||||
private readonly Dictionary<TSrc, TTarget> cache;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the factory with a given mapping.
|
||||
/// </summary>
|
||||
/// <param name="g">The mapping.</param>
|
||||
public CachedFunction(Func<TSrc, TTarget> g)
|
||||
{
|
||||
generator = g;
|
||||
cache = new Dictionary<TSrc, TTarget>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the target for a given source.
|
||||
/// Create it if it does not exist.
|
||||
/// </summary>
|
||||
/// <param name="src">The source object.</param>
|
||||
/// <returns>The created object.</returns>
|
||||
public TTarget this[TSrc src]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!cache.TryGetValue(src, out var result))
|
||||
{
|
||||
result = generator(src);
|
||||
cache[src] = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A factory for mapping a pair of source entities to a target entity.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSrcEntity1">Source entity type 1.</typeparam>
|
||||
/// <typeparam name="TSrcEntity2">Source entity type 2.</typeparam>
|
||||
/// <typeparam name="TTarget">The target type.</typeparam>
|
||||
public class CachedFunction<TSrcEntity1, TSrcEntity2, TTarget>
|
||||
{
|
||||
private readonly CachedFunction<(TSrcEntity1, TSrcEntity2), TTarget> factory;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the factory with a given mapping.
|
||||
/// </summary>
|
||||
/// <param name="g">The mapping.</param>
|
||||
public CachedFunction(Func<TSrcEntity1, TSrcEntity2, TTarget> g)
|
||||
{
|
||||
factory = new CachedFunction<(TSrcEntity1, TSrcEntity2), TTarget>(p => g(p.Item1, p.Item2));
|
||||
}
|
||||
|
||||
public TTarget this[TSrcEntity1 s1, TSrcEntity2 s2] => factory[(s1, s2)];
|
||||
}
|
||||
}
|
|
@ -1,253 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
using Semmle.Extraction.CIL.Entities;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods for creating and caching various entities.
|
||||
/// </summary>
|
||||
internal sealed partial class Context
|
||||
{
|
||||
private readonly Dictionary<object, Label> ids = new Dictionary<object, Label>();
|
||||
|
||||
internal T Populate<T>(T e) where T : IExtractedEntity
|
||||
{
|
||||
if (e.Label.Valid)
|
||||
{
|
||||
return e; // Already populated
|
||||
}
|
||||
|
||||
if (ids.TryGetValue(e, out var existing))
|
||||
{
|
||||
// It exists already
|
||||
e.Label = existing;
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Label = GetNewLabel();
|
||||
DefineLabel(e);
|
||||
ids.Add(e, e.Label);
|
||||
PopulateLater(() =>
|
||||
{
|
||||
foreach (var c in e.Contents)
|
||||
c.Extract(this);
|
||||
});
|
||||
#if DEBUG_LABELS
|
||||
using var writer = new EscapingTextWriter();
|
||||
e.WriteId(writer);
|
||||
var id = writer.ToString();
|
||||
|
||||
if (debugLabels.TryGetValue(id, out var previousEntity))
|
||||
{
|
||||
Extractor.Message(new Message("Duplicate trap ID", id, null, severity: Util.Logging.Severity.Warning));
|
||||
}
|
||||
else
|
||||
{
|
||||
debugLabels.Add(id, e);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
#if DEBUG_LABELS
|
||||
private readonly Dictionary<string, IExtractedEntity> debugLabels = new Dictionary<string, IExtractedEntity>();
|
||||
#endif
|
||||
|
||||
public IExtractedEntity Create(Handle h)
|
||||
{
|
||||
var entity = CreateGeneric(defaultGenericContext, h);
|
||||
return entity;
|
||||
}
|
||||
|
||||
// Lazily cache primitive types.
|
||||
private readonly PrimitiveType[] primitiveTypes = new PrimitiveType[(int)PrimitiveTypeCode.Object + 1];
|
||||
|
||||
public PrimitiveType Create(PrimitiveTypeCode code)
|
||||
{
|
||||
var e = primitiveTypes[(int)code];
|
||||
|
||||
if (e is null)
|
||||
{
|
||||
e = new PrimitiveType(this, code)
|
||||
{
|
||||
Label = GetNewLabel()
|
||||
};
|
||||
DefineLabel(e);
|
||||
primitiveTypes[(int)code] = e;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an entity from a Handle in a GenericContext.
|
||||
/// The type of the returned entity depends on the type of the handle.
|
||||
/// The GenericContext is needed because some handles are generics which
|
||||
/// need to be expanded in terms of the current instantiation. If this sounds
|
||||
/// complex, you are right.
|
||||
///
|
||||
/// The pair (h,genericContext) is cached in case it is needed again.
|
||||
/// </summary>
|
||||
/// <param name="h">The handle of the entity.</param>
|
||||
/// <param name="genericContext">The generic context.</param>
|
||||
/// <returns></returns>
|
||||
public IExtractedEntity CreateGeneric(IGenericContext genericContext, Handle h) => genericHandleFactory[genericContext, h];
|
||||
|
||||
private readonly IGenericContext defaultGenericContext;
|
||||
|
||||
private IExtractedEntity CreateGenericHandle(IGenericContext gc, Handle handle)
|
||||
{
|
||||
IExtractedEntity entity;
|
||||
switch (handle.Kind)
|
||||
{
|
||||
case HandleKind.MethodDefinition:
|
||||
entity = new DefinitionMethod(gc, (MethodDefinitionHandle)handle);
|
||||
break;
|
||||
case HandleKind.MemberReference:
|
||||
entity = Create(gc, (MemberReferenceHandle)handle);
|
||||
break;
|
||||
case HandleKind.MethodSpecification:
|
||||
entity = new MethodSpecificationMethod(gc, (MethodSpecificationHandle)handle);
|
||||
break;
|
||||
case HandleKind.FieldDefinition:
|
||||
entity = new DefinitionField(gc.Context, (FieldDefinitionHandle)handle);
|
||||
break;
|
||||
case HandleKind.TypeReference:
|
||||
var tr = new TypeReferenceType(this, (TypeReferenceHandle)handle);
|
||||
if (tr.TryGetPrimitiveType(out var pt))
|
||||
// Map special names like `System.Int32` to `int`
|
||||
return pt;
|
||||
entity = tr;
|
||||
break;
|
||||
case HandleKind.TypeSpecification:
|
||||
return Entities.Type.DecodeType(gc, (TypeSpecificationHandle)handle);
|
||||
case HandleKind.TypeDefinition:
|
||||
entity = new TypeDefinitionType(this, (TypeDefinitionHandle)handle);
|
||||
break;
|
||||
case HandleKind.StandaloneSignature:
|
||||
var signature = MdReader.GetStandaloneSignature((StandaloneSignatureHandle)handle);
|
||||
var method = signature.DecodeMethodSignature(gc.Context.TypeSignatureDecoder, gc);
|
||||
entity = new FunctionPointerType(this, method);
|
||||
break;
|
||||
default:
|
||||
throw new InternalError("Unhandled handle kind " + handle.Kind);
|
||||
}
|
||||
|
||||
Populate(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
private IExtractedEntity Create(IGenericContext gc, MemberReferenceHandle handle)
|
||||
{
|
||||
var mr = MdReader.GetMemberReference(handle);
|
||||
switch (mr.GetKind())
|
||||
{
|
||||
case MemberReferenceKind.Method:
|
||||
return new MemberReferenceMethod(gc, handle);
|
||||
case MemberReferenceKind.Field:
|
||||
return new MemberReferenceField(gc, handle);
|
||||
default:
|
||||
throw new InternalError("Unhandled member reference handle");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string for a string handle.
|
||||
/// </summary>
|
||||
/// <param name="h">The string handle.</param>
|
||||
/// <returns>The string.</returns>
|
||||
public string GetString(StringHandle h) => MdReader.GetString(h);
|
||||
|
||||
#region Namespaces
|
||||
|
||||
private readonly CachedFunction<StringHandle, Namespace> namespaceFactory;
|
||||
|
||||
public Namespace CreateNamespace(StringHandle fqn) => namespaceFactory[fqn];
|
||||
|
||||
private readonly Lazy<Namespace> globalNamespace, systemNamespace;
|
||||
|
||||
/// <summary>
|
||||
/// The entity representing the global namespace.
|
||||
/// </summary>
|
||||
public Namespace GlobalNamespace => globalNamespace.Value;
|
||||
|
||||
/// <summary>
|
||||
/// The entity representing the System namespace.
|
||||
/// </summary>
|
||||
public Namespace SystemNamespace => systemNamespace.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a namespace from a fully-qualified name.
|
||||
/// </summary>
|
||||
/// <param name="fqn">The fully-qualified namespace name.</param>
|
||||
/// <returns>The namespace entity.</returns>
|
||||
private Namespace CreateNamespace(string fqn) => Populate(new Namespace(this, fqn));
|
||||
|
||||
private readonly CachedFunction<NamespaceDefinitionHandle, Namespace> namespaceDefinitionFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a namespace from a namespace handle.
|
||||
/// </summary>
|
||||
/// <param name="handle">The handle of the namespace.</param>
|
||||
/// <returns>The namespace entity.</returns>
|
||||
public Namespace Create(NamespaceDefinitionHandle handle) => namespaceDefinitionFactory[handle];
|
||||
|
||||
private Namespace CreateNamespace(NamespaceDefinitionHandle handle)
|
||||
{
|
||||
if (handle.IsNil)
|
||||
return GlobalNamespace;
|
||||
var nd = MdReader.GetNamespaceDefinition(handle);
|
||||
return Populate(new Namespace(this, GetString(nd.Name), Create(nd.Parent)));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Locations
|
||||
private readonly CachedFunction<PDB.ISourceFile, PdbSourceFile> sourceFiles;
|
||||
private readonly CachedFunction<PathTransformer.ITransformedPath, Folder> folders;
|
||||
private readonly CachedFunction<PDB.Location, PdbSourceLocation> sourceLocations;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a source file entity from a PDB source file.
|
||||
/// </summary>
|
||||
/// <param name="file">The PDB source file.</param>
|
||||
/// <returns>A source file entity.</returns>
|
||||
public PdbSourceFile CreateSourceFile(PDB.ISourceFile file) => sourceFiles[file];
|
||||
|
||||
/// <summary>
|
||||
/// Creates a folder entity with the given path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the folder.</param>
|
||||
/// <returns>A folder entity.</returns>
|
||||
public Folder CreateFolder(PathTransformer.ITransformedPath path) => folders[path];
|
||||
|
||||
/// <summary>
|
||||
/// Creates a source location.
|
||||
/// </summary>
|
||||
/// <param name="loc">The source location from PDB.</param>
|
||||
/// <returns>A source location entity.</returns>
|
||||
public PdbSourceLocation CreateSourceLocation(PDB.Location loc) => sourceLocations[loc];
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly CachedFunction<IGenericContext, Handle, IExtractedEntity> genericHandleFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the short name of a member, without the preceding interface qualifier.
|
||||
/// </summary>
|
||||
/// <param name="handle">The handle of the name.</param>
|
||||
/// <returns>The short name.</returns>
|
||||
public string ShortName(StringHandle handle)
|
||||
{
|
||||
var str = MdReader.GetString(handle);
|
||||
if (str.EndsWith(".ctor"))
|
||||
return ".ctor";
|
||||
if (str.EndsWith(".cctor"))
|
||||
return ".cctor";
|
||||
var dot = str.LastIndexOf('.');
|
||||
return dot == -1 ? str : str.Substring(dot + 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.PortableExecutable;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// Extraction context for CIL extraction.
|
||||
/// Adds additional context that is specific for CIL extraction.
|
||||
/// One context = one DLL/EXE.
|
||||
/// </summary>
|
||||
internal sealed partial class Context : Extraction.Context, IDisposable
|
||||
{
|
||||
private readonly FileStream stream;
|
||||
private Entities.Assembly? assemblyNull;
|
||||
public MetadataReader MdReader { get; }
|
||||
public PEReader PeReader { get; }
|
||||
public string AssemblyPath { get; }
|
||||
public Entities.Assembly Assembly
|
||||
{
|
||||
get { return assemblyNull!; }
|
||||
set { assemblyNull = value; }
|
||||
}
|
||||
public PDB.IPdb? Pdb { get; }
|
||||
|
||||
public Context(Extractor extractor, TrapWriter trapWriter, string assemblyPath, bool extractPdbs)
|
||||
: base(extractor, trapWriter)
|
||||
{
|
||||
this.AssemblyPath = assemblyPath;
|
||||
stream = File.OpenRead(assemblyPath);
|
||||
PeReader = new PEReader(stream, PEStreamOptions.PrefetchEntireImage);
|
||||
MdReader = PeReader.GetMetadataReader();
|
||||
TypeSignatureDecoder = new Entities.TypeSignatureDecoder(this);
|
||||
|
||||
globalNamespace = new Lazy<Entities.Namespace>(() => Populate(new Entities.Namespace(this, "", null)));
|
||||
systemNamespace = new Lazy<Entities.Namespace>(() => Populate(new Entities.Namespace(this, "System")));
|
||||
genericHandleFactory = new CachedFunction<IGenericContext, Handle, IExtractedEntity>(CreateGenericHandle);
|
||||
namespaceFactory = new CachedFunction<StringHandle, Entities.Namespace>(n => CreateNamespace(MdReader.GetString(n)));
|
||||
namespaceDefinitionFactory = new CachedFunction<NamespaceDefinitionHandle, Entities.Namespace>(CreateNamespace);
|
||||
sourceFiles = new CachedFunction<PDB.ISourceFile, Entities.PdbSourceFile>(path => new Entities.PdbSourceFile(this, path));
|
||||
folders = new CachedFunction<PathTransformer.ITransformedPath, Entities.Folder>(path => new Entities.Folder(this, path));
|
||||
sourceLocations = new CachedFunction<PDB.Location, Entities.PdbSourceLocation>(location => new Entities.PdbSourceLocation(this, location));
|
||||
|
||||
defaultGenericContext = new EmptyContext(this);
|
||||
|
||||
if (extractPdbs)
|
||||
{
|
||||
Pdb = PDB.PdbReader.Create(assemblyPath, PeReader);
|
||||
if (Pdb is not null)
|
||||
{
|
||||
Extractor.Logger.Log(Util.Logging.Severity.Info, string.Format("Found PDB information for {0}", assemblyPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Pdb is not null)
|
||||
Pdb.Dispose();
|
||||
PeReader.Dispose();
|
||||
stream.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract the contents of a given entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity to extract.</param>
|
||||
public void Extract(IExtractedEntity entity)
|
||||
{
|
||||
foreach (var content in entity.Contents)
|
||||
{
|
||||
content.Extract(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteAssemblyPrefix(TextWriter trapFile)
|
||||
{
|
||||
var def = MdReader.GetAssemblyDefinition();
|
||||
trapFile.Write(GetString(def.Name));
|
||||
trapFile.Write('_');
|
||||
trapFile.Write(def.Version.ToString());
|
||||
trapFile.Write(Entities.Type.AssemblyTypeNameSeparator);
|
||||
}
|
||||
|
||||
public Entities.TypeSignatureDecoder TypeSignatureDecoder { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A type used to signify something we can't handle yet.
|
||||
/// Specifically, function pointers (used in C++).
|
||||
/// </summary>
|
||||
public Entities.Type ErrorType
|
||||
{
|
||||
get
|
||||
{
|
||||
var errorType = new Entities.ErrorType(this);
|
||||
Populate(errorType);
|
||||
return errorType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to locate debugging information for a particular method.
|
||||
///
|
||||
/// Returns null on failure, for example if there was no PDB information found for the
|
||||
/// DLL, or if the particular method is compiler generated or doesn't come from source code.
|
||||
/// </summary>
|
||||
/// <param name="handle">The handle of the method.</param>
|
||||
/// <returns>The debugging information, or null if the information could not be located.</returns>
|
||||
public PDB.Method? GetMethodDebugInformation(MethodDefinitionHandle handle)
|
||||
{
|
||||
return Pdb?.GetMethod(handle.ToDebugInformationHandle());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// A generic context which does not contain any type parameters.
|
||||
/// </summary>
|
||||
internal class EmptyContext : IGenericContext
|
||||
{
|
||||
public EmptyContext(Context cx)
|
||||
{
|
||||
Context = cx;
|
||||
}
|
||||
|
||||
public Context Context { get; }
|
||||
|
||||
public IEnumerable<Entities.Type> TypeParameters { get { yield break; } }
|
||||
|
||||
public IEnumerable<Entities.Type> MethodParameters { get { yield break; } }
|
||||
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An array type.
|
||||
/// </summary>
|
||||
internal sealed class ArrayType : Type
|
||||
{
|
||||
private readonly Type elementType;
|
||||
private readonly int rank;
|
||||
|
||||
public ArrayType(Context cx, Type elementType, int rank) : base(cx)
|
||||
{
|
||||
this.rank = rank;
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
public ArrayType(Context cx, Type elementType) : this(cx, elementType, 1)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is ArrayType array && elementType.Equals(array.elementType) && rank == array.rank;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => HashCode.Combine(elementType, rank);
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
elementType.WriteId(trapFile, inContext);
|
||||
trapFile.Write('[');
|
||||
for (var i = 1; i < rank; ++i)
|
||||
{
|
||||
trapFile.Write(',');
|
||||
}
|
||||
trapFile.Write(']');
|
||||
}
|
||||
|
||||
public override string Name => elementType.Name + "[]";
|
||||
|
||||
public override Namespace ContainingNamespace => Context.SystemNamespace;
|
||||
|
||||
public override Type? ContainingType => null;
|
||||
|
||||
public override int ThisTypeParameterCount => elementType.ThisTypeParameterCount;
|
||||
|
||||
public override CilTypeKind Kind => CilTypeKind.Array;
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments) => Context.Populate(new ArrayType(Context, elementType.Construct(typeArguments)));
|
||||
|
||||
public override Type SourceDeclaration => Context.Populate(new ArrayType(Context, elementType.SourceDeclaration));
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var c in base.Contents)
|
||||
yield return c;
|
||||
|
||||
yield return Tuples.cil_array_type(this, elementType, rank);
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) => elementType.WriteAssemblyPrefix(trapFile);
|
||||
|
||||
public override IEnumerable<Type> GenericArguments => elementType.GenericArguments;
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => elementType.TypeParameters;
|
||||
}
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using Semmle.Extraction.Entities;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An assembly to extract.
|
||||
/// </summary>
|
||||
internal class Assembly : LabelledEntity, ILocation
|
||||
{
|
||||
private readonly File file;
|
||||
private readonly AssemblyName assemblyName;
|
||||
|
||||
public Assembly(Context cx) : base(cx)
|
||||
{
|
||||
cx.Assembly = this;
|
||||
var def = cx.MdReader.GetAssemblyDefinition();
|
||||
|
||||
assemblyName = new AssemblyName
|
||||
{
|
||||
Name = cx.MdReader.GetString(def.Name),
|
||||
Version = def.Version,
|
||||
CultureInfo = new CultureInfo(cx.MdReader.GetString(def.Culture))
|
||||
};
|
||||
|
||||
if (!def.PublicKey.IsNil)
|
||||
assemblyName.SetPublicKey(cx.MdReader.GetBlobBytes(def.PublicKey));
|
||||
|
||||
file = new File(cx, cx.AssemblyPath);
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(FullName);
|
||||
trapFile.Write("#file:///");
|
||||
trapFile.Write(Context.AssemblyPath.Replace("\\", "/"));
|
||||
trapFile.Write(";assembly");
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return GetType() == obj?.GetType() && Equals(file, ((Assembly)obj).file);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => 7 * file.GetHashCode();
|
||||
|
||||
private string FullName => assemblyName.GetPublicKey() is null ? assemblyName.FullName + ", PublicKeyToken=null" : assemblyName.FullName;
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return file;
|
||||
yield return Tuples.assemblies(this, file, FullName, assemblyName.Name ?? string.Empty, assemblyName.Version?.ToString() ?? string.Empty);
|
||||
|
||||
if (Context.Pdb is not null)
|
||||
{
|
||||
foreach (var f in Context.Pdb.SourceFiles)
|
||||
{
|
||||
yield return Context.CreateSourceFile(f);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var handle in Context.MdReader.TypeDefinitions)
|
||||
{
|
||||
IExtractionProduct? product = null;
|
||||
try
|
||||
{
|
||||
product = Context.Create(handle);
|
||||
}
|
||||
catch (InternalError e)
|
||||
{
|
||||
Context.ExtractionError("Error processing type definition", e.Message, GeneratedLocation.Create(Context), e.StackTrace);
|
||||
}
|
||||
|
||||
// Limitation of C#: Cannot yield return inside a try-catch.
|
||||
if (product is not null)
|
||||
yield return product;
|
||||
}
|
||||
|
||||
foreach (var handle in Context.MdReader.MethodDefinitions)
|
||||
{
|
||||
IExtractionProduct? product = null;
|
||||
try
|
||||
{
|
||||
product = Context.Create(handle);
|
||||
}
|
||||
catch (InternalError e)
|
||||
{
|
||||
Context.ExtractionError("Error processing bytecode", e.Message, GeneratedLocation.Create(Context), e.StackTrace);
|
||||
}
|
||||
|
||||
if (product is not null)
|
||||
yield return product;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity representing a CIL attribute.
|
||||
/// </summary>
|
||||
internal sealed class Attribute : UnlabelledEntity
|
||||
{
|
||||
private readonly CustomAttributeHandle handle;
|
||||
private readonly CustomAttribute attrib;
|
||||
private readonly IExtractedEntity @object;
|
||||
|
||||
public Attribute(Context cx, IExtractedEntity @object, CustomAttributeHandle handle) : base(cx)
|
||||
{
|
||||
attrib = cx.MdReader.GetCustomAttribute(handle);
|
||||
this.handle = handle;
|
||||
this.@object = @object;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Attribute attribute && handle.Equals(attribute.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
var constructor = (Method)Context.Create(attrib.Constructor);
|
||||
yield return constructor;
|
||||
|
||||
yield return Tuples.cil_attribute(this, @object, constructor);
|
||||
|
||||
CustomAttributeValue<Type> decoded;
|
||||
|
||||
try
|
||||
{
|
||||
decoded = attrib.DecodeValue(new CustomAttributeDecoder(Context));
|
||||
}
|
||||
catch
|
||||
{
|
||||
Context.Extractor.Logger.Log(Util.Logging.Severity.Info,
|
||||
$"Attribute decoding is partial. Decoding attribute {constructor.DeclaringType.GetQualifiedName()} failed on {@object}.");
|
||||
yield break;
|
||||
}
|
||||
|
||||
for (var index = 0; index < decoded.FixedArguments.Length; ++index)
|
||||
{
|
||||
var stringValue = GetStringValue(decoded.FixedArguments[index].Type, decoded.FixedArguments[index].Value);
|
||||
yield return Tuples.cil_attribute_positional_argument(this, index, stringValue);
|
||||
}
|
||||
|
||||
foreach (var p in decoded.NamedArguments)
|
||||
{
|
||||
var stringValue = GetStringValue(p.Type, p.Value);
|
||||
yield return Tuples.cil_attribute_named_argument(this, p.Name!, stringValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetStringValue(Type type, object? value)
|
||||
{
|
||||
if (value is System.Collections.Immutable.ImmutableArray<CustomAttributeTypedArgument<Type>> values)
|
||||
{
|
||||
return "[" + string.Join(",", values.Select(v => GetStringValue(v.Type, v.Value))) + "]";
|
||||
}
|
||||
|
||||
if (type.GetQualifiedName() == "System.Type" &&
|
||||
value is Type t)
|
||||
{
|
||||
return t.GetQualifiedName();
|
||||
}
|
||||
|
||||
return value?.ToString() ?? "null";
|
||||
}
|
||||
|
||||
public static IEnumerable<IExtractionProduct> Populate(Context cx, IExtractedEntity @object, CustomAttributeHandleCollection attributes)
|
||||
{
|
||||
foreach (var attrib in attributes)
|
||||
{
|
||||
yield return new Attribute(cx, @object, attrib);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// A CIL entity which has been extracted.
|
||||
/// </summary>
|
||||
internal interface IExtractedEntity : IExtractionProduct, IEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// The contents of the entity.
|
||||
/// </summary>
|
||||
|
||||
IEnumerable<IExtractionProduct> Contents { get; }
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// Something that is extracted from an entity.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// The extraction algorithm proceeds as follows:
|
||||
/// - Construct entity
|
||||
/// - Call Extract()
|
||||
/// - IExtractedEntity check if already extracted
|
||||
/// - Enumerate Contents to produce more extraction products
|
||||
/// - Extract these until there is nothing left to extract
|
||||
/// </remarks>
|
||||
internal interface IExtractionProduct
|
||||
{
|
||||
/// <summary>
|
||||
/// Perform further extraction/population of this item as necessary.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="cx">The extraction context.</param>
|
||||
void Extract(Context cx);
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// When we decode a type/method signature, we need access to
|
||||
/// generic parameters.
|
||||
/// </summary>
|
||||
internal interface IGenericContext
|
||||
{
|
||||
Context Context { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of generic type parameters/arguments, including type parameters/arguments of
|
||||
/// containing types.
|
||||
/// </summary>
|
||||
IEnumerable<Entities.Type> TypeParameters { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of generic method parameters/arguments.
|
||||
/// </summary>
|
||||
IEnumerable<Entities.Type> MethodParameters { get; }
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// An entity that needs to be populated during extraction.
|
||||
/// This assigns a key and optionally extracts its contents.
|
||||
/// </summary>
|
||||
internal abstract class LabelledEntity : Extraction.LabelledEntity, IExtractedEntity
|
||||
{
|
||||
public override Context Context => (Context)base.Context;
|
||||
|
||||
protected LabelledEntity(Context cx) : base(cx)
|
||||
{
|
||||
}
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException();
|
||||
|
||||
public void Extract(Context cx2)
|
||||
{
|
||||
cx2.Populate(this);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
using var writer = new EscapingTextWriter();
|
||||
WriteQuotedId(writer);
|
||||
return writer.ToString();
|
||||
}
|
||||
|
||||
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
|
||||
|
||||
public abstract IEnumerable<IExtractionProduct> Contents { get; }
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// A tuple that is an extraction product.
|
||||
/// </summary>
|
||||
internal class Tuple : IExtractionProduct
|
||||
{
|
||||
private readonly Extraction.Tuple tuple;
|
||||
|
||||
public Tuple(string name, params object[] args)
|
||||
{
|
||||
tuple = new Extraction.Tuple(name, args);
|
||||
}
|
||||
|
||||
public void Extract(Context cx)
|
||||
{
|
||||
cx.TrapWriter.Emit(tuple);
|
||||
}
|
||||
|
||||
public override string ToString() => tuple.ToString();
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// An entity that has contents to extract. There is no need to populate
|
||||
/// a key as it's done in the constructor.
|
||||
/// </summary>
|
||||
internal abstract class UnlabelledEntity : Extraction.UnlabelledEntity, IExtractedEntity
|
||||
{
|
||||
public override Context Context => (Context)base.Context;
|
||||
|
||||
protected UnlabelledEntity(Context cx) : base(cx)
|
||||
{
|
||||
}
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException();
|
||||
|
||||
public void Extract(Context cx2)
|
||||
{
|
||||
cx2.Extract(this);
|
||||
}
|
||||
|
||||
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
|
||||
|
||||
public abstract IEnumerable<IExtractionProduct> Contents { get; }
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Types that are passed by reference are not written directly to trap files. Instead, the annotation is stored on
|
||||
/// the entity.
|
||||
/// </summary>
|
||||
internal sealed class ByRefType : Type
|
||||
{
|
||||
public ByRefType(Context cx, Type elementType) : base(cx)
|
||||
{
|
||||
ElementType = elementType;
|
||||
}
|
||||
|
||||
public override CilTypeKind Kind => throw new NotImplementedException();
|
||||
|
||||
public override Namespace? ContainingNamespace => throw new NotImplementedException();
|
||||
|
||||
public override Type? ContainingType => throw new NotImplementedException();
|
||||
|
||||
public override int ThisTypeParameterCount => throw new NotImplementedException();
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
|
||||
|
||||
public override string Name => $"{ElementType.Name}&";
|
||||
|
||||
public Type ElementType { get; }
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException();
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
ElementType.WriteId(trapFile, inContext);
|
||||
trapFile.Write('&');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// The CIL database type-kind.
|
||||
/// </summary>
|
||||
public enum CilTypeKind
|
||||
{
|
||||
ValueOrRefType,
|
||||
TypeParameter,
|
||||
Array,
|
||||
Pointer,
|
||||
FunctionPointer
|
||||
}
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A constructed type.
|
||||
/// </summary>
|
||||
internal sealed class ConstructedType : Type
|
||||
{
|
||||
private readonly Type unboundGenericType;
|
||||
|
||||
// Either null or notEmpty
|
||||
private readonly Type[]? thisTypeArguments;
|
||||
|
||||
private readonly Type? containingType;
|
||||
private readonly NamedTypeIdWriter idWriter;
|
||||
|
||||
public ConstructedType(Context cx, Type unboundType, IEnumerable<Type> typeArguments) : base(cx)
|
||||
{
|
||||
idWriter = new NamedTypeIdWriter(this);
|
||||
var suppliedArgs = typeArguments.Count();
|
||||
if (suppliedArgs != unboundType.TotalTypeParametersCount)
|
||||
throw new InternalError("Unexpected number of type arguments in ConstructedType");
|
||||
|
||||
unboundGenericType = unboundType;
|
||||
var thisParams = unboundType.ThisTypeParameterCount;
|
||||
|
||||
if (typeArguments.Count() == thisParams)
|
||||
{
|
||||
containingType = unboundType.ContainingType;
|
||||
thisTypeArguments = typeArguments.ToArray();
|
||||
}
|
||||
else if (thisParams == 0)
|
||||
{
|
||||
// all type arguments belong to containing type
|
||||
containingType = unboundType.ContainingType!.Construct(typeArguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
// some type arguments belong to containing type
|
||||
var parentParams = suppliedArgs - thisParams;
|
||||
containingType = unboundType.ContainingType!.Construct(typeArguments.Take(parentParams));
|
||||
thisTypeArguments = typeArguments.Skip(parentParams).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is ConstructedType t && Equals(unboundGenericType, t.unboundGenericType) && Equals(containingType, t.containingType))
|
||||
{
|
||||
if (thisTypeArguments is null)
|
||||
return t.thisTypeArguments is null;
|
||||
if (!(t.thisTypeArguments is null))
|
||||
return thisTypeArguments.SequenceEqual(t.thisTypeArguments);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var h = unboundGenericType.GetHashCode();
|
||||
h = 13 * h + (containingType is null ? 0 : containingType.GetHashCode());
|
||||
if (!(thisTypeArguments is null))
|
||||
h = h * 13 + thisTypeArguments.SequenceHash();
|
||||
return h;
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var c in base.Contents)
|
||||
yield return c;
|
||||
|
||||
var i = 0;
|
||||
foreach (var type in ThisTypeArguments)
|
||||
{
|
||||
yield return type;
|
||||
yield return Tuples.cil_type_argument(this, i++, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override Type SourceDeclaration => unboundGenericType;
|
||||
|
||||
public override Type? ContainingType => containingType;
|
||||
|
||||
public override string Name => unboundGenericType.Name;
|
||||
|
||||
public override Namespace ContainingNamespace => unboundGenericType.ContainingNamespace!;
|
||||
|
||||
public override CilTypeKind Kind => unboundGenericType.Kind;
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
idWriter.WriteId(trapFile, inContext);
|
||||
}
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) => unboundGenericType.WriteAssemblyPrefix(trapFile);
|
||||
|
||||
public override int ThisTypeParameterCount => thisTypeArguments?.Length ?? 0;
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => GenericArguments;
|
||||
|
||||
public override IEnumerable<Type> ThisTypeArguments => thisTypeArguments.EnumerateNull();
|
||||
|
||||
public override IEnumerable<Type> ThisGenericArguments => thisTypeArguments.EnumerateNull();
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to decode the attribute structure.
|
||||
/// Note that there are some unhandled cases that should be fixed in due course.
|
||||
/// </summary>
|
||||
internal class CustomAttributeDecoder : ICustomAttributeTypeProvider<Type>
|
||||
{
|
||||
private readonly Context cx;
|
||||
public CustomAttributeDecoder(Context cx) { this.cx = cx; }
|
||||
|
||||
public Type GetPrimitiveType(PrimitiveTypeCode typeCode) => cx.Create(typeCode);
|
||||
|
||||
public Type GetSystemType() => new NoMetadataHandleType(cx, "System.Type");
|
||||
|
||||
public Type GetSZArrayType(Type elementType) =>
|
||||
cx.Populate(new ArrayType(cx, elementType));
|
||||
|
||||
public Type GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) =>
|
||||
(Type)cx.Create(handle);
|
||||
|
||||
public Type GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) =>
|
||||
(Type)cx.Create(handle);
|
||||
|
||||
public Type GetTypeFromSerializedName(string name) => new NoMetadataHandleType(cx, name);
|
||||
|
||||
public PrimitiveTypeCode GetUnderlyingEnumType(Type type)
|
||||
{
|
||||
if (type is TypeDefinitionType tdt &&
|
||||
tdt.GetUnderlyingEnumType() is PrimitiveTypeCode underlying)
|
||||
{
|
||||
return underlying;
|
||||
}
|
||||
|
||||
var name = type.GetQualifiedName();
|
||||
|
||||
if (wellKnownEnums.TryGetValue(name, out var code))
|
||||
{
|
||||
cx.Extractor.Logger.Log(Util.Logging.Severity.Debug, $"Using hard coded underlying enum type for {name}");
|
||||
return code;
|
||||
}
|
||||
|
||||
cx.Extractor.Logger.Log(Util.Logging.Severity.Info, $"Couldn't get underlying enum type for {name}");
|
||||
|
||||
// We can't fall back to Int32, because the type returned here defines how many bytes are read from the
|
||||
// stream and how those bytes are interpreted.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsSystemType(Type type) => type.GetQualifiedName() == "System.Type";
|
||||
|
||||
private static readonly Dictionary<string, PrimitiveTypeCode> wellKnownEnums = new Dictionary<string, PrimitiveTypeCode>
|
||||
{
|
||||
{ "System.AttributeTargets", PrimitiveTypeCode.Int32 },
|
||||
{ "System.ComponentModel.EditorBrowsableState", PrimitiveTypeCode.Int32 },
|
||||
{ "System.Diagnostics.DebuggerBrowsableState", PrimitiveTypeCode.Int32 }
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class DefinitionField : Field
|
||||
{
|
||||
private readonly Handle handle;
|
||||
private readonly FieldDefinition fd;
|
||||
|
||||
public DefinitionField(Context cx, FieldDefinitionHandle handle) : base(cx)
|
||||
{
|
||||
this.handle = handle;
|
||||
fd = Context.MdReader.GetFieldDefinition(handle);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is DefinitionField field && handle.Equals(field.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.metadata_handle(this, Context.Assembly, MetadataTokens.GetToken(handle));
|
||||
|
||||
foreach (var c in base.Contents)
|
||||
yield return c;
|
||||
|
||||
if (fd.Attributes.HasFlag(FieldAttributes.Private))
|
||||
yield return Tuples.cil_private(this);
|
||||
|
||||
if (fd.Attributes.HasFlag(FieldAttributes.Public))
|
||||
yield return Tuples.cil_public(this);
|
||||
|
||||
if (fd.Attributes.HasFlag(FieldAttributes.Family))
|
||||
yield return Tuples.cil_protected(this);
|
||||
|
||||
if (fd.Attributes.HasFlag(FieldAttributes.Static))
|
||||
yield return Tuples.cil_static(this);
|
||||
|
||||
if (fd.Attributes.HasFlag(FieldAttributes.Assembly))
|
||||
yield return Tuples.cil_internal(this);
|
||||
|
||||
foreach (var c in Attribute.Populate(Context, this, fd.GetCustomAttributes()))
|
||||
yield return c;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Name => Context.GetString(fd.Name);
|
||||
|
||||
public override Type DeclaringType => (Type)Context.Create(fd.GetDeclaringType());
|
||||
|
||||
public override Type Type => fd.DecodeSignature(Context.TypeSignatureDecoder, DeclaringType);
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -1,299 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A definition method - a method defined in the current assembly.
|
||||
/// </summary>
|
||||
internal sealed class DefinitionMethod : Method
|
||||
{
|
||||
private readonly Handle handle;
|
||||
private readonly MethodDefinition md;
|
||||
private readonly PDB.Method? methodDebugInformation;
|
||||
private readonly Type declaringType;
|
||||
|
||||
private readonly string name;
|
||||
private LocalVariable[]? locals;
|
||||
|
||||
public MethodImplementation? Implementation { get; private set; }
|
||||
|
||||
public override IList<LocalVariable>? LocalVariables => locals;
|
||||
|
||||
public DefinitionMethod(IGenericContext gc, MethodDefinitionHandle handle) : base(gc)
|
||||
{
|
||||
md = Context.MdReader.GetMethodDefinition(handle);
|
||||
this.gc = gc;
|
||||
this.handle = handle;
|
||||
name = Context.GetString(md.Name);
|
||||
|
||||
declaringType = (Type)Context.CreateGeneric(this, md.GetDeclaringType());
|
||||
|
||||
signature = md.DecodeSignature(new SignatureDecoder(), this);
|
||||
|
||||
methodDebugInformation = Context.GetMethodDebugInformation(handle);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is DefinitionMethod method && handle.Equals(method.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override bool IsStatic => !signature.Header.IsInstance;
|
||||
|
||||
public override Type DeclaringType => declaringType;
|
||||
|
||||
public override string Name => Context.ShortName(md.Name);
|
||||
|
||||
public override string NameLabel => name;
|
||||
|
||||
/// <summary>
|
||||
/// Holds if this method has bytecode.
|
||||
/// </summary>
|
||||
public bool HasBytecode => md.ImplAttributes == MethodImplAttributes.IL && md.RelativeVirtualAddress != 0;
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
if (md.GetGenericParameters().Any())
|
||||
{
|
||||
// We need to perform a 2-phase population because some type parameters can
|
||||
// depend on other type parameters (as a constraint).
|
||||
genericParams = new MethodTypeParameter[md.GetGenericParameters().Count];
|
||||
for (var i = 0; i < genericParams.Length; ++i)
|
||||
genericParams[i] = Context.Populate(new MethodTypeParameter(this, this, i));
|
||||
for (var i = 0; i < genericParams.Length; ++i)
|
||||
genericParams[i].PopulateHandle(md.GetGenericParameters()[i]);
|
||||
foreach (var p in genericParams)
|
||||
yield return p;
|
||||
}
|
||||
|
||||
var typeSignature = md.DecodeSignature(Context.TypeSignatureDecoder, this);
|
||||
|
||||
var parameters = GetParameterExtractionProducts(typeSignature.ParameterTypes).ToArray();
|
||||
Parameters = parameters.OfType<Parameter>().ToArray();
|
||||
|
||||
foreach (var c in parameters)
|
||||
yield return c;
|
||||
|
||||
foreach (var c in PopulateFlags)
|
||||
yield return c;
|
||||
|
||||
foreach (var p in md.GetParameters().Select(h => Context.MdReader.GetParameter(h)).Where(p => p.SequenceNumber > 0))
|
||||
{
|
||||
var pe = Parameters[IsStatic ? p.SequenceNumber - 1 : p.SequenceNumber];
|
||||
if (p.Attributes.HasFlag(ParameterAttributes.Out))
|
||||
yield return Tuples.cil_parameter_out(pe);
|
||||
if (p.Attributes.HasFlag(ParameterAttributes.In))
|
||||
yield return Tuples.cil_parameter_in(pe);
|
||||
foreach (var c in Attribute.Populate(Context, pe, p.GetCustomAttributes()))
|
||||
yield return c;
|
||||
}
|
||||
|
||||
yield return Tuples.metadata_handle(this, Context.Assembly, MetadataTokens.GetToken(handle));
|
||||
|
||||
foreach (var m in GetMethodExtractionProducts(Name, declaringType, typeSignature.ReturnType))
|
||||
{
|
||||
yield return m;
|
||||
}
|
||||
|
||||
yield return Tuples.cil_method_source_declaration(this, this);
|
||||
yield return Tuples.cil_method_location(this, Context.Assembly);
|
||||
|
||||
if (HasBytecode)
|
||||
{
|
||||
Implementation = new MethodImplementation(this);
|
||||
yield return Implementation;
|
||||
|
||||
var body = Context.PeReader.GetMethodBody(md.RelativeVirtualAddress);
|
||||
|
||||
if (!body.LocalSignature.IsNil)
|
||||
{
|
||||
var localVariableTypes = System.Collections.Immutable.ImmutableArray<Type>.Empty;
|
||||
var hasError = false;
|
||||
try
|
||||
{
|
||||
var locals = Context.MdReader.GetStandaloneSignature(body.LocalSignature);
|
||||
localVariableTypes = locals.DecodeLocalSignature(Context.TypeSignatureDecoder, this);
|
||||
}
|
||||
catch (System.BadImageFormatException exc)
|
||||
{
|
||||
Context.Extractor.Logger.Log(Util.Logging.Severity.Info,
|
||||
$"Could not decode locals in method {declaringType.GetQualifiedName()}.{name}. {exc}");
|
||||
hasError = true;
|
||||
}
|
||||
|
||||
if (!hasError)
|
||||
{
|
||||
this.locals = new LocalVariable[localVariableTypes.Length];
|
||||
|
||||
for (var l = 0; l < this.locals.Length; ++l)
|
||||
{
|
||||
var t = localVariableTypes[l];
|
||||
if (t is ByRefType brt)
|
||||
{
|
||||
t = brt.ElementType;
|
||||
this.locals[l] = Context.Populate(new LocalVariable(Context, Implementation, l, t));
|
||||
yield return this.locals[l];
|
||||
yield return Tuples.cil_type_annotation(this.locals[l], TypeAnnotation.Ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.locals[l] = Context.Populate(new LocalVariable(Context, Implementation, l, t));
|
||||
yield return this.locals[l];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var jump_table = new Dictionary<int, Instruction>();
|
||||
|
||||
foreach (var c in Decode(body.GetILBytes(), jump_table))
|
||||
yield return c;
|
||||
|
||||
var filter_index = 0;
|
||||
foreach (var region in body.ExceptionRegions)
|
||||
{
|
||||
yield return new ExceptionRegion(this, Implementation, filter_index++, region, jump_table);
|
||||
}
|
||||
|
||||
yield return Tuples.cil_method_stack_size(Implementation, body.MaxStack);
|
||||
|
||||
if (methodDebugInformation is not null)
|
||||
{
|
||||
var sourceLocation = Context.CreateSourceLocation(methodDebugInformation.Location);
|
||||
yield return sourceLocation;
|
||||
yield return Tuples.cil_method_location(this, sourceLocation);
|
||||
}
|
||||
}
|
||||
|
||||
// Flags
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.Private))
|
||||
yield return Tuples.cil_private(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.Public))
|
||||
yield return Tuples.cil_public(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.Family))
|
||||
yield return Tuples.cil_protected(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.Final))
|
||||
yield return Tuples.cil_sealed(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.Virtual))
|
||||
yield return Tuples.cil_virtual(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.Abstract))
|
||||
yield return Tuples.cil_abstract(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.HasSecurity))
|
||||
yield return Tuples.cil_security(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.RequireSecObject))
|
||||
yield return Tuples.cil_requiresecobject(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.SpecialName))
|
||||
yield return Tuples.cil_specialname(this);
|
||||
|
||||
if (md.Attributes.HasFlag(MethodAttributes.NewSlot))
|
||||
yield return Tuples.cil_newslot(this);
|
||||
|
||||
// Populate attributes
|
||||
foreach (var c in Attribute.Populate(Context, this, md.GetCustomAttributes()))
|
||||
yield return c;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<IExtractionProduct> Decode(byte[]? ilbytes, Dictionary<int, Instruction> jump_table)
|
||||
{
|
||||
// Sequence points are stored in order of offset.
|
||||
// We use an enumerator to locate the correct sequence point for each instruction.
|
||||
// The sequence point gives the location of each instruction.
|
||||
// The location of an instruction is given by the sequence point *after* the
|
||||
// instruction.
|
||||
IEnumerator<PDB.SequencePoint>? nextSequencePoint = null;
|
||||
PdbSourceLocation? instructionLocation = null;
|
||||
|
||||
if (methodDebugInformation is not null)
|
||||
{
|
||||
nextSequencePoint = methodDebugInformation.SequencePoints.GetEnumerator();
|
||||
if (nextSequencePoint.MoveNext())
|
||||
{
|
||||
instructionLocation = Context.CreateSourceLocation(nextSequencePoint.Current.Location);
|
||||
yield return instructionLocation;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextSequencePoint = null;
|
||||
}
|
||||
}
|
||||
|
||||
var child = 0;
|
||||
for (var offset = 0; offset < (ilbytes?.Length ?? 0);)
|
||||
{
|
||||
var instruction = new Instruction(Context, this, ilbytes!, offset, child++);
|
||||
yield return instruction;
|
||||
|
||||
if (nextSequencePoint is not null && offset >= nextSequencePoint.Current.Offset)
|
||||
{
|
||||
instructionLocation = Context.CreateSourceLocation(nextSequencePoint.Current.Location);
|
||||
yield return instructionLocation;
|
||||
if (!nextSequencePoint.MoveNext())
|
||||
nextSequencePoint = null;
|
||||
}
|
||||
|
||||
if (instructionLocation is not null)
|
||||
yield return Tuples.cil_instruction_location(instruction, instructionLocation);
|
||||
|
||||
jump_table.Add(instruction.Offset, instruction);
|
||||
offset += instruction.Width;
|
||||
}
|
||||
|
||||
foreach (var i in jump_table)
|
||||
{
|
||||
foreach (var t in i.Value.JumpContents(jump_table))
|
||||
yield return t;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display the instructions in the method in the debugger.
|
||||
/// This is only used for debugging, not in the code itself.
|
||||
/// </summary>
|
||||
public IEnumerable<Instruction> DebugInstructions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (md.ImplAttributes == MethodImplAttributes.IL && md.RelativeVirtualAddress != 0)
|
||||
{
|
||||
var body = Context.PeReader.GetMethodBody(md.RelativeVirtualAddress);
|
||||
|
||||
var ilbytes = body.GetILBytes();
|
||||
|
||||
var child = 0;
|
||||
for (var offset = 0; offset < (ilbytes?.Length ?? 0);)
|
||||
{
|
||||
Instruction decoded;
|
||||
try
|
||||
{
|
||||
decoded = new Instruction(Context, this, ilbytes!, offset, child++);
|
||||
offset += decoded.Width;
|
||||
}
|
||||
catch // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
yield return decoded;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class ErrorType : Type
|
||||
{
|
||||
public ErrorType(Context cx) : base(cx)
|
||||
{
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext) => trapFile.Write("<ErrorType>");
|
||||
|
||||
public override CilTypeKind Kind => CilTypeKind.ValueOrRefType;
|
||||
|
||||
public override string Name => "!error";
|
||||
|
||||
public override Namespace ContainingNamespace => Context.GlobalNamespace;
|
||||
|
||||
public override Type? ContainingType => null;
|
||||
|
||||
public override int ThisTypeParameterCount => 0;
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException();
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An event entity.
|
||||
/// </summary>
|
||||
internal sealed class Event : LabelledEntity
|
||||
{
|
||||
private readonly EventDefinitionHandle handle;
|
||||
private readonly Type parent;
|
||||
private readonly EventDefinition ed;
|
||||
|
||||
public Event(Context cx, Type parent, EventDefinitionHandle handle) : base(cx)
|
||||
{
|
||||
this.handle = handle;
|
||||
this.parent = parent;
|
||||
ed = cx.MdReader.GetEventDefinition(handle);
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
parent.WriteId(trapFile);
|
||||
trapFile.Write('.');
|
||||
trapFile.Write(Context.ShortName(ed.Name));
|
||||
trapFile.Write(";cil-event");
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Event e && handle.Equals(e.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
var signature = (Type)Context.CreateGeneric(parent, ed.Type);
|
||||
yield return signature;
|
||||
|
||||
yield return Tuples.cil_event(this, parent, Context.ShortName(ed.Name), signature);
|
||||
|
||||
var accessors = ed.GetAccessors();
|
||||
if (!accessors.Adder.IsNil)
|
||||
{
|
||||
var adder = (Method)Context.CreateGeneric(parent, accessors.Adder);
|
||||
yield return adder;
|
||||
yield return Tuples.cil_adder(this, adder);
|
||||
}
|
||||
|
||||
if (!accessors.Remover.IsNil)
|
||||
{
|
||||
var remover = (Method)Context.CreateGeneric(parent, accessors.Remover);
|
||||
yield return remover;
|
||||
yield return Tuples.cil_remover(this, remover);
|
||||
}
|
||||
|
||||
if (!accessors.Raiser.IsNil)
|
||||
{
|
||||
var raiser = (Method)Context.CreateGeneric(parent, accessors.Raiser);
|
||||
yield return raiser;
|
||||
yield return Tuples.cil_raiser(this, raiser);
|
||||
}
|
||||
|
||||
foreach (var c in Attribute.Populate(Context, this, ed.GetCustomAttributes()))
|
||||
yield return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception region entity.
|
||||
/// </summary>
|
||||
internal class ExceptionRegion : UnlabelledEntity
|
||||
{
|
||||
private readonly IGenericContext gc;
|
||||
private readonly MethodImplementation method;
|
||||
private readonly int index;
|
||||
private readonly System.Reflection.Metadata.ExceptionRegion r;
|
||||
private readonly Dictionary<int, Instruction> jump_table;
|
||||
|
||||
public ExceptionRegion(IGenericContext gc, MethodImplementation method, int index, System.Reflection.Metadata.ExceptionRegion r, Dictionary<int, Instruction> jump_table) : base(gc.Context)
|
||||
{
|
||||
this.gc = gc;
|
||||
this.method = method;
|
||||
this.index = index;
|
||||
this.r = r;
|
||||
this.jump_table = jump_table;
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
if (!jump_table.TryGetValue(r.TryOffset, out var try_start))
|
||||
throw new InternalError("Failed to retrieve handler");
|
||||
if (!jump_table.TryGetValue(r.TryOffset + r.TryLength, out var try_end))
|
||||
throw new InternalError("Failed to retrieve handler");
|
||||
if (!jump_table.TryGetValue(r.HandlerOffset, out var handler_start))
|
||||
throw new InternalError("Failed to retrieve handler");
|
||||
|
||||
yield return Tuples.cil_handler(this, method, index, (int)r.Kind, try_start, try_end, handler_start);
|
||||
|
||||
if (r.FilterOffset != -1)
|
||||
{
|
||||
if (!jump_table.TryGetValue(r.FilterOffset, out var filter_start))
|
||||
throw new InternalError("ExceptionRegion filter clause");
|
||||
|
||||
yield return Tuples.cil_handler_filter(this, filter_start);
|
||||
}
|
||||
|
||||
if (!r.CatchType.IsNil)
|
||||
{
|
||||
var catchType = (Type)Context.CreateGeneric(gc, r.CatchType);
|
||||
yield return catchType;
|
||||
yield return Tuples.cil_handler_type(this, catchType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An entity representing a field.
|
||||
/// </summary>
|
||||
internal abstract class Field : LabelledEntity, IGenericContext, IMember, ICustomModifierReceiver
|
||||
{
|
||||
protected Field(Context cx) : base(cx)
|
||||
{
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(DeclaringType);
|
||||
trapFile.Write('.');
|
||||
trapFile.Write(Name);
|
||||
trapFile.Write(";cil-field");
|
||||
}
|
||||
|
||||
public abstract string Name { get; }
|
||||
|
||||
public abstract Type DeclaringType { get; }
|
||||
|
||||
public abstract Type Type { get; }
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
var t = Type;
|
||||
if (t is ModifiedType mt)
|
||||
{
|
||||
t = mt.Unmodified;
|
||||
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
|
||||
}
|
||||
if (t is ByRefType brt)
|
||||
{
|
||||
t = brt.ElementType;
|
||||
yield return Tuples.cil_type_annotation(this, TypeAnnotation.Ref);
|
||||
}
|
||||
yield return Tuples.cil_field(this, DeclaringType, Name, t);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract IEnumerable<Type> TypeParameters { get; }
|
||||
|
||||
public abstract IEnumerable<Type> MethodParameters { get; }
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal class File : LabelledEntity, IFileOrFolder
|
||||
{
|
||||
protected string OriginalPath { get; }
|
||||
protected PathTransformer.ITransformedPath TransformedPath { get; }
|
||||
|
||||
public File(Context cx, string path) : base(cx)
|
||||
{
|
||||
this.OriginalPath = path;
|
||||
TransformedPath = Context.Extractor.PathTransformer.Transform(OriginalPath);
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(TransformedPath.DatabaseId);
|
||||
trapFile.Write(";sourcefile");
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return GetType() == obj?.GetType() && OriginalPath == ((File)obj).OriginalPath;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => 11 * OriginalPath.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
if (TransformedPath.ParentDirectory is PathTransformer.ITransformedPath dir)
|
||||
{
|
||||
var parent = Context.CreateFolder(dir);
|
||||
yield return parent;
|
||||
yield return Tuples.containerparent(parent, this);
|
||||
}
|
||||
yield return Tuples.files(this, TransformedPath.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class Folder : LabelledEntity, IFileOrFolder
|
||||
{
|
||||
private readonly PathTransformer.ITransformedPath transformedPath;
|
||||
|
||||
public Folder(Context cx, PathTransformer.ITransformedPath path) : base(cx)
|
||||
{
|
||||
this.transformedPath = path;
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(transformedPath.DatabaseId);
|
||||
trapFile.Write(";folder");
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
if (transformedPath.ParentDirectory is PathTransformer.ITransformedPath parent)
|
||||
{
|
||||
var parentFolder = Context.CreateFolder(parent);
|
||||
yield return parentFolder;
|
||||
yield return Tuples.containerparent(parentFolder, this);
|
||||
}
|
||||
yield return Tuples.folders(this, transformedPath.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Folder folder && transformedPath == folder.transformedPath;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => transformedPath.GetHashCode();
|
||||
}
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class FunctionPointerType : Type, IParameterizable, ICustomModifierReceiver
|
||||
{
|
||||
private readonly MethodSignature<Type> signature;
|
||||
|
||||
public FunctionPointerType(Context cx, MethodSignature<Type> signature) : base(cx)
|
||||
{
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public override CilTypeKind Kind => CilTypeKind.FunctionPointer;
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
using var id = new StringWriter();
|
||||
WriteName(
|
||||
id.Write,
|
||||
t => id.Write(t.Name),
|
||||
signature
|
||||
);
|
||||
return id.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public override Namespace? ContainingNamespace => Context.GlobalNamespace;
|
||||
|
||||
public override Type? ContainingType => null;
|
||||
|
||||
public override int ThisTypeParameterCount => throw new System.NotImplementedException();
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new System.NotImplementedException();
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments) => throw new System.NotImplementedException();
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) { }
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
WriteName(
|
||||
trapFile.Write,
|
||||
t => t.WriteId(trapFile, inContext),
|
||||
signature
|
||||
);
|
||||
}
|
||||
|
||||
internal static void WriteName<TType>(Action<string> write, Action<TType> writeType, MethodSignature<TType> signature)
|
||||
{
|
||||
write("delegate* ");
|
||||
write(GetCallingConvention(signature.Header.CallingConvention));
|
||||
write("<");
|
||||
foreach (var pt in signature.ParameterTypes)
|
||||
{
|
||||
writeType(pt);
|
||||
write(",");
|
||||
}
|
||||
writeType(signature.ReturnType);
|
||||
write(">");
|
||||
}
|
||||
|
||||
internal static string GetCallingConvention(SignatureCallingConvention callingConvention)
|
||||
{
|
||||
if (callingConvention == SignatureCallingConvention.Default)
|
||||
{
|
||||
return "managed";
|
||||
}
|
||||
|
||||
if (callingConvention == SignatureCallingConvention.Unmanaged)
|
||||
{
|
||||
return "unmanaged";
|
||||
}
|
||||
|
||||
return $"unmanaged[{callingConvention}]";
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var c in base.Contents)
|
||||
{
|
||||
yield return c;
|
||||
}
|
||||
|
||||
var retType = signature.ReturnType;
|
||||
if (retType is ModifiedType mt)
|
||||
{
|
||||
retType = mt.Unmodified;
|
||||
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
|
||||
}
|
||||
if (retType is ByRefType byRefType)
|
||||
{
|
||||
retType = byRefType.ElementType;
|
||||
yield return Tuples.cil_type_annotation(this, TypeAnnotation.Ref);
|
||||
}
|
||||
yield return Tuples.cil_function_pointer_return_type(this, retType);
|
||||
|
||||
yield return Tuples.cil_function_pointer_calling_conventions(this, signature.Header.CallingConvention);
|
||||
|
||||
foreach (var p in Method.GetParameterExtractionProducts(signature.ParameterTypes, this, this, Context, 0))
|
||||
{
|
||||
yield return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal static class GenericsHelper
|
||||
{
|
||||
public static TypeTypeParameter[] MakeTypeParameters(Type container, int count)
|
||||
{
|
||||
var newTypeParams = new TypeTypeParameter[count];
|
||||
for (var i = 0; i < newTypeParams.Length; ++i)
|
||||
{
|
||||
newTypeParams[i] = new TypeTypeParameter(container, i);
|
||||
}
|
||||
return newTypeParams;
|
||||
}
|
||||
|
||||
public static string GetNonGenericName(StringHandle name, MetadataReader reader)
|
||||
{
|
||||
var n = reader.GetString(name);
|
||||
return GetNonGenericName(n);
|
||||
}
|
||||
|
||||
public static string GetNonGenericName(string name)
|
||||
{
|
||||
var tick = name.LastIndexOf('`');
|
||||
return tick == -1
|
||||
? name
|
||||
: name.Substring(0, tick);
|
||||
}
|
||||
|
||||
public static int GetGenericTypeParameterCount(StringHandle name, MetadataReader reader)
|
||||
{
|
||||
var n = reader.GetString(name);
|
||||
return GetGenericTypeParameterCount(n);
|
||||
}
|
||||
|
||||
public static int GetGenericTypeParameterCount(string name)
|
||||
{
|
||||
var tick = name.LastIndexOf('`');
|
||||
return tick == -1
|
||||
? 0
|
||||
: int.Parse(name.Substring(tick + 1));
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> GetAllTypeParameters(Type? container, IEnumerable<TypeTypeParameter> thisTypeParameters)
|
||||
{
|
||||
if (container is not null)
|
||||
{
|
||||
foreach (var t in container.TypeParameters)
|
||||
yield return t;
|
||||
}
|
||||
|
||||
foreach (var t in thisTypeParameters)
|
||||
yield return t;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface IFileOrFolder : IEntity
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
public interface ILocation : IEntity
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An entity representing a member.
|
||||
/// Used to type tuples correctly.
|
||||
/// </summary>
|
||||
internal interface IMember : IExtractedEntity
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface IParameterizable : IEntity
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface ITypeSignature
|
||||
{
|
||||
void WriteId(EscapingTextWriter trapFile, IGenericContext gc);
|
||||
}
|
||||
}
|
|
@ -1,508 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A CIL instruction.
|
||||
/// </summary>
|
||||
internal class Instruction : UnlabelledEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// The additional data following the opcode, if any.
|
||||
/// </summary>
|
||||
public enum Payload
|
||||
{
|
||||
None, TypeTok, Field, Target8, Class,
|
||||
Method, Arg8, Local8, Target32, Int8,
|
||||
Int16, Int32, Int64, Float32, Float64,
|
||||
CallSiteDesc, Switch, String, Constructor, ValueType,
|
||||
Type, Arg16, Ignore8, Token, Local16, MethodRef
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For each Payload, how many additional bytes in the bytestream need to be read.
|
||||
/// </summary>
|
||||
private static readonly int[] payloadSizes = {
|
||||
0, 4, 4, 1, 4,
|
||||
4, 1, 1, 4, 1,
|
||||
2, 4, 8, 4, 8,
|
||||
4, -1, 4, 4, 4,
|
||||
4, 2, 1, 4, 2, 4 };
|
||||
|
||||
// Maps opcodes to payloads for each instruction.
|
||||
private static readonly Dictionary<ILOpCode, Payload> opPayload = new Dictionary<ILOpCode, Payload>()
|
||||
{
|
||||
{ ILOpCode.Nop, Payload.None },
|
||||
{ ILOpCode.Break, Payload.None },
|
||||
{ ILOpCode.Ldarg_0, Payload.None },
|
||||
{ ILOpCode.Ldarg_1, Payload.None },
|
||||
{ ILOpCode.Ldarg_2, Payload.None },
|
||||
{ ILOpCode.Ldarg_3, Payload.None },
|
||||
{ ILOpCode.Ldloc_0, Payload.None },
|
||||
{ ILOpCode.Ldloc_1, Payload.None },
|
||||
{ ILOpCode.Ldloc_2, Payload.None },
|
||||
{ ILOpCode.Ldloc_3, Payload.None },
|
||||
{ ILOpCode.Stloc_0, Payload.None },
|
||||
{ ILOpCode.Stloc_1, Payload.None },
|
||||
{ ILOpCode.Stloc_2, Payload.None },
|
||||
{ ILOpCode.Stloc_3, Payload.None },
|
||||
{ ILOpCode.Ldarg_s, Payload.Arg8 },
|
||||
{ ILOpCode.Ldarga_s, Payload.Arg8 },
|
||||
{ ILOpCode.Starg_s, Payload.Arg8 },
|
||||
{ ILOpCode.Ldloc_s, Payload.Local8 },
|
||||
{ ILOpCode.Ldloca_s, Payload.Local8 },
|
||||
{ ILOpCode.Stloc_s, Payload.Local8 },
|
||||
{ ILOpCode.Ldnull, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_m1, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_0, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_1, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_2, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_3, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_4, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_5, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_6, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_7, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_8, Payload.None },
|
||||
{ ILOpCode.Ldc_i4_s, Payload.Int8 },
|
||||
{ ILOpCode.Ldc_i4, Payload.Int32 },
|
||||
{ ILOpCode.Ldc_i8, Payload.Int64 },
|
||||
{ ILOpCode.Ldc_r4, Payload.Float32 },
|
||||
{ ILOpCode.Ldc_r8, Payload.Float64 },
|
||||
{ ILOpCode.Dup, Payload.None },
|
||||
{ ILOpCode.Pop, Payload.None },
|
||||
{ ILOpCode.Jmp, Payload.Method },
|
||||
{ ILOpCode.Call, Payload.Method },
|
||||
{ ILOpCode.Calli, Payload.CallSiteDesc },
|
||||
{ ILOpCode.Ret, Payload.None },
|
||||
{ ILOpCode.Br_s, Payload.Target8 },
|
||||
{ ILOpCode.Brfalse_s, Payload.Target8 },
|
||||
{ ILOpCode.Brtrue_s, Payload.Target8 },
|
||||
{ ILOpCode.Beq_s, Payload.Target8 },
|
||||
{ ILOpCode.Bge_s, Payload.Target8 },
|
||||
{ ILOpCode.Bgt_s, Payload.Target8 },
|
||||
{ ILOpCode.Ble_s, Payload.Target8 },
|
||||
{ ILOpCode.Blt_s, Payload.Target8 },
|
||||
{ ILOpCode.Bne_un_s, Payload.Target8 },
|
||||
{ ILOpCode.Bge_un_s, Payload.Target8 },
|
||||
{ ILOpCode.Bgt_un_s, Payload.Target8 },
|
||||
{ ILOpCode.Ble_un_s, Payload.Target8 },
|
||||
{ ILOpCode.Blt_un_s, Payload.Target8 },
|
||||
{ ILOpCode.Br, Payload.Target32 },
|
||||
{ ILOpCode.Brfalse, Payload.Target32 },
|
||||
{ ILOpCode.Brtrue, Payload.Target32 },
|
||||
{ ILOpCode.Beq, Payload.Target32 },
|
||||
{ ILOpCode.Bge, Payload.Target32 },
|
||||
{ ILOpCode.Bgt, Payload.Target32 },
|
||||
{ ILOpCode.Ble, Payload.Target32 },
|
||||
{ ILOpCode.Blt, Payload.Target32 },
|
||||
{ ILOpCode.Bne_un, Payload.Target32 },
|
||||
{ ILOpCode.Bge_un, Payload.Target32 },
|
||||
{ ILOpCode.Bgt_un, Payload.Target32 },
|
||||
{ ILOpCode.Ble_un, Payload.Target32 },
|
||||
{ ILOpCode.Blt_un, Payload.Target32 },
|
||||
{ ILOpCode.Switch, Payload.Switch },
|
||||
{ ILOpCode.Ldind_i1, Payload.None },
|
||||
{ ILOpCode.Ldind_u1, Payload.None },
|
||||
{ ILOpCode.Ldind_i2, Payload.None },
|
||||
{ ILOpCode.Ldind_u2, Payload.None },
|
||||
{ ILOpCode.Ldind_i4, Payload.None },
|
||||
{ ILOpCode.Ldind_u4, Payload.None },
|
||||
{ ILOpCode.Ldind_i8, Payload.None },
|
||||
{ ILOpCode.Ldind_i, Payload.None },
|
||||
{ ILOpCode.Ldind_r4, Payload.None },
|
||||
{ ILOpCode.Ldind_r8, Payload.None },
|
||||
{ ILOpCode.Ldind_ref, Payload.None },
|
||||
{ ILOpCode.Stind_ref, Payload.None },
|
||||
{ ILOpCode.Stind_i1, Payload.None },
|
||||
{ ILOpCode.Stind_i2, Payload.None },
|
||||
{ ILOpCode.Stind_i4, Payload.None },
|
||||
{ ILOpCode.Stind_i8, Payload.None },
|
||||
{ ILOpCode.Stind_r4, Payload.None },
|
||||
{ ILOpCode.Stind_r8, Payload.None },
|
||||
{ ILOpCode.Add, Payload.None },
|
||||
{ ILOpCode.Sub, Payload.None },
|
||||
{ ILOpCode.Mul, Payload.None },
|
||||
{ ILOpCode.Div, Payload.None },
|
||||
{ ILOpCode.Div_un, Payload.None },
|
||||
{ ILOpCode.Rem, Payload.None },
|
||||
{ ILOpCode.Rem_un, Payload.None },
|
||||
{ ILOpCode.And, Payload.None },
|
||||
{ ILOpCode.Or, Payload.None },
|
||||
{ ILOpCode.Xor, Payload.None },
|
||||
{ ILOpCode.Shl, Payload.None },
|
||||
{ ILOpCode.Shr, Payload.None },
|
||||
{ ILOpCode.Shr_un, Payload.None },
|
||||
{ ILOpCode.Neg, Payload.None },
|
||||
{ ILOpCode.Not, Payload.None },
|
||||
{ ILOpCode.Conv_i1, Payload.None },
|
||||
{ ILOpCode.Conv_i2, Payload.None },
|
||||
{ ILOpCode.Conv_i4, Payload.None },
|
||||
{ ILOpCode.Conv_i8, Payload.None },
|
||||
{ ILOpCode.Conv_r4, Payload.None },
|
||||
{ ILOpCode.Conv_r8, Payload.None },
|
||||
{ ILOpCode.Conv_u4, Payload.None },
|
||||
{ ILOpCode.Conv_u8, Payload.None },
|
||||
{ ILOpCode.Callvirt, Payload.MethodRef },
|
||||
{ ILOpCode.Cpobj, Payload.TypeTok },
|
||||
{ ILOpCode.Ldobj, Payload.TypeTok },
|
||||
{ ILOpCode.Ldstr, Payload.String },
|
||||
{ ILOpCode.Newobj, Payload.Constructor },
|
||||
{ ILOpCode.Castclass, Payload.Class },
|
||||
{ ILOpCode.Isinst, Payload.Class },
|
||||
{ ILOpCode.Conv_r_un, Payload.None },
|
||||
{ ILOpCode.Unbox, Payload.ValueType },
|
||||
{ ILOpCode.Throw, Payload.None },
|
||||
{ ILOpCode.Ldfld, Payload.Field },
|
||||
{ ILOpCode.Ldflda, Payload.Field },
|
||||
{ ILOpCode.Stfld, Payload.Field },
|
||||
{ ILOpCode.Ldsfld, Payload.Field },
|
||||
{ ILOpCode.Ldsflda, Payload.Field },
|
||||
{ ILOpCode.Stsfld, Payload.Field },
|
||||
{ ILOpCode.Stobj, Payload.Field },
|
||||
{ ILOpCode.Conv_ovf_i1_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i2_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i4_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i8_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u1_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u2_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u4_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u8_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i_un, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u_un, Payload.None },
|
||||
{ ILOpCode.Box, Payload.TypeTok },
|
||||
{ ILOpCode.Newarr, Payload.TypeTok },
|
||||
{ ILOpCode.Ldlen, Payload.None },
|
||||
{ ILOpCode.Ldelema, Payload.Class },
|
||||
{ ILOpCode.Ldelem_i1, Payload.None },
|
||||
{ ILOpCode.Ldelem_u1, Payload.None },
|
||||
{ ILOpCode.Ldelem_i2, Payload.None },
|
||||
{ ILOpCode.Ldelem_u2, Payload.None },
|
||||
{ ILOpCode.Ldelem_i4, Payload.None },
|
||||
{ ILOpCode.Ldelem_u4, Payload.None },
|
||||
{ ILOpCode.Ldelem_i8, Payload.None },
|
||||
{ ILOpCode.Ldelem_i, Payload.None },
|
||||
{ ILOpCode.Ldelem_r4, Payload.None },
|
||||
{ ILOpCode.Ldelem_r8, Payload.None },
|
||||
{ ILOpCode.Ldelem_ref, Payload.None },
|
||||
{ ILOpCode.Stelem_i, Payload.None },
|
||||
{ ILOpCode.Stelem_i1, Payload.None },
|
||||
{ ILOpCode.Stelem_i2, Payload.None },
|
||||
{ ILOpCode.Stelem_i4, Payload.None },
|
||||
{ ILOpCode.Stelem_i8, Payload.None },
|
||||
{ ILOpCode.Stelem_r4, Payload.None },
|
||||
{ ILOpCode.Stelem_r8, Payload.None },
|
||||
{ ILOpCode.Stelem_ref, Payload.None },
|
||||
{ ILOpCode.Ldelem, Payload.TypeTok },
|
||||
{ ILOpCode.Stelem, Payload.TypeTok },
|
||||
{ ILOpCode.Unbox_any, Payload.TypeTok },
|
||||
{ ILOpCode.Conv_ovf_i1, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u1, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i2, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u2, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i4, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u4, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i8, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u8, Payload.None },
|
||||
{ ILOpCode.Refanyval, Payload.Type },
|
||||
{ ILOpCode.Ckfinite, Payload.None },
|
||||
{ ILOpCode.Mkrefany, Payload.Class },
|
||||
{ ILOpCode.Ldtoken, Payload.Token },
|
||||
{ ILOpCode.Conv_u2, Payload.None },
|
||||
{ ILOpCode.Conv_u1, Payload.None },
|
||||
{ ILOpCode.Conv_i, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_i, Payload.None },
|
||||
{ ILOpCode.Conv_ovf_u, Payload.None },
|
||||
{ ILOpCode.Add_ovf, Payload.None },
|
||||
{ ILOpCode.Add_ovf_un, Payload.None },
|
||||
{ ILOpCode.Mul_ovf, Payload.None },
|
||||
{ ILOpCode.Mul_ovf_un, Payload.None },
|
||||
{ ILOpCode.Sub_ovf, Payload.None },
|
||||
{ ILOpCode.Sub_ovf_un, Payload.None },
|
||||
{ ILOpCode.Endfinally, Payload.None },
|
||||
{ ILOpCode.Leave, Payload.Target32 },
|
||||
{ ILOpCode.Leave_s, Payload.Target8 },
|
||||
{ ILOpCode.Stind_i, Payload.None },
|
||||
{ ILOpCode.Conv_u, Payload.None },
|
||||
{ ILOpCode.Arglist, Payload.None },
|
||||
{ ILOpCode.Ceq, Payload.None },
|
||||
{ ILOpCode.Cgt, Payload.None },
|
||||
{ ILOpCode.Cgt_un, Payload.None },
|
||||
{ ILOpCode.Clt, Payload.None },
|
||||
{ ILOpCode.Clt_un, Payload.None },
|
||||
{ ILOpCode.Ldftn, Payload.Method },
|
||||
{ ILOpCode.Ldvirtftn, Payload.Method },
|
||||
{ ILOpCode.Ldarg, Payload.Arg16 },
|
||||
{ ILOpCode.Ldarga, Payload.Arg16 },
|
||||
{ ILOpCode.Starg, Payload.Arg16 },
|
||||
{ ILOpCode.Ldloc, Payload.Local16 },
|
||||
{ ILOpCode.Ldloca, Payload.Local16 },
|
||||
{ ILOpCode.Stloc, Payload.Local16 },
|
||||
{ ILOpCode.Localloc, Payload.None },
|
||||
{ ILOpCode.Endfilter, Payload.None },
|
||||
{ ILOpCode.Unaligned, Payload.Ignore8 },
|
||||
{ ILOpCode.Volatile, Payload.None },
|
||||
{ ILOpCode.Tail, Payload.None },
|
||||
{ ILOpCode.Initobj, Payload.TypeTok },
|
||||
{ ILOpCode.Constrained, Payload.Type },
|
||||
{ ILOpCode.Cpblk, Payload.None },
|
||||
{ ILOpCode.Initblk, Payload.None },
|
||||
{ ILOpCode.Rethrow, Payload.None },
|
||||
{ ILOpCode.Sizeof, Payload.TypeTok },
|
||||
{ ILOpCode.Refanytype, Payload.None },
|
||||
{ ILOpCode.Readonly, Payload.None }
|
||||
};
|
||||
|
||||
public DefinitionMethod Method { get; }
|
||||
public ILOpCode OpCode { get; }
|
||||
public int Offset { get; }
|
||||
public int Index { get; }
|
||||
private readonly int payloadValue;
|
||||
private readonly uint unsignedPayloadValue;
|
||||
|
||||
public Payload PayloadType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!opPayload.TryGetValue(OpCode, out var result))
|
||||
throw new InternalError("Unknown op code " + OpCode);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => Index + ": " + OpCode;
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes of this instruction,
|
||||
/// including the payload (if any).
|
||||
/// </summary>
|
||||
public int Width
|
||||
{
|
||||
get
|
||||
{
|
||||
if (OpCode == ILOpCode.Switch)
|
||||
return 5 + 4 * payloadValue;
|
||||
|
||||
return ((int)OpCode > 255 ? 2 : 1) + PayloadSize;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly byte[] data;
|
||||
|
||||
private int PayloadSize => payloadSizes[(int)PayloadType];
|
||||
|
||||
/// <summary>
|
||||
/// Reads the instruction from a byte stream.
|
||||
/// </summary>
|
||||
/// <param name="data">The byte stream.</param>
|
||||
/// <param name="offset">The offset of the instruction.</param>
|
||||
/// <param name="index">The index of this instruction in the callable.</param>
|
||||
public Instruction(Context cx, DefinitionMethod method, byte[] data, int offset, int index) : base(cx)
|
||||
{
|
||||
Method = method;
|
||||
Offset = offset;
|
||||
Index = index;
|
||||
this.data = data;
|
||||
int opcode = data[offset];
|
||||
++offset;
|
||||
|
||||
/*
|
||||
* An opcode is either 1 or 2 bytes, followed by an optional payload depending on the instruction.
|
||||
* Instructions where the first byte is 0xfe are 2-byte instructions.
|
||||
*/
|
||||
if (opcode == 0xfe)
|
||||
opcode = opcode << 8 | data[offset++];
|
||||
OpCode = (ILOpCode)opcode;
|
||||
|
||||
switch (PayloadSize)
|
||||
{
|
||||
case 0:
|
||||
payloadValue = 0;
|
||||
break;
|
||||
case 1:
|
||||
payloadValue = (sbyte)data[offset];
|
||||
unsignedPayloadValue = data[offset];
|
||||
break;
|
||||
case 2:
|
||||
payloadValue = BitConverter.ToInt16(data, offset);
|
||||
unsignedPayloadValue = BitConverter.ToUInt16(data, offset);
|
||||
break;
|
||||
case -1: // Switch
|
||||
case 4:
|
||||
payloadValue = BitConverter.ToInt32(data, offset);
|
||||
break;
|
||||
case 8: // Not handled here.
|
||||
break;
|
||||
default:
|
||||
throw new InternalError("Unhandled CIL instruction Payload");
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
var offset = Offset;
|
||||
|
||||
if (Method.Implementation is null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
yield return Tuples.cil_instruction(this, (int)OpCode, Index, Method.Implementation);
|
||||
|
||||
switch (PayloadType)
|
||||
{
|
||||
case Payload.String:
|
||||
yield return Tuples.cil_value(this, Context.MdReader.GetUserString(MetadataTokens.UserStringHandle(payloadValue)));
|
||||
break;
|
||||
case Payload.Float32:
|
||||
yield return Tuples.cil_value(this, BitConverter.ToSingle(data, offset).ToString());
|
||||
break;
|
||||
case Payload.Float64:
|
||||
yield return Tuples.cil_value(this, BitConverter.ToDouble(data, offset).ToString());
|
||||
break;
|
||||
case Payload.Int8:
|
||||
yield return Tuples.cil_value(this, data[offset].ToString());
|
||||
break;
|
||||
case Payload.Int16:
|
||||
yield return Tuples.cil_value(this, BitConverter.ToInt16(data, offset).ToString());
|
||||
break;
|
||||
case Payload.Int32:
|
||||
yield return Tuples.cil_value(this, BitConverter.ToInt32(data, offset).ToString());
|
||||
break;
|
||||
case Payload.Int64:
|
||||
yield return Tuples.cil_value(this, BitConverter.ToInt64(data, offset).ToString());
|
||||
break;
|
||||
case Payload.Constructor:
|
||||
case Payload.Method:
|
||||
case Payload.MethodRef:
|
||||
case Payload.Class:
|
||||
case Payload.TypeTok:
|
||||
case Payload.Token:
|
||||
case Payload.Type:
|
||||
case Payload.Field:
|
||||
case Payload.ValueType:
|
||||
{
|
||||
// A generic EntityHandle.
|
||||
var handle = MetadataTokens.EntityHandle(payloadValue);
|
||||
var target = Context.CreateGeneric(Method, handle);
|
||||
yield return target;
|
||||
if (target is not null)
|
||||
{
|
||||
yield return Tuples.cil_access(this, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InternalError($"Unable to create payload type {PayloadType} for opcode {OpCode}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Payload.Arg8:
|
||||
case Payload.Arg16:
|
||||
if (Method.Parameters is not null)
|
||||
{
|
||||
yield return Tuples.cil_access(this, Method.Parameters[(int)unsignedPayloadValue]);
|
||||
}
|
||||
break;
|
||||
case Payload.Local8:
|
||||
case Payload.Local16:
|
||||
if (Method.LocalVariables is not null)
|
||||
{
|
||||
yield return Tuples.cil_access(this, Method.LocalVariables[(int)unsignedPayloadValue]);
|
||||
}
|
||||
break;
|
||||
case Payload.None:
|
||||
case Payload.Target8:
|
||||
case Payload.Target32:
|
||||
case Payload.Switch:
|
||||
case Payload.Ignore8:
|
||||
// These are not handled here.
|
||||
// Some of these are handled by JumpContents().
|
||||
break;
|
||||
case Payload.CallSiteDesc:
|
||||
{
|
||||
var handle = MetadataTokens.EntityHandle(payloadValue);
|
||||
IExtractedEntity? target = null;
|
||||
try
|
||||
{
|
||||
target = Context.CreateGeneric(Method, handle);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Context.Extractor.Logger.Log(Util.Logging.Severity.Warning, $"Couldn't interpret payload of payload type {PayloadType} as a function pointer type. {exc.Message} {exc.StackTrace}");
|
||||
}
|
||||
|
||||
if (target is not null)
|
||||
{
|
||||
yield return target;
|
||||
yield return Tuples.cil_access(this, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InternalError($"Unable to create payload type {PayloadType} for opcode {OpCode}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new InternalError($"Unhandled payload type {PayloadType}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called to populate the jumps in each instruction.
|
||||
public IEnumerable<IExtractionProduct> JumpContents(Dictionary<int, Instruction> jump_table)
|
||||
{
|
||||
int target;
|
||||
Instruction? inst;
|
||||
|
||||
switch (PayloadType)
|
||||
{
|
||||
case Payload.Target8:
|
||||
target = Offset + payloadValue + 2;
|
||||
break;
|
||||
case Payload.Target32:
|
||||
target = Offset + payloadValue + 5;
|
||||
break;
|
||||
case Payload.Switch:
|
||||
var end = Offset + Width;
|
||||
|
||||
var offset = Offset + 5;
|
||||
|
||||
for (var b = 0; b < payloadValue; ++b, offset += 4)
|
||||
{
|
||||
target = BitConverter.ToInt32(data, offset) + end;
|
||||
if (jump_table.TryGetValue(target, out inst))
|
||||
{
|
||||
yield return Tuples.cil_switch(this, b, inst);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InternalError("Invalid jump target");
|
||||
}
|
||||
}
|
||||
|
||||
yield break;
|
||||
default:
|
||||
// Not a jump
|
||||
yield break;
|
||||
}
|
||||
|
||||
|
||||
if (jump_table.TryGetValue(target, out inst))
|
||||
{
|
||||
yield return Tuples.cil_jump(this, inst);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sometimes instructions can jump outside the current method.
|
||||
// TODO: Find a solution to this.
|
||||
|
||||
// For now, just log the error
|
||||
Context.ExtractionError("A CIL instruction jumps outside the current method", null, Extraction.Entities.GeneratedLocation.Create(Context), "", Util.Logging.Severity.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal class LocalVariable : LabelledEntity
|
||||
{
|
||||
private readonly MethodImplementation method;
|
||||
private readonly int index;
|
||||
private readonly Type type;
|
||||
|
||||
public LocalVariable(Context cx, MethodImplementation m, int i, Type t) : base(cx)
|
||||
{
|
||||
method = m;
|
||||
index = i;
|
||||
type = t;
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(method);
|
||||
trapFile.Write('_');
|
||||
trapFile.Write(index);
|
||||
trapFile.Write(";cil-local");
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return type;
|
||||
yield return Tuples.cil_local_variable(this, method, index, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class MemberReferenceField : Field
|
||||
{
|
||||
private readonly MemberReferenceHandle handle;
|
||||
private readonly MemberReference mr;
|
||||
private readonly IGenericContext gc;
|
||||
private readonly Type declType;
|
||||
|
||||
public MemberReferenceField(IGenericContext gc, MemberReferenceHandle handle) : base(gc.Context)
|
||||
{
|
||||
this.handle = handle;
|
||||
this.gc = gc;
|
||||
mr = Context.MdReader.GetMemberReference(handle);
|
||||
declType = (Type)Context.CreateGeneric(gc, mr.Parent);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is MemberReferenceField field && handle.Equals(field.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return handle.GetHashCode();
|
||||
}
|
||||
|
||||
public override string Name => Context.GetString(mr.Name);
|
||||
|
||||
public override Type DeclaringType => declType;
|
||||
|
||||
public override Type Type => mr.DecodeFieldSignature(Context.TypeSignatureDecoder, this);
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => gc.TypeParameters.Concat(declType.TypeParameters);
|
||||
|
||||
public override IEnumerable<Type> MethodParameters => gc.MethodParameters.Concat(declType.MethodParameters);
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a late-bound reference to a method.
|
||||
/// </summary>
|
||||
internal sealed class MemberReferenceMethod : Method
|
||||
{
|
||||
private readonly MemberReferenceHandle handle;
|
||||
private readonly MemberReference mr;
|
||||
private readonly Type declaringType;
|
||||
private readonly IGenericContext parent;
|
||||
private readonly Method? sourceDeclaration;
|
||||
|
||||
public MemberReferenceMethod(IGenericContext gc, MemberReferenceHandle handle) : base(gc)
|
||||
{
|
||||
this.handle = handle;
|
||||
this.gc = gc;
|
||||
mr = Context.MdReader.GetMemberReference(handle);
|
||||
|
||||
signature = mr.DecodeMethodSignature(new SignatureDecoder(), gc);
|
||||
|
||||
parent = (IGenericContext)Context.CreateGeneric(gc, mr.Parent);
|
||||
|
||||
var declType = parent is Method parentMethod
|
||||
? parentMethod.DeclaringType
|
||||
: parent as Type;
|
||||
|
||||
if (declType is null)
|
||||
throw new InternalError("Parent context of method is not a type");
|
||||
|
||||
declaringType = declType;
|
||||
nameLabel = Context.GetString(mr.Name);
|
||||
|
||||
var typeSourceDeclaration = declaringType.SourceDeclaration;
|
||||
sourceDeclaration = typeSourceDeclaration == declaringType ? (Method)this : typeSourceDeclaration.LookupMethod(mr.Name, mr.Signature);
|
||||
}
|
||||
|
||||
private readonly string nameLabel;
|
||||
|
||||
public override string NameLabel => nameLabel;
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is MemberReferenceMethod method && handle.Equals(method.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return handle.GetHashCode();
|
||||
}
|
||||
|
||||
public override Method? SourceDeclaration => sourceDeclaration;
|
||||
|
||||
public override bool IsStatic => !signature.Header.IsInstance;
|
||||
|
||||
public override Type DeclaringType => declaringType;
|
||||
|
||||
public override string Name => Context.ShortName(mr.Name);
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => parent.TypeParameters.Concat(gc.TypeParameters);
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
genericParams = new MethodTypeParameter[signature.GenericParameterCount];
|
||||
for (var p = 0; p < genericParams.Length; ++p)
|
||||
genericParams[p] = Context.Populate(new MethodTypeParameter(this, this, p));
|
||||
|
||||
foreach (var p in genericParams)
|
||||
yield return p;
|
||||
|
||||
var typeSignature = mr.DecodeMethodSignature(Context.TypeSignatureDecoder, this);
|
||||
|
||||
var parameters = GetParameterExtractionProducts(typeSignature.ParameterTypes).ToArray();
|
||||
Parameters = parameters.OfType<Parameter>().ToArray();
|
||||
foreach (var p in parameters) yield return p;
|
||||
|
||||
foreach (var f in PopulateFlags) yield return f;
|
||||
|
||||
foreach (var m in GetMethodExtractionProducts(Name, DeclaringType, typeSignature.ReturnType))
|
||||
{
|
||||
yield return m;
|
||||
}
|
||||
|
||||
if (SourceDeclaration is not null)
|
||||
yield return Tuples.cil_method_source_declaration(this, SourceDeclaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A method entity.
|
||||
/// </summary>
|
||||
internal abstract class Method : TypeContainer, IMember, ICustomModifierReceiver, IParameterizable
|
||||
{
|
||||
protected MethodTypeParameter[]? genericParams;
|
||||
protected IGenericContext gc;
|
||||
protected MethodSignature<ITypeSignature> signature;
|
||||
|
||||
protected Method(IGenericContext gc) : base(gc.Context)
|
||||
{
|
||||
this.gc = gc;
|
||||
}
|
||||
|
||||
public ITypeSignature ReturnType => signature.ReturnType;
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => gc.TypeParameters.Concat(DeclaringType.TypeParameters);
|
||||
|
||||
public override IEnumerable<Type> MethodParameters =>
|
||||
genericParams is null ? gc.MethodParameters : gc.MethodParameters.Concat(genericParams);
|
||||
|
||||
public int GenericParameterCount => signature.GenericParameterCount;
|
||||
|
||||
public virtual Method? SourceDeclaration => this;
|
||||
|
||||
public abstract Type DeclaringType { get; }
|
||||
public abstract string Name { get; }
|
||||
|
||||
public virtual IList<LocalVariable>? LocalVariables => throw new NotImplementedException();
|
||||
public IList<Parameter>? Parameters { get; protected set; }
|
||||
|
||||
public abstract string NameLabel { get; }
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
signature.ReturnType.WriteId(trapFile, this);
|
||||
trapFile.Write(' ');
|
||||
DeclaringType.WriteId(trapFile);
|
||||
trapFile.Write('.');
|
||||
trapFile.Write(NameLabel);
|
||||
|
||||
if (signature.GenericParameterCount > 0)
|
||||
{
|
||||
trapFile.Write('`');
|
||||
trapFile.Write(signature.GenericParameterCount);
|
||||
}
|
||||
trapFile.Write('(');
|
||||
var index = 0;
|
||||
foreach (var param in signature.ParameterTypes)
|
||||
{
|
||||
trapFile.WriteSeparator(",", ref index);
|
||||
param.WriteId(trapFile, this);
|
||||
}
|
||||
trapFile.Write(");cil-method");
|
||||
}
|
||||
|
||||
protected IEnumerable<IExtractionProduct> PopulateFlags
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsStatic)
|
||||
yield return Tuples.cil_static(this);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract bool IsStatic { get; }
|
||||
|
||||
protected IEnumerable<IExtractionProduct> GetParameterExtractionProducts(IEnumerable<Type> parameterTypes)
|
||||
{
|
||||
var i = 0;
|
||||
|
||||
if (!IsStatic)
|
||||
{
|
||||
yield return Context.Populate(new Parameter(Context, this, i++, DeclaringType));
|
||||
}
|
||||
|
||||
foreach (var p in GetParameterExtractionProducts(parameterTypes, this, this, Context, i))
|
||||
{
|
||||
yield return p;
|
||||
}
|
||||
}
|
||||
|
||||
internal static IEnumerable<IExtractionProduct> GetParameterExtractionProducts(IEnumerable<Type> parameterTypes, IParameterizable parameterizable, ICustomModifierReceiver receiver, Context cx, int firstChildIndex)
|
||||
{
|
||||
var i = firstChildIndex;
|
||||
foreach (var p in parameterTypes)
|
||||
{
|
||||
var t = p;
|
||||
if (t is ModifiedType mt)
|
||||
{
|
||||
t = mt.Unmodified;
|
||||
yield return Tuples.cil_custom_modifiers(receiver, mt.Modifier, mt.IsRequired);
|
||||
}
|
||||
if (t is ByRefType brt)
|
||||
{
|
||||
t = brt.ElementType;
|
||||
var parameter = cx.Populate(new Parameter(cx, parameterizable, i++, t));
|
||||
yield return parameter;
|
||||
yield return Tuples.cil_type_annotation(parameter, TypeAnnotation.Ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return cx.Populate(new Parameter(cx, parameterizable, i++, t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected IEnumerable<IExtractionProduct> GetMethodExtractionProducts(string name, Type declaringType, Type returnType)
|
||||
{
|
||||
var t = returnType;
|
||||
if (t is ModifiedType mt)
|
||||
{
|
||||
t = mt.Unmodified;
|
||||
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
|
||||
}
|
||||
if (t is ByRefType brt)
|
||||
{
|
||||
t = brt.ElementType;
|
||||
yield return Tuples.cil_type_annotation(this, TypeAnnotation.Ref);
|
||||
}
|
||||
yield return Tuples.cil_method(this, name, declaringType, t);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A method implementation entity.
|
||||
/// In the database, the same method could in principle have multiple implementations.
|
||||
/// </summary>
|
||||
internal class MethodImplementation : UnlabelledEntity
|
||||
{
|
||||
private readonly Method m;
|
||||
|
||||
public MethodImplementation(Method m) : base(m.Context)
|
||||
{
|
||||
this.m = m;
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.cil_method_implementation(this, m, Context.Assembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A constructed method.
|
||||
/// </summary>
|
||||
internal sealed class MethodSpecificationMethod : Method
|
||||
{
|
||||
private readonly MethodSpecificationHandle handle;
|
||||
private readonly MethodSpecification ms;
|
||||
private readonly Method unboundMethod;
|
||||
private readonly ImmutableArray<Type> typeParams;
|
||||
|
||||
public MethodSpecificationMethod(IGenericContext gc, MethodSpecificationHandle handle) : base(gc)
|
||||
{
|
||||
this.handle = handle;
|
||||
ms = Context.MdReader.GetMethodSpecification(handle);
|
||||
typeParams = ms.DecodeSignature(Context.TypeSignatureDecoder, gc);
|
||||
unboundMethod = (Method)Context.CreateGeneric(gc, ms.Method);
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
unboundMethod.WriteId(trapFile);
|
||||
trapFile.Write('<');
|
||||
var index = 0;
|
||||
foreach (var param in typeParams)
|
||||
{
|
||||
trapFile.WriteSeparator(",", ref index);
|
||||
trapFile.WriteSubId(param);
|
||||
}
|
||||
trapFile.Write('>');
|
||||
}
|
||||
|
||||
public override string NameLabel => throw new NotImplementedException();
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is MethodSpecificationMethod method && handle.Equals(method.handle) && typeParams.SequenceEqual(method.typeParams);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode() * 11 + typeParams.SequenceHash();
|
||||
|
||||
public override Method SourceDeclaration => unboundMethod;
|
||||
|
||||
public override Type DeclaringType => unboundMethod.DeclaringType;
|
||||
|
||||
public override string Name => unboundMethod.Name;
|
||||
|
||||
public override bool IsStatic => unboundMethod.IsStatic;
|
||||
|
||||
public override IEnumerable<Type> MethodParameters => typeParams;
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
MethodSignature<Type> constructedTypeSignature;
|
||||
switch (ms.Method.Kind)
|
||||
{
|
||||
case HandleKind.MemberReference:
|
||||
var mr = Context.MdReader.GetMemberReference((MemberReferenceHandle)ms.Method);
|
||||
constructedTypeSignature = mr.DecodeMethodSignature(Context.TypeSignatureDecoder, this);
|
||||
break;
|
||||
case HandleKind.MethodDefinition:
|
||||
var md = Context.MdReader.GetMethodDefinition((MethodDefinitionHandle)ms.Method);
|
||||
constructedTypeSignature = md.DecodeSignature(Context.TypeSignatureDecoder, this);
|
||||
break;
|
||||
default:
|
||||
throw new InternalError($"Unexpected constructed method handle kind {ms.Method.Kind}");
|
||||
}
|
||||
|
||||
var parameters = GetParameterExtractionProducts(constructedTypeSignature.ParameterTypes).ToArray();
|
||||
Parameters = parameters.OfType<Parameter>().ToArray();
|
||||
foreach (var p in parameters)
|
||||
yield return p;
|
||||
|
||||
foreach (var f in PopulateFlags)
|
||||
yield return f;
|
||||
|
||||
foreach (var m in GetMethodExtractionProducts(Name, DeclaringType, constructedTypeSignature.ReturnType))
|
||||
{
|
||||
yield return m;
|
||||
}
|
||||
|
||||
yield return Tuples.cil_method_source_declaration(this, SourceDeclaration);
|
||||
|
||||
if (typeParams.Length != unboundMethod.GenericParameterCount)
|
||||
throw new InternalError("Method type parameter mismatch");
|
||||
|
||||
for (var p = 0; p < typeParams.Length; ++p)
|
||||
{
|
||||
yield return Tuples.cil_type_argument(this, p, typeParams[p]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class MethodTypeParameter : TypeParameter
|
||||
{
|
||||
private readonly Method method;
|
||||
private readonly int index;
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
if (!(inContext && method == gc))
|
||||
{
|
||||
trapFile.WriteSubId(method);
|
||||
}
|
||||
trapFile.Write("!");
|
||||
trapFile.Write(index);
|
||||
}
|
||||
|
||||
public override string Name => "!" + index;
|
||||
|
||||
public MethodTypeParameter(IGenericContext gc, Method m, int index) : base(gc)
|
||||
{
|
||||
method = m;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is MethodTypeParameter tp && method.Equals(tp.method) && index == tp.index;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return method.GetHashCode() * 29 + index;
|
||||
}
|
||||
|
||||
public override TypeContainer Parent => method;
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.cil_type(this, Name, Kind, method, SourceDeclaration);
|
||||
yield return Tuples.cil_type_parameter(method, index, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Modified types are not written directly to trap files. Instead, the modifiers are stored
|
||||
/// on the modifiable entity (field type, property/method/function pointer parameter or return types).
|
||||
/// </summary>
|
||||
internal sealed class ModifiedType : Type
|
||||
{
|
||||
public ModifiedType(Context cx, Type unmodified, Type modifier, bool isRequired) : base(cx)
|
||||
{
|
||||
Unmodified = unmodified;
|
||||
Modifier = modifier;
|
||||
IsRequired = isRequired;
|
||||
}
|
||||
|
||||
public Type Unmodified { get; }
|
||||
public Type Modifier { get; }
|
||||
public bool IsRequired { get; }
|
||||
|
||||
public override CilTypeKind Kind => throw new NotImplementedException();
|
||||
|
||||
public override Namespace? ContainingNamespace => throw new NotImplementedException();
|
||||
|
||||
public override Type? ContainingType => throw new NotImplementedException();
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
public override int ThisTypeParameterCount => throw new NotImplementedException();
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
|
||||
|
||||
public override string Name => $"{Unmodified.Name} {(IsRequired ? "modreq" : "modopt")}({Modifier.Name})";
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException();
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
Unmodified.WriteId(trapFile, inContext);
|
||||
trapFile.Write(IsRequired ? " modreq" : " modopt");
|
||||
trapFile.Write("(");
|
||||
Modifier.WriteId(trapFile, inContext);
|
||||
trapFile.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal class NamedTypeIdWriter
|
||||
{
|
||||
private readonly Type type;
|
||||
|
||||
public NamedTypeIdWriter(Type type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
if (type.IsPrimitiveType)
|
||||
{
|
||||
Type.WritePrimitiveTypeId(trapFile, type.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
var ct = type.ContainingType;
|
||||
if (ct is not null)
|
||||
{
|
||||
ct.WriteId(trapFile, inContext);
|
||||
trapFile.Write('.');
|
||||
}
|
||||
else
|
||||
{
|
||||
type.WriteAssemblyPrefix(trapFile);
|
||||
|
||||
var ns = type.ContainingNamespace!;
|
||||
if (!ns.IsGlobalNamespace)
|
||||
{
|
||||
ns.WriteId(trapFile);
|
||||
trapFile.Write('.');
|
||||
}
|
||||
}
|
||||
|
||||
trapFile.Write(type.Name);
|
||||
|
||||
var thisTypeArguments = type.ThisTypeArguments;
|
||||
if (thisTypeArguments is not null && thisTypeArguments.Any())
|
||||
{
|
||||
trapFile.Write('<');
|
||||
var index = 0;
|
||||
foreach (var t in thisTypeArguments)
|
||||
{
|
||||
trapFile.WriteSeparator(",", ref index);
|
||||
t.WriteId(trapFile);
|
||||
}
|
||||
trapFile.Write('>');
|
||||
}
|
||||
else if (type.ThisTypeParameterCount > 0)
|
||||
{
|
||||
trapFile.Write('`');
|
||||
trapFile.Write(type.ThisTypeParameterCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A namespace.
|
||||
/// </summary>
|
||||
internal sealed class Namespace : TypeContainer
|
||||
{
|
||||
public Namespace? ParentNamespace { get; }
|
||||
public string Name { get; }
|
||||
|
||||
public bool IsGlobalNamespace => ParentNamespace is null;
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
if (ParentNamespace is not null && !ParentNamespace.IsGlobalNamespace)
|
||||
{
|
||||
ParentNamespace.WriteId(trapFile);
|
||||
trapFile.Write('.');
|
||||
}
|
||||
trapFile.Write(Name);
|
||||
trapFile.Write(";namespace");
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is Namespace ns && Name == ns.Name)
|
||||
{
|
||||
if (ParentNamespace is null)
|
||||
return ns.ParentNamespace is null;
|
||||
if (!(ns.ParentNamespace is null))
|
||||
return ParentNamespace.Equals(ns.ParentNamespace);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var h = ParentNamespace is null ? 19 : ParentNamespace.GetHashCode();
|
||||
return 13 * h + Name.GetHashCode();
|
||||
}
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
|
||||
|
||||
private static string parseNamespaceName(string fqn)
|
||||
{
|
||||
var i = fqn.LastIndexOf('.');
|
||||
return i == -1 ? fqn : fqn.Substring(i + 1);
|
||||
}
|
||||
|
||||
private static Namespace? createParentNamespace(Context cx, string fqn)
|
||||
{
|
||||
if (fqn.Length == 0)
|
||||
return null;
|
||||
var i = fqn.LastIndexOf('.');
|
||||
return i == -1 ? cx.GlobalNamespace : cx.Populate(new Namespace(cx, fqn.Substring(0, i)));
|
||||
}
|
||||
|
||||
public Namespace(Context cx, string fqn) : this(cx, parseNamespaceName(fqn), createParentNamespace(cx, fqn))
|
||||
{
|
||||
}
|
||||
|
||||
public Namespace(Context cx, string name, Namespace? parent) : base(cx)
|
||||
{
|
||||
Name = name;
|
||||
ParentNamespace = parent;
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.namespaces(this, Name);
|
||||
if (ParentNamespace is not null)
|
||||
yield return Tuples.parent_namespace(this, ParentNamespace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,162 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed partial class NoMetadataHandleType
|
||||
{
|
||||
/// <summary>
|
||||
/// Parser to split a fully qualified name into short name, namespace or declaring type name, assembly name, and
|
||||
/// type argument names. Names are in the following format:
|
||||
/// <c>N1.N2.T1`2+T2`2[T3,[T4, A1, Version=...],T5,T6], A2, Version=...</c>
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>typeof(System.Collections.Generic.List<int>.Enumerator)
|
||||
/// -> System.Collections.Generic.List`1+Enumerator[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
|
||||
/// typeof(System.Collections.Generic.List<>.Enumerator)
|
||||
/// -> System.Collections.Generic.List`1+Enumerator, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
|
||||
/// </code>
|
||||
/// </example>
|
||||
private class FullyQualifiedNameParser
|
||||
{
|
||||
public string ShortName { get; internal set; }
|
||||
public string? AssemblyName { get; private set; }
|
||||
public IEnumerable<string>? TypeArguments { get; internal set; }
|
||||
public string? UnboundGenericTypeName { get; internal set; }
|
||||
public string ContainerName { get; internal set; }
|
||||
public bool IsContainerNamespace { get; internal set; }
|
||||
|
||||
private string AssemblySuffix => string.IsNullOrWhiteSpace(AssemblyName) ? "" : $", {AssemblyName}";
|
||||
|
||||
public FullyQualifiedNameParser(string name)
|
||||
{
|
||||
ExtractAssemblyName(ref name, out var lastBracketIndex);
|
||||
ExtractTypeArguments(ref name, lastBracketIndex, out var containerTypeArguments);
|
||||
ContainerName = ExtractContainer(ref name, containerTypeArguments);
|
||||
|
||||
ShortName = name;
|
||||
}
|
||||
|
||||
private void ExtractTypeArguments(ref string name, int lastBracketIndex, out string containerTypeArguments)
|
||||
{
|
||||
var firstBracketIndex = name.IndexOf('[');
|
||||
if (firstBracketIndex < 0)
|
||||
{
|
||||
// not generic or non-constructed generic
|
||||
TypeArguments = null;
|
||||
containerTypeArguments = "";
|
||||
UnboundGenericTypeName = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// "T3,[T4, Assembly1, Version=...],T5,T6"
|
||||
string typeArgs;
|
||||
(name, _, typeArgs, _) = name.Split(firstBracketIndex, firstBracketIndex + 1, lastBracketIndex);
|
||||
|
||||
var thisTypeArgCount = GenericsHelper.GetGenericTypeParameterCount(name);
|
||||
if (thisTypeArgCount == 0)
|
||||
{
|
||||
// not generic or non-constructed generic; container is constructed
|
||||
TypeArguments = null;
|
||||
containerTypeArguments = $"[{typeArgs}]";
|
||||
UnboundGenericTypeName = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// constructed generic
|
||||
// "T3,[T4, Assembly1, Version=...]", ["T5", "T6"]
|
||||
var (containerTypeArgs, thisTypeArgs) = ParseTypeArgumentStrings(typeArgs, thisTypeArgCount);
|
||||
|
||||
TypeArguments = thisTypeArgs;
|
||||
|
||||
containerTypeArguments = string.IsNullOrWhiteSpace(containerTypeArgs)
|
||||
? "" // containing type is not constructed generics
|
||||
: $"[{containerTypeArgs}]"; // "T3,[T4, Assembly1, Version=...],,]"
|
||||
|
||||
UnboundGenericTypeName = $"{name}{AssemblySuffix}";
|
||||
}
|
||||
|
||||
private string ExtractContainer(ref string name, string containerTypeArguments)
|
||||
{
|
||||
var lastPlusIndex = name.LastIndexOf('+');
|
||||
IsContainerNamespace = lastPlusIndex < 0;
|
||||
if (IsContainerNamespace)
|
||||
{
|
||||
return ExtractContainerNamespace(ref name);
|
||||
}
|
||||
|
||||
return ExtractContainerType(ref name, containerTypeArguments, lastPlusIndex);
|
||||
}
|
||||
|
||||
private static string ExtractContainerNamespace(ref string name)
|
||||
{
|
||||
var lastDotIndex = name.LastIndexOf('.');
|
||||
if (lastDotIndex >= 0)
|
||||
{
|
||||
string containerName;
|
||||
(containerName, _, name) = name.Split(lastDotIndex, lastDotIndex + 1);
|
||||
return containerName;
|
||||
}
|
||||
|
||||
return ""; // global namespace name
|
||||
}
|
||||
|
||||
private string ExtractContainerType(ref string name, string containerTypeArguments, int lastPlusIndex)
|
||||
{
|
||||
string containerName;
|
||||
(containerName, _, name) = name.Split(lastPlusIndex, lastPlusIndex + 1);
|
||||
return $"{containerName}{containerTypeArguments}{AssemblySuffix}";
|
||||
}
|
||||
|
||||
private void ExtractAssemblyName(ref string name, out int lastBracketIndex)
|
||||
{
|
||||
lastBracketIndex = name.LastIndexOf(']');
|
||||
var assemblyCommaIndex = name.IndexOf(',', lastBracketIndex < 0 ? 0 : lastBracketIndex);
|
||||
if (assemblyCommaIndex >= 0)
|
||||
{
|
||||
// "Assembly2, Version=..."
|
||||
(name, _, AssemblyName) = name.Split(assemblyCommaIndex, assemblyCommaIndex + 2);
|
||||
}
|
||||
}
|
||||
|
||||
private static (string, IEnumerable<string>) ParseTypeArgumentStrings(string typeArgs, int thisTypeArgCount)
|
||||
{
|
||||
var thisTypeArgs = new Stack<string>(thisTypeArgCount);
|
||||
while (typeArgs.Length > 0 && thisTypeArgCount > 0)
|
||||
{
|
||||
int startCurrentType;
|
||||
if (typeArgs[^1] != ']')
|
||||
{
|
||||
startCurrentType = typeArgs.LastIndexOf(',') + 1;
|
||||
thisTypeArgs.Push(typeArgs.Substring(startCurrentType));
|
||||
}
|
||||
else
|
||||
{
|
||||
var bracketCount = 1;
|
||||
for (startCurrentType = typeArgs.Length - 2; startCurrentType >= 0 && bracketCount > 0; startCurrentType--)
|
||||
{
|
||||
if (typeArgs[startCurrentType] == ']')
|
||||
{
|
||||
bracketCount++;
|
||||
}
|
||||
else if (typeArgs[startCurrentType] == '[')
|
||||
{
|
||||
bracketCount--;
|
||||
}
|
||||
}
|
||||
startCurrentType++;
|
||||
thisTypeArgs.Push(typeArgs[(startCurrentType + 1)..^1]);
|
||||
}
|
||||
|
||||
typeArgs = startCurrentType != 0
|
||||
? typeArgs.Substring(0, startCurrentType - 1)
|
||||
: "";
|
||||
|
||||
thisTypeArgCount--;
|
||||
}
|
||||
return (typeArgs, thisTypeArgs.ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,161 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed partial class NoMetadataHandleType : Type
|
||||
{
|
||||
private readonly string originalName;
|
||||
private readonly string name;
|
||||
private readonly string? assemblyName;
|
||||
private readonly string containerName;
|
||||
private readonly bool isContainerNamespace;
|
||||
|
||||
private readonly Lazy<TypeTypeParameter[]>? typeParams;
|
||||
|
||||
// Either null or notEmpty
|
||||
private readonly Type[]? thisTypeArguments;
|
||||
private readonly Type unboundGenericType;
|
||||
private readonly Type? containingType;
|
||||
private readonly Namespace? containingNamespace;
|
||||
|
||||
private readonly NamedTypeIdWriter idWriter;
|
||||
|
||||
public NoMetadataHandleType(Context cx, string originalName) : base(cx)
|
||||
{
|
||||
this.originalName = originalName;
|
||||
this.idWriter = new NamedTypeIdWriter(this);
|
||||
|
||||
var nameParser = new FullyQualifiedNameParser(originalName);
|
||||
|
||||
name = nameParser.ShortName;
|
||||
assemblyName = nameParser.AssemblyName;
|
||||
isContainerNamespace = nameParser.IsContainerNamespace;
|
||||
containerName = nameParser.ContainerName;
|
||||
|
||||
unboundGenericType = nameParser.UnboundGenericTypeName is null
|
||||
? this
|
||||
: new NoMetadataHandleType(Context, nameParser.UnboundGenericTypeName);
|
||||
|
||||
if (nameParser.TypeArguments is not null)
|
||||
{
|
||||
thisTypeArguments = nameParser.TypeArguments.Select(t => new NoMetadataHandleType(Context, t)).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
typeParams = new Lazy<TypeTypeParameter[]>(GenericsHelper.MakeTypeParameters(this, ThisTypeParameterCount));
|
||||
}
|
||||
|
||||
containingType = isContainerNamespace
|
||||
? null
|
||||
: new NoMetadataHandleType(Context, containerName);
|
||||
|
||||
containingNamespace = isContainerNamespace
|
||||
? containerName == Context.GlobalNamespace.Name
|
||||
? Context.GlobalNamespace
|
||||
: containerName == Context.SystemNamespace.Name
|
||||
? Context.SystemNamespace
|
||||
: new Namespace(Context, containerName)
|
||||
: null;
|
||||
|
||||
Populate();
|
||||
}
|
||||
|
||||
private void Populate()
|
||||
{
|
||||
if (ContainingNamespace is not null)
|
||||
{
|
||||
Context.Populate(ContainingNamespace);
|
||||
}
|
||||
|
||||
Context.Populate(this);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is NoMetadataHandleType t && originalName.Equals(t.originalName, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return originalName.GetHashCode(StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var tp in typeParams?.Value ?? Array.Empty<TypeTypeParameter>())
|
||||
yield return tp;
|
||||
|
||||
foreach (var c in base.Contents)
|
||||
yield return c;
|
||||
|
||||
var i = 0;
|
||||
foreach (var type in ThisTypeArguments)
|
||||
{
|
||||
yield return type;
|
||||
yield return Tuples.cil_type_argument(this, i++, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override CilTypeKind Kind => CilTypeKind.ValueOrRefType;
|
||||
|
||||
public override string Name => GenericsHelper.GetNonGenericName(name);
|
||||
|
||||
public override Namespace? ContainingNamespace => containingNamespace;
|
||||
|
||||
public override Type? ContainingType => containingType;
|
||||
|
||||
public override Type SourceDeclaration => unboundGenericType;
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments)
|
||||
{
|
||||
if (TotalTypeParametersCount != typeArguments.Count())
|
||||
throw new InternalError("Mismatched type arguments");
|
||||
|
||||
return Context.Populate(new ConstructedType(Context, this, typeArguments));
|
||||
}
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(assemblyName))
|
||||
{
|
||||
var an = new AssemblyName(assemblyName);
|
||||
trapFile.Write(an.Name);
|
||||
trapFile.Write('_');
|
||||
trapFile.Write((an.Version ?? new Version(0, 0, 0, 0)).ToString());
|
||||
trapFile.Write(Type.AssemblyTypeNameSeparator);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.WriteAssemblyPrefix(trapFile);
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
idWriter.WriteId(trapFile, inContext);
|
||||
}
|
||||
|
||||
public override int ThisTypeParameterCount => unboundGenericType == this
|
||||
? GenericsHelper.GetGenericTypeParameterCount(name)
|
||||
: thisTypeArguments!.Length;
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => unboundGenericType == this
|
||||
? GenericsHelper.GetAllTypeParameters(containingType, typeParams!.Value)
|
||||
: GenericArguments;
|
||||
|
||||
public override IEnumerable<Type> ThisTypeArguments => unboundGenericType == this
|
||||
? base.ThisTypeArguments
|
||||
: thisTypeArguments!;
|
||||
|
||||
public override IEnumerable<Type> ThisGenericArguments => unboundGenericType == this
|
||||
? typeParams!.Value
|
||||
: thisTypeArguments!;
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A parameter entity.
|
||||
/// </summary>
|
||||
internal sealed class Parameter : LabelledEntity
|
||||
{
|
||||
private readonly IParameterizable parameterizable;
|
||||
private readonly int index;
|
||||
private readonly Type type;
|
||||
|
||||
public Parameter(Context cx, IParameterizable p, int i, Type t) : base(cx)
|
||||
{
|
||||
parameterizable = p;
|
||||
index = i;
|
||||
type = t;
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(parameterizable);
|
||||
trapFile.Write('_');
|
||||
trapFile.Write(index);
|
||||
trapFile.Write(";cil-parameter");
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Parameter param && parameterizable.Equals(param.parameterizable) && index == param.index;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return 23 * parameterizable.GetHashCode() + index;
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.cil_parameter(this, parameterizable, index, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal class PdbSourceFile : File
|
||||
{
|
||||
private readonly PDB.ISourceFile file;
|
||||
|
||||
public PdbSourceFile(Context cx, PDB.ISourceFile file) : base(cx, file.Path)
|
||||
{
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var c in base.Contents)
|
||||
yield return c;
|
||||
|
||||
var text = file.Contents;
|
||||
|
||||
if (text is null)
|
||||
Context.Extractor.Logger.Log(Util.Logging.Severity.Warning, string.Format("PDB source file {0} could not be found", OriginalPath));
|
||||
else
|
||||
Context.TrapWriter.Archive(TransformedPath, text);
|
||||
|
||||
yield return Tuples.file_extraction_mode(this, Context.Extractor.Mode | ExtractorMode.Pdb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class PointerType : Type
|
||||
{
|
||||
private readonly Type pointee;
|
||||
|
||||
public PointerType(Context cx, Type pointee) : base(cx)
|
||||
{
|
||||
this.pointee = pointee;
|
||||
|
||||
if (pointee is ModifiedType mt)
|
||||
{
|
||||
cx.Extractor.Logger.Log(
|
||||
Util.Logging.Severity.Info,
|
||||
$"Pointer to modified type {pointee.GetQualifiedName()} is changed to {mt.Unmodified.GetQualifiedName()}");
|
||||
this.pointee = mt.Unmodified;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is PointerType pt && pointee.Equals(pt.pointee);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => HashCode.Combine(pointee, nameof(PointerType));
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
pointee.WriteId(trapFile, inContext);
|
||||
trapFile.Write('*');
|
||||
}
|
||||
|
||||
public override string Name => pointee.Name + "*";
|
||||
|
||||
public override Namespace? ContainingNamespace => pointee.ContainingNamespace;
|
||||
|
||||
public override Type? ContainingType => pointee.ContainingType;
|
||||
|
||||
public override TypeContainer Parent => pointee.Parent;
|
||||
|
||||
public override int ThisTypeParameterCount => 0;
|
||||
|
||||
public override CilTypeKind Kind => CilTypeKind.Pointer;
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) => pointee.WriteAssemblyPrefix(trapFile);
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var c in base.Contents) yield return c;
|
||||
yield return Tuples.cil_pointer_type(this, pointee);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class PrimitiveType : Type
|
||||
{
|
||||
private readonly PrimitiveTypeCode typeCode;
|
||||
public PrimitiveType(Context cx, PrimitiveTypeCode tc) : base(cx)
|
||||
{
|
||||
typeCode = tc;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is PrimitiveType pt && typeCode == pt.typeCode;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => typeCode.GetHashCode();
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
Type.WritePrimitiveTypeId(trapFile, Name);
|
||||
}
|
||||
|
||||
public override string Name => typeCode.Id();
|
||||
|
||||
public override Namespace ContainingNamespace => Context.SystemNamespace;
|
||||
|
||||
public override Type? ContainingType => null;
|
||||
|
||||
public override int ThisTypeParameterCount => 0;
|
||||
|
||||
public override CilTypeKind Kind => CilTypeKind.ValueOrRefType;
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) { }
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A property.
|
||||
/// </summary>
|
||||
internal sealed class Property : LabelledEntity, ICustomModifierReceiver
|
||||
{
|
||||
private readonly Handle handle;
|
||||
private readonly Type type;
|
||||
private readonly PropertyDefinition pd;
|
||||
private readonly IGenericContext gc;
|
||||
|
||||
public Property(IGenericContext gc, Type type, PropertyDefinitionHandle handle) : base(gc.Context)
|
||||
{
|
||||
this.gc = gc;
|
||||
this.handle = handle;
|
||||
pd = Context.MdReader.GetPropertyDefinition(handle);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(type);
|
||||
trapFile.Write('.');
|
||||
trapFile.Write(Context.GetString(pd.Name));
|
||||
trapFile.Write("(");
|
||||
var index = 0;
|
||||
var signature = pd.DecodeSignature(new SignatureDecoder(), gc);
|
||||
foreach (var param in signature.ParameterTypes)
|
||||
{
|
||||
trapFile.WriteSeparator(",", ref index);
|
||||
param.WriteId(trapFile, gc);
|
||||
}
|
||||
trapFile.Write(")");
|
||||
trapFile.Write(";cil-property");
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Property property && Equals(handle, property.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.metadata_handle(this, Context.Assembly, MetadataTokens.GetToken(handle));
|
||||
var sig = pd.DecodeSignature(Context.TypeSignatureDecoder, type);
|
||||
|
||||
var name = Context.ShortName(pd.Name);
|
||||
|
||||
var t = sig.ReturnType;
|
||||
if (t is ModifiedType mt)
|
||||
{
|
||||
t = mt.Unmodified;
|
||||
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
|
||||
}
|
||||
if (t is ByRefType brt)
|
||||
{
|
||||
t = brt.ElementType;
|
||||
yield return Tuples.cil_type_annotation(this, TypeAnnotation.Ref);
|
||||
}
|
||||
yield return Tuples.cil_property(this, type, name, t);
|
||||
|
||||
var accessors = pd.GetAccessors();
|
||||
if (!accessors.Getter.IsNil)
|
||||
{
|
||||
var getter = (Method)Context.CreateGeneric(type, accessors.Getter);
|
||||
yield return getter;
|
||||
yield return Tuples.cil_getter(this, getter);
|
||||
}
|
||||
|
||||
if (!accessors.Setter.IsNil)
|
||||
{
|
||||
var setter = (Method)Context.CreateGeneric(type, accessors.Setter);
|
||||
yield return setter;
|
||||
yield return Tuples.cil_setter(this, setter);
|
||||
}
|
||||
|
||||
foreach (var c in Attribute.Populate(Context, this, pd.GetCustomAttributes()))
|
||||
yield return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,289 +0,0 @@
|
|||
using System.Collections.Immutable;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
public class SignatureDecoder : ISignatureTypeProvider<ITypeSignature, object>
|
||||
{
|
||||
private struct Array : ITypeSignature
|
||||
{
|
||||
private readonly ITypeSignature elementType;
|
||||
private readonly ArrayShape shape;
|
||||
|
||||
public Array(ITypeSignature elementType, ArrayShape shape) : this()
|
||||
{
|
||||
this.elementType = elementType;
|
||||
this.shape = shape;
|
||||
}
|
||||
|
||||
public void WriteId(EscapingTextWriter trapFile, IGenericContext gc)
|
||||
{
|
||||
elementType.WriteId(trapFile, gc);
|
||||
trapFile.Write('[');
|
||||
for (var i = 1; i < shape.Rank; ++i)
|
||||
{
|
||||
trapFile.Write(',');
|
||||
}
|
||||
trapFile.Write(']');
|
||||
}
|
||||
}
|
||||
|
||||
private struct ByRef : ITypeSignature
|
||||
{
|
||||
private readonly ITypeSignature elementType;
|
||||
|
||||
public ByRef(ITypeSignature elementType)
|
||||
{
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
public void WriteId(EscapingTextWriter trapFile, IGenericContext gc)
|
||||
{
|
||||
elementType.WriteId(trapFile, gc);
|
||||
trapFile.Write('&');
|
||||
}
|
||||
}
|
||||
|
||||
private struct FnPtr : ITypeSignature
|
||||
{
|
||||
private readonly MethodSignature<ITypeSignature> signature;
|
||||
|
||||
public FnPtr(MethodSignature<ITypeSignature> signature)
|
||||
{
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public void WriteId(EscapingTextWriter trapFile, IGenericContext gc)
|
||||
{
|
||||
FunctionPointerType.WriteName(
|
||||
trapFile.Write,
|
||||
t => t.WriteId(trapFile, gc),
|
||||
signature
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetArrayType(ITypeSignature elementType, ArrayShape shape) =>
|
||||
new Array(elementType, shape);
|
||||
|
||||
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetByReferenceType(ITypeSignature elementType) =>
|
||||
new ByRef(elementType);
|
||||
|
||||
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetFunctionPointerType(MethodSignature<ITypeSignature> signature) =>
|
||||
new FnPtr(signature);
|
||||
|
||||
private class Instantiation : ITypeSignature
|
||||
{
|
||||
private readonly ITypeSignature genericType;
|
||||
private readonly ImmutableArray<ITypeSignature> typeArguments;
|
||||
|
||||
public Instantiation(ITypeSignature genericType, ImmutableArray<ITypeSignature> typeArguments)
|
||||
{
|
||||
this.genericType = genericType;
|
||||
this.typeArguments = typeArguments;
|
||||
}
|
||||
|
||||
public void WriteId(EscapingTextWriter trapFile, IGenericContext gc)
|
||||
{
|
||||
genericType.WriteId(trapFile, gc);
|
||||
trapFile.Write('<');
|
||||
var index = 0;
|
||||
foreach (var arg in typeArguments)
|
||||
{
|
||||
trapFile.WriteSeparator(",", ref index);
|
||||
arg.WriteId(trapFile, gc);
|
||||
}
|
||||
trapFile.Write('>');
|
||||
}
|
||||
}
|
||||
|
||||
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetGenericInstantiation(ITypeSignature genericType, ImmutableArray<ITypeSignature> typeArguments) =>
|
||||
new Instantiation(genericType, typeArguments);
|
||||
|
||||
private class GenericMethodParameter : ITypeSignature
|
||||
{
|
||||
private readonly object innerGc;
|
||||
private readonly int index;
|
||||
|
||||
public GenericMethodParameter(object innerGc, int index)
|
||||
{
|
||||
this.innerGc = innerGc;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public void WriteId(EscapingTextWriter trapFile, IGenericContext outerGc)
|
||||
{
|
||||
if (!ReferenceEquals(innerGc, outerGc) && innerGc is Method method)
|
||||
{
|
||||
trapFile.WriteSubId(method);
|
||||
}
|
||||
trapFile.Write("M!");
|
||||
trapFile.Write(index);
|
||||
}
|
||||
}
|
||||
|
||||
private class GenericTypeParameter : ITypeSignature
|
||||
{
|
||||
private readonly int index;
|
||||
|
||||
public GenericTypeParameter(int index)
|
||||
{
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public void WriteId(EscapingTextWriter trapFile, IGenericContext gc)
|
||||
{
|
||||
trapFile.Write("T!");
|
||||
trapFile.Write(index);
|
||||
}
|
||||
}
|
||||
|
||||
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetGenericMethodParameter(object genericContext, int index) =>
|
||||
new GenericMethodParameter(genericContext, index);
|
||||
|
||||
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetGenericTypeParameter(object genericContext, int index) =>
|
||||
new GenericTypeParameter(index);
|
||||
|
||||
private class Modified : ITypeSignature
|
||||
{
|
||||
private readonly ITypeSignature unmodifiedType;
|
||||
private readonly ITypeSignature modifier;
|
||||
private readonly bool isRequired;
|
||||
|
||||
public Modified(ITypeSignature unmodifiedType, ITypeSignature modifier, bool isRequired)
|
||||
{
|
||||
this.unmodifiedType = unmodifiedType;
|
||||
this.modifier = modifier;
|
||||
this.isRequired = isRequired;
|
||||
}
|
||||
|
||||
public void WriteId(EscapingTextWriter trapFile, IGenericContext gc)
|
||||
{
|
||||
unmodifiedType.WriteId(trapFile, gc);
|
||||
trapFile.Write(isRequired ? " modreq(" : " modopt(");
|
||||
modifier.WriteId(trapFile, gc);
|
||||
trapFile.Write(")");
|
||||
}
|
||||
}
|
||||
|
||||
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetModifiedType(ITypeSignature modifier, ITypeSignature unmodifiedType, bool isRequired)
|
||||
{
|
||||
return new Modified(unmodifiedType, modifier, isRequired);
|
||||
}
|
||||
|
||||
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetPinnedType(ITypeSignature elementType)
|
||||
{
|
||||
return elementType;
|
||||
}
|
||||
|
||||
private class PointerType : ITypeSignature
|
||||
{
|
||||
private readonly ITypeSignature elementType;
|
||||
|
||||
public PointerType(ITypeSignature elementType)
|
||||
{
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
public void WriteId(EscapingTextWriter trapFile, IGenericContext gc)
|
||||
{
|
||||
elementType.WriteId(trapFile, gc);
|
||||
trapFile.Write('*');
|
||||
}
|
||||
}
|
||||
|
||||
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetPointerType(ITypeSignature elementType)
|
||||
{
|
||||
return new PointerType(elementType);
|
||||
}
|
||||
|
||||
private class Primitive : ITypeSignature
|
||||
{
|
||||
private readonly PrimitiveTypeCode typeCode;
|
||||
|
||||
public Primitive(PrimitiveTypeCode typeCode)
|
||||
{
|
||||
this.typeCode = typeCode;
|
||||
}
|
||||
|
||||
public void WriteId(EscapingTextWriter trapFile, IGenericContext gc)
|
||||
{
|
||||
trapFile.Write(typeCode.Id());
|
||||
}
|
||||
}
|
||||
|
||||
ITypeSignature ISimpleTypeProvider<ITypeSignature>.GetPrimitiveType(PrimitiveTypeCode typeCode)
|
||||
{
|
||||
return new Primitive(typeCode);
|
||||
}
|
||||
|
||||
private class SzArrayType : ITypeSignature
|
||||
{
|
||||
private readonly ITypeSignature elementType;
|
||||
|
||||
public SzArrayType(ITypeSignature elementType)
|
||||
{
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
public void WriteId(EscapingTextWriter trapFile, IGenericContext gc)
|
||||
{
|
||||
elementType.WriteId(trapFile, gc);
|
||||
trapFile.Write("[]");
|
||||
}
|
||||
}
|
||||
|
||||
ITypeSignature ISZArrayTypeProvider<ITypeSignature>.GetSZArrayType(ITypeSignature elementType)
|
||||
{
|
||||
return new SzArrayType(elementType);
|
||||
}
|
||||
|
||||
private class TypeDefinition : ITypeSignature
|
||||
{
|
||||
private readonly TypeDefinitionHandle handle;
|
||||
|
||||
public TypeDefinition(TypeDefinitionHandle handle)
|
||||
{
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
public void WriteId(EscapingTextWriter trapFile, IGenericContext gc)
|
||||
{
|
||||
var type = (Type)gc.Context.Create(handle);
|
||||
type.WriteId(trapFile);
|
||||
}
|
||||
}
|
||||
|
||||
ITypeSignature ISimpleTypeProvider<ITypeSignature>.GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind)
|
||||
{
|
||||
return new TypeDefinition(handle);
|
||||
}
|
||||
|
||||
private class TypeReference : ITypeSignature
|
||||
{
|
||||
private readonly TypeReferenceHandle handle;
|
||||
|
||||
public TypeReference(TypeReferenceHandle handle)
|
||||
{
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
public void WriteId(EscapingTextWriter trapFile, IGenericContext gc)
|
||||
{
|
||||
var type = (Type)gc.Context.Create(handle);
|
||||
type.WriteId(trapFile);
|
||||
}
|
||||
}
|
||||
|
||||
ITypeSignature ISimpleTypeProvider<ITypeSignature>.GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind)
|
||||
{
|
||||
return new TypeReference(handle);
|
||||
}
|
||||
|
||||
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetTypeFromSpecification(MetadataReader reader, object genericContext, TypeSpecificationHandle handle, byte rawTypeKind)
|
||||
{
|
||||
var ts = reader.GetTypeSpecification(handle);
|
||||
return ts.DecodeSignature(this, genericContext);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using Semmle.Extraction.PDB;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class PdbSourceLocation : LabelledEntity, ILocation
|
||||
{
|
||||
private readonly Location location;
|
||||
private readonly PdbSourceFile file;
|
||||
|
||||
public PdbSourceLocation(Context cx, PDB.Location location) : base(cx)
|
||||
{
|
||||
this.location = location;
|
||||
file = cx.CreateSourceFile(location.File);
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
file.WriteId(trapFile);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(location.StartLine);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(location.StartColumn);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(location.EndLine);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(location.EndColumn);
|
||||
trapFile.Write(";sourcelocation");
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is PdbSourceLocation l && location.Equals(l.location);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => location.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return file;
|
||||
yield return Tuples.locations_default(this, file, location.StartLine, location.StartColumn, location.EndLine, location.EndColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,209 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A type.
|
||||
/// </summary>
|
||||
internal abstract class Type : TypeContainer, IMember
|
||||
{
|
||||
internal const string AssemblyTypeNameSeparator = "::";
|
||||
internal const string PrimitiveTypePrefix = "builtin" + AssemblyTypeNameSeparator + "System.";
|
||||
|
||||
protected Type(Context cx) : base(cx) { }
|
||||
|
||||
/// <summary>
|
||||
/// Find the method in this type matching the name and signature.
|
||||
/// </summary>
|
||||
/// <param name="methodName">The handle to the name.</param>
|
||||
/// <param name="signature">
|
||||
/// The handle to the signature. Note that comparing handles is a valid
|
||||
/// shortcut to comparing the signature bytes since handles are unique.
|
||||
/// </param>
|
||||
/// <returns>The method, or 'null' if not found or not supported.</returns>
|
||||
internal virtual Method? LookupMethod(StringHandle methodName, BlobHandle signature)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the assembly identifier of this type.
|
||||
/// </summary>
|
||||
public abstract void WriteAssemblyPrefix(TextWriter trapFile);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the ID part to be used in a method ID.
|
||||
/// </summary>
|
||||
/// <param name="inContext">
|
||||
/// Whether we should output the context prefix of type parameters.
|
||||
/// (This is to avoid infinite recursion generating a method ID that returns a
|
||||
/// type parameter.)
|
||||
/// </param>
|
||||
public abstract void WriteId(EscapingTextWriter trapFile, bool inContext);
|
||||
|
||||
public sealed override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
WriteId(trapFile, false);
|
||||
trapFile.Write(";cil-type");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the friendly qualified name of types, such as
|
||||
/// ``"System.Collection.Generic.List`1"`` or
|
||||
/// ``"System.Collection.Generic.List<System.Int32>"``.
|
||||
///
|
||||
/// Note that method/type generic type parameters never show up in the returned name.
|
||||
/// </summary>
|
||||
public string GetQualifiedName()
|
||||
{
|
||||
using var writer = new EscapingTextWriter();
|
||||
WriteId(writer, false);
|
||||
var name = writer.ToString();
|
||||
return name.Substring(name.IndexOf(AssemblyTypeNameSeparator) + 2).
|
||||
Replace(";namespace", "").
|
||||
Replace(";cil-type", "");
|
||||
}
|
||||
|
||||
public abstract CilTypeKind Kind { get; }
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.cil_type(this, Name, Kind, Parent, SourceDeclaration);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract string Name { get; }
|
||||
|
||||
public abstract Namespace? ContainingNamespace { get; }
|
||||
|
||||
public abstract Type? ContainingType { get; }
|
||||
|
||||
public virtual TypeContainer Parent => (TypeContainer?)ContainingType ?? ContainingNamespace!;
|
||||
|
||||
public abstract Type Construct(IEnumerable<Type> typeArguments);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the type arguments of constructed types. For non-constructed types it returns an
|
||||
/// empty collection.
|
||||
/// </summary>
|
||||
public virtual IEnumerable<Type> ThisTypeArguments
|
||||
{
|
||||
get
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The number of type parameters for non-constructed generic types, the number of type arguments
|
||||
/// for constructed types, or 0.
|
||||
/// </summary>
|
||||
public abstract int ThisTypeParameterCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The total number of type parameters/type arguments (including parent types).
|
||||
/// This is used for internal consistency checking only.
|
||||
/// </summary>
|
||||
public int TotalTypeParametersCount =>
|
||||
ThisTypeParameterCount + (ContainingType?.TotalTypeParametersCount ?? 0);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all bound/unbound generic arguments of a constructed/unbound generic type.
|
||||
/// </summary>
|
||||
public virtual IEnumerable<Type> ThisGenericArguments
|
||||
{
|
||||
get
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IEnumerable<Type> GenericArguments
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ContainingType is not null)
|
||||
{
|
||||
foreach (var t in ContainingType.GenericArguments)
|
||||
yield return t;
|
||||
}
|
||||
|
||||
foreach (var t in ThisGenericArguments)
|
||||
yield return t;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Type SourceDeclaration => this;
|
||||
|
||||
public static void WritePrimitiveTypeId(TextWriter trapFile, string name)
|
||||
{
|
||||
trapFile.Write(PrimitiveTypePrefix);
|
||||
trapFile.Write(name);
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, PrimitiveTypeCode> primitiveTypeCodeMapping = new Dictionary<string, PrimitiveTypeCode>
|
||||
{
|
||||
{"Boolean", PrimitiveTypeCode.Boolean},
|
||||
{"Object", PrimitiveTypeCode.Object},
|
||||
{"Byte", PrimitiveTypeCode.Byte},
|
||||
{"SByte", PrimitiveTypeCode.SByte},
|
||||
{"Int16", PrimitiveTypeCode.Int16},
|
||||
{"UInt16", PrimitiveTypeCode.UInt16},
|
||||
{"Int32", PrimitiveTypeCode.Int32},
|
||||
{"UInt32", PrimitiveTypeCode.UInt32},
|
||||
{"Int64", PrimitiveTypeCode.Int64},
|
||||
{"UInt64", PrimitiveTypeCode.UInt64},
|
||||
{"Single", PrimitiveTypeCode.Single},
|
||||
{"Double", PrimitiveTypeCode.Double},
|
||||
{"String", PrimitiveTypeCode.String},
|
||||
{"Void", PrimitiveTypeCode.Void},
|
||||
{"IntPtr", PrimitiveTypeCode.IntPtr},
|
||||
{"UIntPtr", PrimitiveTypeCode.UIntPtr},
|
||||
{"Char", PrimitiveTypeCode.Char},
|
||||
{"TypedReference", PrimitiveTypeCode.TypedReference}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the primitive type corresponding to this type, if possible.
|
||||
/// </summary>
|
||||
/// <param name="t">The resulting primitive type, or null.</param>
|
||||
/// <returns>True if this type is a primitive type.</returns>
|
||||
public bool TryGetPrimitiveType([NotNullWhen(true)] out PrimitiveType? t)
|
||||
{
|
||||
if (TryGetPrimitiveTypeCode(out var code))
|
||||
{
|
||||
t = Context.Create(code);
|
||||
return true;
|
||||
}
|
||||
|
||||
t = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryGetPrimitiveTypeCode(out PrimitiveTypeCode code)
|
||||
{
|
||||
if (ContainingType is null &&
|
||||
ContainingNamespace?.Name == Context.SystemNamespace.Name &&
|
||||
primitiveTypeCodeMapping.TryGetValue(Name, out code))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
code = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected internal bool IsPrimitiveType => TryGetPrimitiveTypeCode(out _);
|
||||
|
||||
public sealed override IEnumerable<Type> MethodParameters => Enumerable.Empty<Type>();
|
||||
|
||||
public static Type DecodeType(IGenericContext gc, TypeSpecificationHandle handle) =>
|
||||
gc.Context.MdReader.GetTypeSpecification(handle).DecodeSignature(gc.Context.TypeSignatureDecoder, gc);
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
[Flags]
|
||||
public enum TypeAnnotation
|
||||
{
|
||||
None = 0,
|
||||
Ref = 32
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all type containers (namespaces, types, methods).
|
||||
/// </summary>
|
||||
internal abstract class TypeContainer : LabelledEntity, IGenericContext
|
||||
{
|
||||
protected TypeContainer(Context cx) : base(cx)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract IEnumerable<Type> MethodParameters { get; }
|
||||
public abstract IEnumerable<Type> TypeParameters { get; }
|
||||
}
|
||||
}
|
|
@ -1,263 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A type defined in the current assembly.
|
||||
/// </summary>
|
||||
internal sealed class TypeDefinitionType : Type
|
||||
{
|
||||
private readonly TypeDefinitionHandle handle;
|
||||
private readonly TypeDefinition td;
|
||||
private readonly Lazy<IEnumerable<TypeTypeParameter>> typeParams;
|
||||
private readonly Type? declType;
|
||||
private readonly NamedTypeIdWriter idWriter;
|
||||
|
||||
public TypeDefinitionType(Context cx, TypeDefinitionHandle handle) : base(cx)
|
||||
{
|
||||
idWriter = new NamedTypeIdWriter(this);
|
||||
td = cx.MdReader.GetTypeDefinition(handle);
|
||||
this.handle = handle;
|
||||
|
||||
declType =
|
||||
td.GetDeclaringType().IsNil ? null :
|
||||
(Type)cx.Create(td.GetDeclaringType());
|
||||
|
||||
// Lazy because should happen during population.
|
||||
typeParams = new Lazy<IEnumerable<TypeTypeParameter>>(MakeTypeParameters);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is TypeDefinitionType t && handle.Equals(t.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
idWriter.WriteId(trapFile, inContext);
|
||||
}
|
||||
|
||||
public override string Name => GenericsHelper.GetNonGenericName(td.Name, Context.MdReader);
|
||||
|
||||
public override Namespace ContainingNamespace => Context.Create(td.NamespaceDefinition);
|
||||
|
||||
public override Type? ContainingType => declType;
|
||||
|
||||
public override CilTypeKind Kind => CilTypeKind.ValueOrRefType;
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments)
|
||||
{
|
||||
if (TotalTypeParametersCount != typeArguments.Count())
|
||||
throw new InternalError("Mismatched type arguments");
|
||||
|
||||
return Context.Populate(new ConstructedType(Context, this, typeArguments));
|
||||
}
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile)
|
||||
{
|
||||
var ct = ContainingType;
|
||||
if (ct is null)
|
||||
Context.WriteAssemblyPrefix(trapFile);
|
||||
else if (IsPrimitiveType)
|
||||
trapFile.Write(Type.PrimitiveTypePrefix);
|
||||
else
|
||||
ct.WriteAssemblyPrefix(trapFile);
|
||||
}
|
||||
|
||||
private IEnumerable<TypeTypeParameter> MakeTypeParameters()
|
||||
{
|
||||
if (ThisTypeParameterCount == 0)
|
||||
return Enumerable.Empty<TypeTypeParameter>();
|
||||
|
||||
var newTypeParams = new TypeTypeParameter[ThisTypeParameterCount];
|
||||
var genericParams = td.GetGenericParameters();
|
||||
var toSkip = genericParams.Count - newTypeParams.Length;
|
||||
|
||||
// Two-phase population because type parameters can be mutually dependent
|
||||
for (var i = 0; i < newTypeParams.Length; ++i)
|
||||
newTypeParams[i] = Context.Populate(new TypeTypeParameter(this, i));
|
||||
for (var i = 0; i < newTypeParams.Length; ++i)
|
||||
newTypeParams[i].PopulateHandle(genericParams[i + toSkip]);
|
||||
return newTypeParams;
|
||||
}
|
||||
|
||||
public override int ThisTypeParameterCount
|
||||
{
|
||||
get
|
||||
{
|
||||
var containingType = td.GetDeclaringType();
|
||||
var parentTypeParameters = containingType.IsNil
|
||||
? 0
|
||||
: Context.MdReader.GetTypeDefinition(containingType).GetGenericParameters().Count;
|
||||
|
||||
return td.GetGenericParameters().Count - parentTypeParameters;
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => GenericsHelper.GetAllTypeParameters(declType, typeParams!.Value);
|
||||
|
||||
public override IEnumerable<Type> ThisGenericArguments => typeParams.Value;
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.metadata_handle(this, Context.Assembly, MetadataTokens.GetToken(handle));
|
||||
|
||||
foreach (var c in base.Contents) yield return c;
|
||||
|
||||
MakeTypeParameters();
|
||||
|
||||
foreach (var f in td.GetFields())
|
||||
{
|
||||
// Populate field if needed
|
||||
yield return Context.CreateGeneric(this, f);
|
||||
}
|
||||
|
||||
foreach (var prop in td.GetProperties())
|
||||
{
|
||||
yield return new Property(this, this, prop);
|
||||
}
|
||||
|
||||
foreach (var @event in td.GetEvents())
|
||||
{
|
||||
yield return new Event(Context, this, @event);
|
||||
}
|
||||
|
||||
foreach (var a in Attribute.Populate(Context, this, td.GetCustomAttributes()))
|
||||
yield return a;
|
||||
|
||||
foreach (var impl in td.GetMethodImplementations().Select(i => Context.MdReader.GetMethodImplementation(i)))
|
||||
{
|
||||
var m = (Method)Context.CreateGeneric(this, impl.MethodBody);
|
||||
var decl = (Method)Context.CreateGeneric(this, impl.MethodDeclaration);
|
||||
|
||||
yield return m;
|
||||
yield return decl;
|
||||
yield return Tuples.cil_implements(m, decl);
|
||||
}
|
||||
|
||||
if (td.Attributes.HasFlag(TypeAttributes.Abstract))
|
||||
yield return Tuples.cil_abstract(this);
|
||||
|
||||
if (td.Attributes.HasFlag(TypeAttributes.Interface))
|
||||
yield return Tuples.cil_interface(this);
|
||||
else
|
||||
yield return Tuples.cil_class(this);
|
||||
|
||||
if (td.Attributes.HasFlag(TypeAttributes.Public))
|
||||
yield return Tuples.cil_public(this);
|
||||
|
||||
if (td.Attributes.HasFlag(TypeAttributes.Sealed))
|
||||
yield return Tuples.cil_sealed(this);
|
||||
|
||||
if (td.Attributes.HasFlag(TypeAttributes.HasSecurity))
|
||||
yield return Tuples.cil_security(this);
|
||||
|
||||
// Base types
|
||||
|
||||
if (!td.BaseType.IsNil)
|
||||
{
|
||||
var @base = (Type)Context.CreateGeneric(this, td.BaseType);
|
||||
yield return @base;
|
||||
yield return Tuples.cil_base_class(this, @base);
|
||||
|
||||
if (IsSystemEnum(td.BaseType) &&
|
||||
GetUnderlyingEnumType() is var underlying &&
|
||||
underlying.HasValue)
|
||||
{
|
||||
var underlyingType = Context.Create(underlying.Value);
|
||||
yield return underlyingType;
|
||||
yield return Tuples.cil_enum_underlying_type(this, underlyingType);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var @interface in td.GetInterfaceImplementations().Select(i => Context.MdReader.GetInterfaceImplementation(i)))
|
||||
{
|
||||
var t = (Type)Context.CreateGeneric(this, @interface.Interface);
|
||||
yield return t;
|
||||
yield return Tuples.cil_base_interface(this, t);
|
||||
}
|
||||
|
||||
// Only type definitions have locations.
|
||||
yield return Tuples.cil_type_location(this, Context.Assembly);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsSystemEnum(EntityHandle baseType)
|
||||
{
|
||||
return baseType.Kind switch
|
||||
{
|
||||
HandleKind.TypeReference => IsSystemEnum((TypeReferenceHandle)baseType),
|
||||
HandleKind.TypeDefinition => IsSystemEnum((TypeDefinitionHandle)baseType),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
private bool IsSystemEnum(TypeReferenceHandle baseType)
|
||||
{
|
||||
var baseTypeReference = Context.MdReader.GetTypeReference(baseType);
|
||||
|
||||
return IsSystemEnum(baseTypeReference.Name, baseTypeReference.Namespace);
|
||||
}
|
||||
|
||||
private bool IsSystemEnum(TypeDefinitionHandle baseType)
|
||||
{
|
||||
var baseTypeDefinition = Context.MdReader.GetTypeDefinition(baseType);
|
||||
|
||||
return IsSystemEnum(baseTypeDefinition.Name, baseTypeDefinition.Namespace);
|
||||
}
|
||||
|
||||
private bool IsSystemEnum(StringHandle typeName, StringHandle namespaceName)
|
||||
{
|
||||
return Context.MdReader.StringComparer.Equals(typeName, "Enum") &&
|
||||
!namespaceName.IsNil &&
|
||||
Context.MdReader.StringComparer.Equals(namespaceName, "System");
|
||||
}
|
||||
|
||||
internal PrimitiveTypeCode? GetUnderlyingEnumType()
|
||||
{
|
||||
foreach (var handle in td.GetFields())
|
||||
{
|
||||
var field = Context.MdReader.GetFieldDefinition(handle);
|
||||
if (field.Attributes.HasFlag(FieldAttributes.Static))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var blob = Context.MdReader.GetBlobReader(field.Signature);
|
||||
if (blob.ReadSignatureHeader().Kind != SignatureKind.Field)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
return (PrimitiveTypeCode)blob.ReadByte();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal override Method LookupMethod(StringHandle name, BlobHandle signature)
|
||||
{
|
||||
foreach (var h in td.GetMethods())
|
||||
{
|
||||
var md = Context.MdReader.GetMethodDefinition(h);
|
||||
|
||||
if (md.Name == name && md.Signature == signature)
|
||||
{
|
||||
return (Method)Context.Create(h);
|
||||
}
|
||||
}
|
||||
|
||||
throw new InternalError("Couldn't locate method in type");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal abstract class TypeParameter : Type
|
||||
{
|
||||
protected readonly IGenericContext gc;
|
||||
|
||||
protected TypeParameter(IGenericContext gc) : base(gc.Context)
|
||||
{
|
||||
this.gc = gc;
|
||||
}
|
||||
|
||||
public override Namespace? ContainingNamespace => null;
|
||||
|
||||
public override Type? ContainingType => null;
|
||||
|
||||
public override int ThisTypeParameterCount => 0;
|
||||
|
||||
public override CilTypeKind Kind => CilTypeKind.TypeParameter;
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException();
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments) => throw new InternalError("Attempt to construct a type parameter");
|
||||
|
||||
public IEnumerable<IExtractionProduct> PopulateHandle(GenericParameterHandle parameterHandle)
|
||||
{
|
||||
if (!parameterHandle.IsNil)
|
||||
{
|
||||
var tp = Context.MdReader.GetGenericParameter(parameterHandle);
|
||||
|
||||
if (tp.Attributes.HasFlag(GenericParameterAttributes.Contravariant))
|
||||
yield return Tuples.cil_typeparam_contravariant(this);
|
||||
if (tp.Attributes.HasFlag(GenericParameterAttributes.Covariant))
|
||||
yield return Tuples.cil_typeparam_covariant(this);
|
||||
if (tp.Attributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
|
||||
yield return Tuples.cil_typeparam_new(this);
|
||||
if (tp.Attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))
|
||||
yield return Tuples.cil_typeparam_class(this);
|
||||
if (tp.Attributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint))
|
||||
yield return Tuples.cil_typeparam_struct(this);
|
||||
|
||||
foreach (var constraint in tp.GetConstraints().Select(h => Context.MdReader.GetGenericParameterConstraint(h)))
|
||||
{
|
||||
var t = (Type)Context.CreateGeneric(this.gc, constraint.Type);
|
||||
yield return t;
|
||||
yield return Tuples.cil_typeparam_constraint(this, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A type reference, to a type in a referenced assembly.
|
||||
/// </summary>
|
||||
internal sealed class TypeReferenceType : Type
|
||||
{
|
||||
private readonly TypeReferenceHandle handle;
|
||||
private readonly TypeReference tr;
|
||||
private readonly Lazy<TypeTypeParameter[]> typeParams;
|
||||
private readonly NamedTypeIdWriter idWriter;
|
||||
|
||||
public TypeReferenceType(Context cx, TypeReferenceHandle handle) : base(cx)
|
||||
{
|
||||
this.idWriter = new NamedTypeIdWriter(this);
|
||||
this.handle = handle;
|
||||
this.tr = cx.MdReader.GetTypeReference(handle);
|
||||
this.typeParams = new Lazy<TypeTypeParameter[]>(GenericsHelper.MakeTypeParameters(this, ThisTypeParameterCount));
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is TypeReferenceType t && handle.Equals(t.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return handle.GetHashCode();
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var tp in typeParams.Value)
|
||||
yield return tp;
|
||||
|
||||
foreach (var c in base.Contents)
|
||||
yield return c;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Name => GenericsHelper.GetNonGenericName(tr.Name, Context.MdReader);
|
||||
|
||||
public override Namespace ContainingNamespace => Context.CreateNamespace(tr.Namespace);
|
||||
|
||||
public override Type? ContainingType
|
||||
{
|
||||
get
|
||||
{
|
||||
return tr.ResolutionScope.Kind == HandleKind.TypeReference
|
||||
? (Type)Context.Create((TypeReferenceHandle)tr.ResolutionScope)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
public override CilTypeKind Kind => CilTypeKind.ValueOrRefType;
|
||||
|
||||
public override void WriteAssemblyPrefix(TextWriter trapFile)
|
||||
{
|
||||
switch (tr.ResolutionScope.Kind)
|
||||
{
|
||||
case HandleKind.TypeReference:
|
||||
ContainingType!.WriteAssemblyPrefix(trapFile);
|
||||
break;
|
||||
case HandleKind.AssemblyReference:
|
||||
var assemblyDef = Context.MdReader.GetAssemblyReference((AssemblyReferenceHandle)tr.ResolutionScope);
|
||||
trapFile.Write(Context.GetString(assemblyDef.Name));
|
||||
trapFile.Write('_');
|
||||
trapFile.Write(assemblyDef.Version.ToString());
|
||||
trapFile.Write(Entities.Type.AssemblyTypeNameSeparator);
|
||||
break;
|
||||
default:
|
||||
Context.WriteAssemblyPrefix(trapFile);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override int ThisTypeParameterCount => GenericsHelper.GetGenericTypeParameterCount(tr.Name, Context.MdReader);
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => GenericsHelper.GetAllTypeParameters(ContainingType, typeParams!.Value);
|
||||
|
||||
public override IEnumerable<Type> ThisGenericArguments => typeParams.Value;
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
idWriter.WriteId(trapFile, inContext);
|
||||
}
|
||||
|
||||
public override Type Construct(IEnumerable<Type> typeArguments)
|
||||
{
|
||||
if (TotalTypeParametersCount != typeArguments.Count())
|
||||
throw new InternalError("Mismatched type arguments");
|
||||
|
||||
return Context.Populate(new ConstructedType(Context, this, typeArguments));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Decodes a type signature and produces a Type, for use by DecodeSignature() and friends.
|
||||
/// </summary>
|
||||
internal class TypeSignatureDecoder : ISignatureTypeProvider<Type, IGenericContext>
|
||||
{
|
||||
private readonly Context cx;
|
||||
|
||||
public TypeSignatureDecoder(Context cx)
|
||||
{
|
||||
this.cx = cx;
|
||||
}
|
||||
|
||||
Type IConstructedTypeProvider<Type>.GetArrayType(Type elementType, ArrayShape shape) =>
|
||||
cx.Populate(new ArrayType(cx, elementType, shape.Rank));
|
||||
|
||||
Type IConstructedTypeProvider<Type>.GetByReferenceType(Type elementType) =>
|
||||
new ByRefType(cx, elementType);
|
||||
|
||||
Type ISignatureTypeProvider<Type, IGenericContext>.GetFunctionPointerType(MethodSignature<Type> signature) =>
|
||||
cx.Populate(new FunctionPointerType(cx, signature));
|
||||
|
||||
Type IConstructedTypeProvider<Type>.GetGenericInstantiation(Type genericType, ImmutableArray<Type> typeArguments) =>
|
||||
genericType.Construct(typeArguments);
|
||||
|
||||
Type ISignatureTypeProvider<Type, IGenericContext>.GetGenericMethodParameter(IGenericContext genericContext, int index) =>
|
||||
genericContext.MethodParameters.ElementAt(index);
|
||||
|
||||
Type ISignatureTypeProvider<Type, IGenericContext>.GetGenericTypeParameter(IGenericContext genericContext, int index) =>
|
||||
genericContext.TypeParameters.ElementAt(index);
|
||||
|
||||
Type ISignatureTypeProvider<Type, IGenericContext>.GetModifiedType(Type modifier, Type unmodifiedType, bool isRequired) =>
|
||||
new ModifiedType(cx, unmodifiedType, modifier, isRequired);
|
||||
|
||||
Type ISignatureTypeProvider<Type, IGenericContext>.GetPinnedType(Type elementType) => elementType;
|
||||
|
||||
Type IConstructedTypeProvider<Type>.GetPointerType(Type elementType) =>
|
||||
cx.Populate(new PointerType(cx, elementType));
|
||||
|
||||
Type ISimpleTypeProvider<Type>.GetPrimitiveType(PrimitiveTypeCode typeCode) => cx.Create(typeCode);
|
||||
|
||||
Type ISZArrayTypeProvider<Type>.GetSZArrayType(Type elementType) =>
|
||||
cx.Populate(new ArrayType(cx, elementType));
|
||||
|
||||
Type ISimpleTypeProvider<Type>.GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) =>
|
||||
(Type)cx.Create(handle);
|
||||
|
||||
Type ISimpleTypeProvider<Type>.GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) =>
|
||||
(Type)cx.Create(handle);
|
||||
|
||||
Type ISignatureTypeProvider<Type, IGenericContext>.GetTypeFromSpecification(MetadataReader reader, IGenericContext genericContext, TypeSpecificationHandle handle, byte rawTypeKind) =>
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal sealed class TypeTypeParameter : TypeParameter
|
||||
{
|
||||
private readonly Type type;
|
||||
private readonly int index;
|
||||
|
||||
public TypeTypeParameter(Type t, int i) : base(t)
|
||||
{
|
||||
index = i;
|
||||
type = t;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is TypeTypeParameter tp && type.Equals(tp.type) && index == tp.index;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return type.GetHashCode() * 13 + index;
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile, bool inContext)
|
||||
{
|
||||
type.WriteId(trapFile, inContext);
|
||||
trapFile.Write('!');
|
||||
trapFile.Write(index);
|
||||
}
|
||||
|
||||
public override TypeContainer Parent => type;
|
||||
public override string Name => "!" + index;
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => Enumerable.Empty<Type>();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.cil_type(this, Name, Kind, type, SourceDeclaration);
|
||||
yield return Tuples.cil_type_parameter(type, index, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
internal interface ICustomModifierReceiver
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
public static class IdUtils
|
||||
{
|
||||
public static string Id(this PrimitiveTypeCode typeCode)
|
||||
{
|
||||
switch (typeCode)
|
||||
{
|
||||
case PrimitiveTypeCode.Boolean: return "Boolean";
|
||||
case PrimitiveTypeCode.Byte: return "Byte";
|
||||
case PrimitiveTypeCode.Char: return "Char";
|
||||
case PrimitiveTypeCode.Double: return "Double";
|
||||
case PrimitiveTypeCode.Int16: return "Int16";
|
||||
case PrimitiveTypeCode.Int32: return "Int32";
|
||||
case PrimitiveTypeCode.Int64: return "Int64";
|
||||
case PrimitiveTypeCode.IntPtr: return "IntPtr";
|
||||
case PrimitiveTypeCode.Object: return "Object";
|
||||
case PrimitiveTypeCode.SByte: return "SByte";
|
||||
case PrimitiveTypeCode.Single: return "Single";
|
||||
case PrimitiveTypeCode.String: return "String";
|
||||
case PrimitiveTypeCode.UInt16: return "UInt16";
|
||||
case PrimitiveTypeCode.UInt32: return "UInt32";
|
||||
case PrimitiveTypeCode.UInt64: return "UInt64";
|
||||
case PrimitiveTypeCode.UIntPtr: return "UIntPtr";
|
||||
case PrimitiveTypeCode.Void: return "Void";
|
||||
case PrimitiveTypeCode.TypedReference: return "TypedReference";
|
||||
default: throw new InternalError($"Unhandled type code {typeCode}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.PDB
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper for reading PDB files.
|
||||
/// This is needed because there are different libraries for dealing with
|
||||
/// different types of PDB file, even though they share the same file extension.
|
||||
/// </summary>
|
||||
public interface IPdb : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets all source files in this PDB.
|
||||
/// </summary>
|
||||
IEnumerable<ISourceFile> SourceFiles { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Look up a method from a given handle.
|
||||
/// </summary>
|
||||
/// <param name="methodHandle">The handle to query.</param>
|
||||
/// <returns>The method information, or null if the method does not have debug information.</returns>
|
||||
Method? GetMethod(MethodDebugInformationHandle methodHandle);
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
namespace Semmle.Extraction.PDB
|
||||
{
|
||||
/// <summary>
|
||||
/// A source file reference in a PDB file.
|
||||
/// </summary>
|
||||
public interface ISourceFile
|
||||
{
|
||||
string Path { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The contents of the file.
|
||||
/// This property is needed in case the contents
|
||||
/// of the file are embedded in the PDB instead of being on the filesystem.
|
||||
///
|
||||
/// null if the contents are unavailable.
|
||||
/// E.g. if the PDB file exists but the corresponding source files are missing.
|
||||
/// </summary>
|
||||
string? Contents { get; }
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
namespace Semmle.Extraction.PDB
|
||||
{
|
||||
/// <summary>
|
||||
/// A location in source code.
|
||||
/// </summary>
|
||||
public sealed class Location
|
||||
{
|
||||
/// <summary>
|
||||
/// The file containing the code.
|
||||
/// </summary>
|
||||
public ISourceFile File { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The start line of text within the source file.
|
||||
/// </summary>
|
||||
public int StartLine { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The start column of text within the source file.
|
||||
/// </summary>
|
||||
public int StartColumn { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The end line of text within the source file.
|
||||
/// </summary>
|
||||
public int EndLine { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The end column of text within the source file.
|
||||
/// </summary>
|
||||
public int EndColumn { get; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("({0},{1})-({2},{3})", StartLine, StartColumn, EndLine, EndColumn);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Location otherLocation &&
|
||||
File.Equals(otherLocation.File) &&
|
||||
StartLine == otherLocation.StartLine &&
|
||||
StartColumn == otherLocation.StartColumn &&
|
||||
EndLine == otherLocation.EndLine &&
|
||||
EndColumn == otherLocation.EndColumn;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var h1 = StartLine + 37 * (StartColumn + 51 * (EndLine + 97 * EndColumn));
|
||||
return File.GetHashCode() + 17 * h1;
|
||||
}
|
||||
|
||||
public Location(ISourceFile file, int startLine, int startCol, int endLine, int endCol)
|
||||
{
|
||||
File = file;
|
||||
StartLine = startLine;
|
||||
StartColumn = startCol;
|
||||
EndLine = endLine;
|
||||
EndColumn = endCol;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using Microsoft.DiaSymReader;
|
||||
|
||||
#pragma warning disable IDE0060, CA1822
|
||||
|
||||
namespace Semmle.Extraction.PDB
|
||||
{
|
||||
/// <summary>
|
||||
/// This is not used but is seemingly needed in order to use DiaSymReader.
|
||||
/// </summary>
|
||||
internal class MdProvider : ISymReaderMetadataProvider
|
||||
{
|
||||
public MdProvider()
|
||||
{
|
||||
}
|
||||
|
||||
public object? GetMetadataImport() => null;
|
||||
|
||||
public unsafe bool TryGetStandaloneSignature(int standaloneSignatureToken, out byte* signature, out int length) =>
|
||||
throw new NotImplementedException();
|
||||
|
||||
public bool TryGetTypeDefinitionInfo(int typeDefinitionToken, out string namespaceName, out string typeName, out TypeAttributes attributes, out int baseTypeToken) =>
|
||||
throw new NotImplementedException();
|
||||
|
||||
public bool TryGetTypeDefinitionInfo(int typeDefinitionToken, out string namespaceName, out string typeName, out TypeAttributes attributes) =>
|
||||
throw new NotImplementedException();
|
||||
|
||||
public bool TryGetTypeReferenceInfo(int typeReferenceToken, out string namespaceName, out string typeName, out int resolutionScopeToken) =>
|
||||
throw new NotImplementedException();
|
||||
|
||||
public bool TryGetTypeReferenceInfo(int typeReferenceToken, out string namespaceName, out string typeName) =>
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore
|
|
@ -1,99 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.PortableExecutable;
|
||||
|
||||
namespace Semmle.Extraction.PDB
|
||||
{
|
||||
/// <summary>
|
||||
/// A reader of PDB information using System.Reflection.Metadata.
|
||||
/// This is cross platform, and the future of PDB.
|
||||
///
|
||||
/// PDB information can be in a separate PDB file, or embedded in the DLL.
|
||||
/// </summary>
|
||||
internal sealed class MetadataPdbReader : IPdb
|
||||
{
|
||||
private class SourceFile : ISourceFile
|
||||
{
|
||||
public SourceFile(MetadataReader reader, DocumentHandle handle)
|
||||
{
|
||||
var doc = reader.GetDocument(handle);
|
||||
Path = reader.GetString(doc.Name);
|
||||
}
|
||||
|
||||
public string Path { get; private set; }
|
||||
|
||||
public string? Contents => File.Exists(Path) ? File.ReadAllText(Path, System.Text.Encoding.Default) : null;
|
||||
}
|
||||
|
||||
// Turns out to be very important to keep the MetadataReaderProvider live
|
||||
// or the reader will crash.
|
||||
private readonly MetadataReaderProvider provider;
|
||||
private readonly MetadataReader reader;
|
||||
|
||||
public MetadataPdbReader(MetadataReaderProvider provider)
|
||||
{
|
||||
this.provider = provider;
|
||||
reader = provider.GetMetadataReader();
|
||||
}
|
||||
|
||||
public IEnumerable<ISourceFile> SourceFiles => reader.Documents.Select(handle => new SourceFile(reader, handle));
|
||||
|
||||
public Method? GetMethod(MethodDebugInformationHandle handle)
|
||||
{
|
||||
var debugInfo = reader.GetMethodDebugInformation(handle);
|
||||
|
||||
var sequencePoints = debugInfo.GetSequencePoints()
|
||||
.Where(p => !p.Document.IsNil && !p.IsHidden)
|
||||
.Select(p => new SequencePoint(p.Offset, new Location(
|
||||
new SourceFile(reader, p.Document), p.StartLine, p.StartColumn, p.EndLine, p.EndColumn)))
|
||||
.Where(p => p.Location.File.Path is not null)
|
||||
.ToArray();
|
||||
|
||||
return sequencePoints.Any() ? new Method(sequencePoints) : null;
|
||||
}
|
||||
|
||||
public static MetadataPdbReader? CreateFromAssembly(string assemblyPath, PEReader peReader)
|
||||
{
|
||||
var provider = peReader
|
||||
.ReadDebugDirectory()
|
||||
.Where(d => d.Type == DebugDirectoryEntryType.EmbeddedPortablePdb)
|
||||
.Select(dirEntry => peReader.ReadEmbeddedPortablePdbDebugDirectoryData(dirEntry))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (provider is not null)
|
||||
{
|
||||
return new MetadataPdbReader(provider);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (peReader.TryOpenAssociatedPortablePdb(
|
||||
assemblyPath,
|
||||
s => new FileStream(s, FileMode.Open, FileAccess.Read, FileShare.Read),
|
||||
out provider,
|
||||
out _))
|
||||
{
|
||||
return new MetadataPdbReader(provider!);
|
||||
}
|
||||
}
|
||||
|
||||
catch (BadImageFormatException)
|
||||
{
|
||||
// Something is wrong with the file.
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
// The PDB file was not found.
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
provider.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.PDB
|
||||
{
|
||||
public class Method
|
||||
{
|
||||
public IEnumerable<SequencePoint> SequencePoints { get; }
|
||||
|
||||
public Method(IEnumerable<SequencePoint> sequencePoints)
|
||||
{
|
||||
SequencePoints = sequencePoints;
|
||||
}
|
||||
|
||||
public Location Location => SequencePoints.First().Location;
|
||||
}
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using Microsoft.DiaSymReader;
|
||||
|
||||
namespace Semmle.Extraction.PDB
|
||||
{
|
||||
/// <summary>
|
||||
/// A PDB reader using Microsoft.DiaSymReader.Native.
|
||||
/// This is an unmanaged Windows DLL, which therefore only works on Windows.
|
||||
/// </summary>
|
||||
internal sealed class NativePdbReader : IPdb
|
||||
{
|
||||
private sealed class Document : ISourceFile
|
||||
{
|
||||
private readonly ISymUnmanagedDocument document;
|
||||
|
||||
public Document(ISymUnmanagedDocument doc)
|
||||
{
|
||||
document = doc;
|
||||
contents = new Lazy<string?>(() =>
|
||||
{
|
||||
if (document.HasEmbeddedSource(out var isEmbedded) == 0 && isEmbedded)
|
||||
{
|
||||
var rawContents = document.GetEmbeddedSource().ToArray();
|
||||
return System.Text.Encoding.Default.GetString(rawContents);
|
||||
}
|
||||
|
||||
return File.Exists(Path)
|
||||
? File.ReadAllText(Path)
|
||||
: null;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Document otherDoc && Path.Equals(otherDoc.Path);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => Path.GetHashCode();
|
||||
|
||||
public string Path => document.GetName();
|
||||
|
||||
public override string ToString() => Path;
|
||||
|
||||
private readonly Lazy<string?> contents;
|
||||
|
||||
public string? Contents => contents.Value;
|
||||
}
|
||||
|
||||
public IEnumerable<ISourceFile> SourceFiles => reader.GetDocuments().Select(d => new Document(d));
|
||||
|
||||
public Method? GetMethod(MethodDebugInformationHandle h)
|
||||
{
|
||||
var methodToken = MetadataTokens.GetToken(h.ToDefinitionHandle());
|
||||
var method = reader.GetMethod(methodToken);
|
||||
if (method is not null)
|
||||
{
|
||||
if (method.GetSequencePointCount(out var count) != 0 || count == 0)
|
||||
return null;
|
||||
|
||||
var s = method.GetSequencePoints()
|
||||
.Where(sp => !sp.IsHidden)
|
||||
.Select(sp => new SequencePoint(sp.Offset, new Location(
|
||||
new Document(sp.Document), sp.StartLine, sp.StartColumn, sp.EndLine, sp.EndColumn)))
|
||||
.ToArray();
|
||||
|
||||
return s.Any() ? new Method(s) : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private NativePdbReader(string path)
|
||||
{
|
||||
pdbStream = new FileStream(path, FileMode.Open);
|
||||
var metadataProvider = new MdProvider();
|
||||
reader = SymUnmanagedReaderFactory.CreateReader<ISymUnmanagedReader5>(pdbStream, metadataProvider);
|
||||
}
|
||||
|
||||
private readonly ISymUnmanagedReader5 reader;
|
||||
private readonly FileStream pdbStream;
|
||||
|
||||
public static NativePdbReader? CreateFromAssembly(PEReader peReader)
|
||||
{
|
||||
// The Native PDB reader uses an unmanaged Windows DLL
|
||||
// so only works on Windows.
|
||||
if (!Semmle.Util.Win32.IsWindows())
|
||||
return null;
|
||||
|
||||
var debugDirectory = peReader.ReadDebugDirectory();
|
||||
|
||||
var path = debugDirectory
|
||||
.Where(d => d.Type == DebugDirectoryEntryType.CodeView)
|
||||
.Select(peReader.ReadCodeViewDebugDirectoryData)
|
||||
.Select(cv => cv.Path)
|
||||
.FirstOrDefault(File.Exists);
|
||||
|
||||
if (path is not null)
|
||||
{
|
||||
return new NativePdbReader(path);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
pdbStream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
using System.Reflection.PortableExecutable;
|
||||
|
||||
namespace Semmle.Extraction.PDB
|
||||
{
|
||||
internal static class PdbReader
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the PDB information associated with an assembly.
|
||||
/// </summary>
|
||||
/// <param name="assemblyPath">The path to the assembly.</param>
|
||||
/// <param name="peReader">The PE reader for the assembly.</param>
|
||||
/// <returns>A PdbReader, or null if no PDB information is available.</returns>
|
||||
public static IPdb? Create(string assemblyPath, PEReader peReader)
|
||||
{
|
||||
return (IPdb?)MetadataPdbReader.CreateFromAssembly(assemblyPath, peReader) ??
|
||||
NativePdbReader.CreateFromAssembly(peReader);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
namespace Semmle.Extraction.PDB
|
||||
{
|
||||
/// <summary>
|
||||
/// A sequencepoint is a marker in the source code where you can put a breakpoint, and
|
||||
/// maps instructions to source code.
|
||||
/// </summary>
|
||||
public struct SequencePoint
|
||||
{
|
||||
/// <summary>
|
||||
/// The byte-offset of the instruction.
|
||||
/// </summary>
|
||||
public int Offset { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The source location of the instruction.
|
||||
/// </summary>
|
||||
public Location Location { get; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0} = {1}", Offset, Location);
|
||||
}
|
||||
|
||||
public SequencePoint(int offset, Location location)
|
||||
{
|
||||
Offset = offset;
|
||||
Location = location;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Semmle.Extraction.CIL")]
|
||||
[assembly: AssemblyDescription("Semme CIL extractor.")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Semmle.Extraction.CIL")]
|
||||
[assembly: AssemblyCopyright("Copyright © Semmle 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("a23d9ec2-8aae-43da-97cb-579f640b89cd")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -1,34 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Extraction.CIL</AssemblyName>
|
||||
<RootNamespace>Semmle.Extraction.CIL</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>DEBUG;DEBUG_LABELS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.DiaSymReader" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.DiaSymReader.Native" Version="1.7.0" />
|
||||
<PackageReference Include="Microsoft.DiaSymReader.PortablePdb" Version="1.6.0"><IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,227 +0,0 @@
|
|||
using Semmle.Extraction.CIL.Entities;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
|
||||
internal static class Tuples
|
||||
{
|
||||
internal static Tuple assemblies(Assembly assembly, File file, string identifier, string name, string version) =>
|
||||
new Tuple("assemblies", assembly, file, identifier, name, version);
|
||||
|
||||
internal static Tuple cil_abstract(IMember method) =>
|
||||
new Tuple("cil_abstract", method);
|
||||
|
||||
internal static Tuple cil_adder(Event member, Method method) =>
|
||||
new Tuple("cil_adder", member, method);
|
||||
|
||||
internal static Tuple cil_access(Instruction i, IExtractedEntity m) =>
|
||||
new Tuple("cil_access", i, m);
|
||||
|
||||
internal static Tuple cil_attribute(Attribute attribute, IExtractedEntity @object, Method constructor) =>
|
||||
new Tuple("cil_attribute", attribute, @object, constructor);
|
||||
|
||||
internal static Tuple cil_attribute_named_argument(Attribute attribute, string name, string value) =>
|
||||
new Tuple("cil_attribute_named_argument", attribute, name, value);
|
||||
|
||||
internal static Tuple cil_attribute_positional_argument(Attribute attribute, int index, string value) =>
|
||||
new Tuple("cil_attribute_positional_argument", attribute, index, value);
|
||||
|
||||
internal static Tuple cil_array_type(ArrayType array, Type element, int rank) =>
|
||||
new Tuple("cil_array_type", array, element, rank);
|
||||
|
||||
internal static Tuple cil_base_class(Type t, Type @base) =>
|
||||
new Tuple("cil_base_class", t, @base);
|
||||
|
||||
internal static Tuple cil_enum_underlying_type(Type t, PrimitiveType underlying) =>
|
||||
new Tuple("cil_enum_underlying_type", t, underlying);
|
||||
|
||||
internal static Tuple cil_base_interface(Type t, Type @base) =>
|
||||
new Tuple("cil_base_interface", t, @base);
|
||||
|
||||
internal static Tuple cil_class(TypeDefinitionType type) =>
|
||||
new Tuple("cil_class", type);
|
||||
|
||||
internal static Tuple cil_event(Event e, Type parent, string name, Type type) =>
|
||||
new Tuple("cil_event", e, parent, name, type);
|
||||
|
||||
internal static Tuple cil_field(Field field, Type parent, string name, Type fieldType) =>
|
||||
new Tuple("cil_field", field, parent, name, fieldType);
|
||||
|
||||
internal static Tuple cil_getter(Property member, Method method) =>
|
||||
new Tuple("cil_getter", member, method);
|
||||
|
||||
internal static Tuple cil_handler(ExceptionRegion region, MethodImplementation method, int index, int kind,
|
||||
Instruction region_start,
|
||||
Instruction region_end,
|
||||
Instruction handler_start) =>
|
||||
new Tuple("cil_handler", region, method, index, kind, region_start, region_end, handler_start);
|
||||
|
||||
internal static Tuple cil_handler_filter(ExceptionRegion region, Instruction filter_start) =>
|
||||
new Tuple("cil_handler_filter", region, filter_start);
|
||||
|
||||
internal static Tuple cil_handler_type(ExceptionRegion region, Type t) =>
|
||||
new Tuple("cil_handler_type", region, t);
|
||||
|
||||
internal static Tuple cil_implements(Method derived, Method declaration) =>
|
||||
new Tuple("cil_implements", derived, declaration);
|
||||
|
||||
internal static Tuple cil_instruction(Instruction instruction, int opcode, int index, MethodImplementation parent) =>
|
||||
new Tuple("cil_instruction", instruction, opcode, index, parent);
|
||||
|
||||
internal static Tuple cil_instruction_location(Instruction i, PdbSourceLocation loc) =>
|
||||
new Tuple("cil_instruction_location", i, loc);
|
||||
|
||||
internal static Tuple cil_interface(TypeDefinitionType type) =>
|
||||
new Tuple("cil_interface", type);
|
||||
|
||||
internal static Tuple cil_internal(DefinitionField field) =>
|
||||
new Tuple("cil_internal", field);
|
||||
|
||||
internal static Tuple cil_jump(Instruction from, Instruction to) =>
|
||||
new Tuple("cil_jump", from, to);
|
||||
|
||||
internal static Tuple cil_local_variable(LocalVariable l, MethodImplementation m, int i, Type t) =>
|
||||
new Tuple("cil_local_variable", l, m, i, t);
|
||||
|
||||
internal static Tuple cil_method(Method method, string name, Type declType, Type returnType) =>
|
||||
new Tuple("cil_method", method, name, declType, returnType);
|
||||
|
||||
internal static Tuple cil_function_pointer_return_type(FunctionPointerType fnptr, Type returnType) =>
|
||||
new Tuple("cil_function_pointer_return_type", fnptr, returnType);
|
||||
|
||||
internal static Tuple cil_function_pointer_calling_conventions(FunctionPointerType fnptr, System.Reflection.Metadata.SignatureCallingConvention callingConvention) =>
|
||||
new Tuple("cil_function_pointer_calling_conventions", fnptr, (int)callingConvention);
|
||||
|
||||
internal static Tuple cil_method_implementation(MethodImplementation impl, Method method, Assembly assembly) =>
|
||||
new Tuple("cil_method_implementation", impl, method, assembly);
|
||||
|
||||
internal static Tuple cil_method_location(Method m, ILocation a) =>
|
||||
new Tuple("cil_method_location", m, a);
|
||||
|
||||
internal static Tuple cil_method_source_declaration(Method method, Method sourceDecl) =>
|
||||
new Tuple("cil_method_source_declaration", method, sourceDecl);
|
||||
|
||||
internal static Tuple cil_method_stack_size(MethodImplementation method, int stackSize) =>
|
||||
new Tuple("cil_method_stack_size", method, stackSize);
|
||||
|
||||
internal static Tuple cil_newslot(Method method) =>
|
||||
new Tuple("cil_newslot", method);
|
||||
|
||||
internal static Tuple cil_parameter(Parameter p, IParameterizable m, int i, Type t) =>
|
||||
new Tuple("cil_parameter", p, m, i, t);
|
||||
|
||||
internal static Tuple cil_parameter_in(Parameter p) =>
|
||||
new Tuple("cil_parameter_in", p);
|
||||
|
||||
internal static Tuple cil_parameter_out(Parameter p) =>
|
||||
new Tuple("cil_parameter_out", p);
|
||||
|
||||
internal static Tuple cil_pointer_type(PointerType t, Type pointee) =>
|
||||
new Tuple("cil_pointer_type", t, pointee);
|
||||
|
||||
internal static Tuple cil_private(IMember modifiable) =>
|
||||
new Tuple("cil_private", modifiable);
|
||||
|
||||
internal static Tuple cil_protected(IMember modifiable) =>
|
||||
new Tuple("cil_protected", modifiable);
|
||||
|
||||
internal static Tuple cil_property(Property p, Type parent, string name, Type propType) =>
|
||||
new Tuple("cil_property", p, parent, name, propType);
|
||||
|
||||
internal static Tuple cil_public(IMember modifiable) =>
|
||||
new Tuple("cil_public", modifiable);
|
||||
|
||||
internal static Tuple cil_raiser(Event member, Method method) =>
|
||||
new Tuple("cil_raiser", member, method);
|
||||
|
||||
internal static Tuple cil_requiresecobject(Method method) =>
|
||||
new Tuple("cil_requiresecobject", method);
|
||||
|
||||
internal static Tuple cil_remover(Event member, Method method) =>
|
||||
new Tuple("cil_remover", member, method);
|
||||
|
||||
internal static Tuple cil_sealed(IMember modifiable) =>
|
||||
new Tuple("cil_sealed", modifiable);
|
||||
|
||||
internal static Tuple cil_security(IMember method) =>
|
||||
new Tuple("cil_security", method);
|
||||
|
||||
internal static Tuple cil_setter(Property member, Method method) =>
|
||||
new Tuple("cil_setter", member, method);
|
||||
|
||||
internal static Tuple cil_specialname(Method method) =>
|
||||
new Tuple("cil_specialname", method);
|
||||
|
||||
internal static Tuple cil_static(IMember modifiable) =>
|
||||
new Tuple("cil_static", modifiable);
|
||||
|
||||
internal static Tuple cil_switch(Instruction from, int index, Instruction to) =>
|
||||
new Tuple("cil_switch", from, index, to);
|
||||
|
||||
internal static Tuple cil_type(Type t, string name, CilTypeKind kind, TypeContainer parent, Type sourceDecl) =>
|
||||
new Tuple("cil_type", t, name, (int)kind, parent, sourceDecl);
|
||||
|
||||
internal static Tuple cil_type_argument(TypeContainer constructedTypeOrMethod, int index, Type argument) =>
|
||||
new Tuple("cil_type_argument", constructedTypeOrMethod, index, argument);
|
||||
|
||||
internal static Tuple cil_type_location(Type t, Assembly a) =>
|
||||
new Tuple("cil_type_location", t, a);
|
||||
|
||||
internal static Tuple cil_type_parameter(TypeContainer unboundTypeOrMethod, int index, TypeParameter parameter) =>
|
||||
new Tuple("cil_type_parameter", unboundTypeOrMethod, index, parameter);
|
||||
|
||||
internal static Tuple cil_typeparam_covariant(TypeParameter p) =>
|
||||
new Tuple("cil_typeparam_covariant", p);
|
||||
|
||||
internal static Tuple cil_typeparam_contravariant(TypeParameter p) =>
|
||||
new Tuple("cil_typeparam_contravariant", p);
|
||||
|
||||
internal static Tuple cil_typeparam_class(TypeParameter p) =>
|
||||
new Tuple("cil_typeparam_class", p);
|
||||
|
||||
internal static Tuple cil_typeparam_constraint(TypeParameter p, Type constraint) =>
|
||||
new Tuple("cil_typeparam_constraint", p, constraint);
|
||||
|
||||
internal static Tuple cil_typeparam_new(TypeParameter p) =>
|
||||
new Tuple("cil_typeparam_new", p);
|
||||
|
||||
internal static Tuple cil_typeparam_struct(TypeParameter p) =>
|
||||
new Tuple("cil_typeparam_struct", p);
|
||||
|
||||
internal static Tuple cil_value(Instruction i, string value) =>
|
||||
new Tuple("cil_value", i, value);
|
||||
|
||||
internal static Tuple cil_virtual(Method method) =>
|
||||
new Tuple("cil_virtual", method);
|
||||
|
||||
internal static Tuple cil_custom_modifiers(ICustomModifierReceiver receiver, Type modifier, bool isRequired) =>
|
||||
new Tuple("cil_custom_modifiers", receiver, modifier, isRequired ? 1 : 0);
|
||||
|
||||
internal static Tuple cil_type_annotation(IExtractedEntity receiver, TypeAnnotation annotation) =>
|
||||
new Tuple("cil_type_annotation", receiver, (int)annotation);
|
||||
|
||||
internal static Tuple containerparent(Folder parent, IFileOrFolder child) =>
|
||||
new Tuple("containerparent", parent, child);
|
||||
|
||||
internal static Tuple files(File file, string fullName) =>
|
||||
new Tuple("files", file, fullName);
|
||||
|
||||
internal static Tuple file_extraction_mode(File file, ExtractorMode mode) =>
|
||||
new Tuple("file_extraction_mode", file, mode);
|
||||
|
||||
internal static Tuple folders(Folder folder, string path) =>
|
||||
new Tuple("folders", folder, path);
|
||||
|
||||
internal static Tuple locations_default(PdbSourceLocation label, File file, int startLine, int startCol, int endLine, int endCol) =>
|
||||
new Tuple("locations_default", label, file, startLine, startCol, endLine, endCol);
|
||||
|
||||
internal static Tuple metadata_handle(IExtractedEntity entity, Assembly assembly, int handleValue) =>
|
||||
new Tuple("metadata_handle", entity, assembly, handleValue);
|
||||
|
||||
internal static Tuple namespaces(Namespace ns, string name) =>
|
||||
new Tuple("namespaces", ns, name);
|
||||
|
||||
internal static Tuple parent_namespace(TypeContainer child, Namespace parent) =>
|
||||
new Tuple("parent_namespace", child, parent);
|
||||
}
|
||||
}
|
|
@ -58,7 +58,6 @@ namespace Semmle.Extraction.CSharp.Standalone
|
|||
output.WriteLine("Additional options:\n");
|
||||
output.WriteLine(" --threads:nnn Specify number of threads (default=CPU cores)");
|
||||
output.WriteLine(" --verbose Produce more output");
|
||||
output.WriteLine(" --pdb Cross-reference information from PDBs where available");
|
||||
}
|
||||
|
||||
private Options()
|
||||
|
|
|
@ -66,9 +66,6 @@ namespace Semmle.Extraction.CSharp
|
|||
{
|
||||
foreach (var assembly in compilation.References.OfType<PortableExecutableReference>())
|
||||
{
|
||||
// CIL first - it takes longer.
|
||||
if (options.CIL)
|
||||
extractionTasks.Add(() => DoExtractCIL(assembly));
|
||||
extractionTasks.Add(() => DoAnalyseReferenceAssembly(assembly));
|
||||
}
|
||||
}
|
||||
|
@ -177,17 +174,6 @@ namespace Semmle.Extraction.CSharp
|
|||
}
|
||||
}
|
||||
|
||||
private void DoExtractCIL(PortableExecutableReference r)
|
||||
{
|
||||
var currentTaskId = IncrementTaskCount();
|
||||
ReportProgressTaskStarted(currentTaskId, r.FilePath);
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
CIL.Analyser.ExtractCIL(r.FilePath!, Logger, options, out var trapFile, out var extracted);
|
||||
stopwatch.Stop();
|
||||
ReportProgressTaskDone(currentTaskId, r.FilePath, trapFile, stopwatch.Elapsed, extracted ? AnalysisAction.Extracted : AnalysisAction.UpToDate);
|
||||
}
|
||||
|
||||
private void DoExtractTree(SyntaxTree tree)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CIL\Semmle.Extraction.CIL.csproj" />
|
||||
<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" />
|
||||
|
|
|
@ -22,14 +22,12 @@ namespace Semmle.Extraction.Tests
|
|||
{
|
||||
options = CSharp.Options.CreateWithEnvironment(Array.Empty<string>());
|
||||
Assert.True(options.Cache);
|
||||
Assert.False(options.CIL);
|
||||
Assert.Null(options.Framework);
|
||||
Assert.Null(options.CompilerName);
|
||||
Assert.Empty(options.CompilerArguments);
|
||||
Assert.True(options.Threads >= 1);
|
||||
Assert.Equal(Verbosity.Info, options.LegacyVerbosity);
|
||||
Assert.False(options.Console);
|
||||
Assert.False(options.PDB);
|
||||
Assert.False(options.Fast);
|
||||
Assert.Equal(TrapWriter.CompressionMode.Brotli, options.TrapCompression);
|
||||
}
|
||||
|
@ -48,25 +46,6 @@ namespace Semmle.Extraction.Tests
|
|||
Assert.False(options.Cache);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CIL()
|
||||
{
|
||||
options = CSharp.Options.CreateWithEnvironment(Array.Empty<string>());
|
||||
Assert.False(options.CIL);
|
||||
|
||||
Environment.SetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OPTION_CIL", "false");
|
||||
options = CSharp.Options.CreateWithEnvironment(Array.Empty<string>());
|
||||
Assert.False(options.CIL);
|
||||
|
||||
Environment.SetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OPTION_CIL", "true");
|
||||
options = CSharp.Options.CreateWithEnvironment(Array.Empty<string>());
|
||||
Assert.True(options.CIL);
|
||||
|
||||
Environment.SetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OPTION_CIL", null);
|
||||
options = CSharp.Options.CreateWithEnvironment(Array.Empty<string>());
|
||||
Assert.False(options.CIL);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompilerArguments()
|
||||
{
|
||||
|
@ -141,13 +120,6 @@ namespace Semmle.Extraction.Tests
|
|||
Assert.True(options.Console);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PDB()
|
||||
{
|
||||
options = CSharp.Options.CreateWithEnvironment(new string[] { "--pdb" });
|
||||
Assert.True(options.PDB);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Compiler()
|
||||
{
|
||||
|
|
|
@ -55,21 +55,11 @@ namespace Semmle.Extraction
|
|||
/// </summary>
|
||||
public bool Console { get; private set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Holds if CIL should be extracted.
|
||||
/// </summary>
|
||||
public bool CIL { get; private set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Holds if assemblies shouldn't be extracted twice.
|
||||
/// </summary>
|
||||
public bool Cache { get; private set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to extract PDB information.
|
||||
/// </summary>
|
||||
public bool PDB { get; private set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether "fast extraction mode" has been enabled.
|
||||
/// </summary>
|
||||
|
@ -102,9 +92,6 @@ namespace Semmle.Extraction
|
|||
return true;
|
||||
}
|
||||
return false;
|
||||
case "cil":
|
||||
CIL = Boolean.Parse(value);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -128,12 +115,7 @@ namespace Semmle.Extraction
|
|||
case "cache":
|
||||
Cache = value;
|
||||
return true;
|
||||
case "pdb":
|
||||
PDB = value;
|
||||
CIL = true;
|
||||
return true;
|
||||
case "fast":
|
||||
CIL = !value;
|
||||
Fast = value;
|
||||
return true;
|
||||
case "qltest":
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace Semmle.Util
|
|||
|
||||
public static class OptionsExtensions
|
||||
{
|
||||
private static readonly string[] ExtractorOptions = new[] { "trap_compression", "cil" };
|
||||
private static readonly string[] ExtractorOptions = ["trap_compression"];
|
||||
private static List<string> GetExtractorOptions()
|
||||
{
|
||||
var extractorOptions = new List<string>();
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
category: breaking
|
||||
---
|
||||
* The CIL extractor has been deleted and the corresponding extractor option `cil` has been removed. It is no longer possible to do CIL extraction.
|
|
@ -1,5 +0,0 @@
|
|||
using System;
|
||||
|
||||
class Test
|
||||
{
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,47 +0,0 @@
|
|||
import semmle.code.cil.Attribute
|
||||
import semmle.code.cil.Declaration
|
||||
|
||||
deprecated private predicate isOsSpecific(Declaration d) {
|
||||
d.getFullyQualifiedName()
|
||||
.matches("%" +
|
||||
[
|
||||
"libobjc", "libproc", "libc", "Interop.OSReleaseFile", "Interop.Sys",
|
||||
"System.Runtime.InteropServices.ObjectiveC.ObjectiveCMarshal",
|
||||
"System.Diagnostics.Tracing.XplatEventLogger", "System.Threading.AutoreleasePool",
|
||||
"System.CLRConfig", "System.Diagnostics.Tracing.EventSource.<WriteEventString>",
|
||||
"System.IO.FileSystem.<TryCloneFile>"
|
||||
] + "%")
|
||||
}
|
||||
|
||||
deprecated query predicate attrNoArg(string dec, string attr) {
|
||||
exists(Declaration d, Attribute a |
|
||||
not isOsSpecific(d) and
|
||||
a.getDeclaration() = d and
|
||||
not exists(a.getAnArgument())
|
||||
|
|
||||
dec = d.toStringWithTypes() and
|
||||
attr = a.toStringWithTypes()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated query predicate attrArgNamed(string dec, string attr, string name, string value) {
|
||||
exists(Declaration d, Attribute a |
|
||||
a.getDeclaration() = d and
|
||||
not isOsSpecific(d) and
|
||||
a.getNamedArgument(name) = value
|
||||
|
|
||||
dec = d.toStringWithTypes() and
|
||||
attr = a.toStringWithTypes()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated query predicate attrArgPositional(string dec, string attr, int index, string value) {
|
||||
exists(Declaration d, Attribute a |
|
||||
a.getDeclaration() = d and
|
||||
not isOsSpecific(d) and
|
||||
a.getArgument(index) = value
|
||||
|
|
||||
dec = d.toStringWithTypes() and
|
||||
attr = a.toStringWithTypes()
|
||||
)
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
semmle-extractor-options: --cil
|
|
@ -1,14 +0,0 @@
|
|||
tooManyHandles
|
||||
tooManyMatchingHandles
|
||||
missingCil
|
||||
csharpLocationViolation
|
||||
matchingObjectMethods
|
||||
| Equals(object) | System.Boolean System.Object.Equals(System.Object) |
|
||||
| Equals(object, object) | System.Boolean System.Object.Equals(System.Object,System.Object) |
|
||||
| GetHashCode() | System.Int32 System.Object.GetHashCode() |
|
||||
| GetType() | System.Type System.Object.GetType() |
|
||||
| MemberwiseClone() | System.Object System.Object.MemberwiseClone() |
|
||||
| Object() | System.Void System.Object..ctor() |
|
||||
| ReferenceEquals(object, object) | System.Boolean System.Object.ReferenceEquals(System.Object,System.Object) |
|
||||
| ToString() | System.String System.Object.ToString() |
|
||||
| ~Object() | System.Void System.Object.Finalize() |
|
|
@ -1,68 +0,0 @@
|
|||
import csharp
|
||||
import cil
|
||||
import dotnet
|
||||
import semmle.code.csharp.commons.QualifiedName
|
||||
|
||||
deprecated class MetadataEntity extends DotNet::NamedElement, @metadata_entity {
|
||||
int getHandle() { metadata_handle(this, _, result) }
|
||||
|
||||
predicate hasHandle() { exists(this.getHandle()) }
|
||||
|
||||
Assembly getAssembly() { metadata_handle(this, result, _) }
|
||||
}
|
||||
|
||||
deprecated query predicate tooManyHandles(string s) {
|
||||
exists(MetadataEntity e, Assembly a, string qualifier, string name |
|
||||
strictcount(int handle | metadata_handle(e, a, handle)) > 1 and
|
||||
e.hasFullyQualifiedName(qualifier, name) and
|
||||
s = getQualifiedName(qualifier, name)
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private class UniqueMetadataEntity extends MetadataEntity {
|
||||
UniqueMetadataEntity() {
|
||||
// Tuple types such as `(,)` and `ValueTuple`2` share the same handle
|
||||
not this instanceof TupleType and
|
||||
not exists(string name |
|
||||
this.hasFullyQualifiedName("System", name) and
|
||||
name.matches("System.ValueTuple%")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated query predicate tooManyMatchingHandles(string s) {
|
||||
exists(UniqueMetadataEntity e, Assembly a, int handle, string qualifier, string name |
|
||||
metadata_handle(e, a, handle) and
|
||||
strictcount(UniqueMetadataEntity e2 | metadata_handle(e2, a, handle)) > 2 and
|
||||
e.hasFullyQualifiedName(qualifier, name) and
|
||||
s = getQualifiedName(qualifier, name)
|
||||
)
|
||||
}
|
||||
|
||||
deprecated query predicate missingCil(Element e) {
|
||||
(
|
||||
e instanceof Callable
|
||||
or
|
||||
e instanceof Type
|
||||
or
|
||||
e instanceof Field
|
||||
) and
|
||||
e.fromLibrary() and
|
||||
e.(MetadataEntity).hasHandle() and
|
||||
not exists(CIL::Element ce | ce.(MetadataEntity).matchesHandle(e))
|
||||
}
|
||||
|
||||
deprecated query predicate csharpLocationViolation(Element e) {
|
||||
e.fromLibrary() and
|
||||
e.(MetadataEntity).hasHandle() and
|
||||
not e.getALocation() = e.(MetadataEntity).getAssembly()
|
||||
}
|
||||
|
||||
deprecated query predicate matchingObjectMethods(string s1, string s2) {
|
||||
exists(Callable m1, CIL::Method m2 |
|
||||
m1.getDeclaringType().hasFullyQualifiedName("System", "Object") and
|
||||
m1.(DotNet::Callable).matchesHandle(m2) and
|
||||
s1 = m1.toStringWithTypes() and
|
||||
s2 = m2.toStringWithTypes()
|
||||
)
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
using System;
|
||||
|
||||
class Test
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
}
|
||||
}
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,6 +0,0 @@
|
|||
import cil
|
||||
import semmle.code.cil.ConsistencyChecks
|
||||
|
||||
deprecated query predicate consistencyViolation(ConsistencyViolation v, string message) {
|
||||
message = v.getMessage()
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
semmle-extractor-options: --cil
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче