Skip to content

Commit 3e2f6e5

Browse files
authored
Merge pull request #21351 from michaelnebel/csharp/fixpartialmethod
C#: Fix issue with partial method extraction.
2 parents 0947323 + 7de476a commit 3e2f6e5

26 files changed

+283
-185
lines changed

csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,15 @@ public static bool IsUnboundGenericType(this INamedTypeSymbol type) =>
728728
public static INamedTypeSymbol? GetNonObjectBaseType(this ITypeSymbol symbol, Context cx) =>
729729
symbol is ITypeParameterSymbol || SymbolEqualityComparer.Default.Equals(symbol.BaseType, cx.Compilation.ObjectType) ? null : symbol.BaseType;
730730

731+
public static IMethodSymbol GetBodyDeclaringSymbol(this IMethodSymbol method) =>
732+
method.PartialImplementationPart ?? method;
733+
734+
public static IPropertySymbol GetBodyDeclaringSymbol(this IPropertySymbol property) =>
735+
property.PartialImplementationPart ?? property;
736+
737+
public static IEventSymbol GetBodyDeclaringSymbol(this IEventSymbol symbol) =>
738+
symbol.PartialImplementationPart ?? symbol;
739+
731740
[return: NotNullIfNotNull(nameof(symbol))]
732741
public static IEntity? CreateEntity(this Context cx, ISymbol symbol)
733742
{

csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public override void Populate(TextWriter trapFile)
7070

7171
Overrides(trapFile);
7272

73-
if (Symbol.FromSource() && Block is null)
73+
if (Symbol.FromSource() && !HasBody)
7474
{
7575
trapFile.compiler_generated(this);
7676
}

csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedSymbol.cs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@ namespace Semmle.Extraction.CSharp.Entities
99
{
1010
internal abstract class CachedSymbol<T> : CachedEntity<T> where T : class, ISymbol
1111
{
12+
private readonly Lazy<BlockSyntax?> blockLazy;
13+
private readonly Lazy<ExpressionSyntax?> expressionBodyLazy;
14+
1215
protected CachedSymbol(Context cx, T init)
1316
: base(cx, init)
1417
{
18+
blockLazy = new Lazy<BlockSyntax?>(() => GetBlock(Symbol));
19+
expressionBodyLazy = new Lazy<ExpressionSyntax?>(() => GetExpressionBody(Symbol));
1520
}
1621

1722
public virtual Type? ContainingType => Symbol.ContainingType is not null
@@ -87,31 +92,29 @@ protected void BindComments()
8792
Context.BindComments(this, FullLocation);
8893
}
8994

90-
protected virtual T BodyDeclaringSymbol => Symbol;
91-
92-
public BlockSyntax? Block
95+
private static BlockSyntax? GetBlock(T symbol)
9396
{
94-
get
95-
{
96-
return BodyDeclaringSymbol.DeclaringSyntaxReferences
97+
return symbol.DeclaringSyntaxReferences
9798
.SelectMany(r => r.GetSyntax().ChildNodes())
9899
.OfType<BlockSyntax>()
99100
.FirstOrDefault();
100-
}
101101
}
102102

103-
public ExpressionSyntax? ExpressionBody
103+
private static ExpressionSyntax? GetExpressionBody(T symbol)
104104
{
105-
get
106-
{
107-
return BodyDeclaringSymbol.DeclaringSyntaxReferences
105+
return symbol.DeclaringSyntaxReferences
108106
.SelectMany(r => r.GetSyntax().ChildNodes())
109107
.OfType<ArrowExpressionClauseSyntax>()
110108
.Select(arrow => arrow.Expression)
111109
.FirstOrDefault();
112-
}
113110
}
114111

112+
public BlockSyntax? Block => blockLazy.Value;
113+
114+
public ExpressionSyntax? ExpressionBody => expressionBodyLazy.Value;
115+
116+
public bool HasBody => Block is not null || ExpressionBody is not null;
117+
115118
public virtual bool IsSourceDeclaration => Symbol.IsSourceDeclaration();
116119

117120
public override bool NeedsPopulation => Context.Defines(Symbol);

csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public override void Populate(TextWriter trapFile)
4242
return;
4343
}
4444

45-
if (MakeSynthetic)
45+
if (MakeSyntheticBody)
4646
{
4747
// Create a synthetic empty body for primary and default constructors.
4848
Statements.SyntheticEmptyBlock.Create(Context, this, 0, Location);
@@ -60,7 +60,7 @@ protected override void ExtractInitializers(TextWriter trapFile)
6060
// Do not extract initializers for constructed types.
6161
// Extract initializers for constructors with a body, primary constructors
6262
// and default constructors for classes and structs declared in source code.
63-
if (Block is null && ExpressionBody is null && !MakeSynthetic || Context.OnlyScaffold)
63+
if (!HasBody && !MakeSyntheticBody || Context.OnlyScaffold)
6464
{
6565
return;
6666
}
@@ -211,7 +211,7 @@ Symbol.ContainingType.TypeKind is TypeKind.Class or TypeKind.Struct &&
211211
/// </summary>
212212
private bool IsBestSourceLocation => ReportingLocation is not null && Context.IsLocationInContext(ReportingLocation);
213213

214-
private bool MakeSynthetic => (IsPrimary || (IsDefault && IsBestSourceLocation)) && !Context.OnlyScaffold;
214+
private bool MakeSyntheticBody => (IsPrimary || (IsDefault && IsBestSourceLocation)) && !Context.OnlyScaffold;
215215

216216
[return: NotNullIfNotNull(nameof(constructor))]
217217
public static new Constructor? Create(Context cx, IMethodSymbol? constructor)

csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ internal class Event : CachedSymbol<IEventSymbol>
1111
private Event(Context cx, IEventSymbol init)
1212
: base(cx, init) { }
1313

14-
protected override IEventSymbol BodyDeclaringSymbol => Symbol.PartialImplementationPart ?? Symbol;
15-
16-
public override Microsoft.CodeAnalysis.Location? ReportingLocation => BodyDeclaringSymbol.Locations.BestOrDefault();
17-
1814
public override void WriteId(EscapingTextWriter trapFile)
1915
{
2016
trapFile.WriteSubId(ContainingType!);
@@ -31,8 +27,8 @@ public override void Populate(TextWriter trapFile)
3127
var type = Type.Create(Context, Symbol.Type);
3228
trapFile.events(this, Symbol.GetName(), ContainingType!, type.TypeRef, Create(Context, Symbol.OriginalDefinition));
3329

34-
var adder = BodyDeclaringSymbol.AddMethod;
35-
var remover = BodyDeclaringSymbol.RemoveMethod;
30+
var adder = Symbol.AddMethod;
31+
var remover = Symbol.RemoveMethod;
3632

3733
if (adder is not null)
3834
Method.Create(Context, adder);
@@ -76,7 +72,7 @@ public override void Populate(TextWriter trapFile)
7672
}
7773
}
7874

79-
public static Event Create(Context cx, IEventSymbol symbol) => EventFactory.Instance.CreateEntityFromSymbol(cx, symbol);
75+
public static Event Create(Context cx, IEventSymbol symbol) => EventFactory.Instance.CreateEntityFromSymbol(cx, symbol.GetBodyDeclaringSymbol());
8076

8177
private class EventFactory : CachedEntityFactory<IEventSymbol, Event>
8278
{

csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public override void Populate(TextWriter trapFile)
5959

6060
Overrides(trapFile);
6161

62-
if (Symbol.FromSource() && Block is null)
62+
if (Symbol.FromSource() && !HasBody)
6363
{
6464
trapFile.compiler_generated(this);
6565
}

csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ public override void Populate(TextWriter trapFile)
2020
var type = Type.Create(Context, Symbol.Type);
2121
trapFile.indexers(this, Symbol.GetName(useMetadataName: true), ContainingType!, type.TypeRef, OriginalDefinition);
2222

23-
var getter = BodyDeclaringSymbol.GetMethod;
24-
var setter = BodyDeclaringSymbol.SetMethod;
23+
var getter = Symbol.GetMethod;
24+
var setter = Symbol.SetMethod;
2525

2626
if (getter is null && setter is null)
2727
Context.ModelError(Symbol, "No indexer accessor defined");
@@ -81,7 +81,7 @@ public override void Populate(TextWriter trapFile)
8181
TypeMention.Create(Context, syntax.Type, this, type);
8282
}
8383

84-
public static new Indexer Create(Context cx, IPropertySymbol prop) => IndexerFactory.Instance.CreateEntityFromSymbol(cx, prop);
84+
public static new Indexer Create(Context cx, IPropertySymbol prop) => IndexerFactory.Instance.CreateEntityFromSymbol(cx, prop.GetBodyDeclaringSymbol());
8585

8686
public override void WriteId(EscapingTextWriter trapFile)
8787
{

csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ protected virtual void PopulateMethodBody(TextWriter trapFile)
8585
else
8686
Expression.Create(Context, expr!, this, 0);
8787

88-
NumberOfLines(trapFile, BodyDeclaringSymbol, this);
88+
NumberOfLines(trapFile, Symbol, this);
8989
});
9090
}
9191
}

csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,12 @@ protected OrdinaryMethod(Context cx, IMethodSymbol init)
1414

1515
public override string Name => Symbol.GetName();
1616

17-
protected override IMethodSymbol BodyDeclaringSymbol => Symbol.PartialImplementationPart ?? Symbol;
18-
1917
public IMethodSymbol SourceDeclaration => Symbol.OriginalDefinition;
2018

2119
public override Microsoft.CodeAnalysis.Location ReportingLocation =>
2220
IsCompilerGeneratedDelegate()
2321
? Symbol.ContainingType.GetSymbolLocation()
24-
: BodyDeclaringSymbol.GetSymbolLocation();
22+
: Symbol.GetSymbolLocation();
2523

2624
public override bool NeedsPopulation =>
2725
(base.NeedsPopulation || IsCompilerGeneratedDelegate()) &&
@@ -77,7 +75,7 @@ Symbol.ContainingType is INamedTypeSymbol nt &&
7775
cx.ExtractionContext.Logger.LogWarning("Reduced extension method symbols should not be directly extracted.");
7876
}
7977

80-
return OrdinaryMethodFactory.Instance.CreateEntityFromSymbol(cx, method);
78+
return OrdinaryMethodFactory.Instance.CreateEntityFromSymbol(cx, method.GetBodyDeclaringSymbol());
8179
}
8280

8381
private class OrdinaryMethodFactory : CachedEntityFactory<IMethodSymbol, OrdinaryMethod>

csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ protected Property(Context cx, IPropertySymbol init)
2121

2222
private Type Type => type.Value;
2323

24-
protected override IPropertySymbol BodyDeclaringSymbol => Symbol.PartialImplementationPart ?? Symbol;
25-
26-
public override Microsoft.CodeAnalysis.Location? ReportingLocation => BodyDeclaringSymbol.Locations.BestOrDefault();
27-
2824
public override void WriteId(EscapingTextWriter trapFile)
2925
{
3026
trapFile.WriteSubId(Type);
@@ -46,8 +42,8 @@ public override void Populate(TextWriter trapFile)
4642
var type = Type;
4743
trapFile.properties(this, Symbol.GetName(), ContainingType!, type.TypeRef, Create(Context, Symbol.OriginalDefinition));
4844

49-
var getter = BodyDeclaringSymbol.GetMethod;
50-
var setter = BodyDeclaringSymbol.SetMethod;
45+
var getter = Symbol.GetMethod;
46+
var setter = Symbol.SetMethod;
5147

5248
if (getter is not null)
5349
Method.Create(Context, getter);
@@ -132,7 +128,7 @@ public static Property Create(Context cx, IPropertySymbol prop)
132128
{
133129
var isIndexer = prop.IsIndexer || prop.Parameters.Any();
134130

135-
return isIndexer ? Indexer.Create(cx, prop) : PropertyFactory.Instance.CreateEntityFromSymbol(cx, prop);
131+
return isIndexer ? Indexer.Create(cx, prop) : PropertyFactory.Instance.CreateEntityFromSymbol(cx, prop.GetBodyDeclaringSymbol());
136132
}
137133

138134
private class PropertyFactory : CachedEntityFactory<IPropertySymbol, Property>

0 commit comments

Comments
 (0)