77
88namespace Semmle . Extraction . CSharp . Entities
99{
10- internal class Parameter : CachedSymbol < IParameterSymbol > , IExpressionParentEntity
10+ // Marker interface for parameter entities.
11+ public interface IParameterEntity : IEntity { }
12+ internal class Parameter : CachedSymbol < IParameterSymbol > , IExpressionParentEntity , IParameterEntity
1113 {
1214 protected IEntity ? Parent { get ; set ; }
1315 protected Parameter Original { get ; }
16+ private int PositionOffset { get ; set ; }
1417
15- protected Parameter ( Context cx , IParameterSymbol init , IEntity ? parent , Parameter ? original )
18+ private Parameter ( Context cx , IParameterSymbol init , IEntity ? parent , Parameter ? original , int positionOffset )
1619 : base ( cx , init )
1720 {
1821 Parent = parent ;
1922 Original = original ?? this ;
23+ PositionOffset = positionOffset ;
24+ }
25+
26+ protected Parameter ( Context cx , IParameterSymbol init , IEntity ? parent , Parameter ? original )
27+ : this ( cx , init , parent , original , 0 )
28+ {
2029 }
2130
2231 public override Microsoft . CodeAnalysis . Location ReportingLocation => Symbol . GetSymbolLocation ( ) ;
@@ -32,7 +41,7 @@ public enum Kind
3241 RefReadOnly = 6
3342 }
3443
35- protected virtual int Ordinal => Symbol . Ordinal ;
44+ protected virtual int Ordinal => Symbol . Ordinal + PositionOffset ;
3645
3746 private Kind ParamKind
3847 {
@@ -55,30 +64,35 @@ private Kind ParamKind
5564 if ( Ordinal == 0 )
5665 {
5766 if ( Symbol . ContainingSymbol is IMethodSymbol method && method . IsExtensionMethod )
67+ {
5868 return Kind . This ;
69+ }
5970 }
6071 return Kind . None ;
6172 }
6273 }
6374 }
6475
65- public static Parameter Create ( Context cx , IParameterSymbol param , IEntity parent , Parameter ? original = null )
76+ public static Parameter Create ( Context cx , IParameterSymbol param , IEntity parent , Parameter ? original = null , int positionOffset = 0 )
6677 {
6778 var cachedSymbol = cx . GetPossiblyCachedParameterSymbol ( param ) ;
68- return ParameterFactory . Instance . CreateEntity ( cx , cachedSymbol , ( cachedSymbol , parent , original ) ) ;
79+ return ParameterFactory . Instance . CreateEntity ( cx , cachedSymbol , ( cachedSymbol , parent , original , positionOffset ) ) ;
6980 }
7081
7182 public static Parameter Create ( Context cx , IParameterSymbol param )
7283 {
7384 var cachedSymbol = cx . GetPossiblyCachedParameterSymbol ( param ) ;
74- return ParameterFactory . Instance . CreateEntity ( cx , cachedSymbol , ( cachedSymbol , null , null ) ) ;
85+ return ParameterFactory . Instance . CreateEntity ( cx , cachedSymbol , ( cachedSymbol , null , null , 0 ) ) ;
7586 }
7687
7788 public override void WriteId ( EscapingTextWriter trapFile )
7889 {
7990 if ( Parent is null )
8091 Parent = Method . Create ( Context , Symbol . ContainingSymbol as IMethodSymbol ) ;
8192
93+ if ( Parent is null && Symbol . ContainingSymbol is INamedTypeSymbol type && type . IsExtension )
94+ Parent = Type . Create ( Context , type ) ;
95+
8296 if ( Parent is null )
8397 throw new InternalError ( Symbol , "Couldn't get parent of symbol." ) ;
8498
@@ -194,11 +208,11 @@ Symbol.ContainingSymbol is IMethodSymbol ms &&
194208 return syntax ? . Default ;
195209 }
196210
197- private class ParameterFactory : CachedEntityFactory < ( IParameterSymbol , IEntity ? , Parameter ? ) , Parameter >
211+ private class ParameterFactory : CachedEntityFactory < ( IParameterSymbol , IEntity ? , Parameter ? , int ) , Parameter >
198212 {
199213 public static ParameterFactory Instance { get ; } = new ParameterFactory ( ) ;
200214
201- public override Parameter Create ( Context cx , ( IParameterSymbol , IEntity ? , Parameter ? ) init ) => new Parameter ( cx , init . Item1 , init . Item2 , init . Item3 ) ;
215+ public override Parameter Create ( Context cx , ( IParameterSymbol , IEntity ? , Parameter ? , int ) init ) => new Parameter ( cx , init . Item1 , init . Item2 , init . Item3 , init . Item4 ) ;
202216 }
203217
204218 public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour . OptionalLabel ;
@@ -243,6 +257,111 @@ private class VarargsTypeFactory : CachedEntityFactory<string?, VarargsType>
243257 }
244258 }
245259
260+ /// <summary>
261+ /// Synthetic parameter for extension methods declared using the extensions syntax.
262+ /// That is, we add a synthetic parameter s to IsValid in the following example:
263+ /// extension(string s) {
264+ /// public bool IsValid() { ... }
265+ /// }
266+ ///
267+ /// Note, that we use the characteristics of the parameter of the associated (compiler generated) extension method
268+ /// to populate the database.
269+ /// </summary>
270+ internal class ImplicitExtensionParameter : Parameter
271+ {
272+ private Method ExtensionMethod { get ; init ; }
273+
274+ private ImplicitExtensionParameter ( Context cx , Method method )
275+ #nullable disable warnings
276+ : base ( cx , method . Symbol . AssociatedExtensionImplementation . Parameters [ 0 ] , method , null )
277+ {
278+ ExtensionMethod = method ;
279+ }
280+ #nullable restore warnings
281+
282+ protected override int Ordinal => 0 ;
283+
284+ private Kind ParamKind
285+ {
286+ get
287+ {
288+ switch ( Symbol . RefKind )
289+ {
290+ case RefKind . Ref :
291+ return Kind . Ref ;
292+ case RefKind . In :
293+ return Kind . In ;
294+ case RefKind . RefReadOnlyParameter :
295+ return Kind . RefReadOnly ;
296+ default :
297+ return Kind . None ;
298+ }
299+ }
300+ }
301+
302+ private string Name => Symbol . Name ;
303+
304+ public override bool IsSourceDeclaration => ExtensionMethod . Symbol . IsSourceDeclaration ( ) ;
305+
306+ /// <summary>
307+ /// Bind comments to this symbol.
308+ /// Comments are only bound to source declarations.
309+ /// </summary>
310+ protected override void BindComments ( )
311+ {
312+ if ( IsSourceDeclaration && Symbol . FromSource ( ) )
313+ Context . BindComments ( this , FullLocation ) ;
314+ }
315+
316+ public override void Populate ( TextWriter trapFile )
317+ {
318+ PopulateAttributes ( ) ;
319+ PopulateNullability ( trapFile , Symbol . GetAnnotatedType ( ) ) ;
320+ PopulateRefKind ( trapFile , Symbol . RefKind ) ;
321+
322+ var type = Type . Create ( Context , Symbol . Type ) ;
323+ trapFile . @params ( this , Name , type . TypeRef , Ordinal , ParamKind , Parent ! , this ) ;
324+
325+ if ( Context . OnlyScaffold )
326+ {
327+ return ;
328+ }
329+
330+ if ( Context . ExtractLocation ( Symbol ) )
331+ {
332+ var locations = Context . GetLocations ( Symbol ) ;
333+ WriteLocationsToTrap ( trapFile . param_location , this , locations ) ;
334+ }
335+
336+ if ( ! IsSourceDeclaration || ! Symbol . FromSource ( ) )
337+ return ;
338+
339+ BindComments ( ) ;
340+
341+ if ( IsSourceDeclaration )
342+ {
343+ foreach ( var syntax in Symbol . DeclaringSyntaxReferences
344+ . Select ( d => d . GetSyntax ( ) )
345+ . OfType < ParameterSyntax > ( )
346+ . Where ( s => s . Type is not null ) )
347+ {
348+ TypeMention . Create ( Context , syntax . Type ! , this , type ) ;
349+ }
350+ }
351+ }
352+
353+ public static ImplicitExtensionParameter Create ( Context cx , Method method ) => ImplicitExtensionParameterFactory . Instance . CreateEntity ( cx , typeof ( ImplicitExtensionParameter ) , method ) ;
354+
355+ private class ImplicitExtensionParameterFactory : CachedEntityFactory < Method , ImplicitExtensionParameter >
356+ {
357+ public static ImplicitExtensionParameterFactory Instance { get ; } = new ImplicitExtensionParameterFactory ( ) ;
358+
359+ public override ImplicitExtensionParameter Create ( Context cx , Method init ) => new ImplicitExtensionParameter ( cx , init ) ;
360+ }
361+
362+
363+ }
364+
246365 internal class VarargsParam : Parameter
247366 {
248367#nullable disable warnings
0 commit comments