diff --git a/csharp/CSharp.sln b/csharp/CSharp.sln index dddba01c6ed3..f4cde4624d45 100644 --- a/csharp/CSharp.sln +++ b/csharp/CSharp.sln @@ -4,8 +4,6 @@ VisualStudioVersion = 15.0.27130.2036 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Util", "extractor\Semmle.Util\Semmle.Util.csproj", "{CDD7AD69-0FD8-40F0-A9DA-F1077A2A85D6}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction", "extractor\Semmle.Extraction\Semmle.Extraction.csproj", "{81EAAD75-4BE1-44E4-91DF-20778216DB64}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp", "extractor\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj", "{C4D62DA0-B64B-440B-86DC-AB52318CB8BF}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp.DependencyFetching", "extractor\Semmle.Extraction.CSharp.DependencyFetching\Semmle.Extraction.CSharp.DependencyFetching.csproj", "{541D1AC5-E42C-4AB2-A1A4-C2355CE2A2EF}" diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/BUILD.bazel b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/BUILD.bazel index 71f541540779..4be9954a2740 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/BUILD.bazel +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/BUILD.bazel @@ -14,7 +14,7 @@ codeql_csharp_library( nowarn = ["CA1822"], visibility = ["//csharp:__subpackages__"], deps = [ - "//csharp/extractor/Semmle.Extraction", + "//csharp/extractor/Semmle.Extraction.CSharp", "//csharp/extractor/Semmle.Util", ], ) diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs index 0676042eb42f..c77daa8899c8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs @@ -15,7 +15,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching internal class NugetExeWrapper : IDisposable { private readonly string? nugetExe; - private readonly Util.Logging.ILogger logger; + private readonly Semmle.Util.Logging.ILogger logger; public int PackageCount => fileProvider.PackagesConfigs.Count; @@ -33,7 +33,7 @@ internal class NugetExeWrapper : IDisposable /// /// Create the package manager for a specified source tree. /// - public NugetExeWrapper(FileProvider fileProvider, TemporaryDirectory packageDirectory, Util.Logging.ILogger logger) + public NugetExeWrapper(FileProvider fileProvider, TemporaryDirectory packageDirectory, Semmle.Util.Logging.ILogger logger) { this.fileProvider = fileProvider; this.packageDirectory = packageDirectory; diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Semmle.Extraction.CSharp.DependencyFetching.csproj b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Semmle.Extraction.CSharp.DependencyFetching.csproj index 82003c4dd142..424094c1ed6e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Semmle.Extraction.CSharp.DependencyFetching.csproj +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Semmle.Extraction.CSharp.DependencyFetching.csproj @@ -5,7 +5,7 @@ - + diff --git a/csharp/extractor/Semmle.Extraction.CSharp/BUILD.bazel b/csharp/extractor/Semmle.Extraction.CSharp/BUILD.bazel index f5d36340bd63..42495f63ed44 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/BUILD.bazel +++ b/csharp/extractor/Semmle.Extraction.CSharp/BUILD.bazel @@ -6,17 +6,18 @@ load( codeql_csharp_library( name = "Semmle.Extraction.CSharp", srcs = glob([ + "CodeAnalysisExtensions/**/*.cs", "Comments/**/*.cs", "Entities/**/*.cs", "Extractor/**/*.cs", "Kinds/**/*.cs", "Populators/**/*.cs", + "Trap/**/*.cs", "*.cs", ]), allow_unsafe_blocks = True, visibility = ["//csharp:__subpackages__"], deps = [ - "//csharp/extractor/Semmle.Extraction", "//csharp/extractor/Semmle.Extraction.CSharp.Util", "//csharp/extractor/Semmle.Util", "@paket.main//basic.compilerlog.util", diff --git a/csharp/extractor/Semmle.Extraction.CSharp/CachedEntityFactory.cs b/csharp/extractor/Semmle.Extraction.CSharp/CachedEntityFactory.cs deleted file mode 100644 index 2673ed0d7ef3..000000000000 --- a/csharp/extractor/Semmle.Extraction.CSharp/CachedEntityFactory.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Semmle.Extraction.CSharp -{ - /// - /// A factory for creating cached entities. - /// - internal abstract class CachedEntityFactory - : Extraction.CachedEntityFactory where TEntity : CachedEntity - { - /// - /// Initializes the entity, but does not generate any trap code. - /// - public sealed override TEntity Create(Extraction.Context cx, TInit init) - { - return Create((Context)cx, init); - } - - public abstract TEntity Create(Context cx, TInit init); - } -} diff --git a/csharp/extractor/Semmle.Extraction/LocationExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/LocationExtensions.cs similarity index 98% rename from csharp/extractor/Semmle.Extraction/LocationExtensions.cs rename to csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/LocationExtensions.cs index f615fe659632..6d1d644e82ce 100644 --- a/csharp/extractor/Semmle.Extraction/LocationExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/LocationExtensions.cs @@ -3,7 +3,7 @@ using System.Linq; using Microsoft.CodeAnalysis; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { public static class LocationExtensions { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs similarity index 100% rename from csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs rename to csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Comments/CommentBlock.cs b/csharp/extractor/Semmle.Extraction.CSharp/Comments/CommentBlock.cs index 48dcd9f85a18..08db5bba0138 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Comments/CommentBlock.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Comments/CommentBlock.cs @@ -12,7 +12,7 @@ internal class CommentBlock public IEnumerable CommentLines => lines; - public Location Location { get; private set; } + public Microsoft.CodeAnalysis.Location Location { get; private set; } public CommentBlock(CommentLine firstLine) { @@ -49,7 +49,7 @@ public void AddCommentLine(CommentLine line) { Location = !lines.Any() ? line.Location - : Location.Create( + : Microsoft.CodeAnalysis.Location.Create( line.Location.SourceTree!, new TextSpan(Location.SourceSpan.Start, line.Location.SourceSpan.End - Location.SourceSpan.Start)); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Comments/CommentProcessor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Comments/CommentProcessor.cs index d8c9152bec11..6b6e363ba5f7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Comments/CommentProcessor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Comments/CommentProcessor.cs @@ -19,10 +19,10 @@ public void AddComment(CommentLine comment) } // Comments sorted by location. - private readonly SortedDictionary comments = new SortedDictionary(new LocationComparer()); + private readonly SortedDictionary comments = new SortedDictionary(new LocationComparer()); // Program elements sorted by location. - private readonly SortedDictionary elements = new SortedDictionary(new LocationComparer()); + private readonly SortedDictionary elements = new SortedDictionary(new LocationComparer()); private readonly Dictionary duplicationGuardKeys = new Dictionary(); @@ -33,9 +33,9 @@ public void AddComment(CommentLine comment) return null; } - private class LocationComparer : IComparer + private class LocationComparer : IComparer { - public int Compare(Location? l1, Location? l2) => CommentProcessor.Compare(l1, l2); + public int Compare(Microsoft.CodeAnalysis.Location? l1, Microsoft.CodeAnalysis.Location? l2) => CommentProcessor.Compare(l1, l2); } /// @@ -44,7 +44,7 @@ private class LocationComparer : IComparer /// First location /// Second location /// <0 if l1 before l2, >0 if l1 after l2, else 0. - private static int Compare(Location? l1, Location? l2) + private static int Compare(Microsoft.CodeAnalysis.Location? l1, Microsoft.CodeAnalysis.Location? l2) { if (object.ReferenceEquals(l1, l2)) return 0; @@ -68,7 +68,7 @@ private static int Compare(Location? l1, Location? l2) /// The label of the element in the trap file. /// The duplication guard key of the element, if any. /// The location of the element. - public void AddElement(Label elementLabel, Key? duplicationGuardKey, Location? loc) + public void AddElement(Label elementLabel, Key? duplicationGuardKey, Microsoft.CodeAnalysis.Location? loc) { if (loc is not null && loc.IsInSource) elements[loc] = elementLabel; @@ -78,7 +78,7 @@ public void AddElement(Label elementLabel, Key? duplicationGuardKey, Location? l // Ensure that commentBlock and element refer to the same file // which can happen when processing multiple files. - private static void EnsureSameFile(Comments.CommentBlock commentBlock, ref KeyValuePair? element) + private static void EnsureSameFile(Comments.CommentBlock commentBlock, ref KeyValuePair? element) { if (element is not null && element.Value.Key.SourceTree != commentBlock.Location.SourceTree) element = null; @@ -96,9 +96,9 @@ private static void EnsureSameFile(Comments.CommentBlock commentBlock, ref KeyVa /// Output binding information. private void GenerateBindings( Comments.CommentBlock commentBlock, - KeyValuePair? previousElement, - KeyValuePair? nextElement, - KeyValuePair? parentElement, + KeyValuePair? previousElement, + KeyValuePair? nextElement, + KeyValuePair? parentElement, CommentBindingCallback callback ) { @@ -125,7 +125,7 @@ CommentBindingCallback callback } // Heuristic to decide which is the "best" element associated with the comment. - KeyValuePair? bestElement; + KeyValuePair? bestElement; if (previousElement is not null && previousElement.Value.Key.EndLine() == commentBlock.Location.StartLine()) { @@ -180,14 +180,14 @@ CommentBindingCallback callback private class ElementStack { // Invariant: the top of the stack must be contained by items below it. - private readonly Stack> elementStack = new Stack>(); + private readonly Stack> elementStack = new(); /// /// Add a new element to the stack. /// /// The stack is maintained. /// The new element to push. - public void Push(KeyValuePair value) + public void Push(KeyValuePair value) { // Maintain the invariant by popping existing elements while (elementStack.Count > 0 && !elementStack.Peek().Key.Contains(value.Key)) @@ -201,7 +201,7 @@ public void Push(KeyValuePair value) /// /// The location of the comment. /// An element completely containing l, or null if none found. - public KeyValuePair? FindParent(Location l) => + public KeyValuePair? FindParent(Microsoft.CodeAnalysis.Location l) => elementStack.Where(v => v.Key.Contains(l)).FirstOrNull(); /// @@ -209,7 +209,7 @@ public void Push(KeyValuePair value) /// /// The location of the comment. /// The element before l, or null. - public KeyValuePair? FindBefore(Location l) + public KeyValuePair? FindBefore(Microsoft.CodeAnalysis.Location l) { return elementStack .Where(v => v.Key.SourceSpan.End < l.SourceSpan.Start) @@ -222,7 +222,7 @@ public void Push(KeyValuePair value) /// The location of the comment. /// The next element. /// The next element. - public KeyValuePair? FindAfter(Location comment, KeyValuePair? next) + public KeyValuePair? FindAfter(Microsoft.CodeAnalysis.Location comment, KeyValuePair? next) { var p = FindParent(comment); return next.HasValue && p.HasValue && p.Value.Key.Before(next.Value.Key) ? null : next; @@ -233,7 +233,7 @@ public void Push(KeyValuePair value) private void GenerateBindings( Comments.CommentBlock block, ElementStack elementStack, - KeyValuePair? nextElement, + KeyValuePair? nextElement, CommentBindingCallback cb ) { @@ -259,8 +259,8 @@ CommentBindingCallback cb /// Where to send the results. /// true if there are more comments to process, false otherwise. private bool GenerateBindings( - IEnumerator> commentEnumerator, - KeyValuePair? nextElement, + IEnumerator> commentEnumerator, + KeyValuePair? nextElement, ElementStack elementStack, CommentBindingCallback cb ) @@ -319,8 +319,8 @@ public void GenerateBindings(CommentBindingCallback cb) var elementStack = new ElementStack(); - using IEnumerator> elementEnumerator = elements.GetEnumerator(); - using IEnumerator> commentEnumerator = comments.GetEnumerator(); + using IEnumerator> elementEnumerator = elements.GetEnumerator(); + using IEnumerator> commentEnumerator = comments.GetEnumerator(); if (!commentEnumerator.MoveNext()) { // There are no comments to process. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Assembly.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Assembly.cs index 0fa9422e08ca..cc36e41ff588 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Assembly.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Assembly.cs @@ -3,10 +3,8 @@ namespace Semmle.Extraction.CSharp.Entities { - internal class Assembly : Extraction.Entities.Location + internal class Assembly : Location { - public override Context Context => (Context)base.Context; - private readonly string assemblyPath; private readonly IAssemblySymbol assembly; private readonly bool isOutputAssembly; @@ -56,7 +54,7 @@ public override bool Equals(object? obj) return false; } - public static Extraction.Entities.Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => AssemblyConstructorFactory.Instance.CreateEntity(cx, loc, loc); + public static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => AssemblyConstructorFactory.Instance.CreateEntity(cx, loc, loc); private class AssemblyConstructorFactory : CachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs index a70b84dde1df..e4799c05507f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs @@ -151,9 +151,9 @@ private void ExtractArguments(TextWriter trapFile) public override Microsoft.CodeAnalysis.Location? ReportingLocation => attributeSyntax?.Name.GetLocation(); - private Semmle.Extraction.Entities.Location? location; + private Location? location; - private Semmle.Extraction.Entities.Location Location => + private Location Location => location ??= Context.CreateLocation(attributeSyntax is null ? entity.ReportingLocation : attributeSyntax.Name.GetLocation()); diff --git a/csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntity`1.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntity.cs similarity index 98% rename from csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntity`1.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntity.cs index 82ded71a9cd5..ed0a21bc0836 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntity`1.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntity.cs @@ -2,7 +2,7 @@ using System.IO; using Microsoft.CodeAnalysis; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp.Entities { /// /// A cached entity. diff --git a/csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntityFactory.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntityFactory.cs similarity index 56% rename from csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntityFactory.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntityFactory.cs index 60c6a7cade17..6753dce9c722 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntityFactory.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntityFactory.cs @@ -1,13 +1,10 @@ -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { /// /// A factory for creating cached entities. /// - public abstract class CachedEntityFactory where TEntity : CachedEntity + public abstract class CachedEntityFactory where TEntity : Entities.CachedEntity { - /// - /// Initializes the entity, but does not generate any trap code. - /// public abstract TEntity Create(Context cx, TInit init); } } diff --git a/csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntityFactoryExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntityFactoryExtensions.cs similarity index 88% rename from csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntityFactoryExtensions.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntityFactoryExtensions.cs index f8a08298cca6..d7ca1293e33c 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntityFactoryExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntityFactoryExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.CodeAnalysis; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { public static class CachedEntityFactoryExtensions { @@ -16,7 +16,7 @@ public static class CachedEntityFactoryExtensions /// The initializer for the entity. /// The entity. public static TEntity CreateEntity(this CachedEntityFactory factory, Context cx, object cacheKey, TInit init) - where TEntity : CachedEntity => cx.CreateEntity(factory, cacheKey, init); + where TEntity : Entities.CachedEntity => cx.CreateEntity(factory, cacheKey, init); /// /// Creates and populates a new entity from an `ISymbol`, or returns the existing one @@ -30,6 +30,6 @@ public static TEntity CreateEntity(this CachedEntityFactoryThe entity. public static TEntity CreateEntityFromSymbol(this CachedEntityFactory factory, Context cx, TSymbol init) where TSymbol : ISymbol - where TEntity : CachedEntity => cx.CreateEntityFromSymbol(factory, init); + where TEntity : Entities.CachedEntity => cx.CreateEntityFromSymbol(factory, init); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CachedSymbol.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedSymbol.cs similarity index 95% rename from csharp/extractor/Semmle.Extraction.CSharp/Entities/CachedSymbol.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedSymbol.cs index 4a4d483ea372..c39eb6076b57 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CachedSymbol.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedSymbol.cs @@ -1,8 +1,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -89,7 +87,7 @@ protected void ExtractCompilerGenerated(TextWriter trapFile) /// public virtual Microsoft.CodeAnalysis.Location? FullLocation => Symbol.Locations.BestOrDefault(); - public virtual IEnumerable Locations + public virtual IEnumerable Locations { get { @@ -143,6 +141,6 @@ public ExpressionSyntax? ExpressionBody public override bool NeedsPopulation => Context.Defines(Symbol); - public Extraction.Entities.Location Location => Context.CreateLocation(ReportingLocation); + public Location Location => Context.CreateLocation(ReportingLocation); } } diff --git a/csharp/extractor/Semmle.Extraction/Entities/Base/Entity.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/Entity.cs similarity index 96% rename from csharp/extractor/Semmle.Extraction/Entities/Base/Entity.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/Entity.cs index 9cd645ae1d41..ca1887b3be9c 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Base/Entity.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/Entity.cs @@ -2,11 +2,11 @@ using System.IO; using Microsoft.CodeAnalysis; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { public abstract class Entity : IEntity { - public virtual Context Context { get; } + public Context Context { get; } protected Entity(Context context) { diff --git a/csharp/extractor/Semmle.Extraction/Entities/Base/FreshEntity.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/FreshEntity.cs similarity index 95% rename from csharp/extractor/Semmle.Extraction/Entities/Base/FreshEntity.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/FreshEntity.cs index 7ecdab8086ee..87776fa8c6b1 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Base/FreshEntity.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/FreshEntity.cs @@ -1,6 +1,6 @@ using System.IO; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp.Entities { /// /// An entity which has a default "*" ID assigned to it. diff --git a/csharp/extractor/Semmle.Extraction/Entities/Base/IEntity.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/IEntity.cs similarity index 98% rename from csharp/extractor/Semmle.Extraction/Entities/Base/IEntity.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/IEntity.cs index 3700e61b22ea..d8d3c538e42c 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Base/IEntity.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/IEntity.cs @@ -1,7 +1,7 @@ using System.IO; using Microsoft.CodeAnalysis; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { /// /// Any program entity which has a corresponding label in the trap file. diff --git a/csharp/extractor/Semmle.Extraction/Entities/Base/LabelledEntity.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/LabelledEntity.cs similarity index 80% rename from csharp/extractor/Semmle.Extraction/Entities/Base/LabelledEntity.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/LabelledEntity.cs index 4694332fd52c..e458c935b0ee 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Base/LabelledEntity.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/LabelledEntity.cs @@ -1,4 +1,4 @@ -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { public abstract class LabelledEntity : Entity { diff --git a/csharp/extractor/Semmle.Extraction/Entities/Base/UnlabelledEntity.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/UnlabelledEntity.cs similarity index 92% rename from csharp/extractor/Semmle.Extraction/Entities/Base/UnlabelledEntity.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/UnlabelledEntity.cs index 2faf15689edc..2bfcc35b274c 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Base/UnlabelledEntity.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/UnlabelledEntity.cs @@ -1,4 +1,4 @@ -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { public abstract class UnlabelledEntity : Entity { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CachedEntity.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CachedEntity.cs deleted file mode 100644 index 603a1d822b19..000000000000 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CachedEntity.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Semmle.Extraction.CSharp.Entities -{ - internal abstract class CachedEntity : Extraction.CachedEntity where T : notnull - { - public override Context Context => (Context)base.Context; - - protected CachedEntity(Context context, T symbol) - : base(context, symbol) - { - } - } -} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs index 9029eb071d44..7638eefce125 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs @@ -1,5 +1,4 @@ using System.IO; -using Semmle.Extraction.Entities; namespace Semmle.Extraction.CSharp.Entities { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Compilation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Compilation.cs index ecb5d51d44d5..2c74775460da 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Compilation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Compilation.cs @@ -3,7 +3,6 @@ using System.IO; using System.Linq; using Microsoft.CodeAnalysis; -using Semmle.Extraction.Entities; using Semmle.Util; namespace Semmle.Extraction.CSharp.Entities diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs index 047a7b68ae6d..c3ce2bb6d29e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs @@ -116,7 +116,7 @@ protected override void ExtractInitializers(TextWriter trapFile) } } - private void ExtractSourceInitializer(TextWriter trapFile, ITypeSymbol? type, IMethodSymbol? symbol, ArgumentListSyntax arguments, Location location) + private void ExtractSourceInitializer(TextWriter trapFile, ITypeSymbol? type, IMethodSymbol? symbol, ArgumentListSyntax arguments, Microsoft.CodeAnalysis.Location location) { var initInfo = new ExpressionInfo(Context, AnnotatedTypeSymbol.CreateNotAnnotated(type), diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs index cdd2964ff216..f5021d38eeb5 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs @@ -15,7 +15,7 @@ internal class Expression : FreshEntity, IExpressionParentEntity { private readonly IExpressionInfo info; public AnnotatedTypeSymbol? Type { get; private set; } - public Extraction.Entities.Location Location { get; } + public Location Location { get; } public ExprKind Kind { get; } internal Expression(IExpressionInfo info, bool shouldPopulate = true) @@ -62,7 +62,7 @@ protected sealed override void Populate(TextWriter trapFile) type.PopulateGenerics(); } - public override Location? ReportingLocation => Location.Symbol; + public override Microsoft.CodeAnalysis.Location? ReportingLocation => Location.Symbol; internal void SetType(ITypeSymbol? type) { @@ -138,7 +138,7 @@ private static bool ContainsPattern(SyntaxNode node) => /// Creates a generated expression from a typed constant. /// public static Expression? CreateGenerated(Context cx, TypedConstant constant, IExpressionParentEntity parent, - int childIndex, Extraction.Entities.Location location) + int childIndex, Location location) { if (constant.IsNull || constant.Type is null) @@ -176,7 +176,7 @@ private static bool ContainsPattern(SyntaxNode node) => /// Creates a generated expression for a default argument value. /// public static Expression? CreateGenerated(Context cx, IParameterSymbol parameter, IExpressionParentEntity parent, - int childIndex, Extraction.Entities.Location location) + int childIndex, Location location) { if (!parameter.HasExplicitDefaultValue || parameter.Type is IErrorTypeSymbol) @@ -315,7 +315,7 @@ public static bool IsDynamic(Context cx, ExpressionSyntax node) /// /// Given `b` in `a?.b.c`, return `(a?.b, a?.b)`. - /// + /// /// Given `c` in `a?.b?.c.d`, return `(b?.c, a?.b?.c)`. /// /// A MemberBindingExpression. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionInfo.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionInfo.cs index 3474ad4a8183..8ebc0e2a0efa 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionInfo.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionInfo.cs @@ -10,14 +10,14 @@ internal class ExpressionInfo : IExpressionInfo { public Context Context { get; } public AnnotatedTypeSymbol? Type { get; } - public Extraction.Entities.Location Location { get; } + public Location Location { get; } public ExprKind Kind { get; } public IExpressionParentEntity Parent { get; } public int Child { get; } public bool IsCompilerGenerated { get; } public string? ExprValue { get; } - public ExpressionInfo(Context cx, AnnotatedTypeSymbol? type, Extraction.Entities.Location location, ExprKind kind, + public ExpressionInfo(Context cx, AnnotatedTypeSymbol? type, Location location, ExprKind kind, IExpressionParentEntity parent, int child, bool isCompilerGenerated, string? value) { Context = cx; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs index a78f7e8c80b9..924382a55507 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs @@ -115,9 +115,9 @@ public string? ExprValue } } - private Extraction.Entities.Location? cachedLocation; + private Location? cachedLocation; - public Extraction.Entities.Location Location + public Location Location { get { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs index 302bcaded39a..72993e2db010 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs @@ -88,7 +88,7 @@ private NormalArrayCreation(ExpressionNodeInfo info) : base(info) { } public static Expression Create(ExpressionNodeInfo info) => new NormalArrayCreation(info).TryPopulate(); - public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, IEnumerable items, Semmle.Extraction.Entities.Location location) + public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, IEnumerable items, Location location) { var info = new ExpressionInfo( cx, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs index 62e23e3b66dc..20a5dc611a31 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs @@ -32,7 +32,7 @@ protected override void PopulateExpression(TextWriter trapFile) public override Microsoft.CodeAnalysis.Location ReportingLocation => Syntax.GetLocation(); - public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, object? value, Action createChild, Extraction.Entities.Location location) + public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, object? value, Action createChild, Location location) { var info = new ExpressionInfo( cx, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs index 968f2e8f43b7..a7758e4243f9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs @@ -15,7 +15,7 @@ protected override void PopulateExpression(TextWriter trapFile) TypeAccess.Create(Context, Syntax.Type, this, 0); } - public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Extraction.Entities.Location location, string? value) + public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Location location, string? value) { var info = new ExpressionInfo( cx, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs index 3e886a9c3ac9..b0508bf83b7e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs @@ -55,7 +55,7 @@ private void AddOperatorCall(IMethodSymbol method) /// Creates a new generated expression with an implicit conversion added. /// public static Expression CreateGeneratedConversion(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object value, - Extraction.Entities.Location location) + Location location) { ExpressionInfo create(ExprKind kind, string? v) => new ExpressionInfo( @@ -85,7 +85,7 @@ ExpressionInfo create(ExprKind kind, string? v) => /// Creates a new generated cast expression. /// public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object value, - Extraction.Entities.Location location) + Location location) { var info = new ExpressionInfo(cx, AnnotatedTypeSymbol.CreateNotAnnotated(type), diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs index cdc2e87798ec..92e2b910f992 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs @@ -36,7 +36,7 @@ protected override void PopulateExpression(TextWriter trapFile) } } - public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int index, Extraction.Entities.Location location) + public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int index, Location location) { var info = new ExpressionInfo( cx, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs index 72d54abf6c1a..d471839f97a3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs @@ -37,7 +37,7 @@ private static ExprKind GetKind(ExpressionNodeInfo info) return GetExprKind(type, info.Node, info.Location, info.Context); } - private static ExprKind GetExprKind(ITypeSymbol? type, ExpressionSyntax? expr, Extraction.Entities.Location loc, Context context) + private static ExprKind GetExprKind(ITypeSymbol? type, ExpressionSyntax? expr, Location loc, Context context) { switch (type?.SpecialType) { @@ -87,7 +87,7 @@ private static ExprKind GetExprKind(ITypeSymbol? type, ExpressionSyntax? expr, E } public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object? value, - Extraction.Entities.Location location) + Location location) { var kind = value is null ? ExprKind.NULL_LITERAL : GetExprKind(type, null, location, cx); var info = new ExpressionInfo( @@ -103,7 +103,7 @@ public static Expression CreateGenerated(Context cx, IExpressionParentEntity par return new Expression(info); } - public static Expression CreateGeneratedNullLiteral(Context cx, IExpressionParentEntity parent, int childIndex, Extraction.Entities.Location location) + public static Expression CreateGeneratedNullLiteral(Context cx, IExpressionParentEntity parent, int childIndex, Location location) { var info = new ExpressionInfo( cx, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/DateTimeObjectCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/DateTimeObjectCreation.cs index 012a30d81cc4..98f7a8bce924 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/DateTimeObjectCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/DateTimeObjectCreation.cs @@ -49,7 +49,7 @@ protected void PopulateExpression(TextWriter trapFile) // The `type` symbol must be a System.DateTime type and the value must be a System.DateTime object. // The expression that is being created is a call to the System.DateTime(long) constructor, where // the number of ticks from the `value` object is used as the argument to the constructor call. - public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object? value, Extraction.Entities.Location location) + public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object? value, Location location) { var constructorSymbol = GetDateTimeConstructor(type) ?? throw new InternalError("Could not find symbol for System.DateTime(long)"); var expr = new DateTimeObjectCreation(constructorSymbol, new ExpressionInfo( @@ -68,4 +68,4 @@ public static Expression CreateGenerated(Context cx, IExpressionParentEntity par return expr.TryPopulate(); } } -} \ No newline at end of file +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/This.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/This.cs index 33f2ad9fbc78..53dfc84de094 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/This.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/This.cs @@ -7,7 +7,7 @@ internal class This : Expression { private This(IExpressionInfo info) : base(info) { } - public static This CreateImplicit(Context cx, ITypeSymbol @class, Extraction.Entities.Location loc, IExpressionParentEntity parent, int child) => + public static This CreateImplicit(Context cx, ITypeSymbol @class, Location loc, IExpressionParentEntity parent, int child) => new This(new ExpressionInfo(cx, AnnotatedTypeSymbol.CreateNotAnnotated(@class), loc, Kinds.ExprKind.THIS_ACCESS, parent, child, isCompilerGenerated: true, null)); public static This CreateExplicit(ExpressionNodeInfo info) => new This(info.SetKind(ExprKind.THIS_ACCESS)); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs index b4e678d8ab6b..55afd83318ef 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs @@ -35,7 +35,7 @@ protected override void PopulateExpression(TextWriter trapFile) public static Expression Create(ExpressionNodeInfo info) => new TypeAccess(info).TryPopulate(); - public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, Extraction.Entities.Location location) + public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, Location location) { var typeAccessInfo = new ExpressionInfo( cx, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs index b36c1e425a03..cb205d383ac0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs @@ -17,7 +17,7 @@ protected override void PopulateExpression(TextWriter trapFile) TypeAccess.Create(Context, Syntax.Type, this, TypeAccessIndex); } - public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, Extraction.Entities.Location location) + public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, Location location) { var info = new ExpressionInfo( cx, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs index 5931feb070c0..c44f9e2b9468 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs @@ -13,7 +13,7 @@ internal class VariableDeclaration : Expression { private VariableDeclaration(IExpressionInfo info) : base(info) { } - public static VariableDeclaration Create(Context cx, ISymbol symbol, AnnotatedTypeSymbol? type, TypeSyntax? optionalSyntax, Extraction.Entities.Location exprLocation, bool isVar, IExpressionParentEntity parent, int child) + public static VariableDeclaration Create(Context cx, ISymbol symbol, AnnotatedTypeSymbol? type, TypeSyntax? optionalSyntax, Location exprLocation, bool isVar, IExpressionParentEntity parent, int child) { var ret = new VariableDeclaration(new ExpressionInfo(cx, type, exprLocation, ExprKind.LOCAL_VAR_DECL, parent, child, isCompilerGenerated: false, null)); cx.Try(null, null, () => diff --git a/csharp/extractor/Semmle.Extraction/Entities/ExtractionMessage.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExtractionMessage.cs similarity index 93% rename from csharp/extractor/Semmle.Extraction/Entities/ExtractionMessage.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/ExtractionMessage.cs index 514ce433c0ac..f8a771ae6d0e 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/ExtractionMessage.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExtractionMessage.cs @@ -3,7 +3,7 @@ using System.Threading; using Semmle.Util; -namespace Semmle.Extraction.Entities +namespace Semmle.Extraction.CSharp.Entities { internal class ExtractionMessage : FreshEntity { @@ -40,7 +40,7 @@ protected override void Populate(TextWriter trapFile) if (val == limit + 1) { Context.ExtractionContext.Logger.LogWarning($"Stopped logging extractor messages after reaching {limit}"); - _ = new ExtractionMessage(Context, new Message($"Stopped logging extractor messages after reaching {limit}", null, null, null, Util.Logging.Severity.Warning), bypassLimit: true); + _ = new ExtractionMessage(Context, new Message($"Stopped logging extractor messages after reaching {limit}", null, null, null, Semmle.Util.Logging.Severity.Warning), bypassLimit: true); } return; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs index 4894da062e3f..0a91eb57ecdf 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs @@ -4,7 +4,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CSharp.Entities.Expressions; -using Semmle.Extraction.Entities; using Semmle.Extraction.Kinds; namespace Semmle.Extraction.CSharp.Entities @@ -105,7 +104,7 @@ public override void Populate(TextWriter trapFile) } } - private Expression AddInitializerAssignment(TextWriter trapFile, ExpressionSyntax initializer, Extraction.Entities.Location loc, + private Expression AddInitializerAssignment(TextWriter trapFile, ExpressionSyntax initializer, Location loc, string? constValue, ref int child) { var type = Symbol.GetAnnotatedType(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/FreshEntity.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/FreshEntity.cs deleted file mode 100644 index 79144e109d41..000000000000 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/FreshEntity.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Semmle.Extraction.CSharp.Entities -{ - internal abstract class FreshEntity : Extraction.FreshEntity - { - public override Context Context => (Context)base.Context; - - protected FreshEntity(Context cx) - : base(cx) - { - } - } -} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionInfo.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionInfo.cs index ea43b19456cf..167ad8066718 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionInfo.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionInfo.cs @@ -18,7 +18,7 @@ internal interface IExpressionInfo /// /// The location of the expression. /// - Extraction.Entities.Location Location { get; } + Location Location { get; } /// /// The kind of the expression. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/File.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/File.cs similarity index 76% rename from csharp/extractor/Semmle.Extraction.CSharp/Entities/File.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/File.cs index bd2a7fbd181f..61c4bb3e7cca 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/File.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/File.cs @@ -6,21 +6,36 @@ namespace Semmle.Extraction.CSharp.Entities { - internal class File : Extraction.Entities.File + public class File : CachedEntity { - public override Context Context => (Context)base.Context; + protected readonly string originalPath; + private readonly Lazy transformedPathLazy; + protected PathTransformer.ITransformedPath TransformedPath => transformedPathLazy.Value; + public override Microsoft.CodeAnalysis.Location? ReportingLocation => null; + + public override bool NeedsPopulation => true; protected File(Context cx, string path) : base(cx, path) { + originalPath = path; + var adjustedPath = BinaryLogExtractionContext.GetAdjustedPath(Context.ExtractionContext, originalPath) ?? path; + transformedPathLazy = new Lazy(() => Context.ExtractionContext.PathTransformer.Transform(adjustedPath)); } + public override void WriteId(EscapingTextWriter trapFile) + { + trapFile.Write(TransformedPath.DatabaseId); + trapFile.Write(";sourcefile"); + } + + public override void Populate(TextWriter trapFile) { trapFile.files(this, TransformedPath.Value); if (TransformedPath.ParentDirectory is PathTransformer.ITransformedPath dir) - trapFile.containerparent(Extraction.Entities.Folder.Create(Context, dir), this); + trapFile.containerparent(Folder.Create(Context, dir), this); var trees = Context.Compilation.SyntaxTrees.Where(t => t.FilePath == originalPath); diff --git a/csharp/extractor/Semmle.Extraction/Entities/Folder.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/Folder.cs similarity index 97% rename from csharp/extractor/Semmle.Extraction/Entities/Folder.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/Folder.cs index 465d545d9833..bef3e23ee2b8 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Folder.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/Folder.cs @@ -1,6 +1,6 @@ using System.IO; -namespace Semmle.Extraction.Entities +namespace Semmle.Extraction.CSharp.Entities { public sealed class Folder : CachedEntity { diff --git a/csharp/extractor/Semmle.Extraction/Entities/GeneratedFile.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/GeneratedFile.cs similarity index 95% rename from csharp/extractor/Semmle.Extraction/Entities/GeneratedFile.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/GeneratedFile.cs index b4a771f53db1..5a62619fd060 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/GeneratedFile.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/GeneratedFile.cs @@ -1,6 +1,6 @@ using System.IO; -namespace Semmle.Extraction.Entities +namespace Semmle.Extraction.CSharp.Entities { internal class GeneratedFile : File { diff --git a/csharp/extractor/Semmle.Extraction/Entities/GeneratedLocation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/GeneratedLocation.cs similarity index 96% rename from csharp/extractor/Semmle.Extraction/Entities/GeneratedLocation.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/GeneratedLocation.cs index db552f7e4529..d12f1ca51e00 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/GeneratedLocation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/GeneratedLocation.cs @@ -1,6 +1,6 @@ using System.IO; -namespace Semmle.Extraction.Entities +namespace Semmle.Extraction.CSharp.Entities { public class GeneratedLocation : SourceLocation { diff --git a/csharp/extractor/Semmle.Extraction/Entities/Location.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/Location.cs similarity index 91% rename from csharp/extractor/Semmle.Extraction/Entities/Location.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/Location.cs index d77fb46544d5..9f9e15e33f33 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Location.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/Location.cs @@ -1,4 +1,4 @@ -namespace Semmle.Extraction.Entities +namespace Semmle.Extraction.CSharp.Entities { #nullable disable warnings public abstract class Location : CachedEntity diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/NonGeneratedSourceLocation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/NonGeneratedSourceLocation.cs similarity index 77% rename from csharp/extractor/Semmle.Extraction.CSharp/Entities/NonGeneratedSourceLocation.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/NonGeneratedSourceLocation.cs index df41abd524d3..69e9ea4e9dc7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/NonGeneratedSourceLocation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/NonGeneratedSourceLocation.cs @@ -1,22 +1,18 @@ -using System; using System.IO; using Microsoft.CodeAnalysis; -using Semmle.Util.Logging; namespace Semmle.Extraction.CSharp.Entities { - internal class NonGeneratedSourceLocation : Extraction.Entities.SourceLocation + internal class NonGeneratedSourceLocation : SourceLocation { - public override Context Context => (Context)base.Context; - - protected NonGeneratedSourceLocation(Context cx, Location init) + protected NonGeneratedSourceLocation(Context cx, Microsoft.CodeAnalysis.Location init) : base(cx, init) { Position = init.GetLineSpan(); FileEntity = File.Create(Context, Position.Path); } - public static NonGeneratedSourceLocation Create(Context cx, Location loc) => SourceLocationFactory.Instance.CreateEntity(cx, loc, loc); + public static NonGeneratedSourceLocation Create(Context cx, Microsoft.CodeAnalysis.Location loc) => SourceLocationFactory.Instance.CreateEntity(cx, loc, loc); public override void Populate(TextWriter trapFile) { @@ -28,7 +24,7 @@ public override void Populate(TextWriter trapFile) if (mapped.HasMappedPath && mapped.IsValid) { var path = Context.TryAdjustRelativeMappedFilePath(mapped.Path, Position.Path); - var mappedLoc = Create(Context, Location.Create(path, default, mapped.Span)); + var mappedLoc = Create(Context, Microsoft.CodeAnalysis.Location.Create(path, default, mapped.Span)); trapFile.locations_mapped(this, mappedLoc); } @@ -58,11 +54,11 @@ public override void WriteId(EscapingTextWriter trapFile) trapFile.Write(Position.Span.End.Character); } - private class SourceLocationFactory : CachedEntityFactory + private class SourceLocationFactory : CachedEntityFactory { public static SourceLocationFactory Instance { get; } = new SourceLocationFactory(); - public override NonGeneratedSourceLocation Create(Context cx, Location init) => new NonGeneratedSourceLocation(cx, init); + public override NonGeneratedSourceLocation Create(Context cx, Microsoft.CodeAnalysis.Location init) => new NonGeneratedSourceLocation(cx, init); } } } diff --git a/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/SourceLocation.cs similarity index 84% rename from csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/SourceLocation.cs index d126f5521658..382a4899a833 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Locations/SourceLocation.cs @@ -1,4 +1,4 @@ -namespace Semmle.Extraction.Entities +namespace Semmle.Extraction.CSharp.Entities { public abstract class SourceLocation : Location { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index c1a2082a3ba2..6890ca490847 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -290,7 +290,7 @@ public static void AddExplicitInterfaceQualifierToId(Context cx, EscapingTextWri public Method OriginalDefinition => Create(Context, Symbol.OriginalDefinition); - public override Location? FullLocation => ReportingLocation; + public override Microsoft.CodeAnalysis.Location? FullLocation => ReportingLocation; public override bool IsSourceDeclaration => Symbol.IsSourceDeclaration(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs index 390311ca94b1..cb1bb6e930da 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs @@ -3,12 +3,12 @@ namespace Semmle.Extraction.CSharp.Entities { - internal class Modifier : Extraction.CachedEntity + internal class Modifier : CachedEntity { private Modifier(Context cx, string init) : base(cx, init) { } - public override Location? ReportingLocation => null; + public override Microsoft.CodeAnalysis.Location? ReportingLocation => null; public override void WriteId(EscapingTextWriter trapFile) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs index 874d8e1b69f3..e431ff0a7202 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs @@ -8,7 +8,7 @@ internal sealed class Namespace : CachedEntity private Namespace(Context cx, INamespaceSymbol init) : base(cx, init) { } - public override Location? ReportingLocation => null; + public override Microsoft.CodeAnalysis.Location? ReportingLocation => null; public override void Populate(TextWriter trapFile) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs index 8c6a65ad5538..76d518776caa 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs @@ -4,7 +4,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CSharp.Populators; -using Semmle.Extraction.Entities; namespace Semmle.Extraction.CSharp.Entities { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs index 0d7bdd31354b..3b16cfc31f0f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs @@ -1,7 +1,6 @@ using System.IO; using Microsoft.CodeAnalysis.CSharp; using Semmle.Extraction.CSharp.Populators; -using Semmle.Extraction.Entities; namespace Semmle.Extraction.CSharp.Entities { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/SyntheticEmptyBlock.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/SyntheticEmptyBlock.cs index 670d338d2b3c..6d6ebba24fb9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/SyntheticEmptyBlock.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/SyntheticEmptyBlock.cs @@ -1,7 +1,6 @@ using System.IO; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.Entities; using Semmle.Extraction.Kinds; namespace Semmle.Extraction.CSharp.Entities.Statements diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index 75a931e2266f..189a07f6f476 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -101,7 +101,7 @@ public override void Populate(TextWriter trapFile) public override IEnumerable TypeMentions => TypeArguments; - public override IEnumerable Locations + public override IEnumerable Locations { get { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs index 67a68958a0f4..9791f386a199 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs @@ -102,7 +102,7 @@ public NullabilityEntity(Context cx, Nullability init) : base(cx, init) { } - public override Location ReportingLocation => throw new System.NotImplementedException(); + public override Microsoft.CodeAnalysis.Location ReportingLocation => throw new System.NotImplementedException(); public override bool NeedsPopulation => true; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameterConstraints.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameterConstraints.cs index 8684c0b820d1..6f85759dee0f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameterConstraints.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameterConstraints.cs @@ -49,7 +49,7 @@ public override void Populate(TextWriter trapFile) } } - public override Location? ReportingLocation => null; + public override Microsoft.CodeAnalysis.Location? ReportingLocation => null; public static TypeParameterConstraints Create(Context cx, TypeParameter p) => TypeParameterConstraintsFactory.Instance.CreateEntity(cx, (typeof(TypeParameterConstraints), p), p); @@ -62,4 +62,3 @@ private class TypeParameterConstraintsFactory : CachedEntityFactory /// The scope of symbols in an assembly. diff --git a/csharp/extractor/Semmle.Extraction/Extractor/BinaryLogExtractionContext.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/BinaryLogExtractionContext.cs similarity index 98% rename from csharp/extractor/Semmle.Extraction/Extractor/BinaryLogExtractionContext.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Extractor/BinaryLogExtractionContext.cs index 5e3ac901bb01..e4ad5f83e2a2 100644 --- a/csharp/extractor/Semmle.Extraction/Extractor/BinaryLogExtractionContext.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/BinaryLogExtractionContext.cs @@ -4,7 +4,7 @@ using Microsoft.CodeAnalysis; using Semmle.Util.Logging; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { public class BinaryLogExtractionContext : ExtractionContext { diff --git a/csharp/extractor/Semmle.Extraction/Options.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/CommonOptions.cs similarity index 99% rename from csharp/extractor/Semmle.Extraction/Options.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Extractor/CommonOptions.cs index ba809e7cfcbc..3595096c1864 100644 --- a/csharp/extractor/Semmle.Extraction/Options.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/CommonOptions.cs @@ -2,7 +2,7 @@ using Semmle.Util; using Semmle.Util.Logging; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { /// /// Represents the parsed state of the command line arguments. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs index 654ce0cc0f50..8d819d715f9f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs @@ -2,8 +2,9 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; +using System.Linq; using Microsoft.CodeAnalysis; -using Semmle.Extraction.Entities; +using Semmle.Util.Logging; namespace Semmle.Extraction.CSharp { @@ -11,8 +12,453 @@ namespace Semmle.Extraction.CSharp /// State that needs to be available throughout the extraction process. /// There is one Context object per trap output file. /// - internal class Context : Extraction.Context + public class Context { + /// + /// Access various extraction functions, e.g. logger, trap writer. + /// + public ExtractionContext ExtractionContext { get; } + + /// + /// Access to the trap file. + /// + public TrapWriter TrapWriter { get; } + + /// + /// Holds if assembly information should be prefixed to TRAP labels. + /// + public bool ShouldAddAssemblyTrapPrefix { get; } + + public IList TrapStackSuffix { get; } = new List(); + + private int GetNewId() => TrapWriter.IdCounter++; + + // A recursion guard against writing to the trap file whilst writing an id to the trap file. + private bool writingLabel = false; + + private readonly Queue labelQueue = []; + + protected void DefineLabel(IEntity entity) + { + if (writingLabel) + { + // Don't define a label whilst writing a label. + labelQueue.Enqueue(entity); + } + else + { + try + { + writingLabel = true; + entity.DefineLabel(TrapWriter.Writer); + } + finally + { + writingLabel = false; + if (labelQueue.Any()) + { + DefineLabel(labelQueue.Dequeue()); + } + } + } + } + +#if DEBUG_LABELS + private void CheckEntityHasUniqueLabel(string id, CachedEntity entity) + { + if (idLabelCache.ContainsKey(id)) + { + this.Extractor.Message(new Message("Label collision for " + id, entity.Label.ToString(), CreateLocation(entity.ReportingLocation), "", Severity.Warning)); + } + else + { + idLabelCache[id] = entity; + } + } +#endif + + protected Label GetNewLabel() => new Label(GetNewId()); + + internal TEntity CreateEntity(CachedEntityFactory factory, object cacheKey, TInit init) + where TEntity : Entities.CachedEntity => + cacheKey is ISymbol s ? CreateEntity(factory, s, init, symbolEntityCache) : CreateEntity(factory, cacheKey, init, objectEntityCache); + + internal TEntity CreateEntityFromSymbol(CachedEntityFactory factory, TSymbol init) + where TSymbol : ISymbol + where TEntity : Entities.CachedEntity => CreateEntity(factory, init, init, symbolEntityCache); + + + /// + /// Creates and populates a new entity, or returns the existing one from the cache. + /// + /// The entity factory. + /// The key used for caching. + /// The initializer for the entity. + /// The dictionary to use for caching. + /// The new/existing entity. + private TEntity CreateEntity(CachedEntityFactory factory, TCacheKey cacheKey, TInit init, IDictionary dictionary) + where TCacheKey : notnull + where TEntity : Entities.CachedEntity + { + if (dictionary.TryGetValue(cacheKey, out var cached)) + return (TEntity)cached; + + using (StackGuard) + { + var label = GetNewLabel(); + var entity = factory.Create(this, init); + entity.Label = label; + + dictionary[cacheKey] = entity; + + DefineLabel(entity); + if (entity.NeedsPopulation) + Populate(init as ISymbol, entity); + +#if DEBUG_LABELS + using var id = new EscapingTextWriter(); + entity.WriteQuotedId(id); + CheckEntityHasUniqueLabel(id.ToString(), entity); +#endif + + return entity; + } + } + + /// + /// Creates a fresh label with ID "*", and set it on the + /// supplied object. + /// + internal void AddFreshLabel(Entity entity) + { + entity.Label = GetNewLabel(); + entity.DefineFreshLabel(TrapWriter.Writer); + } + +#if DEBUG_LABELS + private readonly Dictionary idLabelCache = new Dictionary(); +#endif + + private readonly IDictionary objectEntityCache = new Dictionary(); + private readonly IDictionary symbolEntityCache = new Dictionary(10000, SymbolEqualityComparer.Default); + + /// + /// Queue of items to populate later. + /// The only reason for this is so that the call stack does not + /// grow indefinitely, causing a potential stack overflow. + /// + private readonly Queue populateQueue = new Queue(); + + /// + /// Enqueue the given action to be performed later. + /// + /// The action to run. + public void PopulateLater(Action a, bool preserveDuplicationKey = true) + { + var key = preserveDuplicationKey ? GetCurrentTagStackKey() : null; + if (key is not null) + { + // If we are currently executing with a duplication guard, then the same + // guard must be used for the deferred action + populateQueue.Enqueue(() => WithDuplicationGuard(key, a)); + } + else + { + populateQueue.Enqueue(a); + } + } + + /// + /// Runs the main populate loop until there's nothing left to populate. + /// + public void PopulateAll() + { + while (populateQueue.Any()) + { + try + { + populateQueue.Dequeue()(); + } + catch (InternalError ex) + { + ExtractionError(new Message(ex.Text, ex.EntityText, CreateLocation(ex.Location), ex.StackTrace)); + } + catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] + { + ExtractionError($"Uncaught exception. {ex.Message}", null, CreateLocation(), ex.StackTrace); + } + } + } + + private int currentRecursiveDepth = 0; + private const int maxRecursiveDepth = 150; + + private void EnterScope() + { + if (currentRecursiveDepth >= maxRecursiveDepth) + throw new StackOverflowException($"Maximum nesting depth of {maxRecursiveDepth} exceeded"); + ++currentRecursiveDepth; + } + + private void ExitScope() + { + --currentRecursiveDepth; + } + + public IDisposable StackGuard => new ScopeGuard(this); + + private sealed class ScopeGuard : IDisposable + { + private readonly Context cx; + + public ScopeGuard(Context c) + { + cx = c; + cx.EnterScope(); + } + + public void Dispose() + { + cx.ExitScope(); + } + } + + private class PushEmitter : ITrapEmitter + { + private readonly Key key; + + public PushEmitter(Key key) + { + this.key = key; + } + + public void EmitTrap(TextWriter trapFile) + { + trapFile.Write(".push "); + key.AppendTo(trapFile); + trapFile.WriteLine(); + } + } + + private class PopEmitter : ITrapEmitter + { + public void EmitTrap(TextWriter trapFile) + { + trapFile.WriteLine(".pop"); + } + } + + private readonly Stack tagStack = new Stack(); + + /// + /// Populates an entity, handling the tag stack appropriately + /// + /// Symbol for reporting errors. + /// The entity to populate. + /// Thrown on invalid trap stack behaviour. + private void Populate(ISymbol? optionalSymbol, Entities.CachedEntity entity) + { + if (writingLabel) + { + // Don't write tuples etc if we're currently defining a label + PopulateLater(() => Populate(optionalSymbol, entity)); + return; + } + + bool duplicationGuard, deferred; + + if (ExtractionContext.Mode is ExtractorMode.Standalone) + { + duplicationGuard = false; + deferred = false; + } + else + { + switch (entity.TrapStackBehaviour) + { + case TrapStackBehaviour.NeedsLabel: + if (!tagStack.Any()) + ExtractionError("TagStack unexpectedly empty", optionalSymbol, entity); + duplicationGuard = false; + deferred = false; + break; + case TrapStackBehaviour.NoLabel: + duplicationGuard = false; + deferred = tagStack.Any(); + break; + case TrapStackBehaviour.OptionalLabel: + duplicationGuard = false; + deferred = false; + break; + case TrapStackBehaviour.PushesLabel: + duplicationGuard = true; + deferred = tagStack.Any(); + break; + default: + throw new InternalError("Unexpected TrapStackBehaviour"); + } + } + + var a = duplicationGuard && IsEntityDuplicationGuarded(entity, out var loc) + ? (() => + { + var args = new object[TrapStackSuffix.Count + 2]; + args[0] = entity; + args[1] = loc; + for (var i = 0; i < TrapStackSuffix.Count; i++) + { + args[i + 2] = TrapStackSuffix[i]; + } + WithDuplicationGuard(new Key(args), () => entity.Populate(TrapWriter.Writer)); + }) + : (Action)(() => this.Try(null, optionalSymbol, () => entity.Populate(TrapWriter.Writer))); + + if (deferred) + populateQueue.Enqueue(a); + else + a(); + } + + protected Key? GetCurrentTagStackKey() => tagStack.Count > 0 + ? tagStack.Peek() + : null; + + /// + /// Log an extraction error. + /// + /// The error message. + /// A textual representation of the failed entity. + /// The location of the error. + /// An optional stack trace of the error, or null. + /// The severity of the error. + public void ExtractionError(string message, string? entityText, Entities.Location? location, string? stackTrace = null, Severity severity = Severity.Error) + { + var msg = new Message(message, entityText, location, stackTrace, severity); + ExtractionError(msg); + } + + /// + /// Log an extraction error. + /// + /// The text of the message. + /// The symbol of the error, or null. + /// The entity of the error, or null. + private void ExtractionError(string message, ISymbol? optionalSymbol, Entity optionalEntity) + { + if (!(optionalSymbol is null)) + { + ExtractionError(message, optionalSymbol.ToDisplayString(), CreateLocation(optionalSymbol.Locations.BestOrDefault())); + } + else if (!(optionalEntity is null)) + { + ExtractionError(message, optionalEntity.Label.ToString(), CreateLocation(optionalEntity.ReportingLocation)); + } + else + { + ExtractionError(message, null, CreateLocation()); + } + } + + /// + /// Log an extraction message. + /// + /// The message to log. + private void ExtractionError(Message msg) + { + _ = new Entities.ExtractionMessage(this, msg); + ExtractionContext.Message(msg); + } + + private void ExtractionError(InternalError error) + { + ExtractionError(new Message(error.Message, error.EntityText, CreateLocation(error.Location), error.StackTrace, Severity.Error)); + } + + private void ReportError(InternalError error) + { + if (!ExtractionContext.Mode.HasFlag(ExtractorMode.Standalone)) + throw error; + + ExtractionError(error); + } + + /// + /// Signal an error in the program model. + /// + /// The syntax node causing the failure. + /// The error message. + public void ModelError(SyntaxNode node, string msg) + { + ReportError(new InternalError(node, msg)); + } + + /// + /// Signal an error in the program model. + /// + /// Symbol causing the error. + /// The error message. + public void ModelError(ISymbol symbol, string msg) + { + ReportError(new InternalError(symbol, msg)); + } + + /// + /// Signal an error in the program model. + /// + /// The location of the error. + /// The error message. + public void ModelError(CSharp.Entities.Location loc, string msg) + { + ReportError(new InternalError(loc.ReportingLocation, msg)); + } + + /// + /// Signal an error in the program model. + /// + /// The error message. + public void ModelError(string msg) + { + ReportError(new InternalError(msg)); + } + + /// + /// Tries the supplied action , and logs an uncaught + /// exception error if the action fails. + /// + /// Optional syntax node for error reporting. + /// Optional symbol for error reporting. + /// The action to perform. + public void Try(SyntaxNode? node, ISymbol? symbol, Action a) + { + try + { + a(); + } + catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] + { + Message message; + + if (node is not null) + { + message = Message.Create(this, ex.Message, node, ex.StackTrace); + } + else if (symbol is not null) + { + message = Message.Create(this, ex.Message, symbol, ex.StackTrace); + } + else if (ex is InternalError ie) + { + message = new Message(ie.Text, ie.EntityText, CreateLocation(ie.Location), ex.StackTrace); + } + else + { + message = new Message($"Uncaught exception. {ex.Message}", null, CreateLocation(), ex.StackTrace); + } + + ExtractionError(message); + } + } + /// /// The program database provided by Roslyn. /// There's one per syntax tree, which makes things awkward. @@ -77,9 +523,11 @@ internal void CacheLambdaParameterSymbol(IParameterSymbol param, SyntaxNode synt internal CommentProcessor CommentGenerator { get; } = new CommentProcessor(); - public Context(ExtractionContext extractionContext, Compilation c, TrapWriter trapWriter, IExtractionScope scope, bool addAssemblyTrapPrefix) - : base(extractionContext, trapWriter, addAssemblyTrapPrefix) + public Context(ExtractionContext extractionContext, Compilation c, TrapWriter trapWriter, IExtractionScope scope, bool shouldAddAssemblyTrapPrefix = false) { + ExtractionContext = extractionContext; + TrapWriter = trapWriter; + ShouldAddAssemblyTrapPrefix = shouldAddAssemblyTrapPrefix; Compilation = c; this.scope = scope; } @@ -102,7 +550,11 @@ public bool Defines(ISymbol symbol) => !SymbolEqualityComparer.Default.Equals(symbol, symbol.OriginalDefinition) || scope.InScope(symbol); - public override void WithDuplicationGuard(Key key, Action a) + /// + /// Runs the given action , guarding for trap duplication + /// based on key . + /// + public void WithDuplicationGuard(Key key, Action a) { if (IsAssemblyScope) { @@ -113,21 +565,31 @@ public override void WithDuplicationGuard(Key key, Action a) } else { - base.WithDuplicationGuard(key, a); + tagStack.Push(key); + TrapWriter.Emit(new PushEmitter(key)); + try + { + a(); + } + finally + { + TrapWriter.Emit(new PopEmitter()); + tagStack.Pop(); + } } } - public override Extraction.Entities.Location CreateLocation() + public Entities.Location CreateLocation() { return SourceTree is null - ? GeneratedLocation.Create(this) + ? Entities.GeneratedLocation.Create(this) : CreateLocation(Microsoft.CodeAnalysis.Location.Create(SourceTree, Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(0, 0))); } - public override Extraction.Entities.Location CreateLocation(Microsoft.CodeAnalysis.Location? location) + public Entities.Location CreateLocation(Microsoft.CodeAnalysis.Location? location) { return (location is null || location.Kind == LocationKind.None) - ? GeneratedLocation.Create(this) + ? Entities.GeneratedLocation.Create(this) : location.IsInSource ? Entities.NonGeneratedSourceLocation.Create(this, location) : Entities.Assembly.Create(this, location); @@ -145,7 +607,7 @@ public void BindComments(Entity entity, Microsoft.CodeAnalysis.Location? l) CommentGenerator.AddElement(entity.Label, duplicationGuardKey, l); } - protected override bool IsEntityDuplicationGuarded(IEntity entity, [NotNullWhen(true)] out Extraction.Entities.Location? loc) + private bool IsEntityDuplicationGuarded(IEntity entity, [NotNullWhen(true)] out Entities.Location? loc) { if (CreateLocation(entity.ReportingLocation) is Entities.NonGeneratedSourceLocation l) { @@ -169,7 +631,7 @@ protected override bool IsEntityDuplicationGuarded(IEntity entity, [NotNullWhen( /// /// The entity to extract. /// True only on the first call for a particular entity. - internal bool ExtractGenerics(CachedEntity entity) + internal bool ExtractGenerics(CSharp.Entities.CachedEntity entity) { if (extractedGenerics.Contains(entity.Label)) { diff --git a/csharp/extractor/Semmle.Extraction/CsProjFile.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/CsProjFile.cs similarity index 99% rename from csharp/extractor/Semmle.Extraction/CsProjFile.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Extractor/CsProjFile.cs index bed9d746996b..665eb0bf3462 100644 --- a/csharp/extractor/Semmle.Extraction/CsProjFile.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/CsProjFile.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Xml; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { /// /// Represents a .csproj file and reads information from it. diff --git a/csharp/extractor/Semmle.Extraction/Extractor/ExtractionContext.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/ExtractionContext.cs similarity index 98% rename from csharp/extractor/Semmle.Extraction/Extractor/ExtractionContext.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Extractor/ExtractionContext.cs index 26b30ad004b2..619eb9953471 100644 --- a/csharp/extractor/Semmle.Extraction/Extractor/ExtractionContext.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/ExtractionContext.cs @@ -2,7 +2,7 @@ using Semmle.Util.Logging; using CompilationInfo = (string key, string value); -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { /// /// Implementation of the main extractor state. diff --git a/csharp/extractor/Semmle.Extraction/Extractor/ExtractorMode.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/ExtractorMode.cs similarity index 88% rename from csharp/extractor/Semmle.Extraction/Extractor/ExtractorMode.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Extractor/ExtractorMode.cs index cc1f5cc04132..6729878e5639 100644 --- a/csharp/extractor/Semmle.Extraction/Extractor/ExtractorMode.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/ExtractorMode.cs @@ -1,6 +1,6 @@ using System; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { /// /// The mode in which a file is extracted. diff --git a/csharp/extractor/Semmle.Extraction/FilePattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/FilePattern.cs similarity index 99% rename from csharp/extractor/Semmle.Extraction/FilePattern.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Extractor/FilePattern.cs index 8c8e190a3ced..8220260369d7 100644 --- a/csharp/extractor/Semmle.Extraction/FilePattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/FilePattern.cs @@ -6,7 +6,7 @@ using System.Text.RegularExpressions; using Semmle.Util; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { public sealed class InvalidFilePatternException : Exception { diff --git a/csharp/extractor/Semmle.Extraction/IExtractionScope.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/IExtractionScope.cs similarity index 96% rename from csharp/extractor/Semmle.Extraction/IExtractionScope.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Extractor/IExtractionScope.cs index f12823b3f969..4a3ffe852e27 100644 --- a/csharp/extractor/Semmle.Extraction/IExtractionScope.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/IExtractionScope.cs @@ -1,6 +1,6 @@ using Microsoft.CodeAnalysis; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { /// /// Defines which entities belong in the trap file diff --git a/csharp/extractor/Semmle.Extraction/Message.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Message.cs similarity index 96% rename from csharp/extractor/Semmle.Extraction/Message.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Extractor/Message.cs index 7239c5880cb6..4825c6c3fe1b 100644 --- a/csharp/extractor/Semmle.Extraction/Message.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Message.cs @@ -1,9 +1,8 @@ -using System.Linq; -using System.Text; +using System.Text; using Microsoft.CodeAnalysis; using Semmle.Util.Logging; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { /// /// Encapsulates information for a log message. diff --git a/csharp/extractor/Semmle.Extraction/PathTransformer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/PathTransformer.cs similarity index 99% rename from csharp/extractor/Semmle.Extraction/PathTransformer.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Extractor/PathTransformer.cs index e67d60b11df4..79108d10d52e 100644 --- a/csharp/extractor/Semmle.Extraction/PathTransformer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/PathTransformer.cs @@ -5,7 +5,7 @@ using Semmle.Util; using Semmle.Util.Logging; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { /// /// A class for interpreting path transformers specified using the environment diff --git a/csharp/extractor/Semmle.Extraction/SourceScope.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/SourceScope.cs similarity index 93% rename from csharp/extractor/Semmle.Extraction/SourceScope.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Extractor/SourceScope.cs index 784dc8fdc938..6eff9c713cc6 100644 --- a/csharp/extractor/Semmle.Extraction/SourceScope.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/SourceScope.cs @@ -2,7 +2,7 @@ using Microsoft.CodeAnalysis; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { /// diff --git a/csharp/extractor/Semmle.Extraction/TrapWriter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TrapWriter.cs similarity index 99% rename from csharp/extractor/Semmle.Extraction/TrapWriter.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Extractor/TrapWriter.cs index f773207e6540..4830c3209c26 100644 --- a/csharp/extractor/Semmle.Extraction/TrapWriter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TrapWriter.cs @@ -5,7 +5,7 @@ using Semmle.Util; using Semmle.Util.Logging; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { public interface ITrapEmitter { diff --git a/csharp/extractor/Semmle.Extraction/InternalError.cs b/csharp/extractor/Semmle.Extraction.CSharp/InternalError.cs similarity index 95% rename from csharp/extractor/Semmle.Extraction/InternalError.cs rename to csharp/extractor/Semmle.Extraction.CSharp/InternalError.cs index f162316618e8..7b42432be255 100644 --- a/csharp/extractor/Semmle.Extraction/InternalError.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/InternalError.cs @@ -1,8 +1,7 @@ using System; -using System.Linq; using Microsoft.CodeAnalysis; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { /// /// Exception thrown whenever extraction encounters something unexpected. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj b/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj index 00a84ec3627a..3794d25df50c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj +++ b/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj @@ -1,7 +1,6 @@ - diff --git a/csharp/extractor/Semmle.Extraction/EscapingTextWriter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Trap/EscapingTextWriter.cs similarity index 99% rename from csharp/extractor/Semmle.Extraction/EscapingTextWriter.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Trap/EscapingTextWriter.cs index 2374b398843d..63f5e81c3586 100644 --- a/csharp/extractor/Semmle.Extraction/EscapingTextWriter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Trap/EscapingTextWriter.cs @@ -4,7 +4,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { /// /// A `TextWriter` object that wraps another `TextWriter` object, and which diff --git a/csharp/extractor/Semmle.Extraction/Id.cs b/csharp/extractor/Semmle.Extraction.CSharp/Trap/Key.cs similarity index 76% rename from csharp/extractor/Semmle.Extraction/Id.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Trap/Key.cs index c66688f0760e..273da621dce2 100644 --- a/csharp/extractor/Semmle.Extraction/Id.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Trap/Key.cs @@ -1,52 +1,13 @@ using System; using System.IO; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { - /// - /// An ID. Either a fresh ID (`*`), a key, or a label (https://semmle.com/wiki/display/IN/TRAP+Files): - /// - /// ``` - /// id ::= '*' | key | label - /// ``` - /// - public interface IId - { - /// - /// Appends this ID to the supplied trap builder. - /// - void AppendTo(TextWriter trapFile); - } - - /// - /// A fresh ID (`*`). - /// - public class FreshId : IId - { - private FreshId() { } - - /// - /// Gets the singleton instance. - /// - public static IId Instance { get; } = new FreshId(); - - public override string ToString() => "*"; - - public override bool Equals(object? obj) => obj?.GetType() == GetType(); - - public override int GetHashCode() => 0; - - public void AppendTo(TextWriter trapFile) - { - trapFile.Write('*'); - } - } - /// /// A key. Either a simple key, e.g. `@"bool A.M();method"`, or a compound key, e.g. /// `@"{0} {1}.M();method"` where `0` and `1` are both labels. /// - public class Key : IId + public class Key { private readonly StringWriter trapBuilder = new StringWriter(); diff --git a/csharp/extractor/Semmle.Extraction/TrapExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/Trap/TrapExtensions.cs similarity index 99% rename from csharp/extractor/Semmle.Extraction/TrapExtensions.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Trap/TrapExtensions.cs index 5c65e41f0ab7..787ba62e3e82 100644 --- a/csharp/extractor/Semmle.Extraction/TrapExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Trap/TrapExtensions.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { public static class TrapExtensions { diff --git a/csharp/extractor/Semmle.Extraction/TrapStackBehaviour.cs b/csharp/extractor/Semmle.Extraction.CSharp/Trap/TrapStackBehaviour.cs similarity index 95% rename from csharp/extractor/Semmle.Extraction/TrapStackBehaviour.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Trap/TrapStackBehaviour.cs index 0966a4816afe..023170d18872 100644 --- a/csharp/extractor/Semmle.Extraction/TrapStackBehaviour.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Trap/TrapStackBehaviour.cs @@ -1,4 +1,4 @@ -namespace Semmle.Extraction +namespace Semmle.Extraction.CSharp { /// /// How an entity behaves with respect to .push and .pop diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Trap/Tuples.cs similarity index 94% rename from csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Trap/Tuples.cs index 49d08fc80ef7..8960b6adb67f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Trap/Tuples.cs @@ -3,7 +3,6 @@ using Semmle.Util; using Semmle.Extraction.CSharp.Entities; using Semmle.Extraction.CSharp.Entities.Expressions; -using Semmle.Extraction.Entities; using Semmle.Extraction.Kinds; namespace Semmle.Extraction.CSharp @@ -17,7 +16,22 @@ namespace Semmle.Extraction.CSharp /// internal static class Tuples { - internal static void assemblies(this System.IO.TextWriter trapFile, Assembly assembly, Extraction.Entities.File file, string identifier, string name, string version) => + public static void containerparent(this TextWriter trapFile, Folder parent, IEntity child) => + trapFile.WriteTuple("containerparent", parent, child); + + internal static void extractor_messages(this TextWriter trapFile, ExtractionMessage error, Semmle.Util.Logging.Severity severity, string errorMessage, string entityText, Location location, string stackTrace) => + trapFile.WriteTuple("extractor_messages", error, (int)severity, "C# extractor", errorMessage, entityText, location, stackTrace); + + public static void files(this TextWriter trapFile, Entities.File file, string fullName) => + trapFile.WriteTuple("files", file, fullName); + + internal static void folders(this TextWriter trapFile, Folder folder, string path) => + trapFile.WriteTuple("folders", folder, path); + + public static void locations_default(this TextWriter trapFile, SourceLocation label, Entities.File file, int startLine, int startCol, int endLine, int endCol) => + trapFile.WriteTuple("locations_default", label, file, startLine, startCol, endLine, endCol); + + internal static void assemblies(this TextWriter trapFile, Assembly assembly, Entities.File file, string identifier, string name, string version) => trapFile.WriteTuple("assemblies", assembly, file, identifier, name, version); internal static void accessor_location(this TextWriter trapFile, Accessor accessorKey, Location location) => @@ -74,10 +88,10 @@ internal static void compilation_expanded_args(this TextWriter trapFile, Compila internal static void compilation_info(this TextWriter trapFile, Compilation compilation, string infoKey, string infoValue) => trapFile.WriteTuple("compilation_info", compilation, infoKey, infoValue); - internal static void compilation_compiling_files(this TextWriter trapFile, Compilation compilation, int index, Extraction.Entities.File file) => + internal static void compilation_compiling_files(this TextWriter trapFile, Compilation compilation, int index, Entities.File file) => trapFile.WriteTuple("compilation_compiling_files", compilation, index, file); - internal static void compilation_referencing_files(this TextWriter trapFile, Compilation compilation, int index, Extraction.Entities.File file) => + internal static void compilation_referencing_files(this TextWriter trapFile, Compilation compilation, int index, Entities.File file) => trapFile.WriteTuple("compilation_referencing_files", compilation, index, file); internal static void compilation_finished(this TextWriter trapFile, Compilation compilation, float cpuSeconds, float elapsedSeconds) => @@ -398,7 +412,7 @@ internal static void pragma_warnings(this TextWriter trapFile, PragmaWarningDire internal static void pragma_warning_error_codes(this TextWriter trapFile, PragmaWarningDirective pragma, string errorCode, int child) => trapFile.WriteTuple("pragma_warning_error_codes", pragma, errorCode, child); - internal static void pragma_checksums(this TextWriter trapFile, PragmaChecksumDirective pragma, Extraction.Entities.File file, string guid, string bytes) => + internal static void pragma_checksums(this TextWriter trapFile, PragmaChecksumDirective pragma, Entities.File file, string guid, string bytes) => trapFile.WriteTuple("pragma_checksums", pragma, file, guid, bytes); internal static void directive_defines(this TextWriter trapFile, DefineDirective directive, string name) => @@ -422,7 +436,7 @@ internal static void directive_lines(this TextWriter trapFile, LineOrSpanDire internal static void directive_line_value(this TextWriter trapFile, LineDirective directive, int line) => trapFile.WriteTuple("directive_line_value", directive, line); - internal static void directive_line_file(this TextWriter trapFile, LineOrSpanDirective directive, Extraction.Entities.File file) where T : LineOrSpanDirectiveTriviaSyntax => + internal static void directive_line_file(this TextWriter trapFile, LineOrSpanDirective directive, Entities.File file) where T : LineOrSpanDirectiveTriviaSyntax => trapFile.WriteTuple("directive_line_file", directive, file); internal static void directive_line_offset(this TextWriter trapFile, LineSpanDirective directive, int offset) => diff --git a/csharp/extractor/Semmle.Extraction.Tests/BUILD.bazel b/csharp/extractor/Semmle.Extraction.Tests/BUILD.bazel index dfdf41150ea8..df9799d3f959 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/BUILD.bazel +++ b/csharp/extractor/Semmle.Extraction.Tests/BUILD.bazel @@ -9,7 +9,6 @@ codeql_xunit_test( "*.cs", ]), deps = [ - "//csharp/extractor/Semmle.Extraction", "//csharp/extractor/Semmle.Extraction.CSharp", "//csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching", "//csharp/extractor/Semmle.Extraction.CSharp.Standalone:bin/Semmle.Extraction.CSharp.Standalone", diff --git a/csharp/extractor/Semmle.Extraction.Tests/FilePattern.cs b/csharp/extractor/Semmle.Extraction.Tests/FilePattern.cs index 9985a6f06c68..e4ed2721bf99 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/FilePattern.cs +++ b/csharp/extractor/Semmle.Extraction.Tests/FilePattern.cs @@ -1,4 +1,5 @@ using Xunit; +using Semmle.Extraction.CSharp; namespace Semmle.Extraction.Tests { diff --git a/csharp/extractor/Semmle.Extraction.Tests/Options.cs b/csharp/extractor/Semmle.Extraction.Tests/Options.cs index 1978732ee07b..76a03996df0d 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/Options.cs +++ b/csharp/extractor/Semmle.Extraction.Tests/Options.cs @@ -4,6 +4,7 @@ using System.Text.RegularExpressions; using Semmle.Util; using Semmle.Util.Logging; +using Semmle.Extraction.CSharp; namespace Semmle.Extraction.Tests { diff --git a/csharp/extractor/Semmle.Extraction.Tests/PathTransformer.cs b/csharp/extractor/Semmle.Extraction.Tests/PathTransformer.cs index e629c406457c..be73becd25d2 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/PathTransformer.cs +++ b/csharp/extractor/Semmle.Extraction.Tests/PathTransformer.cs @@ -1,5 +1,6 @@ using Xunit; using Semmle.Util; +using Semmle.Extraction.CSharp; namespace Semmle.Extraction.Tests { diff --git a/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj b/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj index 60994237e152..d3940eb3df9f 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj +++ b/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj @@ -4,7 +4,6 @@ - diff --git a/csharp/extractor/Semmle.Extraction/BUILD.bazel b/csharp/extractor/Semmle.Extraction/BUILD.bazel deleted file mode 100644 index 83dfb8235e88..000000000000 --- a/csharp/extractor/Semmle.Extraction/BUILD.bazel +++ /dev/null @@ -1,36 +0,0 @@ -load( - "//misc/bazel:csharp.bzl", - "codeql_csharp_library", -) - -config_setting( - name = "debug_build", - values = { - "compilation_mode": "dbg", - }, -) - -codeql_csharp_library( - name = "Semmle.Extraction", - srcs = glob([ - "Entities/**/*.cs", - "Extractor/**/*.cs", - "*.cs", - ]), - # enable via -c dbg on the bazel command line/in .bazelrc.local - defines = select({ - ":debug_build": [ - "TRACE", - "DEBUG", - "DEBUG_LABELS", - ], - "//conditions:default": [], - }), - internals_visible_to = ["Semmle.Extraction.CSharp"], - visibility = ["//csharp:__subpackages__"], - deps = [ - "//csharp/extractor/Semmle.Util", - "@paket.main//microsoft.build", - "@paket.main//microsoft.codeanalysis", - ], -) diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs deleted file mode 100644 index 8b7b750768c4..000000000000 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ /dev/null @@ -1,500 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Linq; -using Microsoft.CodeAnalysis; -using Semmle.Util.Logging; -using Semmle.Extraction.Entities; - -namespace Semmle.Extraction -{ - /// - /// State that needs to be available throughout the extraction process. - /// There is one Context object per trap output file. - /// - public class Context - { - /// - /// Access various extraction functions, e.g. logger, trap writer. - /// - public ExtractionContext ExtractionContext { get; } - - /// - /// Access to the trap file. - /// - public TrapWriter TrapWriter { get; } - - /// - /// Holds if assembly information should be prefixed to TRAP labels. - /// - public bool ShouldAddAssemblyTrapPrefix { get; } - - public IList TrapStackSuffix { get; } = new List(); - - private int GetNewId() => TrapWriter.IdCounter++; - - // A recursion guard against writing to the trap file whilst writing an id to the trap file. - private bool writingLabel = false; - - private readonly Queue labelQueue = []; - - protected void DefineLabel(IEntity entity) - { - if (writingLabel) - { - // Don't define a label whilst writing a label. - labelQueue.Enqueue(entity); - } - else - { - try - { - writingLabel = true; - entity.DefineLabel(TrapWriter.Writer); - } - finally - { - writingLabel = false; - if (labelQueue.Any()) - { - DefineLabel(labelQueue.Dequeue()); - } - } - } - } - -#if DEBUG_LABELS - private void CheckEntityHasUniqueLabel(string id, CachedEntity entity) - { - if (idLabelCache.ContainsKey(id)) - { - this.Extractor.Message(new Message("Label collision for " + id, entity.Label.ToString(), CreateLocation(entity.ReportingLocation), "", Severity.Warning)); - } - else - { - idLabelCache[id] = entity; - } - } -#endif - - protected Label GetNewLabel() => new Label(GetNewId()); - - internal TEntity CreateEntity(CachedEntityFactory factory, object cacheKey, TInit init) - where TEntity : CachedEntity => - cacheKey is ISymbol s ? CreateEntity(factory, s, init, symbolEntityCache) : CreateEntity(factory, cacheKey, init, objectEntityCache); - - internal TEntity CreateEntityFromSymbol(CachedEntityFactory factory, TSymbol init) - where TSymbol : ISymbol - where TEntity : CachedEntity => CreateEntity(factory, init, init, symbolEntityCache); - - /// - /// Creates and populates a new entity, or returns the existing one from the cache. - /// - /// The entity factory. - /// The key used for caching. - /// The initializer for the entity. - /// The dictionary to use for caching. - /// The new/existing entity. - private TEntity CreateEntity(CachedEntityFactory factory, TCacheKey cacheKey, TInit init, IDictionary dictionary) - where TCacheKey : notnull - where TEntity : CachedEntity - { - if (dictionary.TryGetValue(cacheKey, out var cached)) - return (TEntity)cached; - - using (StackGuard) - { - var label = GetNewLabel(); - var entity = factory.Create(this, init); - entity.Label = label; - - dictionary[cacheKey] = entity; - - DefineLabel(entity); - if (entity.NeedsPopulation) - Populate(init as ISymbol, entity); - -#if DEBUG_LABELS - using var id = new EscapingTextWriter(); - entity.WriteQuotedId(id); - CheckEntityHasUniqueLabel(id.ToString(), entity); -#endif - - return entity; - } - } - - /// - /// Creates a fresh label with ID "*", and set it on the - /// supplied object. - /// - internal void AddFreshLabel(Entity entity) - { - entity.Label = GetNewLabel(); - entity.DefineFreshLabel(TrapWriter.Writer); - } - -#if DEBUG_LABELS - private readonly Dictionary idLabelCache = new Dictionary(); -#endif - - private readonly IDictionary objectEntityCache = new Dictionary(); - private readonly IDictionary symbolEntityCache = new Dictionary(10000, SymbolEqualityComparer.Default); - - /// - /// Queue of items to populate later. - /// The only reason for this is so that the call stack does not - /// grow indefinitely, causing a potential stack overflow. - /// - private readonly Queue populateQueue = new Queue(); - - /// - /// Enqueue the given action to be performed later. - /// - /// The action to run. - public void PopulateLater(Action a, bool preserveDuplicationKey = true) - { - var key = preserveDuplicationKey ? GetCurrentTagStackKey() : null; - if (key is not null) - { - // If we are currently executing with a duplication guard, then the same - // guard must be used for the deferred action - populateQueue.Enqueue(() => WithDuplicationGuard(key, a)); - } - else - { - populateQueue.Enqueue(a); - } - } - - /// - /// Runs the main populate loop until there's nothing left to populate. - /// - public void PopulateAll() - { - while (populateQueue.Any()) - { - try - { - populateQueue.Dequeue()(); - } - catch (InternalError ex) - { - ExtractionError(new Message(ex.Text, ex.EntityText, CreateLocation(ex.Location), ex.StackTrace)); - } - catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] - { - ExtractionError($"Uncaught exception. {ex.Message}", null, CreateLocation(), ex.StackTrace); - } - } - } - - protected Context(ExtractionContext extractionContext, TrapWriter trapWriter, bool shouldAddAssemblyTrapPrefix = false) - { - ExtractionContext = extractionContext; - TrapWriter = trapWriter; - ShouldAddAssemblyTrapPrefix = shouldAddAssemblyTrapPrefix; - } - - private int currentRecursiveDepth = 0; - private const int maxRecursiveDepth = 150; - - private void EnterScope() - { - if (currentRecursiveDepth >= maxRecursiveDepth) - throw new StackOverflowException($"Maximum nesting depth of {maxRecursiveDepth} exceeded"); - ++currentRecursiveDepth; - } - - private void ExitScope() - { - --currentRecursiveDepth; - } - - public IDisposable StackGuard => new ScopeGuard(this); - - private sealed class ScopeGuard : IDisposable - { - private readonly Context cx; - - public ScopeGuard(Context c) - { - cx = c; - cx.EnterScope(); - } - - public void Dispose() - { - cx.ExitScope(); - } - } - - private class PushEmitter : ITrapEmitter - { - private readonly Key key; - - public PushEmitter(Key key) - { - this.key = key; - } - - public void EmitTrap(TextWriter trapFile) - { - trapFile.Write(".push "); - key.AppendTo(trapFile); - trapFile.WriteLine(); - } - } - - private class PopEmitter : ITrapEmitter - { - public void EmitTrap(TextWriter trapFile) - { - trapFile.WriteLine(".pop"); - } - } - - private readonly Stack tagStack = new Stack(); - - /// - /// Populates an entity, handling the tag stack appropriately - /// - /// Symbol for reporting errors. - /// The entity to populate. - /// Thrown on invalid trap stack behaviour. - private void Populate(ISymbol? optionalSymbol, CachedEntity entity) - { - if (writingLabel) - { - // Don't write tuples etc if we're currently defining a label - PopulateLater(() => Populate(optionalSymbol, entity)); - return; - } - - bool duplicationGuard, deferred; - - if (ExtractionContext.Mode is ExtractorMode.Standalone) - { - duplicationGuard = false; - deferred = false; - } - else - { - switch (entity.TrapStackBehaviour) - { - case TrapStackBehaviour.NeedsLabel: - if (!tagStack.Any()) - ExtractionError("TagStack unexpectedly empty", optionalSymbol, entity); - duplicationGuard = false; - deferred = false; - break; - case TrapStackBehaviour.NoLabel: - duplicationGuard = false; - deferred = tagStack.Any(); - break; - case TrapStackBehaviour.OptionalLabel: - duplicationGuard = false; - deferred = false; - break; - case TrapStackBehaviour.PushesLabel: - duplicationGuard = true; - deferred = duplicationGuard && tagStack.Any(); - break; - default: - throw new InternalError("Unexpected TrapStackBehaviour"); - } - } - - var a = duplicationGuard && IsEntityDuplicationGuarded(entity, out var loc) - ? (() => - { - var args = new object[TrapStackSuffix.Count + 2]; - args[0] = entity; - args[1] = loc; - for (var i = 0; i < TrapStackSuffix.Count; i++) - { - args[i + 2] = TrapStackSuffix[i]; - } - WithDuplicationGuard(new Key(args), () => entity.Populate(TrapWriter.Writer)); - }) - : (Action)(() => this.Try(null, optionalSymbol, () => entity.Populate(TrapWriter.Writer))); - - if (deferred) - populateQueue.Enqueue(a); - else - a(); - } - - protected virtual bool IsEntityDuplicationGuarded(IEntity entity, [NotNullWhen(returnValue: true)] out Entities.Location? loc) - { - loc = null; - return false; - } - - /// - /// Runs the given action , guarding for trap duplication - /// based on key . - /// - public virtual void WithDuplicationGuard(Key key, Action a) - { - tagStack.Push(key); - TrapWriter.Emit(new PushEmitter(key)); - try - { - a(); - } - finally - { - TrapWriter.Emit(new PopEmitter()); - tagStack.Pop(); - } - } - - protected Key? GetCurrentTagStackKey() => tagStack.Count > 0 - ? tagStack.Peek() - : null; - - /// - /// Log an extraction error. - /// - /// The error message. - /// A textual representation of the failed entity. - /// The location of the error. - /// An optional stack trace of the error, or null. - /// The severity of the error. - public void ExtractionError(string message, string? entityText, Entities.Location? location, string? stackTrace = null, Severity severity = Severity.Error) - { - var msg = new Message(message, entityText, location, stackTrace, severity); - ExtractionError(msg); - } - - /// - /// Log an extraction error. - /// - /// The text of the message. - /// The symbol of the error, or null. - /// The entity of the error, or null. - private void ExtractionError(string message, ISymbol? optionalSymbol, Entity optionalEntity) - { - if (!(optionalSymbol is null)) - { - ExtractionError(message, optionalSymbol.ToDisplayString(), CreateLocation(optionalSymbol.Locations.BestOrDefault())); - } - else if (!(optionalEntity is null)) - { - ExtractionError(message, optionalEntity.Label.ToString(), CreateLocation(optionalEntity.ReportingLocation)); - } - else - { - ExtractionError(message, null, CreateLocation()); - } - } - - /// - /// Log an extraction message. - /// - /// The message to log. - private void ExtractionError(Message msg) - { - new ExtractionMessage(this, msg); - ExtractionContext.Message(msg); - } - - private void ExtractionError(InternalError error) - { - ExtractionError(new Message(error.Message, error.EntityText, CreateLocation(error.Location), error.StackTrace, Severity.Error)); - } - - private void ReportError(InternalError error) - { - if (!ExtractionContext.Mode.HasFlag(ExtractorMode.Standalone)) - throw error; - - ExtractionError(error); - } - - /// - /// Signal an error in the program model. - /// - /// The syntax node causing the failure. - /// The error message. - public void ModelError(SyntaxNode node, string msg) - { - ReportError(new InternalError(node, msg)); - } - - /// - /// Signal an error in the program model. - /// - /// Symbol causing the error. - /// The error message. - public void ModelError(ISymbol symbol, string msg) - { - ReportError(new InternalError(symbol, msg)); - } - - /// - /// Signal an error in the program model. - /// - /// The location of the error. - /// The error message. - public void ModelError(Entities.Location loc, string msg) - { - ReportError(new InternalError(loc.ReportingLocation, msg)); - } - - /// - /// Signal an error in the program model. - /// - /// The error message. - public void ModelError(string msg) - { - ReportError(new InternalError(msg)); - } - - /// - /// Tries the supplied action , and logs an uncaught - /// exception error if the action fails. - /// - /// Optional syntax node for error reporting. - /// Optional symbol for error reporting. - /// The action to perform. - public void Try(SyntaxNode? node, ISymbol? symbol, Action a) - { - try - { - a(); - } - catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] - { - Message message; - - if (node is not null) - { - message = Message.Create(this, ex.Message, node, ex.StackTrace); - } - else if (symbol is not null) - { - message = Message.Create(this, ex.Message, symbol, ex.StackTrace); - } - else if (ex is InternalError ie) - { - message = new Message(ie.Text, ie.EntityText, CreateLocation(ie.Location), ex.StackTrace); - } - else - { - message = new Message($"Uncaught exception. {ex.Message}", null, CreateLocation(), ex.StackTrace); - } - - ExtractionError(message); - } - } - - public virtual Entities.Location CreateLocation() => - GeneratedLocation.Create(this); - - public virtual Entities.Location CreateLocation(Microsoft.CodeAnalysis.Location? location) => - CreateLocation(); - } -} diff --git a/csharp/extractor/Semmle.Extraction/Entities/File.cs b/csharp/extractor/Semmle.Extraction/Entities/File.cs deleted file mode 100644 index dda965920ae1..000000000000 --- a/csharp/extractor/Semmle.Extraction/Entities/File.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; - -namespace Semmle.Extraction.Entities -{ - public abstract class File : CachedEntity - { - protected File(Context cx, string path) - : base(cx, path) - { - originalPath = path; - var adjustedPath = BinaryLogExtractionContext.GetAdjustedPath(Context.ExtractionContext, originalPath) ?? path; - transformedPathLazy = new Lazy(() => Context.ExtractionContext.PathTransformer.Transform(adjustedPath)); - } - - protected readonly string originalPath; - private readonly Lazy transformedPathLazy; - protected PathTransformer.ITransformedPath TransformedPath => transformedPathLazy.Value; - - public override bool NeedsPopulation => true; - - public override void WriteId(EscapingTextWriter trapFile) - { - trapFile.Write(TransformedPath.DatabaseId); - trapFile.Write(";sourcefile"); - } - - public override Microsoft.CodeAnalysis.Location? ReportingLocation => null; - } -} diff --git a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj b/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj deleted file mode 100644 index 2173a50f2ad3..000000000000 --- a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - Semmle.Extraction.ruleset - - - - - - - - diff --git a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.ruleset b/csharp/extractor/Semmle.Extraction/Semmle.Extraction.ruleset deleted file mode 100644 index 14df29e3653b..000000000000 --- a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.ruleset +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/csharp/extractor/Semmle.Extraction/Tuple.cs b/csharp/extractor/Semmle.Extraction/Tuple.cs deleted file mode 100644 index bfe660926d6d..000000000000 --- a/csharp/extractor/Semmle.Extraction/Tuple.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.IO; - -namespace Semmle.Extraction -{ - /// - /// A tuple represents a string of the form "a(b,c,d)". - /// - public struct Tuple : ITrapEmitter - { - private readonly string name; - private readonly object[] args; - - public Tuple(string name, params object[] args) - { - this.name = name; - this.args = args; - } - - /// - /// Constructs a unique string for this tuple. - /// - /// The trap file to write to. - public void EmitTrap(TextWriter trapFile) - { - trapFile.WriteTuple(name, args); - } - - public override string ToString() - { - // Only implemented for debugging purposes - using var writer = new StringWriter(); - EmitTrap(writer); - return writer.ToString(); - } - } -} diff --git a/csharp/extractor/Semmle.Extraction/Tuples.cs b/csharp/extractor/Semmle.Extraction/Tuples.cs deleted file mode 100644 index cddec9322863..000000000000 --- a/csharp/extractor/Semmle.Extraction/Tuples.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Semmle.Extraction.Entities; - -namespace Semmle.Extraction -{ - /// - /// Methods for creating DB tuples. - /// - public static class Tuples - { - public static void containerparent(this System.IO.TextWriter trapFile, Folder parent, IEntity child) - { - trapFile.WriteTuple("containerparent", parent, child); - } - - internal static void extractor_messages(this System.IO.TextWriter trapFile, ExtractionMessage error, Semmle.Util.Logging.Severity severity, string errorMessage, string entityText, Location location, string stackTrace) - { - trapFile.WriteTuple("extractor_messages", error, (int)severity, "C# extractor", errorMessage, entityText, location, stackTrace); - } - - public static void files(this System.IO.TextWriter trapFile, File file, string fullName) - { - trapFile.WriteTuple("files", file, fullName); - } - - internal static void folders(this System.IO.TextWriter trapFile, Folder folder, string path) - { - trapFile.WriteTuple("folders", folder, path); - } - - public static void locations_default(this System.IO.TextWriter trapFile, SourceLocation label, Entities.File file, int startLine, int startCol, int endLine, int endCol) - { - trapFile.WriteTuple("locations_default", label, file, startLine, startCol, endLine, endCol); - } - } -} diff --git a/csharp/extractor/Semmle.Extraction/paket.references b/csharp/extractor/Semmle.Extraction/paket.references deleted file mode 100644 index 310fffb853f1..000000000000 --- a/csharp/extractor/Semmle.Extraction/paket.references +++ /dev/null @@ -1,2 +0,0 @@ -Microsoft.Build -Microsoft.CodeAnalysis