|
| 1 | +using System.IO; |
| 2 | +using System.Linq; |
| 3 | +using Microsoft.CodeAnalysis; |
| 4 | +using Microsoft.CodeAnalysis.CSharp.Syntax; |
| 5 | + |
| 6 | +namespace Semmle.Extraction.CSharp.Entities |
| 7 | +{ |
| 8 | + /// <summary> |
| 9 | + /// Synthetic parameter for extension methods declared using the extension syntax. |
| 10 | + /// That is, we add a synthetic parameter s to IsValid in the following example: |
| 11 | + /// extension(string s) { |
| 12 | + /// public bool IsValid() { ... } |
| 13 | + /// } |
| 14 | + /// |
| 15 | + /// Note, that we use the characteristics of the parameter of the extension type |
| 16 | + /// to populate the database. |
| 17 | + /// </summary> |
| 18 | + internal class SyntheticExtensionParameter : FreshEntity, IParameter |
| 19 | + { |
| 20 | + private Method ExtensionMethod { get; } |
| 21 | + private IParameterSymbol ExtensionParameter { get; } |
| 22 | + private SyntheticExtensionParameter Original { get; } |
| 23 | + |
| 24 | + private SyntheticExtensionParameter(Context cx, Method method, IParameterSymbol parameter, SyntheticExtensionParameter? original) : base(cx) |
| 25 | + { |
| 26 | + ExtensionMethod = method; |
| 27 | + ExtensionParameter = parameter; |
| 28 | + Original = original ?? this; |
| 29 | + } |
| 30 | + |
| 31 | + private static int Ordinal => 0; |
| 32 | + |
| 33 | + private Parameter.Kind ParamKind |
| 34 | + { |
| 35 | + get |
| 36 | + { |
| 37 | + switch (ExtensionParameter.RefKind) |
| 38 | + { |
| 39 | + case RefKind.Ref: |
| 40 | + return Parameter.Kind.Ref; |
| 41 | + case RefKind.In: |
| 42 | + return Parameter.Kind.In; |
| 43 | + case RefKind.RefReadOnlyParameter: |
| 44 | + return Parameter.Kind.RefReadOnly; |
| 45 | + default: |
| 46 | + return Parameter.Kind.None; |
| 47 | + } |
| 48 | + } |
| 49 | + } |
| 50 | + |
| 51 | + private string Name => ExtensionParameter.Name; |
| 52 | + |
| 53 | + private bool IsSourceDeclaration => ExtensionMethod.Symbol.IsSourceDeclaration(); |
| 54 | + |
| 55 | + private void PopulateAttributes() |
| 56 | + { |
| 57 | + // Only extract attributes for source declarations |
| 58 | + if (ReferenceEquals(ExtensionParameter, ExtensionParameter.OriginalDefinition)) |
| 59 | + Attribute.ExtractAttributes(Context, ExtensionParameter, this); |
| 60 | + } |
| 61 | + |
| 62 | + /// <summary> |
| 63 | + /// Bind comments to this symbol. |
| 64 | + /// Comments are only bound to source declarations. |
| 65 | + /// </summary> |
| 66 | + private void BindComments() |
| 67 | + { |
| 68 | + if (IsSourceDeclaration && ExtensionParameter.FromSource()) |
| 69 | + Context.BindComments(this, ExtensionParameter.Locations.BestOrDefault()); |
| 70 | + } |
| 71 | + |
| 72 | + protected override void Populate(TextWriter trapFile) |
| 73 | + { |
| 74 | + PopulateAttributes(); |
| 75 | + PopulateNullability(trapFile, ExtensionParameter.GetAnnotatedType()); |
| 76 | + PopulateRefKind(trapFile, ExtensionParameter.RefKind); |
| 77 | + |
| 78 | + var type = Type.Create(Context, ExtensionParameter.Type); |
| 79 | + trapFile.@params(this, Name, type.TypeRef, Ordinal, ParamKind, ExtensionMethod, Original); |
| 80 | + |
| 81 | + if (Context.OnlyScaffold) |
| 82 | + { |
| 83 | + return; |
| 84 | + } |
| 85 | + |
| 86 | + if (Context.ExtractLocation(ExtensionParameter)) |
| 87 | + { |
| 88 | + var locations = Context.GetLocations(ExtensionParameter); |
| 89 | + WriteLocationsToTrap(trapFile.param_location, this, locations); |
| 90 | + } |
| 91 | + |
| 92 | + BindComments(); |
| 93 | + |
| 94 | + if (IsSourceDeclaration) |
| 95 | + { |
| 96 | + foreach (var syntax in ExtensionParameter.DeclaringSyntaxReferences |
| 97 | + .Select(d => d.GetSyntax()) |
| 98 | + .OfType<ParameterSyntax>() |
| 99 | + .Where(s => s.Type is not null)) |
| 100 | + { |
| 101 | + TypeMention.Create(Context, syntax.Type!, this, type); |
| 102 | + } |
| 103 | + } |
| 104 | + } |
| 105 | + |
| 106 | + public static SyntheticExtensionParameter Create(Context cx, Method method, IParameterSymbol parameter, SyntheticExtensionParameter? original) |
| 107 | + { |
| 108 | + var p = new SyntheticExtensionParameter(cx, method, parameter, original); |
| 109 | + p.TryPopulate(); |
| 110 | + return p; |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | +} |
0 commit comments