Make derived 'Context' classes internal and adjust visibility of members in base 'Context'

This commit is contained in:
Tamas Vajk 2021-02-17 10:41:53 +01:00
Родитель 539fdf952a
Коммит 841ef9a4ae
43 изменённых файлов: 145 добавлений и 136 удалений

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

@ -24,7 +24,7 @@ namespace Semmle.Extraction.CIL.Driver
{ {
var sw = new Stopwatch(); var sw = new Stopwatch();
sw.Start(); sw.Start();
Entities.Assembly.ExtractCIL(layout, assemblyPath, logger, nocache, extractPdbs, trapCompression, out _, out _); Analyser.ExtractCIL(layout, assemblyPath, logger, nocache, extractPdbs, trapCompression, out _, out _);
sw.Stop(); sw.Stop();
logger.Log(Severity.Info, " {0} ({1})", assemblyPath, sw.Elapsed); logger.Log(Severity.Info, " {0} ({1})", assemblyPath, sw.Elapsed);
} }

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

@ -0,0 +1,53 @@
using Semmle.Util.Logging;
using System;
using Semmle.Util;
using Semmle.Extraction.CIL.Entities;
namespace Semmle.Extraction.CIL
{
public static class Analyser
{
private static void ExtractCIL(Extractor 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(Layout layout, string assemblyPath, ILogger logger, bool nocache, bool extractPdbs, TrapWriter.CompressionMode trapCompression, out string trapFile, out bool extracted)
{
trapFile = "";
extracted = false;
try
{
var canonicalPathCache = CanonicalPathCache.Create(logger, 1000);
var pathTransformer = new PathTransformer(canonicalPathCache);
var extractor = new Extractor(false, assemblyPath, logger, pathTransformer);
var transformedAssemblyPath = pathTransformer.Transform(assemblyPath);
var project = layout.LookupProjectOrDefault(transformedAssemblyPath);
using var trapWriter = project.CreateTrapWriter(logger, transformedAssemblyPath.WithSuffix(".cil"), trapCompression, discardDuplicates: true);
trapFile = trapWriter.TrapFile;
if (nocache || !System.IO.File.Exists(trapFile))
{
ExtractCIL(extractor, trapWriter, extractPdbs);
extracted = true;
}
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
logger.Log(Severity.Error, string.Format("Exception extracting {0}: {1}", assemblyPath, ex));
}
}
}
}

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

@ -9,11 +9,11 @@ namespace Semmle.Extraction.CIL
/// <summary> /// <summary>
/// Provides methods for creating and caching various entities. /// Provides methods for creating and caching various entities.
/// </summary> /// </summary>
public sealed partial class Context internal sealed partial class Context
{ {
private readonly Dictionary<object, Label> ids = new Dictionary<object, Label>(); private readonly Dictionary<object, Label> ids = new Dictionary<object, Label>();
public T Populate<T>(T e) where T : IExtractedEntity internal T Populate<T>(T e) where T : IExtractedEntity
{ {
if (e.Label.Valid) if (e.Label.Valid)
{ {
@ -28,7 +28,7 @@ namespace Semmle.Extraction.CIL
else else
{ {
e.Label = GetNewLabel(); e.Label = GetNewLabel();
DefineLabel(e, TrapWriter.Writer, Extractor); DefineLabel(e);
ids.Add(e, e.Label); ids.Add(e, e.Label);
PopulateLater(() => PopulateLater(() =>
{ {
@ -76,7 +76,7 @@ namespace Semmle.Extraction.CIL
{ {
Label = GetNewLabel() Label = GetNewLabel()
}; };
DefineLabel(e, TrapWriter.Writer, Extractor); DefineLabel(e);
primitiveTypes[(int)code] = e; primitiveTypes[(int)code] = e;
} }

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

@ -10,7 +10,7 @@ namespace Semmle.Extraction.CIL
/// Adds additional context that is specific for CIL extraction. /// Adds additional context that is specific for CIL extraction.
/// One context = one DLL/EXE. /// One context = one DLL/EXE.
/// </summary> /// </summary>
public sealed partial class Context : Extraction.Context, IDisposable internal sealed partial class Context : Extraction.Context, IDisposable
{ {
private readonly FileStream stream; private readonly FileStream stream;
private Entities.Assembly? assemblyNull; private Entities.Assembly? assemblyNull;

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

@ -5,7 +5,7 @@ namespace Semmle.Extraction.CIL
/// <summary> /// <summary>
/// A generic context which does not contain any type parameters. /// A generic context which does not contain any type parameters.
/// </summary> /// </summary>
public class EmptyContext : IGenericContext internal class EmptyContext : IGenericContext
{ {
public EmptyContext(Context cx) public EmptyContext(Context cx)
{ {

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

@ -1,18 +1,15 @@
using System.Reflection; using System.Reflection;
using System.Globalization; using System.Globalization;
using System.Collections.Generic; using System.Collections.Generic;
using Semmle.Util.Logging;
using System;
using Semmle.Extraction.Entities; using Semmle.Extraction.Entities;
using System.IO; using System.IO;
using Semmle.Util;
namespace Semmle.Extraction.CIL.Entities namespace Semmle.Extraction.CIL.Entities
{ {
/// <summary> /// <summary>
/// An assembly to extract. /// An assembly to extract.
/// </summary> /// </summary>
public class Assembly : LabelledEntity, ILocation internal class Assembly : LabelledEntity, ILocation
{ {
private readonly File file; private readonly File file;
private readonly AssemblyName assemblyName; private readonly AssemblyName assemblyName;
@ -101,48 +98,5 @@ namespace Semmle.Extraction.CIL.Entities
} }
} }
} }
private static void ExtractCIL(Extractor 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(Layout layout, string assemblyPath, ILogger logger, bool nocache, bool extractPdbs, TrapWriter.CompressionMode trapCompression, out string trapFile, out bool extracted)
{
trapFile = "";
extracted = false;
try
{
var canonicalPathCache = CanonicalPathCache.Create(logger, 1000);
var pathTransformer = new PathTransformer(canonicalPathCache);
var extractor = new Extractor(false, assemblyPath, logger, pathTransformer);
var transformedAssemblyPath = pathTransformer.Transform(assemblyPath);
var project = layout.LookupProjectOrDefault(transformedAssemblyPath);
using var trapWriter = project.CreateTrapWriter(logger, transformedAssemblyPath.WithSuffix(".cil"), trapCompression, discardDuplicates: true);
trapFile = trapWriter.TrapFile;
if (nocache || !System.IO.File.Exists(trapFile))
{
ExtractCIL(extractor, trapWriter, extractPdbs);
extracted = true;
}
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
logger.Log(Severity.Error, string.Format("Exception extracting {0}: {1}", assemblyPath, ex));
}
}
} }
} }

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

@ -5,7 +5,7 @@ namespace Semmle.Extraction.CIL
/// <summary> /// <summary>
/// A CIL entity which has been extracted. /// A CIL entity which has been extracted.
/// </summary> /// </summary>
public interface IExtractedEntity : IExtractionProduct, IEntity internal interface IExtractedEntity : IExtractionProduct, IEntity
{ {
/// <summary> /// <summary>
/// The contents of the entity. /// The contents of the entity.

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

@ -12,7 +12,7 @@ namespace Semmle.Extraction.CIL
/// - Enumerate Contents to produce more extraction products /// - Enumerate Contents to produce more extraction products
/// - Extract these until there is nothing left to extract /// - Extract these until there is nothing left to extract
/// </remarks> /// </remarks>
public interface IExtractionProduct internal interface IExtractionProduct
{ {
/// <summary> /// <summary>
/// Perform further extraction/population of this item as necessary. /// Perform further extraction/population of this item as necessary.

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

@ -6,7 +6,7 @@ namespace Semmle.Extraction.CIL
/// When we decode a type/method signature, we need access to /// When we decode a type/method signature, we need access to
/// generic parameters. /// generic parameters.
/// </summary> /// </summary>
public interface IGenericContext internal interface IGenericContext
{ {
Context Cx { get; } Context Cx { get; }

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

@ -8,7 +8,7 @@ namespace Semmle.Extraction.CIL
/// An entity that needs to be populated during extraction. /// An entity that needs to be populated during extraction.
/// This assigns a key and optionally extracts its contents. /// This assigns a key and optionally extracts its contents.
/// </summary> /// </summary>
public abstract class LabelledEntity : Extraction.LabelledEntity, IExtractedEntity internal abstract class LabelledEntity : Extraction.LabelledEntity, IExtractedEntity
{ {
// todo: with .NET 5 this can override the base context, and change the return type. // todo: with .NET 5 this can override the base context, and change the return type.
public Context Cx => (Context)base.Context; public Context Cx => (Context)base.Context;

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

@ -7,7 +7,7 @@ namespace Semmle.Extraction.CIL
/// An entity that has contents to extract. There is no need to populate /// An entity that has contents to extract. There is no need to populate
/// a key as it's done in the contructor. /// a key as it's done in the contructor.
/// </summary> /// </summary>
public abstract class UnlabelledEntity : Extraction.UnlabelledEntity, IExtractedEntity internal abstract class UnlabelledEntity : Extraction.UnlabelledEntity, IExtractedEntity
{ {
// todo: with .NET 5 this can override the base context, and change the return type. // todo: with .NET 5 this can override the base context, and change the return type.
public Context Cx => (Context)base.Context; public Context Cx => (Context)base.Context;

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

@ -9,7 +9,7 @@ namespace Semmle.Extraction.CIL.Entities
/// <summary> /// <summary>
/// A constructed type. /// A constructed type.
/// </summary> /// </summary>
public sealed class ConstructedType : Type internal sealed class ConstructedType : Type
{ {
private readonly Type unboundGenericType; private readonly Type unboundGenericType;

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

@ -3,7 +3,7 @@ using System.IO;
namespace Semmle.Extraction.CIL.Entities namespace Semmle.Extraction.CIL.Entities
{ {
public class File : LabelledEntity, IFileOrFolder internal class File : LabelledEntity, IFileOrFolder
{ {
protected string OriginalPath { get; } protected string OriginalPath { get; }
protected PathTransformer.ITransformedPath TransformedPath { get; } protected PathTransformer.ITransformedPath TransformedPath { get; }

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

@ -3,7 +3,7 @@ using System.IO;
namespace Semmle.Extraction.CIL.Entities namespace Semmle.Extraction.CIL.Entities
{ {
public sealed class Folder : LabelledEntity, IFileOrFolder internal sealed class Folder : LabelledEntity, IFileOrFolder
{ {
private readonly PathTransformer.ITransformedPath transformedPath; private readonly PathTransformer.ITransformedPath transformedPath;

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

@ -7,7 +7,7 @@ namespace Semmle.Extraction.CIL.Entities
/// <summary> /// <summary>
/// A namespace. /// A namespace.
/// </summary> /// </summary>
public sealed class Namespace : TypeContainer internal sealed class Namespace : TypeContainer
{ {
public Namespace? ParentNamespace { get; } public Namespace? ParentNamespace { get; }
public string Name { get; } public string Name { get; }

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

@ -2,7 +2,7 @@ using System.Collections.Generic;
namespace Semmle.Extraction.CIL.Entities namespace Semmle.Extraction.CIL.Entities
{ {
public class PdbSourceFile : File internal class PdbSourceFile : File
{ {
private readonly PDB.ISourceFile file; private readonly PDB.ISourceFile file;

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

@ -5,7 +5,7 @@ using System.IO;
namespace Semmle.Extraction.CIL.Entities namespace Semmle.Extraction.CIL.Entities
{ {
public sealed class PrimitiveType : Type internal sealed class PrimitiveType : Type
{ {
private readonly PrimitiveTypeCode typeCode; private readonly PrimitiveTypeCode typeCode;
public PrimitiveType(Context cx, PrimitiveTypeCode tc) : base(cx) public PrimitiveType(Context cx, PrimitiveTypeCode tc) : base(cx)

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

@ -4,7 +4,7 @@ using Semmle.Extraction.PDB;
namespace Semmle.Extraction.CIL.Entities namespace Semmle.Extraction.CIL.Entities
{ {
public sealed class PdbSourceLocation : LabelledEntity, ILocation internal sealed class PdbSourceLocation : LabelledEntity, ILocation
{ {
private readonly Location location; private readonly Location location;
private readonly PdbSourceFile file; private readonly PdbSourceFile file;

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

@ -9,7 +9,7 @@ namespace Semmle.Extraction.CIL.Entities
/// <summary> /// <summary>
/// A type. /// A type.
/// </summary> /// </summary>
public abstract class Type : TypeContainer, IMember internal abstract class Type : TypeContainer, IMember
{ {
internal const string AssemblyTypeNameSeparator = "::"; internal const string AssemblyTypeNameSeparator = "::";
internal const string PrimitiveTypePrefix = "builtin" + AssemblyTypeNameSeparator + "System."; internal const string PrimitiveTypePrefix = "builtin" + AssemblyTypeNameSeparator + "System.";

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

@ -6,7 +6,7 @@ namespace Semmle.Extraction.CIL.Entities
/// <summary> /// <summary>
/// Base class for all type containers (namespaces, types, methods). /// Base class for all type containers (namespaces, types, methods).
/// </summary> /// </summary>
public abstract class TypeContainer : LabelledEntity, IGenericContext internal abstract class TypeContainer : LabelledEntity, IGenericContext
{ {
protected TypeContainer(Context cx) : base(cx) protected TypeContainer(Context cx) : base(cx)
{ {

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

@ -11,7 +11,7 @@ namespace Semmle.Extraction.CIL.Entities
/// <summary> /// <summary>
/// A type defined in the current assembly. /// A type defined in the current assembly.
/// </summary> /// </summary>
public sealed class TypeDefinitionType : Type internal sealed class TypeDefinitionType : Type
{ {
private readonly TypeDefinitionHandle handle; private readonly TypeDefinitionHandle handle;
private readonly TypeDefinition td; private readonly TypeDefinition td;

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

@ -9,7 +9,7 @@ namespace Semmle.Extraction.CIL.Entities
/// <summary> /// <summary>
/// A type reference, to a type in a referenced assembly. /// A type reference, to a type in a referenced assembly.
/// </summary> /// </summary>
public sealed class TypeReferenceType : Type internal sealed class TypeReferenceType : Type
{ {
private readonly TypeReferenceHandle handle; private readonly TypeReferenceHandle handle;
private readonly TypeReference tr; private readonly TypeReference tr;

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

@ -8,7 +8,7 @@ namespace Semmle.Extraction.CIL.Entities
/// <summary> /// <summary>
/// Decodes a type signature and produces a Type, for use by DecodeSignature() and friends. /// Decodes a type signature and produces a Type, for use by DecodeSignature() and friends.
/// </summary> /// </summary>
public class TypeSignatureDecoder : ISignatureTypeProvider<Type, IGenericContext> internal class TypeSignatureDecoder : ISignatureTypeProvider<Type, IGenericContext>
{ {
private readonly Context cx; private readonly Context cx;

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

@ -310,7 +310,7 @@ namespace Semmle.Extraction.CSharp
{ {
var stopwatch = new Stopwatch(); var stopwatch = new Stopwatch();
stopwatch.Start(); stopwatch.Start();
CIL.Entities.Assembly.ExtractCIL(layout, r.FilePath, Logger, !options.Cache, options.PDB, options.TrapCompression, out var trapFile, out var extracted); CIL.Analyser.ExtractCIL(layout, r.FilePath, Logger, !options.Cache, options.PDB, options.TrapCompression, out var trapFile, out var extracted);
stopwatch.Stop(); stopwatch.Stop();
ReportProgress(r.FilePath, trapFile, stopwatch.Elapsed, extracted ? AnalysisAction.Extracted : AnalysisAction.UpToDate); ReportProgress(r.FilePath, trapFile, stopwatch.Elapsed, extracted ? AnalysisAction.Extracted : AnalysisAction.UpToDate);
} }

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

@ -1,11 +1,9 @@
using Microsoft.CodeAnalysis;
namespace Semmle.Extraction.CSharp namespace Semmle.Extraction.CSharp
{ {
/// <summary> /// <summary>
/// A factory for creating cached entities. /// A factory for creating cached entities.
/// </summary> /// </summary>
public abstract class CachedEntityFactory<TInit, TEntity> internal abstract class CachedEntityFactory<TInit, TEntity>
: Extraction.CachedEntityFactory<TInit, TEntity> where TEntity : CachedEntity : Extraction.CachedEntityFactory<TInit, TEntity> where TEntity : CachedEntity
{ {
/// <summary> /// <summary>

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

@ -2,6 +2,7 @@ using Microsoft.CodeAnalysis;
using System; using System;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Semmle.Extraction.Entities; using Semmle.Extraction.Entities;
using System.Collections.Generic;
namespace Semmle.Extraction.CSharp namespace Semmle.Extraction.CSharp
{ {
@ -9,7 +10,7 @@ namespace Semmle.Extraction.CSharp
/// State that needs to be available throughout the extraction process. /// State that needs to be available throughout the extraction process.
/// There is one Context object per trap output file. /// There is one Context object per trap output file.
/// </summary> /// </summary>
public class Context : Extraction.Context internal class Context : Extraction.Context
{ {
/// <summary> /// <summary>
/// The program database provided by Roslyn. /// The program database provided by Roslyn.
@ -50,7 +51,7 @@ namespace Semmle.Extraction.CSharp
public bool IsAssemblyScope => scope is AssemblyScope; public bool IsAssemblyScope => scope is AssemblyScope;
public SyntaxTree SourceTree => scope is SourceScope sc ? sc.SourceTree : null; private SyntaxTree SourceTree => scope is SourceScope sc ? sc.SourceTree : null;
/// <summary> /// <summary>
/// Whether the given symbol needs to be defined in this context. /// Whether the given symbol needs to be defined in this context.
@ -116,5 +117,28 @@ namespace Semmle.Extraction.CSharp
loc = null; loc = null;
return false; return false;
} }
private readonly HashSet<Label> extractedGenerics = new HashSet<Label>();
/// <summary>
/// Should the given entity be extracted?
/// A second call to this method will always return false,
/// on the assumption that it would have been extracted on the first call.
///
/// This is used to track the extraction of generics, which cannot be extracted
/// in a top-down manner.
/// </summary>
/// <param name="entity">The entity to extract.</param>
/// <returns>True only on the first call for a particular entity.</returns>
internal bool ExtractGenerics(CachedEntity entity)
{
if (extractedGenerics.Contains(entity.Label))
{
return false;
}
extractedGenerics.Add(entity.Label);
return true;
}
} }
} }

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

@ -4,7 +4,7 @@ using System.IO;
namespace Semmle.Extraction.CSharp.Entities namespace Semmle.Extraction.CSharp.Entities
{ {
public class Assembly : Extraction.Entities.Location internal class Assembly : Extraction.Entities.Location
{ {
// todo: this can be changed to an override after the .NET 5 upgrade // todo: this can be changed to an override after the .NET 5 upgrade
private new Context Context => (Context)base.Context; private new Context Context => (Context)base.Context;

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

@ -1,6 +1,6 @@
namespace Semmle.Extraction.CSharp.Entities namespace Semmle.Extraction.CSharp.Entities
{ {
public abstract class CachedEntity<T> : Extraction.CachedEntity<T> internal abstract class CachedEntity<T> : Extraction.CachedEntity<T>
{ {
// todo: this can be changed to an override after the .NET 5 upgrade // todo: this can be changed to an override after the .NET 5 upgrade
protected new Context Context => (Context)base.Context; protected new Context Context => (Context)base.Context;

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

@ -9,7 +9,7 @@ using System.Reflection.Metadata.Ecma335;
namespace Semmle.Extraction.CSharp.Entities namespace Semmle.Extraction.CSharp.Entities
{ {
public abstract class CachedSymbol<T> : CachedEntity<T> where T : ISymbol internal abstract class CachedSymbol<T> : CachedEntity<T> where T : ISymbol
{ {
// todo: this can be changed to an override after the .NET 5 upgrade // todo: this can be changed to an override after the .NET 5 upgrade
protected new Context Context => (Context)base.Context; protected new Context Context => (Context)base.Context;

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

@ -6,7 +6,7 @@ using Semmle.Util;
namespace Semmle.Extraction.CSharp.Entities namespace Semmle.Extraction.CSharp.Entities
{ {
public class Compilation : CachedEntity<object> internal class Compilation : CachedEntity<object>
{ {
private static (string Cwd, string[] Args) settings; private static (string Cwd, string[] Args) settings;
private static int hashCode; private static int hashCode;

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

@ -8,7 +8,7 @@ using System.IO;
namespace Semmle.Extraction.CSharp.Entities namespace Semmle.Extraction.CSharp.Entities
{ {
public class Constructor : Method internal class Constructor : Method
{ {
private Constructor(Context cx, IMethodSymbol init) private Constructor(Context cx, IMethodSymbol init)
: base(cx, init) { } : base(cx, init) { }

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

@ -23,12 +23,13 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
private static ExprKind GetKind(Context cx, BinaryExpressionSyntax node) private static ExprKind GetKind(Context cx, BinaryExpressionSyntax node)
{ {
var k = GetBinaryTokenKind(cx, node.OperatorToken.Kind()); var k = GetBinaryTokenKind(cx, node);
return GetCallType(cx, node).AdjustKind(k); return GetCallType(cx, node).AdjustKind(k);
} }
private static ExprKind GetBinaryTokenKind(Context cx, SyntaxKind kind) private static ExprKind GetBinaryTokenKind(Context cx, BinaryExpressionSyntax node)
{ {
var kind = node.OperatorToken.Kind();
switch (kind) switch (kind)
{ {
case SyntaxKind.LessThanToken: return ExprKind.LT; case SyntaxKind.LessThanToken: return ExprKind.LT;
@ -54,7 +55,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
case SyntaxKind.QuestionQuestionToken: return ExprKind.NULL_COALESCING; case SyntaxKind.QuestionQuestionToken: return ExprKind.NULL_COALESCING;
// !! And the rest // !! And the rest
default: default:
cx.ModelError($"Unhandled operator type {kind}"); cx.ModelError(node, $"Unhandled operator type {kind}");
return ExprKind.UNKNOWN; return ExprKind.UNKNOWN;
} }
} }

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

@ -52,7 +52,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
ObjectInitializer.Create(new ExpressionNodeInfo(Context, Syntax.Initializer, this, -1).SetType(Type)); ObjectInitializer.Create(new ExpressionNodeInfo(Context, Syntax.Initializer, this, -1).SetType(Type));
break; break;
default: default:
Context.ModelError("Unhandled initializer in object creation"); Context.ModelError(Syntax.Initializer, "Unhandled initializer in object creation");
break; break;
} }
} }

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

@ -6,7 +6,7 @@ using System.Linq;
namespace Semmle.Extraction.CSharp.Entities namespace Semmle.Extraction.CSharp.Entities
{ {
public class File : Extraction.Entities.File internal class File : Extraction.Entities.File
{ {
// todo: this can be changed to an override after the .NET 5 upgrade // todo: this can be changed to an override after the .NET 5 upgrade
private new Context Context => (Context)base.Context; private new Context Context => (Context)base.Context;

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

@ -1,6 +1,6 @@
namespace Semmle.Extraction.CSharp.Entities namespace Semmle.Extraction.CSharp.Entities
{ {
public abstract class FreshEntity : Extraction.FreshEntity internal abstract class FreshEntity : Extraction.FreshEntity
{ {
// todo: this can be changed to an override after the .NET 5 upgrade // todo: this can be changed to an override after the .NET 5 upgrade
protected new Context Context => (Context)base.Context; protected new Context Context => (Context)base.Context;

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

@ -8,7 +8,7 @@ using System.Linq;
namespace Semmle.Extraction.CSharp.Entities namespace Semmle.Extraction.CSharp.Entities
{ {
public abstract class Method : CachedSymbol<IMethodSymbol>, IExpressionParentEntity, IStatementParentEntity internal abstract class Method : CachedSymbol<IMethodSymbol>, IExpressionParentEntity, IStatementParentEntity
{ {
protected Method(Context cx, IMethodSymbol init) protected Method(Context cx, IMethodSymbol init)
: base(cx, init) { } : base(cx, init) { }

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

@ -3,7 +3,7 @@ using System.IO;
namespace Semmle.Extraction.CSharp.Entities namespace Semmle.Extraction.CSharp.Entities
{ {
public class NonGeneratedSourceLocation : Extraction.Entities.SourceLocation internal class NonGeneratedSourceLocation : Extraction.Entities.SourceLocation
{ {
// todo: this can be changed to an override after the .NET 5 upgrade // todo: this can be changed to an override after the .NET 5 upgrade
private new Context Context => (Context)base.Context; private new Context Context => (Context)base.Context;

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

@ -7,7 +7,7 @@ using System.IO;
namespace Semmle.Extraction.CSharp.Entities namespace Semmle.Extraction.CSharp.Entities
{ {
public class Parameter : CachedSymbol<IParameterSymbol>, IExpressionParentEntity internal class Parameter : CachedSymbol<IParameterSymbol>, IExpressionParentEntity
{ {
protected IEntity Parent { get; set; } protected IEntity Parent { get; set; }
protected Parameter Original { get; } protected Parameter Original { get; }

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

@ -5,7 +5,7 @@ using System.Linq;
namespace Semmle.Extraction.CSharp.Entities namespace Semmle.Extraction.CSharp.Entities
{ {
public sealed class Nullability internal sealed class Nullability
{ {
public int Annotation { get; } public int Annotation { get; }
@ -96,7 +96,7 @@ namespace Semmle.Extraction.CSharp.Entities
} }
} }
public class NullabilityEntity : CachedEntity<Nullability> internal class NullabilityEntity : CachedEntity<Nullability>
{ {
public NullabilityEntity(Context cx, Nullability init) : base(cx, init) public NullabilityEntity(Context cx, Nullability init) : base(cx, init)
{ {

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

@ -8,7 +8,7 @@ using System.Linq;
namespace Semmle.Extraction.CSharp.Entities namespace Semmle.Extraction.CSharp.Entities
{ {
public abstract class Type : CachedSymbol<ITypeSymbol> internal abstract class Type : CachedSymbol<ITypeSymbol>
{ {
protected Type(Context cx, ITypeSymbol init) protected Type(Context cx, ITypeSymbol init)
: base(cx, init) { } : base(cx, init) { }

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

@ -18,7 +18,7 @@ namespace Semmle.Extraction.CSharp.Entities
var returnType = Type.Create(Context, Symbol.ReturnType); var returnType = Type.Create(Context, Symbol.ReturnType);
trapFile.operators(this, trapFile.operators(this,
Symbol.Name, Symbol.Name,
OperatorSymbol(Context, Symbol.Name), OperatorSymbol(Context, Symbol),
ContainingType, ContainingType,
returnType.TypeRef, returnType.TypeRef,
(UserOperator)OriginalDefinition); (UserOperator)OriginalDefinition);
@ -176,10 +176,11 @@ namespace Semmle.Extraction.CSharp.Entities
/// <param name="cx">Extractor context.</param> /// <param name="cx">Extractor context.</param>
/// <param name="methodName">The method name.</param> /// <param name="methodName">The method name.</param>
/// <returns>The converted name.</returns> /// <returns>The converted name.</returns>
public static string OperatorSymbol(Context cx, string methodName) private static string OperatorSymbol(Context cx, IMethodSymbol method)
{ {
var methodName = method.Name;
if (!OperatorSymbol(methodName, out var result)) if (!OperatorSymbol(methodName, out var result))
cx.ModelError($"Unhandled operator name in OperatorSymbol(): '{methodName}'"); cx.ModelError(method, $"Unhandled operator name in OperatorSymbol(): '{methodName}'");
return result; return result;
} }

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

@ -9,7 +9,7 @@ using System.Linq;
namespace Semmle.Extraction.CSharp.Populators namespace Semmle.Extraction.CSharp.Populators
{ {
public class TypeContainerVisitor : CSharpSyntaxVisitor internal class TypeContainerVisitor : CSharpSyntaxVisitor
{ {
protected Context Cx { get; } protected Context Cx { get; }
protected IEntity Parent { get; } protected IEntity Parent { get; }

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

@ -35,19 +35,19 @@ namespace Semmle.Extraction
// A recursion guard against writing to the trap file whilst writing an id to the trap file. // A recursion guard against writing to the trap file whilst writing an id to the trap file.
private bool writingLabel = false; private bool writingLabel = false;
public void DefineLabel(IEntity entity, TextWriter trapFile, Extractor extractor) protected void DefineLabel(IEntity entity)
{ {
if (writingLabel) if (writingLabel)
{ {
// Don't define a label whilst writing a label. // Don't define a label whilst writing a label.
PopulateLater(() => DefineLabel(entity, trapFile, extractor)); PopulateLater(() => DefineLabel(entity));
} }
else else
{ {
try try
{ {
writingLabel = true; writingLabel = true;
entity.DefineLabel(trapFile, extractor); entity.DefineLabel(TrapWriter.Writer, Extractor);
} }
finally finally
{ {
@ -70,13 +70,13 @@ namespace Semmle.Extraction
} }
#endif #endif
public Label GetNewLabel() => new Label(GetNewId()); protected Label GetNewLabel() => new Label(GetNewId());
public TEntity CreateEntity<TInit, TEntity>(CachedEntityFactory<TInit, TEntity> factory, object cacheKey, TInit init) internal TEntity CreateEntity<TInit, TEntity>(CachedEntityFactory<TInit, TEntity> factory, object cacheKey, TInit init)
where TEntity : CachedEntity => where TEntity : CachedEntity =>
cacheKey is ISymbol s ? CreateEntity(factory, s, init, symbolEntityCache) : CreateEntity(factory, cacheKey, init, objectEntityCache); cacheKey is ISymbol s ? CreateEntity(factory, s, init, symbolEntityCache) : CreateEntity(factory, cacheKey, init, objectEntityCache);
public TEntity CreateEntityFromSymbol<TSymbol, TEntity>(CachedEntityFactory<TSymbol, TEntity> factory, TSymbol init) internal TEntity CreateEntityFromSymbol<TSymbol, TEntity>(CachedEntityFactory<TSymbol, TEntity> factory, TSymbol init)
where TSymbol : ISymbol where TSymbol : ISymbol
where TEntity : CachedEntity => CreateEntity(factory, init, init, symbolEntityCache); where TEntity : CachedEntity => CreateEntity(factory, init, init, symbolEntityCache);
@ -103,7 +103,7 @@ namespace Semmle.Extraction
dictionary[cacheKey] = entity; dictionary[cacheKey] = entity;
DefineLabel(entity, TrapWriter.Writer, Extractor); DefineLabel(entity);
if (entity.NeedsPopulation) if (entity.NeedsPopulation)
Populate(init as ISymbol, entity); Populate(init as ISymbol, entity);
@ -117,32 +117,11 @@ namespace Semmle.Extraction
} }
} }
/// <summary>
/// Should the given entity be extracted?
/// A second call to this method will always return false,
/// on the assumption that it would have been extracted on the first call.
///
/// This is used to track the extraction of generics, which cannot be extracted
/// in a top-down manner.
/// </summary>
/// <param name="entity">The entity to extract.</param>
/// <returns>True only on the first call for a particular entity.</returns>
public bool ExtractGenerics(CachedEntity entity)
{
if (extractedGenerics.Contains(entity.Label))
{
return false;
}
extractedGenerics.Add(entity.Label);
return true;
}
/// <summary> /// <summary>
/// Creates a fresh label with ID "*", and set it on the /// Creates a fresh label with ID "*", and set it on the
/// supplied <paramref name="entity"/> object. /// supplied <paramref name="entity"/> object.
/// </summary> /// </summary>
public void AddFreshLabel(Entity entity) internal void AddFreshLabel(Entity entity)
{ {
entity.Label = GetNewLabel(); entity.Label = GetNewLabel();
entity.DefineFreshLabel(TrapWriter.Writer); entity.DefineFreshLabel(TrapWriter.Writer);
@ -154,7 +133,6 @@ namespace Semmle.Extraction
private readonly IDictionary<object, CachedEntity> objectEntityCache = new Dictionary<object, CachedEntity>(); private readonly IDictionary<object, CachedEntity> objectEntityCache = new Dictionary<object, CachedEntity>();
private readonly IDictionary<ISymbol, CachedEntity> symbolEntityCache = new Dictionary<ISymbol, CachedEntity>(10000, SymbolEqualityComparer.Default); private readonly IDictionary<ISymbol, CachedEntity> symbolEntityCache = new Dictionary<ISymbol, CachedEntity>(10000, SymbolEqualityComparer.Default);
private readonly HashSet<Label> extractedGenerics = new HashSet<Label>();
/// <summary> /// <summary>
/// Queue of items to populate later. /// Queue of items to populate later.
@ -204,11 +182,11 @@ namespace Semmle.Extraction
} }
} }
public Context(Extractor e, TrapWriter trapWriter, bool addAssemblyTrapPrefix = false) protected Context(Extractor extractor, TrapWriter trapWriter, bool shouldAddAssemblyTrapPrefix = false)
{ {
Extractor = e; Extractor = extractor;
TrapWriter = trapWriter; TrapWriter = trapWriter;
ShouldAddAssemblyTrapPrefix = addAssemblyTrapPrefix; ShouldAddAssemblyTrapPrefix = shouldAddAssemblyTrapPrefix;
} }
private int currentRecursiveDepth = 0; private int currentRecursiveDepth = 0;
@ -277,7 +255,7 @@ namespace Semmle.Extraction
/// <param name="optionalSymbol">Symbol for reporting errors.</param> /// <param name="optionalSymbol">Symbol for reporting errors.</param>
/// <param name="entity">The entity to populate.</param> /// <param name="entity">The entity to populate.</param>
/// <exception cref="InternalError">Thrown on invalid trap stack behaviour.</exception> /// <exception cref="InternalError">Thrown on invalid trap stack behaviour.</exception>
public void Populate(ISymbol? optionalSymbol, CachedEntity entity) private void Populate(ISymbol? optionalSymbol, CachedEntity entity)
{ {
if (writingLabel) if (writingLabel)
{ {
@ -372,7 +350,7 @@ namespace Semmle.Extraction
/// <param name="message">The text of the message.</param> /// <param name="message">The text of the message.</param>
/// <param name="optionalSymbol">The symbol of the error, or null.</param> /// <param name="optionalSymbol">The symbol of the error, or null.</param>
/// <param name="optionalEntity">The entity of the error, or null.</param> /// <param name="optionalEntity">The entity of the error, or null.</param>
public void ExtractionError(string message, ISymbol? optionalSymbol, Entity optionalEntity) private void ExtractionError(string message, ISymbol? optionalSymbol, Entity optionalEntity)
{ {
if (!(optionalSymbol is null)) if (!(optionalSymbol is null))
{ {
@ -392,9 +370,9 @@ namespace Semmle.Extraction
/// Log an extraction message. /// Log an extraction message.
/// </summary> /// </summary>
/// <param name="msg">The message to log.</param> /// <param name="msg">The message to log.</param>
public void ExtractionError(Message msg) private void ExtractionError(Message msg)
{ {
new Entities.ExtractionMessage(this, msg); new ExtractionMessage(this, msg);
Extractor.Message(msg); Extractor.Message(msg);
} }
@ -412,7 +390,7 @@ namespace Semmle.Extraction
/// <summary> /// <summary>
/// Signal an error in the program model. /// Signal an error in the program model.
/// </summary> /// </summary>
/// <param name="node">Symbol causing the error.</param> /// <param name="symbol">Symbol causing the error.</param>
/// <param name="msg">The error message.</param> /// <param name="msg">The error message.</param>
public void ModelError(ISymbol symbol, string msg) public void ModelError(ISymbol symbol, string msg)
{ {