C#: Migrate extractor to this repository.

This commit is contained in:
calum
2018-10-08 12:47:37 +01:00
parent 3e022ad36f
commit 103d140e71
247 changed files with 25866 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
using Microsoft.CodeAnalysis;
namespace Semmle.Extraction.Entities
{
public class Assembly : Location
{
readonly string assemblyPath;
readonly IAssemblySymbol assembly;
Assembly(Context cx, Microsoft.CodeAnalysis.Location init)
: base(cx, init)
{
if (init == null)
{
// This is the output assembly
assemblyPath = cx.Extractor.OutputPath;
assembly = cx.Compilation.Assembly;
}
else
{
assembly = symbol.MetadataModule.ContainingAssembly;
var identity = assembly.Identity;
var idString = identity.Name + " " + identity.Version;
assemblyPath = cx.Extractor.GetAssemblyFile(idString);
}
}
public override void Populate()
{
if (assemblyPath != null)
{
Context.Emit(Tuples.assemblies(this, File.Create(Context, assemblyPath), assembly.ToString(),
assembly.Identity.Name, assembly.Identity.Version.ToString()));
}
}
public override bool NeedsPopulation => true;
public override int GetHashCode() =>
symbol == null ? 91187354 : symbol.GetHashCode();
public override bool Equals(object obj)
{
var other = obj as Assembly;
if (other == null || other.GetType() != typeof(Assembly))
return false;
return Equals(symbol, other.symbol);
}
public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => AssemblyConstructorFactory.Instance.CreateEntity(cx, loc);
class AssemblyConstructorFactory : ICachedEntityFactory<Microsoft.CodeAnalysis.Location, Assembly>
{
public static readonly AssemblyConstructorFactory Instance = new AssemblyConstructorFactory();
public Assembly Create(Context cx, Microsoft.CodeAnalysis.Location init) => new Assembly(cx, init);
}
public static Location CreateOutputAssembly(Context cx)
{
if (cx.Extractor.OutputPath == null)
throw new InternalError("Attempting to create the output assembly in standalone extraction mode");
return AssemblyConstructorFactory.Instance.CreateEntity(cx, null);
}
public override IId Id
{
get
{
return assemblyPath == null
? new Key(assembly, ";assembly")
: new Key(assembly, "#file:///", assemblyPath.Replace("\\", "/"), ";assembly");
}
}
}
}

View File

@@ -0,0 +1,124 @@
using Semmle.Util;
using System;
using System.IO;
using System.Linq;
namespace Semmle.Extraction.Entities
{
public class File : CachedEntity<string>
{
File(Context cx, string path)
: base(cx, path)
{
Path = path;
}
public string Path
{
get;
private set;
}
public string DatabasePath => FileAsDatabaseString(Path);
public override bool NeedsPopulation => Context.DefinesFile(Path) || Path == Context.Extractor.OutputPath;
public override void Populate()
{
if (Path == null)
{
Context.Emit(Tuples.files(this, "", "", ""));
}
else
{
var fi = new FileInfo(Path);
string extension = fi.Extension ?? "";
string name = fi.Name;
name = name.Substring(0, name.Length - extension.Length);
int fromSource = extension.ToLowerInvariant().Equals(".cs") ? 1 : 2;
// remove the dot from the extension
if (extension.Length > 0)
extension = extension.Substring(1);
Context.Emit(Tuples.files(this, DatabasePath, name, extension));
Context.Emit(Tuples.containerparent(Entities.Folder.Create(Context, fi.Directory), this));
if (fromSource == 1)
{
foreach (var text in Context.Compilation.SyntaxTrees.
Where(t => t.FilePath == Path).
Select(tree => tree.GetText()))
{
var rawText = text.ToString();
var lineCounts = LineCounter.ComputeLineCounts(rawText);
if (rawText.Length > 0 && rawText[rawText.Length - 1] != '\n') lineCounts.Total++;
Context.Emit(Tuples.numlines(this, lineCounts));
Context.TrapWriter.Archive(fi.FullName, text.Encoding);
}
}
Context.Emit(Tuples.file_extraction_mode(this, Context.Extractor.Standalone ? 1 : 0));
}
}
public override IId Id
{
get
{
return Path == null ?
new Key("GENERATED;sourcefile") :
new Key(DatabasePath, ";sourcefile");
}
}
internal static string FileAsDatabaseString(string fileName)
{
fileName = fileName.Replace('\\', '/');
if (fileName.Length > 1 && fileName[1] == ':')
fileName = Char.ToUpper(fileName[0]) + fileName.Substring(1);
return fileName;
}
public static File Create(Context cx, string path) => FileFactory.Instance.CreateEntity(cx, path);
public static File CreateGenerated(Context cx) => GeneratedFile.Create(cx);
class GeneratedFile : File
{
GeneratedFile(Context cx)
: base(cx, "") { }
public override bool NeedsPopulation => true;
public override void Populate()
{
Context.Emit(Tuples.files(this, "", "", ""));
}
public override IId Id => new Key("GENERATED;sourcefile");
public static GeneratedFile Create(Context cx) =>
GeneratedFileFactory.Instance.CreateEntity(cx, null);
class GeneratedFileFactory : ICachedEntityFactory<string, GeneratedFile>
{
public static readonly GeneratedFileFactory Instance = new GeneratedFileFactory();
public GeneratedFile Create(Context cx, string init) => new GeneratedFile(cx);
}
}
public override Microsoft.CodeAnalysis.Location ReportingLocation => null;
class FileFactory : ICachedEntityFactory<string, File>
{
public static readonly FileFactory Instance = new FileFactory();
public File Create(Context cx, string init) => new File(cx, init);
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
}

View File

@@ -0,0 +1,55 @@
using System.IO;
namespace Semmle.Extraction.Entities
{
class Folder : CachedEntity<DirectoryInfo>
{
Folder(Context cx, DirectoryInfo init)
: base(cx, init)
{
Path = init.FullName;
}
public string Path
{
get;
private set;
}
public string DatabasePath => File.FileAsDatabaseString(Path);
public override void Populate()
{
// Ensure that the name of the root directory is consistent
// with the XmlTrapWriter.
// Linux/Windows: java.io.File.getName() returns ""
// On Linux: System.IO.DirectoryInfo.Name returns "/"
// On Windows: System.IO.DirectoryInfo.Name returns "L:\"
string shortName = symbol.Parent == null ? "" : symbol.Name;
Context.Emit(Tuples.folders(this, DatabasePath, shortName));
if (symbol.Parent != null)
{
Context.Emit(Tuples.containerparent(Create(Context, symbol.Parent), this));
}
}
public override bool NeedsPopulation => true;
public override IId Id => new Key(DatabasePath, ";folder");
public static Folder Create(Context cx, DirectoryInfo folder) =>
FolderFactory.Instance.CreateEntity(cx, folder);
public override Microsoft.CodeAnalysis.Location ReportingLocation => null;
class FolderFactory : ICachedEntityFactory<DirectoryInfo, Folder>
{
public static readonly FolderFactory Instance = new FolderFactory();
public Folder Create(Context cx, DirectoryInfo init) => new Folder(cx, init);
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
}

View File

@@ -0,0 +1,33 @@
namespace Semmle.Extraction.Entities
{
public class GeneratedLocation : SourceLocation
{
readonly File GeneratedFile;
GeneratedLocation(Context cx)
: base(cx, null)
{
GeneratedFile = File.CreateGenerated(cx);
}
public override void Populate()
{
Context.Emit(Tuples.locations_default(this, GeneratedFile, 0, 0, 0, 0));
}
public override IId Id => new Key("loc,", GeneratedFile, ",0,0,0,0");
public override int GetHashCode() => 98732567;
public override bool Equals(object obj) => obj != null && obj.GetType() == typeof(GeneratedLocation);
public static GeneratedLocation Create(Context cx) => GeneratedLocationFactory.Instance.CreateEntity(cx, null);
class GeneratedLocationFactory : ICachedEntityFactory<string, GeneratedLocation>
{
public static GeneratedLocationFactory Instance = new GeneratedLocationFactory();
public GeneratedLocation Create(Context cx, string init) => new GeneratedLocation(cx);
}
}
}

View File

@@ -0,0 +1,30 @@
namespace Semmle.Extraction.Entities
{
public abstract class Location : CachedEntity<Microsoft.CodeAnalysis.Location>
{
public Location(Context cx, Microsoft.CodeAnalysis.Location init)
: base(cx, init) { }
internal static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) =>
loc == null ? GeneratedLocation.Create(cx)
: loc.IsInSource ? SourceLocation.Create(cx, loc)
: Assembly.Create(cx, loc);
public override Microsoft.CodeAnalysis.Location ReportingLocation => symbol;
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel;
}
public static class LocationExtensions
{
/// <summary>
/// Creates a Location entity.
/// </summary>
/// <param name="cx">The extraction context.</param>
/// <param name="location">The CodeAnalysis location.</param>
/// <returns>The Location entity.</returns>
public static Location Create(this Context cx, Microsoft.CodeAnalysis.Location location) =>
Location.Create(cx, location);
}
}

View File

@@ -0,0 +1,52 @@
using Microsoft.CodeAnalysis;
namespace Semmle.Extraction.Entities
{
public class SourceLocation : Location
{
protected SourceLocation(Context cx, Microsoft.CodeAnalysis.Location init)
: base(cx, init) { }
public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => SourceLocationFactory.Instance.CreateEntity(cx, loc);
public override void Populate()
{
Position = symbol.GetLineSpan();
FileEntity = File.Create(Context, Position.Path);
Context.Emit(Tuples.locations_default(this, FileEntity, Position.Span.Start.Line + 1, Position.Span.Start.Character + 1,
Position.Span.End.Line + 1, Position.Span.End.Character));
}
public override bool NeedsPopulation => true;
public FileLinePositionSpan Position
{
get;
private set;
}
public File FileEntity
{
get;
private set;
}
public override IId Id
{
get
{
FileLinePositionSpan l = symbol.GetLineSpan();
FileEntity = Entities.File.Create(Context, l.Path);
return new Key("loc,", FileEntity, ",", l.Span.Start.Line + 1, ",",
l.Span.Start.Character + 1, ",", l.Span.End.Line + 1, ",", l.Span.End.Character);
}
}
class SourceLocationFactory : ICachedEntityFactory<Microsoft.CodeAnalysis.Location, SourceLocation>
{
public static readonly SourceLocationFactory Instance = new SourceLocationFactory();
public SourceLocation Create(Context cx, Microsoft.CodeAnalysis.Location init) => new SourceLocation(cx, init);
}
}
}