Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions csharp/extractor/Semmle.Extraction.CSharp/Entities/Assembly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,14 @@ public static Assembly CreateOutputAssembly(Context cx)

public override void WriteId(EscapingTextWriter trapFile)
{
if (isOutputAssembly && Context.ExtractionContext.IsStandalone)
if (Context.ExtractionContext.IsStandalone)
{
trapFile.Write("buildlessOutputAssembly");
}
else
{
trapFile.Write(assembly.ToString());
WriteStarId(trapFile);
return;
}

trapFile.Write(assembly.ToString());

if (assemblyPath is not null)
{
trapFile.Write("#file:///");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ public override void Populate(TextWriter trapFile)
ContainingType!.PopulateGenerics();

trapFile.constructors(this, Symbol.ContainingType.Name, ContainingType, (Constructor)OriginalDefinition);
trapFile.constructor_location(this, Location);
if (Context.ExtractLocation(Symbol))
{
trapFile.constructor_location(this, Location);
}

if (MakeSynthetic)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System.IO;
using System.Threading;

namespace Semmle.Extraction.CSharp.Entities
{
public class EmptyLocation : SourceLocation
{
private readonly File generatedFile;

// The Ql library assumes the presence of a single "empty" location.
private static EmptyLocation? instance;
private static readonly Lock instanceLock = new();

private EmptyLocation(Context cx)
: base(cx, null)
{
generatedFile = GeneratedFile.Create(cx);
}

public override void Populate(TextWriter trapFile)
{
trapFile.locations_default(this, generatedFile, 0, 0, 0, 0);
}

public override void WriteId(EscapingTextWriter trapFile)
{
if (Context.ExtractionContext.IsStandalone)
{
WriteStarId(trapFile);
return;
}

trapFile.Write("loc,");
trapFile.WriteSubId(generatedFile);
trapFile.Write(",0,0,0,0");
}

public override int GetHashCode() => 98732567;

public override bool Equals(object? obj) => obj is not null && obj.GetType() == typeof(EmptyLocation);

public static EmptyLocation Create(Context cx)
{
lock (instanceLock)
{
instance ??= EmptyLocationFactory.Instance.CreateEntity(cx, typeof(EmptyLocation), null);
return instance;
}
}

private class EmptyLocationFactory : CachedEntityFactory<string?, EmptyLocation>
{
public static EmptyLocationFactory Instance { get; } = new EmptyLocationFactory();

public override EmptyLocation Create(Context cx, string? init) => new EmptyLocation(cx);
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,24 @@ public abstract class Location : CachedEntity<Microsoft.CodeAnalysis.Location?>
{
#nullable restore warnings
protected Location(Context cx, Microsoft.CodeAnalysis.Location? init)
: base(cx, init) { }
: base(cx, init)
{ }

protected static void WriteStarId(EscapingTextWriter writer)
{
writer.Write('*');
}

public sealed override void WriteQuotedId(EscapingTextWriter writer)
{
if (Context.ExtractionContext.IsStandalone)
{
WriteStarId(writer);
return;
}

base.WriteQuotedId(writer);
}

public override Microsoft.CodeAnalysis.Location? ReportingLocation => Symbol;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ public File FileEntity

public override void WriteId(EscapingTextWriter trapFile)
{
if (Context.ExtractionContext.IsStandalone)
{
WriteStarId(trapFile);
return;
}

trapFile.Write("loc,");
trapFile.WriteSubId(FileEntity);
trapFile.Write(',');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@ public override void Populate(TextWriter trapFile)
}
}

foreach (var l in Locations)
trapFile.method_location(this, l);
if (Context.ExtractLocation(Symbol))
{
foreach (var l in Locations)
trapFile.method_location(this, l);
}

PopulateGenerics(trapFile);
Overrides(trapFile);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public override void Populate(TextWriter trapFile)
var typeKey = VarargsType.Create(Context);
// !! Maybe originaldefinition is wrong
trapFile.@params(this, "", typeKey, Ordinal, Kind.None, Parent!, this);
trapFile.param_location(this, GeneratedLocation.Create(Context));
trapFile.param_location(this, EmptyLocation.Create(Context));
}

protected override int Ordinal => ((Method)Parent!).OriginalDefinition.Symbol.Parameters.Length;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,9 @@ private void DoAnalyseCompilation()

compilationEntity = Entities.Compilation.Create(cx);

// Ensure that the empty location is always created.
Entities.EmptyLocation.Create(cx);

ExtractionContext.CompilationInfos.ForEach(ci => trapWriter.Writer.compilation_info(compilationEntity, ci.key, ci.value));

ReportProgressTaskDone(currentTaskId, assemblyPath, trapWriter.TrapFile, stopwatch.Elapsed, AnalysisAction.Extracted);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,10 @@ public bool Defines(ISymbol symbol) =>
!SymbolEqualityComparer.Default.Equals(symbol, symbol.OriginalDefinition) ||
scope.InScope(symbol);

public bool ExtractLocation(ISymbol symbol) =>
SymbolEqualityComparer.Default.Equals(symbol, symbol.OriginalDefinition) &&
scope.InScope(symbol);

/// <summary>
/// Runs the given action <paramref name="a"/>, guarding for trap duplication
/// based on key <paramref name="key"/>.
Expand Down Expand Up @@ -582,14 +586,14 @@ public void WithDuplicationGuard(Key key, Action a)
public Entities.Location CreateLocation()
{
return SourceTree is null
? Entities.GeneratedLocation.Create(this)
? Entities.EmptyLocation.Create(this)
: CreateLocation(Microsoft.CodeAnalysis.Location.Create(SourceTree, Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(0, 0)));
}

public Entities.Location CreateLocation(Microsoft.CodeAnalysis.Location? location)
{
return (location is null || location.Kind == LocationKind.None)
? Entities.GeneratedLocation.Create(this)
? Entities.EmptyLocation.Create(this)
: location.IsInSource
? Entities.NonGeneratedSourceLocation.Create(this, location)
: Entities.Assembly.Create(this, location);
Expand Down
2 changes: 1 addition & 1 deletion csharp/ql/lib/semmle/code/csharp/Callable.qll
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ class Method extends Callable, Virtualizable, Attributable, @method {
result = Virtualizable.super.getAnUltimateImplementor()
}

override Location getALocation() { method_location(this, result) }
override Location getALocation() { method_location(this.getUnboundDeclaration(), result) }

/** Holds if this method is an extension method. */
predicate isExtensionMethod() { this.getParameter(0).hasExtensionMethodModifier() }
Expand Down
18 changes: 18 additions & 0 deletions csharp/ql/test/library-tests/locations/A.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

public abstract class A<T>
{
public void Apply(T t) { }
public abstract object ToObject(T t);
}

public class A2 : A<string>
{
public override object ToObject(string t) => t;

public void M()
{
A2 other = new();
other.Apply("");
}
}
6 changes: 6 additions & 0 deletions csharp/ql/test/library-tests/locations/B.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using System;

public class B : A<int>
{
public override object ToObject(int t) => t;
}
12 changes: 12 additions & 0 deletions csharp/ql/test/library-tests/locations/C.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

class C
{
public void M()
{
B b = new B();
b.Apply(0);
A2 a2 = new A2();
a2.Apply("");
}
}
10 changes: 10 additions & 0 deletions csharp/ql/test/library-tests/locations/locations.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
| A.cs:3:23:3:26 | A<Int32> | A.cs:5:17:5:21 | Apply | A.cs:5:17:5:21 | A.cs:5:17:5:21 |
| A.cs:3:23:3:26 | A<Int32> | A.cs:6:28:6:35 | ToObject | A.cs:6:28:6:35 | A.cs:6:28:6:35 |
| A.cs:3:23:3:26 | A<String> | A.cs:5:17:5:21 | Apply | A.cs:5:17:5:21 | A.cs:5:17:5:21 |
| A.cs:3:23:3:26 | A<String> | A.cs:6:28:6:35 | ToObject | A.cs:6:28:6:35 | A.cs:6:28:6:35 |
| A.cs:3:23:3:26 | A`1 | A.cs:5:17:5:21 | Apply | A.cs:5:17:5:21 | A.cs:5:17:5:21 |
| A.cs:3:23:3:26 | A`1 | A.cs:6:28:6:35 | ToObject | A.cs:6:28:6:35 | A.cs:6:28:6:35 |
| A.cs:9:14:9:15 | A2 | A.cs:11:28:11:35 | ToObject | A.cs:11:28:11:35 | A.cs:11:28:11:35 |
| A.cs:9:14:9:15 | A2 | A.cs:13:17:13:17 | M | A.cs:13:17:13:17 | A.cs:13:17:13:17 |
| B.cs:3:14:3:14 | B | B.cs:5:28:5:35 | ToObject | B.cs:5:28:5:35 | B.cs:5:28:5:35 |
| C.cs:3:7:3:7 | C | C.cs:5:17:5:17 | M | C.cs:5:17:5:17 | C.cs:5:17:5:17 |
5 changes: 5 additions & 0 deletions csharp/ql/test/library-tests/locations/locations.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import csharp

from Type t, Method m, SourceLocation l
where t = m.getDeclaringType() and l = m.getLocation() and not l instanceof EmptyLocation
select t, m, l
1 change: 1 addition & 0 deletions csharp/ql/test/library-tests/locations/options
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
semmle-extractor-options: --standalone
Loading