Skip to content
Merged
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
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);
WriteLocationToTrap(trapFile.constructor_location, this, Location);
if (Context.ExtractLocation(Symbol) && (!IsDefault || IsBestSourceLocation))
{
WriteLocationToTrap(trapFile.constructor_location, this, Location);
}

if (MakeSynthetic)
{
Expand Down Expand Up @@ -168,7 +171,15 @@ Symbol.ContainingType.TypeKind is TypeKind.Class or TypeKind.Struct &&
Symbol.ContainingType.IsSourceDeclaration() &&
!Symbol.ContainingType.IsAnonymousType;

private bool MakeSynthetic => IsPrimary || IsDefault;
/// <summary>
/// Returns true if we consider the reporting location of this constructor entity the best
/// location of the constructor.
/// For partial classes with default constructors, Roslyn consider each partial class declaration
/// as the possible location for the implicit default constructor.
/// </summary>
private bool IsBestSourceLocation => ReportingLocation is not null && Context.IsLocationInContext(ReportingLocation);

private bool MakeSynthetic => IsPrimary || (IsDefault && IsBestSourceLocation);

[return: NotNullIfNotNull(nameof(constructor))]
public static new Constructor? Create(Context cx, IMethodSymbol? constructor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ public override void Populate(TextWriter trapFile)
ContainingType!.PopulateGenerics();

trapFile.destructors(this, $"~{Symbol.ContainingType.Name}", ContainingType, OriginalDefinition(Context, this, Symbol));
WriteLocationToTrap(trapFile.destructor_location, this, Location);
if (Context.ExtractLocation(Symbol))
{
WriteLocationToTrap(trapFile.destructor_location, this, Location);
}
}

private static new Destructor OriginalDefinition(Context cx, Destructor original, IMethodSymbol symbol)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ public override void Populate(TextWriter trapFile)
}
}

WriteLocationsToTrap(trapFile.field_location, this, Locations);
if (Context.ExtractLocation(Symbol))
{
WriteLocationsToTrap(trapFile.field_location, this, Locations);
}

if (!IsSourceDeclaration || !Symbol.FromSource())
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,10 @@ public override void Populate(TextWriter trapFile)
var type = Type.Create(Context, Symbol.Type);
trapFile.@params(this, Name, type.TypeRef, Ordinal, ParamKind, Parent!, Original);

foreach (var l in Symbol.Locations)
if (Context.ExtractLocation(Symbol))
{
WriteLocationToTrap(trapFile.param_location, this, Context.CreateLocation(l));
var locations = Context.GetLocations(Symbol);
WriteLocationsToTrap(trapFile.param_location, this, locations);
}

if (!Symbol.Locations.Any() &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ public override void Populate(TextWriter trapFile)
returnType.TypeRef,
(UserOperator)OriginalDefinition);

WriteLocationsToTrap(trapFile.operator_location, this, Locations);
if (Context.ExtractLocation(Symbol))
{
WriteLocationsToTrap(trapFile.operator_location, this, Locations);
}

if (IsSourceDeclaration)
{
Expand Down
4 changes: 4 additions & 0 deletions csharp/ql/lib/change-notes/2025-10-10-entity-locations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The extraction of location information for parameters, fields, constructors, destructors and user operators has been optimized. Previously, location information was extracted multiple times for each bound generic. Now, only the location of the unbound generic declaration is extracted during the extraction phase, and the QL library explicitly reuses this location for all bound instances of the same generic.
6 changes: 3 additions & 3 deletions csharp/ql/lib/semmle/code/csharp/Callable.qll
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ class Constructor extends Callable, Member, Attributable, @constructor {

override Constructor getUnboundDeclaration() { constructors(this, _, _, result) }

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

override predicate fromSource() { Member.super.fromSource() and not this.isCompilerGenerated() }

Expand Down Expand Up @@ -450,7 +450,7 @@ class Destructor extends Callable, Member, Attributable, @destructor {

override Destructor getUnboundDeclaration() { destructors(this, _, _, result) }

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

override string toString() { result = Callable.super.toString() }

Expand Down Expand Up @@ -484,7 +484,7 @@ class Operator extends Callable, Member, Attributable, Overridable, @operator {

override Operator getUnboundDeclaration() { operators(this, _, _, _, _, result) }

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

override string toString() { result = Callable.super.toString() }

Expand Down
4 changes: 2 additions & 2 deletions csharp/ql/lib/semmle/code/csharp/Variable.qll
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ class Parameter extends LocalScopeVariable, Attributable, TopLevelExprParent, @p
params(this, _, getTypeRef(result), _, _, _, _)
}

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

override string toString() { result = this.getName() }

Expand Down Expand Up @@ -449,7 +449,7 @@ class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent
fields(this, _, _, _, getTypeRef(result), _)
}

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

override string toString() { result = Variable.super.toString() }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,6 @@
| Assignables.cs:92:23:92:23 | b |
| Assignables.cs:92:33:92:33 | s |
| Assignables.cs:95:40:95:44 | tuple |
| Assignables.cs:97:24:97:24 | Item1 |
| Assignables.cs:97:27:97:36 | Item2 |
| Assignables.cs:101:6:101:8 | Item1 |
| Assignables.cs:101:11:101:24 | Item2 |
| Assignables.cs:101:12:101:15 | Item1 |
| Assignables.cs:101:18:101:23 | Item2 |
| Assignables.cs:108:13:108:13 | i |
| Assignables.cs:109:14:109:14 | p |
| Assignables.cs:113:25:113:25 | i |
Expand All @@ -69,8 +63,6 @@
| Assignables.cs:132:13:132:13 | x |
| Assignables.cs:133:29:133:29 | s |
| Assignables.cs:138:19:138:19 | x |
| Discards.cs:5:6:5:8 | Item1 |
| Discards.cs:5:11:5:16 | Item2 |
| Discards.cs:5:30:5:30 | x |
| Discards.cs:19:14:19:14 | x |
| Discards.cs:20:17:20:17 | y |
Expand Down
20 changes: 8 additions & 12 deletions csharp/ql/test/library-tests/csharp7/TupleTypes.expected
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple<int, (string, int)> | 2 | 0 | CSharp7.cs:96:19:96:19 | Item1 |
| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple<int, (string, int)> | 2 | 1 | CSharp7.cs:102:22:102:46 | Item2 |
| (Int32,Double) | (int, double) | ValueTuple<int, double> | 2 | 0 | CSharp7.cs:213:6:213:8 | Item1 |
| (Int32,Double) | (int, double) | ValueTuple<int, double> | 2 | 1 | CSharp7.cs:213:11:213:16 | Item2 |
| (Int32,Int32) | (int, int) | ValueTuple<int, int> | 2 | 0 | CSharp7.cs:62:10:62:10 | Item1 |
| (Int32,Int32) | (int, int) | ValueTuple<int, int> | 2 | 1 | CSharp7.cs:62:17:62:17 | Item2 |
| (Int32,String) | (int, string) | ValueTuple<int, string> | 2 | 0 | CSharp7.cs:95:19:95:19 | Item1 |
| (Int32,String) | (int, string) | ValueTuple<int, string> | 2 | 1 | CSharp7.cs:95:22:95:37 | Item2 |
| (String,Int32) | (string, int) | ValueTuple<string, int> | 2 | 0 | CSharp7.cs:82:17:82:17 | Item1 |
| (String,Int32) | (string, int) | ValueTuple<string, int> | 2 | 1 | CSharp7.cs:82:23:82:23 | Item2 |
| (String,String) | (string, string) | ValueTuple<string, string> | 2 | 0 | CSharp7.cs:87:19:87:27 | Item1 |
| (String,String) | (string, string) | ValueTuple<string, string> | 2 | 1 | CSharp7.cs:87:30:87:33 | Item2 |
| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple<int, (string, int)> | 2 | 0 | Item1 |
| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple<int, (string, int)> | 2 | 1 | Item2 |
| (Int32,Double) | (int, double) | ValueTuple<int, double> | 2 | 0 | Item1 |
| (Int32,Double) | (int, double) | ValueTuple<int, double> | 2 | 1 | Item2 |
| (Int32,String) | (int, string) | ValueTuple<int, string> | 2 | 0 | Item1 |
| (Int32,String) | (int, string) | ValueTuple<int, string> | 2 | 1 | Item2 |
| (String,String) | (string, string) | ValueTuple<string, string> | 2 | 0 | Item1 |
| (String,String) | (string, string) | ValueTuple<string, string> | 2 | 1 | Item2 |
4 changes: 2 additions & 2 deletions csharp/ql/test/library-tests/csharp7/TupleTypes.ql
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import csharp

from TupleType tt, int i
where tt.getAnElement().fromSource()
where tt.fromSource()
select tt.getName(), tt.toStringWithTypes(), tt.getUnderlyingType().toStringWithTypes(),
tt.getArity(), i, tt.getElement(i)
tt.getArity(), i, tt.getElement(i).getName()
9 changes: 7 additions & 2 deletions csharp/ql/test/library-tests/locations/A.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ public abstract class A<T>
public abstract T Prop { get; }
public abstract T this[int index] { get; set; }
public abstract event EventHandler Event;
public void Apply(T t) { }
public abstract object ToObject(T t);
public void Apply(T t1) { }
public abstract object ToObject(T t2);
public object Field;
public A() { }
public A(T t) { }
~A() { }
public static A<T> operator +(A<T> a1, A<T> a2) { return a1; }
}

public class A2 : A<string>
Expand Down
Loading
Loading