diff --git a/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs index 72f78f160598..c69ca53452cb 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using Microsoft.CodeAnalysis; +using Semmle.Util; using Semmle.Extraction.CSharp.Entities; namespace Semmle.Extraction.CSharp @@ -164,6 +165,7 @@ public static void BuildTypeId(this ITypeSymbol type, Context cx, EscapingTextWr case TypeKind.Enum: case TypeKind.Delegate: case TypeKind.Error: + case TypeKind.Extension: var named = (INamedTypeSymbol)type; named.BuildNamedTypeId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType); return; @@ -275,6 +277,16 @@ private static void BuildFunctionPointerTypeId(this IFunctionPointerTypeSymbol f public static IEnumerable GetTupleElementsMaybeNull(this INamedTypeSymbol type) => type.TupleElements; + private static string GetExtensionTypeName(this INamedTypeSymbol named, Context cx) + { + var type = named.ExtensionParameter?.Type.Name; + if (type is null) + { + cx.ModelError(named, "Failed to get extension method type."); + } + return $"extension({type ?? "unknown"})"; + } + private static void BuildQualifierAndName(INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined) { if (named.ContainingType is not null) @@ -289,8 +301,19 @@ private static void BuildQualifierAndName(INamedTypeSymbol named, Context cx, Es named.ContainingNamespace.BuildNamespace(cx, trapFile); } - var name = named.IsFileLocal ? named.MetadataName : named.Name; - trapFile.Write(name); + if (named.IsFileLocal) + { + trapFile.Write(named.MetadataName); + } + else if (named.IsExtension) + { + var name = GetExtensionTypeName(named, cx); + trapFile.Write(name); + } + else + { + trapFile.Write(named.Name); + } } private static void BuildTupleId(INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined) @@ -391,6 +414,7 @@ public static void BuildDisplayName(this ITypeSymbol type, Context cx, TextWrite case TypeKind.Enum: case TypeKind.Delegate: case TypeKind.Error: + case TypeKind.Extension: var named = (INamedTypeSymbol)type; named.BuildNamedTypeDisplayName(cx, trapFile, constructUnderlyingTupleType); return; @@ -484,6 +508,13 @@ private static void BuildNamedTypeDisplayName(this INamedTypeSymbol namedType, C return; } + if (namedType.IsExtension) + { + var name = GetExtensionTypeName(namedType, cx); + trapFile.Write(name); + return; + } + if (namedType.IsAnonymousType) { namedType.BuildAnonymousName(cx, trapFile); @@ -596,6 +627,87 @@ public static bool IsSourceDeclaration(this IParameterSymbol parameter) return true; } + /// + /// Return true if this method is a compiler-generated extension method. + /// + public static bool IsCompilerGeneratedExtensionMethod(this IMethodSymbol method) => + method.TryGetExtensionMethod(out _); + + /// + /// Returns true if this method is a compiler-generated extension method, + /// and outputs the original extension method declaration. + /// + public static bool TryGetExtensionMethod(this IMethodSymbol method, out IMethodSymbol? declaration) + { + declaration = null; + if (method.IsImplicitlyDeclared && method.ContainingSymbol is INamedTypeSymbol containingType) + { + // Extension types are declared within the same type as the generated + // extension method implementation. + var extensions = containingType.GetMembers() + .OfType() + .Where(t => t.IsExtension); + // Find the (possibly unbound) original extension method that maps to this implementation (if any). + var unboundDeclaration = extensions.SelectMany(e => e.GetMembers()) + .OfType() + .FirstOrDefault(m => SymbolEqualityComparer.Default.Equals(m.AssociatedExtensionImplementation, method.ConstructedFrom)); + + var isFullyConstructed = method.IsBoundGenericMethod(); + if (isFullyConstructed && unboundDeclaration?.ContainingType is INamedTypeSymbol extensionType) + { + try + { + // Use the type arguments from the constructed extension method to construct the extension type. + var arguments = method.TypeArguments.ToArray(); + var (extensionTypeArguments, extensionMethodArguments) = arguments.SplitAt(extensionType.TypeParameters.Length); + + // Construct the extension type. + var boundExtensionType = extensionType.IsUnboundGenericType() + ? extensionType.Construct(extensionTypeArguments.ToArray()) + : extensionType; + + // Find the extension method declaration within the constructed extension type. + var extensionDeclaration = boundExtensionType.GetMembers() + .OfType() + .First(c => SymbolEqualityComparer.Default.Equals(c.OriginalDefinition, unboundDeclaration)); + + // If the extension declaration is unbound apply the remaning type arguments and construct it. + declaration = extensionDeclaration.IsUnboundGenericMethod() + ? extensionDeclaration.Construct(extensionMethodArguments.ToArray()) + : extensionDeclaration; + } + catch (Exception) + { + // If anything goes wrong, fall back to the unbound declaration. + declaration = unboundDeclaration; + } + } + else + { + declaration = unboundDeclaration; + } + + } + return declaration is not null; + } + + /// + /// Returns true if this method is an unbound generic method. + /// + public static bool IsUnboundGenericMethod(this IMethodSymbol method) => + method.IsGenericMethod && SymbolEqualityComparer.Default.Equals(method.ConstructedFrom, method); + + /// + /// Returns true if this method is a bound generic method. + /// + public static bool IsBoundGenericMethod(this IMethodSymbol method) => method.IsGenericMethod && !method.IsUnboundGenericMethod(); + + /// + /// Returns true if this type is an unbound generic type. + /// + public static bool IsUnboundGenericType(this INamedTypeSymbol type) => + type.IsGenericType && SymbolEqualityComparer.Default.Equals(type.ConstructedFrom, type); + /// /// Gets the base type of `symbol`. Unlike `symbol.BaseType`, this excludes effective base /// types of type parameters as well as `object` base types. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntity.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntity.cs index 2002fe0f1d7a..39d0f886b813 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntity.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntity.cs @@ -54,22 +54,6 @@ public string DebugContents } } - protected static void WriteLocationToTrap(Action writeAction, T1 entity, Location l) - { - if (l is not EmptyLocation) - { - writeAction(entity, l); - } - } - - protected static void WriteLocationsToTrap(Action writeAction, T1 entity, IEnumerable locations) - { - foreach (var loc in locations) - { - WriteLocationToTrap(writeAction, entity, loc); - } - } - public override bool NeedsPopulation { get; } public override int GetHashCode() => Symbol is null ? 0 : Symbol.GetHashCode(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedSymbol.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedSymbol.cs index 92861e97fdd8..1a69b0e08b2b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedSymbol.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedSymbol.cs @@ -32,32 +32,6 @@ protected void PopulateAttributes() Attribute.ExtractAttributes(Context, Symbol, this); } - protected void PopulateNullability(TextWriter trapFile, AnnotatedTypeSymbol type) - { - var n = NullabilityEntity.Create(Context, Nullability.Create(type)); - if (!type.HasObliviousNullability()) - { - trapFile.type_nullability(this, n); - } - } - - protected void PopulateRefKind(TextWriter trapFile, RefKind kind) - { - switch (kind) - { - case RefKind.Out: - trapFile.type_annotation(this, Kinds.TypeAnnotation.Out); - break; - case RefKind.Ref: - trapFile.type_annotation(this, Kinds.TypeAnnotation.Ref); - break; - case RefKind.RefReadOnly: - case RefKind.RefReadOnlyParameter: - trapFile.type_annotation(this, Kinds.TypeAnnotation.ReadonlyRef); - break; - } - } - protected void PopulateScopedKind(TextWriter trapFile, ScopedKind kind) { switch (kind) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/Entity.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/Entity.cs index ca1887b3be9c..94b2e16e9e6b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/Entity.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/Entity.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.IO; using Microsoft.CodeAnalysis; +using Semmle.Extraction.CSharp.Entities; namespace Semmle.Extraction.CSharp { @@ -24,7 +26,7 @@ public virtual void WriteQuotedId(EscapingTextWriter trapFile) trapFile.WriteUnescaped('\"'); } - public abstract Location? ReportingLocation { get; } + public abstract Microsoft.CodeAnalysis.Location? ReportingLocation { get; } public abstract TrapStackBehaviour TrapStackBehaviour { get; } @@ -65,6 +67,48 @@ public string GetDebugLabel() } #endif + protected void PopulateRefKind(TextWriter trapFile, RefKind kind) + { + switch (kind) + { + case RefKind.Out: + trapFile.type_annotation(this, Kinds.TypeAnnotation.Out); + break; + case RefKind.Ref: + trapFile.type_annotation(this, Kinds.TypeAnnotation.Ref); + break; + case RefKind.RefReadOnly: + case RefKind.RefReadOnlyParameter: + trapFile.type_annotation(this, Kinds.TypeAnnotation.ReadonlyRef); + break; + } + } + + protected void PopulateNullability(TextWriter trapFile, AnnotatedTypeSymbol type) + { + var n = NullabilityEntity.Create(Context, Nullability.Create(type)); + if (!type.HasObliviousNullability()) + { + trapFile.type_nullability(this, n); + } + } + + protected static void WriteLocationToTrap(Action writeAction, T1 entity, Entities.Location l) + { + if (l is not EmptyLocation) + { + writeAction(entity, l); + } + } + + protected static void WriteLocationsToTrap(Action writeAction, T1 entity, IEnumerable locations) + { + foreach (var loc in locations) + { + WriteLocationToTrap(writeAction, entity, loc); + } + } + public override string ToString() => Label.ToString(); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs index a6272974c22b..26d64339ef06 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs @@ -24,6 +24,16 @@ private Invocation(ExpressionNodeInfo info) private bool IsExplicitDelegateInvokeCall() => Kind == ExprKind.DELEGATE_INVOCATION && Context.GetModel(Syntax.Expression).GetSymbolInfo(Syntax.Expression).Symbol is IMethodSymbol m && m.MethodKind == MethodKind.DelegateInvoke; + private bool IsOperatorCall() => Kind == ExprKind.OPERATOR_INVOCATION; + + private bool IsValidMemberAccessKind() + { + return Kind == ExprKind.METHOD_INVOCATION || + IsEventDelegateCall() || + IsExplicitDelegateInvokeCall() || + IsOperatorCall(); + } + protected override void PopulateExpression(TextWriter trapFile) { if (IsNameof(Syntax)) @@ -37,7 +47,7 @@ protected override void PopulateExpression(TextWriter trapFile) var target = TargetSymbol; switch (Syntax.Expression) { - case MemberAccessExpressionSyntax memberAccess when Kind == ExprKind.METHOD_INVOCATION || IsEventDelegateCall() || IsExplicitDelegateInvokeCall(): + case MemberAccessExpressionSyntax memberAccess when IsValidMemberAccessKind(): memberName = memberAccess.Name.Identifier.Text; if (Syntax.Expression.Kind() == SyntaxKind.SimpleMemberAccessExpression) // Qualified method call; `x.M()` @@ -113,14 +123,31 @@ private static bool IsDynamicCall(ExpressionNodeInfo info) public SymbolInfo SymbolInfo => info.SymbolInfo; + private static bool IsOperatorLikeCall(ExpressionNodeInfo info) + { + return info.SymbolInfo.Symbol is IMethodSymbol method && + method.TryGetExtensionMethod(out var original) && + original!.MethodKind == MethodKind.UserDefinedOperator; + } + public IMethodSymbol? TargetSymbol { get { var si = SymbolInfo; - if (si.Symbol is not null) - return si.Symbol as IMethodSymbol; + if (si.Symbol is ISymbol symbol) + { + var method = symbol as IMethodSymbol; + // Case for compiler-generated extension methods. + if (method is not null && + method.TryGetExtensionMethod(out var original)) + { + return original; + } + + return method; + } if (si.CandidateReason == CandidateReason.OverloadResolutionFailure) { @@ -196,15 +223,25 @@ private static bool IsLocalFunctionInvocation(ExpressionNodeInfo info) private static ExprKind GetKind(ExpressionNodeInfo info) { - return IsNameof((InvocationExpressionSyntax)info.Node) - ? ExprKind.NAMEOF - : IsDelegateLikeCall(info) - ? IsDelegateInvokeCall(info) - ? ExprKind.DELEGATE_INVOCATION - : ExprKind.FUNCTION_POINTER_INVOCATION - : IsLocalFunctionInvocation(info) - ? ExprKind.LOCAL_FUNCTION_INVOCATION - : ExprKind.METHOD_INVOCATION; + if (IsNameof((InvocationExpressionSyntax)info.Node)) + { + return ExprKind.NAMEOF; + } + if (IsDelegateLikeCall(info)) + { + return IsDelegateInvokeCall(info) + ? ExprKind.DELEGATE_INVOCATION + : ExprKind.FUNCTION_POINTER_INVOCATION; + } + if (IsLocalFunctionInvocation(info)) + { + return ExprKind.LOCAL_FUNCTION_INVOCATION; + } + if (IsOperatorLikeCall(info)) + { + return ExprKind.OPERATOR_INVOCATION; + } + return ExprKind.METHOD_INVOCATION; } private static bool IsNameof(InvocationExpressionSyntax syntax) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index c92c561f31b6..ecf1e1f0ee93 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -14,9 +14,28 @@ internal abstract class Method : CachedSymbol, IExpressionParentE protected Method(Context cx, IMethodSymbol init) : base(cx, init) { } + private IParameter? SyntheticParameter { get; set; } + + private int SynthesizeExtensionParameter() + { + // Synthesize implicit parameter for extension methods declared using extension(...) syntax. + if (Symbol.ContainingSymbol is INamedTypeSymbol type && + type.IsExtension && type.ExtensionParameter is IParameterSymbol parameter && + !string.IsNullOrEmpty(parameter.Name) && !Symbol.IsStatic) + { + var originalSyntheticParam = OriginalDefinition.SyntheticParameter; + SyntheticParameter = ImplicitExtensionParameter.Create(Context, this, parameter, originalSyntheticParam); + return 1; + } + + return 0; + } + protected void PopulateParameters() { var originalMethod = OriginalDefinition; + var positionOffset = SynthesizeExtensionParameter(); + IEnumerable parameters = Symbol.Parameters; IEnumerable originalParameters = originalMethod.Symbol.Parameters; @@ -24,8 +43,8 @@ protected void PopulateParameters() { var original = SymbolEqualityComparer.Default.Equals(p.paramSymbol, p.originalParam) ? null - : Parameter.Create(Context, p.originalParam, originalMethod); - Parameter.Create(Context, p.paramSymbol, this, original); + : Parameter.Create(Context, p.originalParam, originalMethod, null, positionOffset); + Parameter.Create(Context, p.paramSymbol, this, original, positionOffset); } if (Symbol.IsVararg) @@ -302,9 +321,9 @@ public static void AddExplicitInterfaceQualifierToId(Context cx, EscapingTextWri /// /// Whether this method has unbound type parameters. /// - public bool IsUnboundGeneric => IsGeneric && SymbolEqualityComparer.Default.Equals(Symbol.ConstructedFrom, Symbol); + public bool IsUnboundGeneric => Symbol.IsUnboundGenericMethod(); - public bool IsBoundGeneric => IsGeneric && !IsUnboundGeneric; + public bool IsBoundGeneric => Symbol.IsBoundGenericMethod(); protected IMethodSymbol ConstructedFromSymbol => Symbol.ConstructedFrom; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs index 22bcd1dce2c8..2fb148358e8c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs @@ -23,7 +23,11 @@ protected OrdinaryMethod(Context cx, IMethodSymbol init) ? Symbol.ContainingType.GetSymbolLocation() : BodyDeclaringSymbol.GetSymbolLocation(); - public override bool NeedsPopulation => base.NeedsPopulation || IsCompilerGeneratedDelegate(); + public override bool NeedsPopulation => + (base.NeedsPopulation || IsCompilerGeneratedDelegate()) && + // Exclude compiler-generated extension methods. A call to such a method + // is replaced by a call to the defining extension method. + !Symbol.IsCompilerGeneratedExtensionMethod(); public override void Populate(TextWriter trapFile) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs index 49ef9a4a6e9a..540de3ad61bd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs @@ -7,16 +7,25 @@ namespace Semmle.Extraction.CSharp.Entities { - internal class Parameter : CachedSymbol, IExpressionParentEntity + // Marker interface for parameter entities. + public interface IParameter : IEntity { } + internal class Parameter : CachedSymbol, IExpressionParentEntity, IParameter { protected IEntity? Parent { get; set; } protected Parameter Original { get; } + private int PositionOffset { get; set; } - protected Parameter(Context cx, IParameterSymbol init, IEntity? parent, Parameter? original) + private Parameter(Context cx, IParameterSymbol init, IEntity? parent, Parameter? original, int positionOffset) : base(cx, init) { Parent = parent; Original = original ?? this; + PositionOffset = positionOffset; + } + + protected Parameter(Context cx, IParameterSymbol init, IEntity? parent, Parameter? original) + : this(cx, init, parent, original, 0) + { } public override Microsoft.CodeAnalysis.Location ReportingLocation => Symbol.GetSymbolLocation(); @@ -32,7 +41,7 @@ public enum Kind RefReadOnly = 6 } - protected virtual int Ordinal => Symbol.Ordinal; + protected virtual int Ordinal => Symbol.Ordinal + PositionOffset; private Kind ParamKind { @@ -55,23 +64,25 @@ private Kind ParamKind if (Ordinal == 0) { if (Symbol.ContainingSymbol is IMethodSymbol method && method.IsExtensionMethod) + { return Kind.This; + } } return Kind.None; } } } - public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter? original = null) + public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter? original = null, int positionOffset = 0) { var cachedSymbol = cx.GetPossiblyCachedParameterSymbol(param); - return ParameterFactory.Instance.CreateEntity(cx, cachedSymbol, (cachedSymbol, parent, original)); + return ParameterFactory.Instance.CreateEntity(cx, cachedSymbol, (cachedSymbol, parent, original, positionOffset)); } public static Parameter Create(Context cx, IParameterSymbol param) { var cachedSymbol = cx.GetPossiblyCachedParameterSymbol(param); - return ParameterFactory.Instance.CreateEntity(cx, cachedSymbol, (cachedSymbol, null, null)); + return ParameterFactory.Instance.CreateEntity(cx, cachedSymbol, (cachedSymbol, null, null, 0)); } public override void WriteId(EscapingTextWriter trapFile) @@ -79,6 +90,9 @@ public override void WriteId(EscapingTextWriter trapFile) if (Parent is null) Parent = Method.Create(Context, Symbol.ContainingSymbol as IMethodSymbol); + if (Parent is null && Symbol.ContainingSymbol is INamedTypeSymbol type && type.IsExtension) + Parent = Type.Create(Context, type); + if (Parent is null) throw new InternalError(Symbol, "Couldn't get parent of symbol."); @@ -194,11 +208,11 @@ Symbol.ContainingSymbol is IMethodSymbol ms && return syntax?.Default; } - private class ParameterFactory : CachedEntityFactory<(IParameterSymbol, IEntity?, Parameter?), Parameter> + private class ParameterFactory : CachedEntityFactory<(IParameterSymbol, IEntity?, Parameter?, int), Parameter> { public static ParameterFactory Instance { get; } = new ParameterFactory(); - public override Parameter Create(Context cx, (IParameterSymbol, IEntity?, Parameter?) init) => new Parameter(cx, init.Item1, init.Item2, init.Item3); + public override Parameter Create(Context cx, (IParameterSymbol, IEntity?, Parameter?, int) init) => new Parameter(cx, init.Item1, init.Item2, init.Item3, init.Item4); } public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; @@ -243,6 +257,115 @@ private class VarargsTypeFactory : CachedEntityFactory } } + /// + /// Synthetic parameter for extension methods declared using the extensions syntax. + /// That is, we add a synthetic parameter s to IsValid in the following example: + /// extension(string s) { + /// public bool IsValid() { ... } + /// } + /// + /// Note, that we use the characteristics of the parameter of the associated (compiler generated) extension method + /// to populate the database. + /// + internal class ImplicitExtensionParameter : FreshEntity, IParameter + { + private Method ExtensionMethod { get; } + private IParameterSymbol ExtensionParameter { get; } + private IParameter Original { get; } + + private ImplicitExtensionParameter(Context cx, Method method, IParameterSymbol parameter, IParameter? original) : base(cx) + { + ExtensionMethod = method; + ExtensionParameter = parameter; + Original = original ?? this; + } + + private static int Ordinal => 0; + + private Parameter.Kind ParamKind + { + get + { + switch (ExtensionParameter.RefKind) + { + case RefKind.Ref: + return Parameter.Kind.Ref; + case RefKind.In: + return Parameter.Kind.In; + case RefKind.RefReadOnlyParameter: + return Parameter.Kind.RefReadOnly; + default: + return Parameter.Kind.None; + } + } + } + + private string Name => ExtensionParameter.Name; + + private bool IsSourceDeclaration => ExtensionMethod.Symbol.IsSourceDeclaration(); + + private void PopulateAttributes() + { + // Only extract attributes for source declarations + if (ReferenceEquals(ExtensionParameter, ExtensionParameter.OriginalDefinition)) + Attribute.ExtractAttributes(Context, ExtensionParameter, this); + } + + /// + /// Bind comments to this symbol. + /// Comments are only bound to source declarations. + /// + private void BindComments() + { + if (IsSourceDeclaration && ExtensionParameter.FromSource()) + Context.BindComments(this, ExtensionParameter.Locations.BestOrDefault()); + } + + protected override void Populate(TextWriter trapFile) + { + PopulateAttributes(); + PopulateNullability(trapFile, ExtensionParameter.GetAnnotatedType()); + PopulateRefKind(trapFile, ExtensionParameter.RefKind); + + var type = Type.Create(Context, ExtensionParameter.Type); + trapFile.@params(this, Name, type.TypeRef, Ordinal, ParamKind, ExtensionMethod, Original); + + if (Context.OnlyScaffold) + { + return; + } + + if (Context.ExtractLocation(ExtensionParameter)) + { + var locations = Context.GetLocations(ExtensionParameter); + WriteLocationsToTrap(trapFile.param_location, this, locations); + } + + if (!IsSourceDeclaration || !ExtensionParameter.FromSource()) + return; + + BindComments(); + + if (IsSourceDeclaration) + { + foreach (var syntax in ExtensionParameter.DeclaringSyntaxReferences + .Select(d => d.GetSyntax()) + .OfType() + .Where(s => s.Type is not null)) + { + TypeMention.Create(Context, syntax.Type!, this, type); + } + } + } + + public static ImplicitExtensionParameter Create(Context cx, Method method, IParameterSymbol parameter, IParameter? original) + { + var p = new ImplicitExtensionParameter(cx, method, parameter, original); + p.TryPopulate(); + return p; + } + } + internal class VarargsParam : Parameter { #nullable disable warnings diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs index d48d778cb75a..4010142655cd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs @@ -103,6 +103,7 @@ public override void Populate(TextWriter trapFile) trapFile.expr_access(access, this); if (!Symbol.IsStatic) { + // TODO: What about the containing type for extensions? This.CreateImplicit(Context, Symbol.ContainingType, Location, access, -1); } }); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index dcf2bffe095f..d89f3db11e64 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -20,6 +20,8 @@ private NamedType(Context cx, INamedTypeSymbol init, bool constructUnderlyingTup public static NamedType Create(Context cx, INamedTypeSymbol type) => NamedTypeFactory.Instance.CreateEntityFromSymbol(cx, type); + public NamedType OriginalDefinition => Create(Context, Symbol.OriginalDefinition); + /// /// Creates a named type entity from a tuple type. Unlike , this /// will create an entity for the underlying `System.ValueTuple` struct. @@ -90,6 +92,25 @@ public override void Populate(TextWriter trapFile) { trapFile.anonymous_types(this); } + + if (Symbol.IsExtension && Symbol.ExtensionParameter is IParameterSymbol parameter) + { + // For some reason an extension type has a receiver parameter with an empty name + // even when there is no parameter. + if (!string.IsNullOrEmpty(parameter.Name)) + { + var originalType = OriginalDefinition; + // In case the this is constructed generic, we also need to create the unbound parameter. + var originalParameter = SymbolEqualityComparer.Default.Equals(Symbol, originalType.Symbol.ExtensionParameter) || originalType.Symbol.ExtensionParameter is null + ? null + : Parameter.Create(Context, originalType.Symbol.ExtensionParameter, originalType); + Parameter.Create(Context, parameter, this, originalParameter); + } + + // Use the parameter type as the receiver type. + var receiverType = Type.Create(Context, parameter.Type).TypeRef; + trapFile.extension_receiver_type(this, receiverType); + } } private readonly Lazy typeArgumentsLazy; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs index 3e79a8f81018..0f28a1153e22 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs @@ -105,6 +105,7 @@ public Kinds.TypeKind GetTypeKind(Context cx, bool constructUnderlyingTupleType) case TypeKind.Pointer: return Kinds.TypeKind.POINTER; case TypeKind.FunctionPointer: return Kinds.TypeKind.FUNCTION_POINTER; case TypeKind.Error: return Kinds.TypeKind.UNKNOWN; + case TypeKind.Extension: return Kinds.TypeKind.EXTENSION; default: cx.ModelError(Symbol, $"Unhandled type kind '{Symbol.TypeKind}'"); return Kinds.TypeKind.UNKNOWN; @@ -366,7 +367,7 @@ private class DelegateTypeParameter : Parameter private DelegateTypeParameter(Context cx, IParameterSymbol init, IEntity parent, Parameter? original) : base(cx, init, parent, original) { } - public static new DelegateTypeParameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter? original = null) => + public static DelegateTypeParameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter? original = null) => // We need to use a different cache key than `param` to avoid mixing up // `DelegateTypeParameter`s and `Parameter`s DelegateTypeParameterFactory.Instance.CreateEntity(cx, (typeof(DelegateTypeParameter), new SymbolEqualityWrapper(param)), (param, parent, original)); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs index fc9358ffc2dc..b87bf9e10d08 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs @@ -68,6 +68,7 @@ public override Type ContainingType /// private bool IsImplicitOperator(out ITypeSymbol containingType) { + // TODO: Do we need to handle extension operators here? containingType = Symbol.ContainingType; if (containingType is not null) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/TypeKind.cs b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/TypeKind.cs index a35f25c7596c..9088a11da61f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/TypeKind.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/TypeKind.cs @@ -38,5 +38,6 @@ public enum TypeKind TUPLE = 32, FUNCTION_POINTER = 33, INLINE_ARRAY = 34, + EXTENSION = 35 } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Trap/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Trap/Tuples.cs index b789eaa2e9c7..1a25da058bd8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Trap/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Trap/Tuples.cs @@ -202,6 +202,9 @@ internal static void exprorstmt_name(this TextWriter trapFile, IEntity expr, str internal static void extend(this TextWriter trapFile, Type type, Type super) => trapFile.WriteTuple("extend", type, super); + internal static void extension_receiver_type(this TextWriter trapFile, Type @extension, Type receiverType) => + trapFile.WriteTuple("extension_receiver_type", extension, receiverType); + internal static void anonymous_types(this TextWriter trapFile, Type type) => trapFile.WriteTuple("anonymous_types", type); @@ -292,10 +295,10 @@ internal static void operators(this TextWriter trapFile, UserOperator method, st internal static void overrides(this TextWriter trapFile, Method overriding, Method overridden) => trapFile.WriteTuple("overrides", overriding, overridden); - internal static void param_location(this TextWriter trapFile, Parameter param, Location location) => + internal static void param_location(this TextWriter trapFile, IParameter param, Location location) => trapFile.WriteTuple("param_location", param, location); - internal static void @params(this TextWriter trapFile, Parameter param, string name, Type type, int child, Parameter.Kind mode, IEntity method, Parameter originalDefinition) => + internal static void @params(this TextWriter trapFile, IParameter param, string name, Type type, int child, Parameter.Kind mode, IEntity method, IParameter originalDefinition) => trapFile.WriteTuple("params", param, name, type, child, (int)mode, method, originalDefinition); internal static void parent_namespace(this TextWriter trapFile, IEntity type, Namespace parent) => diff --git a/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs b/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs index 1ca676f0ce6d..b43d85d2ad42 100644 --- a/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs +++ b/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs @@ -119,5 +119,24 @@ public static int SequenceHash(this IEnumerable items) where T : notnull /// public static IEnumerable WhereNotNull(this IEnumerable items) where T : class => items.Where(i => i is not null)!; + + /// + /// Splits the sequence at the given index. + /// + public static (IEnumerable, IEnumerable) SplitAt(this IEnumerable items, int index) + { + var left = new List(); + var right = new List(); + var i = 0; + foreach (var item in items) + { + if (i < index) + left.Add(item); + else + right.Add(item); + i++; + } + return (left, right); + } } } diff --git a/csharp/ql/lib/semmle/code/csharp/Callable.qll b/csharp/ql/lib/semmle/code/csharp/Callable.qll index 49a2271b27c8..985cdb8f1b26 100644 --- a/csharp/ql/lib/semmle/code/csharp/Callable.qll +++ b/csharp/ql/lib/semmle/code/csharp/Callable.qll @@ -221,6 +221,23 @@ class Callable extends Parameterizable, ExprOrStmtParent, @callable { /** Gets a `Call` that has this callable as a target. */ Call getACall() { this = result.getTarget() } + + /** Holds if this callable is declared in an extension type. */ + predicate isInExtension() { this.getDeclaringType() instanceof ExtensionType } +} + +/** + * A callable that is declared as an extension. + * + * Either an extension method (`ExtensionMethod`), an extension operator + * (`ExtensionOperator`) or an extension accessor (`ExtensionAccessor`). + */ +abstract class ExtensionCallable extends Callable { + /** Gets the type being extended by this method. */ + pragma[noinline] + Type getExtendedType() { result = this.getDeclaringType().(ExtensionType).getExtendedType() } + + override string getAPrimaryQlClass() { result = "ExtensionCallable" } } /** @@ -267,8 +284,11 @@ class Method extends Callable, Virtualizable, Attributable, @method { override Location getALocation() { method_location(this.getUnboundDeclaration(), result) } + /** Holds if this method is a classic extension method. */ + predicate isClassicExtensionMethod() { this.getParameter(0).hasExtensionMethodModifier() } + /** Holds if this method is an extension method. */ - predicate isExtensionMethod() { this.getParameter(0).hasExtensionMethodModifier() } + predicate isExtensionMethod() { this.isClassicExtensionMethod() or this.isInExtension() } /** Gets the type of the `params` parameter of this method, if any. */ Type getParamsType() { @@ -296,7 +316,17 @@ class Method extends Callable, Virtualizable, Attributable, @method { } /** - * An extension method, for example + * An extension method. + * + * Either a classic extension method (`ClassicExtensionMethod`) or an extension + * type extension method (`ExtensionTypeExtensionMethod`). + */ +abstract class ExtensionMethod extends ExtensionCallable, Method { + override string getAPrimaryQlClass() { result = "ExtensionMethod" } +} + +/** + * An extension method, for example * * ```csharp * static bool IsDefined(this Widget w) { @@ -304,16 +334,28 @@ class Method extends Callable, Virtualizable, Attributable, @method { * } * ``` */ -class ExtensionMethod extends Method { - ExtensionMethod() { this.isExtensionMethod() } - - override predicate isStatic() { any() } +class ClassicExtensionMethod extends ExtensionMethod { + ClassicExtensionMethod() { this.isClassicExtensionMethod() } - /** Gets the type being extended by this method. */ pragma[noinline] - Type getExtendedType() { result = this.getParameter(0).getType() } + override Type getExtendedType() { result = this.getParameter(0).getType() } - override string getAPrimaryQlClass() { result = "ExtensionMethod" } + override predicate isStatic() { any() } +} + +/** + * An extension method declared in an extension type, for example `IsNullOrEmpty` in + * + * ```csharp + * static class MyExtensions { + * extension(string s) { + * public bool IsNullOrEmpty() { ... } + * } + * } + * ``` + */ +class ExtensionTypeExtensionMethod extends ExtensionMethod { + ExtensionTypeExtensionMethod() { this.isInExtension() } } /** @@ -536,6 +578,20 @@ class RecordCloneMethod extends Method { } } +/** + * An extension operator, for example `*` in + * ```csharp + * static class MyExtensions { + * extension(string s) { + * public static string operator *(int s1, string s2) { ... } + * } + * } + * ``` + */ +class ExtensionOperator extends ExtensionCallable, Operator { + ExtensionOperator() { this.isInExtension() } +} + /** * A user-defined unary operator - an operator taking one operand. * diff --git a/csharp/ql/lib/semmle/code/csharp/Member.qll b/csharp/ql/lib/semmle/code/csharp/Member.qll index a196d3b3fc70..d4be2eaae972 100644 --- a/csharp/ql/lib/semmle/code/csharp/Member.qll +++ b/csharp/ql/lib/semmle/code/csharp/Member.qll @@ -469,7 +469,7 @@ class Virtualizable extends Overridable, Member, @virtualizable { /** * A parameterizable declaration. Either a callable (`Callable`), a delegate - * type (`DelegateType`), or an indexer (`Indexer`). + * type (`DelegateType`), an indexer (`Indexer`) or an extension block (`ExtensionType`). */ class Parameterizable extends Declaration, @parameterizable { /** Gets raw parameter `i`, including the `this` parameter at index 0. */ diff --git a/csharp/ql/lib/semmle/code/csharp/Property.qll b/csharp/ql/lib/semmle/code/csharp/Property.qll index e651639b6313..37156929b9cc 100644 --- a/csharp/ql/lib/semmle/code/csharp/Property.qll +++ b/csharp/ql/lib/semmle/code/csharp/Property.qll @@ -260,6 +260,20 @@ class Property extends DeclarationWithGetSetAccessors, @property { override string getAPrimaryQlClass() { result = "Property" } } +/** + * An extension property, for example `FirstChar` in + * ```csharp + * static class MyExtensions { + * extension(string s) { + * public char FirstChar { get { ... } } + * } + * } + * ``` + */ +class ExtensionProperty extends Property { + ExtensionProperty() { this.getDeclaringType() instanceof ExtensionType } +} + /** * An indexer, for example `string this[int i]` on line 2 in * @@ -413,6 +427,21 @@ class Accessor extends Callable, Modifiable, Attributable, Overridable, @callabl override string toString() { result = this.getName() } } +/** + * An extension accessor. Either a getter (`Getter`), a setter (`Setter`) of an + * extension property, for example `get` in + * ```csharp + * static class MyExtensions { + * extension(string s) { + * public char FirstChar { get { ... } } + * } + * } + * ``` + */ +class ExtensionAccessor extends ExtensionCallable, Accessor { + ExtensionAccessor() { this.getDeclaringType() instanceof ExtensionType } +} + /** * A `get` accessor, for example `get { return p; }` in * diff --git a/csharp/ql/lib/semmle/code/csharp/Type.qll b/csharp/ql/lib/semmle/code/csharp/Type.qll index 1efb1aa93bff..12fce3cb7f93 100644 --- a/csharp/ql/lib/semmle/code/csharp/Type.qll +++ b/csharp/ql/lib/semmle/code/csharp/Type.qll @@ -17,7 +17,8 @@ private import semmle.code.csharp.frameworks.system.runtime.CompilerServices * * Either a value or reference type (`ValueOrRefType`), the `void` type (`VoidType`), * a pointer type (`PointerType`), the arglist type (`ArglistType`), an unknown - * type (`UnknownType`), or a type parameter (`TypeParameter`). + * type (`UnknownType`), a type parameter (`TypeParameter`) or + * an extension type (`ExtensionType`). */ class Type extends Member, TypeContainer, @type { /** Gets the name of this type without additional syntax such as `[]` or `*`. */ @@ -1326,3 +1327,34 @@ class TypeMention extends @type_mention { /** Gets the location of this type mention. */ Location getLocation() { type_mention_location(this, result) } } + +/** + * A type extension declaration, for example `extensions(string s) { ... }` in + * ```csharp + * static class MyExtensions { + * extensions(string s) { ... } + * ``` + */ +class ExtensionType extends Parameterizable, @extension_type { + /** + * Gets the receiver parameter of this extension type, if any. + */ + Parameter getReceiverParameter() { result = this.getParameter(0) } + + /** + * Holds if this extension type has a receiver parameter. + */ + predicate hasReceiverParameter() { exists(this.getReceiverParameter()) } + + /** + * Gets the type being extended by this extension type. + */ + Type getExtendedType() { + extension_receiver_type(this, result) + or + not extension_receiver_type(this, any(Type t)) and + extension_receiver_type(this, getTypeRef(result)) + } + + override string getAPrimaryQlClass() { result = "ExtensionType" } +} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/ExternalFlow.qll index 61954f63e10b..d358c4aa441a 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/ExternalFlow.qll @@ -214,7 +214,7 @@ module ModelValidation { not namespace.regexpMatch("[a-zA-Z0-9_\\.]+") and result = "Dubious namespace \"" + namespace + "\" in " + pred + " model." or - not type.regexpMatch("[a-zA-Z0-9_<>,\\+]+") and + not type.regexpMatch("[a-zA-Z0-9_<>,\\(\\)\\+]+") and result = "Dubious type \"" + type + "\" in " + pred + " model." or not name.regexpMatch("[a-zA-Z0-9_<>,\\.]*") and diff --git a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll index c61ad0f2a2a9..a83967441d74 100644 --- a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll +++ b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll @@ -87,7 +87,8 @@ private module Internal { newtype TDispatchCall = TDispatchMethodCall(MethodCall mc) { not isReflectionCall(mc, _, _, _, _) and - not mc.isLateBound() + not mc.isLateBound() and + not isExtensionAccessorCall(mc) } or TDispatchAccessorCall(AccessorCall ac) or TDispatchOperatorCall(OperatorCall oc) { not oc.isLateBound() } or @@ -110,7 +111,8 @@ private module Internal { c instanceof ConstructorInitializer or c instanceof LocalFunctionCall - } + } or + TDispatchExtensionAccessorCall(MethodCall mc) { isExtensionAccessorCall(mc) } cached Expr getCall(DispatchCall dc) { result = dc.(DispatchCallImpl).getCall() } @@ -142,6 +144,8 @@ private module Internal { import Cached + private predicate isExtensionAccessorCall(MethodCall mc) { exists(mc.getTargetAccessor()) } + /** * Holds if `mc` is a reflection call to a method named `name`, where * `object` is the object on which to invoke the method (`null` if a @@ -819,6 +823,33 @@ private module Internal { override Method getAStaticTarget() { result = this.getCall().getTarget() } } + /** + * A call to an extension accessor method. + */ + private class DispatchExtensionAccessorCall extends DispatchCallImpl, + TDispatchExtensionAccessorCall + { + override MethodCall getCall() { this = TDispatchExtensionAccessorCall(result) } + + private Expr getArgumentForParameter(Parameter p) { + this.getCall().getTargetAccessor().getAParameter() = p and + result = this.getCall().getArgument(p.getPosition()) + } + + override Expr getArgument(int i) { + exists(MethodCall call, Parameter p | call = this.getCall() | + p = call.getTargetAccessor().getParameter(i) and + result = this.getArgumentForParameter(p) + ) + } + + override Expr getQualifier() { result = this.getCall().getQualifier() } + + override Accessor getAStaticTarget() { result = this.getCall().getTargetAccessor() } + + override RuntimeCallable getADynamicTarget() { result = this.getAStaticTarget() } + } + /** * An ordinary operator call. * diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Access.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Access.qll index eafc4fac491f..614b82f30d98 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Access.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Access.qll @@ -223,6 +223,42 @@ class ParameterAccess extends LocalScopeVariableAccess, @parameter_access_expr { override string getAPrimaryQlClass() { result = "ParameterAccess" } } +/** + * An access to a synthetic parameter for an extension method, for example the + * access to `s` on line 3 in + * + * ```csharp + * static class MyExtensions { + * extension(string s) { + * public bool IsEmpty() { return s == string.Empty; } + * } + * } + * ``` + */ +class SyntheticParameterAccess extends ParameterAccess { + private Parameter p; + + SyntheticParameterAccess() { + exists(ExtensionType et | + p = et.getReceiverParameter() and + expr_access(this, p) + ) + } + + override Parameter getTarget() { + exists(ExtensionCallable c | + this.getEnclosingCallable+() = c and + result = c.getParameter(0) + ) + } + + override string toString() { + result = "access to synthetic parameter " + this.getTarget().getName() + } + + override string getAPrimaryQlClass() { result = "SyntheticParameterAccess" } +} + /** * An access to a parameter that reads the underlying value, for example * the access to `p` on line 2 in diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll index eecbc35900aa..8a6576cf5d6b 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll @@ -267,9 +267,32 @@ class Call extends Expr, @call { class MethodCall extends Call, QualifiableExpr, LateBindableExpr, @method_invocation_expr { override Method getTarget() { expr_call(this, result) } + /** + * Gets the accessor that was used to generate this method, if any. For example, the + * method call `MyExtensions.get_FirstChar(s)` on line 9 is generated from the property + * accessor `get_FirstChar` on line 3 in + * ```csharp + * static class MyExtensions { + * extension(string s) { + * public char FirstChar { get { ... } } + * } + * } + * + * class A { + * char M(string s) { + * return MyExtensions.get_FirstChar(s); + * } + * } + */ + Accessor getTargetAccessor() { expr_call(this, result) } + override Method getQualifiedDeclaration() { result = this.getTarget() } - override string toString() { result = "call to method " + concat(this.getTarget().getName()) } + override string toString() { + if exists(this.getTargetAccessor()) + then result = "call to extension accessor " + concat(this.getTargetAccessor().getName()) + else result = "call to method " + concat(this.getTarget().getName()) + } override string getAPrimaryQlClass() { result = "MethodCall" } @@ -479,6 +502,29 @@ class OperatorCall extends Call, LateBindableExpr, @operator_invocation_expr { override string getAPrimaryQlClass() { result = "OperatorCall" } } +/** + * A call to an extension operator, for example `3 * s` on + * line 9 in + * ```csharp + * static class MyExtensions { + * extension(string s) { + * public static string operator *(int i, string s) { ... } + * } + * } + * + * class A { + * string M(string s) { + * return 3 * s; + * } + * } + * ``` + */ +class ExtensionOperatorCall extends OperatorCall { + ExtensionOperatorCall() { this.getTarget() instanceof ExtensionOperator } + + override string getAPrimaryQlClass() { result = "ExtensionOperatorCall" } +} + /** * A call to a user-defined mutator operator, for example `a++` on * line 7 in @@ -577,7 +623,7 @@ class FunctionPointerCall extends DelegateLikeCall, @function_pointer_invocation /** * A call to an accessor. Either a property accessor call (`PropertyCall`), - * an indexer accessor call (`IndexerCall`), or an event accessor call + * an indexer accessor call (`IndexerCall`) or an event accessor call * (`EventCall`). */ class AccessorCall extends Call, QualifiableExpr, @call_access_expr { @@ -658,6 +704,43 @@ class IndexerCall extends AccessorCall, IndexerAccessExpr { override string getAPrimaryQlClass() { result = "IndexerCall" } } +/** + * A call to an extension property accessor (via the property), for example + * `s.FirstChar` on line 9 in + * ```csharp + * static class MyExtensions { + * extension(string s) { + * public char FirstChar { get { ... } } + * } + * } + * + * class A { + * char M(string s) { + * return s.FirstChar; + * } + * } + * ``` + */ +class ExtensionPropertyCall extends PropertyCall { + private ExtensionProperty prop; + + ExtensionPropertyCall() { this.getProperty() = prop } + + override Expr getArgument(int i) { + if prop.isStatic() + then result = super.getArgument(i) + else ( + // Shift arguments as the qualifier is an explicit argument in the getter/setter. + i = 0 and + result = this.getQualifier() + or + result = super.getArgument(i - 1) + ) + } + + override string getAPrimaryQlClass() { result = "ExtensionPropertyCall" } +} + /** * A call to an event accessor, for example the call to `add_Click` * (defined on line 5) on line 12 in diff --git a/csharp/ql/lib/semmlecode.csharp.dbscheme b/csharp/ql/lib/semmlecode.csharp.dbscheme index 68b5aec54e50..a39a96d1f33b 100644 --- a/csharp/ql/lib/semmlecode.csharp.dbscheme +++ b/csharp/ql/lib/semmlecode.csharp.dbscheme @@ -222,7 +222,7 @@ overlayChangedFiles( | @using_directive | @type_parameter_constraints | @externalDataElement | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; -@declaration = @callable | @generic | @assignable | @namespace; +@declaration = @callable | @generic | @assignable | @namespace | @extension_type; @named_element = @namespace | @declaration; @@ -492,6 +492,7 @@ case @type.kind of | 32 = @tuple_type | 33 = @function_pointer_type | 34 = @inline_array_type +| 35 = @extension_type ; @simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; @@ -502,7 +503,7 @@ case @type.kind of @value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type; @ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type - | @dynamic_type; + | @dynamic_type | @extension_type; @value_or_ref_type = @value_type | @ref_type; typerefs( @@ -541,6 +542,10 @@ function_pointer_return_type( unique int function_pointer_id: @function_pointer_type ref, int return_type_id: @type_or_ref ref); +extension_receiver_type( + unique int extension: @extension_type ref, + int receiver_type_id: @type_or_ref ref); + extend( int sub: @type ref, int super: @type_or_ref ref); @@ -903,7 +908,7 @@ localvar_location( unique int id: @local_variable ref, int loc: @location ref); -@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type; +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type | @extension_type; #keyset[name, parent_id] #keyset[index, parent_id] diff --git a/csharp/ql/test/library-tests/dataflow/extensions/ExtensionFlow.expected b/csharp/ql/test/library-tests/dataflow/extensions/ExtensionFlow.expected new file mode 100644 index 000000000000..cce3fd86550d --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/extensions/ExtensionFlow.expected @@ -0,0 +1,502 @@ +models +edges +| extensions.cs:5:22:5:24 | obj : B | extensions.cs:23:24:23:26 | access to synthetic parameter obj | provenance | | +| extensions.cs:5:22:5:24 | obj : B | extensions.cs:23:24:23:26 | access to synthetic parameter obj | provenance | | +| extensions.cs:5:22:5:24 | obj : B | extensions.cs:28:24:28:26 | access to synthetic parameter obj | provenance | | +| extensions.cs:5:22:5:24 | obj : B | extensions.cs:28:24:28:26 | access to synthetic parameter obj | provenance | | +| extensions.cs:5:22:5:24 | obj : B | extensions.cs:51:20:51:22 | access to synthetic parameter obj | provenance | | +| extensions.cs:5:22:5:24 | obj : B | extensions.cs:51:20:51:22 | access to synthetic parameter obj | provenance | | +| extensions.cs:11:24:11:37 | call to method Source : B | extensions.cs:108:18:108:26 | access to property Prop1 : B | provenance | | +| extensions.cs:11:24:11:37 | call to method Source : B | extensions.cs:108:18:108:26 | access to property Prop1 : B | provenance | | +| extensions.cs:11:24:11:37 | call to method Source : B | extensions.cs:111:18:111:44 | call to extension accessor get_Prop1 : B | provenance | | +| extensions.cs:11:24:11:37 | call to method Source : B | extensions.cs:111:18:111:44 | call to extension accessor get_Prop1 : B | provenance | | +| extensions.cs:13:13:13:15 | value : B | extensions.cs:15:24:15:28 | access to parameter value | provenance | | +| extensions.cs:13:13:13:15 | value : B | extensions.cs:15:24:15:28 | access to parameter value | provenance | | +| extensions.cs:36:24:36:38 | call to method Source : B | extensions.cs:194:18:194:35 | access to property StaticProp1 : B | provenance | | +| extensions.cs:36:24:36:38 | call to method Source : B | extensions.cs:194:18:194:35 | access to property StaticProp1 : B | provenance | | +| extensions.cs:36:24:36:38 | call to method Source : B | extensions.cs:197:18:197:47 | call to extension accessor get_StaticProp1 : B | provenance | | +| extensions.cs:36:24:36:38 | call to method Source : B | extensions.cs:197:18:197:47 | call to extension accessor get_StaticProp1 : B | provenance | | +| extensions.cs:38:13:38:15 | value : B | extensions.cs:40:24:40:28 | access to parameter value | provenance | | +| extensions.cs:38:13:38:15 | value : B | extensions.cs:40:24:40:28 | access to parameter value | provenance | | +| extensions.cs:46:20:46:33 | call to method Source : B | extensions.cs:127:18:127:25 | call to method M1 : B | provenance | | +| extensions.cs:46:20:46:33 | call to method Source : B | extensions.cs:127:18:127:25 | call to method M1 : B | provenance | | +| extensions.cs:46:20:46:33 | call to method Source : B | extensions.cs:130:18:130:37 | call to method M1 : B | provenance | | +| extensions.cs:46:20:46:33 | call to method Source : B | extensions.cs:130:18:130:37 | call to method M1 : B | provenance | | +| extensions.cs:59:48:59:48 | a : B | extensions.cs:61:20:61:20 | access to parameter a | provenance | | +| extensions.cs:59:48:59:48 | a : B | extensions.cs:61:20:61:20 | access to parameter a | provenance | | +| extensions.cs:67:20:67:33 | call to method Source : B | extensions.cs:185:18:185:24 | call to operator - : B | provenance | | +| extensions.cs:67:20:67:33 | call to method Source : B | extensions.cs:185:18:185:24 | call to operator - : B | provenance | | +| extensions.cs:67:20:67:33 | call to method Source : B | extensions.cs:188:18:188:52 | call to operator - : B | provenance | | +| extensions.cs:67:20:67:33 | call to method Source : B | extensions.cs:188:18:188:52 | call to operator - : B | provenance | | +| extensions.cs:76:17:76:17 | b : B | extensions.cs:80:20:80:20 | access to synthetic parameter b : B | provenance | | +| extensions.cs:76:17:76:17 | b : B | extensions.cs:80:20:80:20 | access to synthetic parameter b : B | provenance | | +| extensions.cs:76:17:76:17 | b : B | extensions.cs:85:20:85:20 | access to synthetic parameter b | provenance | | +| extensions.cs:76:17:76:17 | b : B | extensions.cs:85:20:85:20 | access to synthetic parameter b | provenance | | +| extensions.cs:89:20:89:20 | t : B | extensions.cs:93:20:93:20 | access to synthetic parameter t | provenance | | +| extensions.cs:89:20:89:20 | t : B | extensions.cs:93:20:93:20 | access to synthetic parameter t | provenance | | +| extensions.cs:96:33:96:37 | other : B | extensions.cs:98:20:98:24 | access to parameter other : B | provenance | | +| extensions.cs:96:33:96:37 | other : B | extensions.cs:98:20:98:24 | access to parameter other : B | provenance | | +| extensions.cs:108:13:108:14 | access to local variable b1 : B | extensions.cs:109:14:109:15 | access to local variable b1 | provenance | | +| extensions.cs:108:13:108:14 | access to local variable b1 : B | extensions.cs:109:14:109:15 | access to local variable b1 | provenance | | +| extensions.cs:108:18:108:26 | access to property Prop1 : B | extensions.cs:108:13:108:14 | access to local variable b1 : B | provenance | | +| extensions.cs:108:18:108:26 | access to property Prop1 : B | extensions.cs:108:13:108:14 | access to local variable b1 : B | provenance | | +| extensions.cs:111:13:111:14 | access to local variable b2 : B | extensions.cs:112:14:112:15 | access to local variable b2 | provenance | | +| extensions.cs:111:13:111:14 | access to local variable b2 : B | extensions.cs:112:14:112:15 | access to local variable b2 | provenance | | +| extensions.cs:111:18:111:44 | call to extension accessor get_Prop1 : B | extensions.cs:111:13:111:14 | access to local variable b2 : B | provenance | | +| extensions.cs:111:18:111:44 | call to extension accessor get_Prop1 : B | extensions.cs:111:13:111:14 | access to local variable b2 : B | provenance | | +| extensions.cs:118:21:118:32 | call to method Source : B | extensions.cs:13:13:13:15 | value : B | provenance | | +| extensions.cs:118:21:118:32 | call to method Source : B | extensions.cs:13:13:13:15 | value : B | provenance | | +| extensions.cs:120:13:120:13 | access to local variable b : B | extensions.cs:121:37:121:37 | access to local variable b : B | provenance | | +| extensions.cs:120:13:120:13 | access to local variable b : B | extensions.cs:121:37:121:37 | access to local variable b : B | provenance | | +| extensions.cs:120:17:120:30 | call to method Source : B | extensions.cs:120:13:120:13 | access to local variable b : B | provenance | | +| extensions.cs:120:17:120:30 | call to method Source : B | extensions.cs:120:13:120:13 | access to local variable b : B | provenance | | +| extensions.cs:121:37:121:37 | access to local variable b : B | extensions.cs:13:13:13:15 | value : B | provenance | | +| extensions.cs:121:37:121:37 | access to local variable b : B | extensions.cs:13:13:13:15 | value : B | provenance | | +| extensions.cs:127:13:127:14 | access to local variable b1 : B | extensions.cs:128:14:128:15 | access to local variable b1 | provenance | | +| extensions.cs:127:13:127:14 | access to local variable b1 : B | extensions.cs:128:14:128:15 | access to local variable b1 | provenance | | +| extensions.cs:127:18:127:25 | call to method M1 : B | extensions.cs:127:13:127:14 | access to local variable b1 : B | provenance | | +| extensions.cs:127:18:127:25 | call to method M1 : B | extensions.cs:127:13:127:14 | access to local variable b1 : B | provenance | | +| extensions.cs:130:13:130:14 | access to local variable b2 : B | extensions.cs:131:14:131:15 | access to local variable b2 | provenance | | +| extensions.cs:130:13:130:14 | access to local variable b2 : B | extensions.cs:131:14:131:15 | access to local variable b2 | provenance | | +| extensions.cs:130:18:130:37 | call to method M1 : B | extensions.cs:130:13:130:14 | access to local variable b2 : B | provenance | | +| extensions.cs:130:18:130:37 | call to method M1 : B | extensions.cs:130:13:130:14 | access to local variable b2 : B | provenance | | +| extensions.cs:136:13:136:14 | access to local variable b1 : B | extensions.cs:137:9:137:10 | access to local variable b1 : B | provenance | | +| extensions.cs:136:13:136:14 | access to local variable b1 : B | extensions.cs:137:9:137:10 | access to local variable b1 : B | provenance | | +| extensions.cs:136:18:136:29 | call to method Source : B | extensions.cs:136:13:136:14 | access to local variable b1 : B | provenance | | +| extensions.cs:136:18:136:29 | call to method Source : B | extensions.cs:136:13:136:14 | access to local variable b1 : B | provenance | | +| extensions.cs:137:9:137:10 | access to local variable b1 : B | extensions.cs:5:22:5:24 | obj : B | provenance | | +| extensions.cs:137:9:137:10 | access to local variable b1 : B | extensions.cs:5:22:5:24 | obj : B | provenance | | +| extensions.cs:139:13:139:14 | access to local variable b2 : B | extensions.cs:140:25:140:26 | access to local variable b2 : B | provenance | | +| extensions.cs:139:13:139:14 | access to local variable b2 : B | extensions.cs:140:25:140:26 | access to local variable b2 : B | provenance | | +| extensions.cs:139:18:139:31 | call to method Source : B | extensions.cs:139:13:139:14 | access to local variable b2 : B | provenance | | +| extensions.cs:139:18:139:31 | call to method Source : B | extensions.cs:139:13:139:14 | access to local variable b2 : B | provenance | | +| extensions.cs:140:25:140:26 | access to local variable b2 : B | extensions.cs:5:22:5:24 | obj : B | provenance | | +| extensions.cs:140:25:140:26 | access to local variable b2 : B | extensions.cs:5:22:5:24 | obj : B | provenance | | +| extensions.cs:145:13:145:14 | access to local variable b1 : B | extensions.cs:146:18:146:19 | access to local variable b1 : B | provenance | | +| extensions.cs:145:13:145:14 | access to local variable b1 : B | extensions.cs:146:18:146:19 | access to local variable b1 : B | provenance | | +| extensions.cs:145:13:145:14 | access to local variable b1 : B | extensions.cs:149:34:149:35 | access to local variable b1 : B | provenance | | +| extensions.cs:145:13:145:14 | access to local variable b1 : B | extensions.cs:149:34:149:35 | access to local variable b1 : B | provenance | | +| extensions.cs:145:18:145:29 | call to method Source : B | extensions.cs:145:13:145:14 | access to local variable b1 : B | provenance | | +| extensions.cs:145:18:145:29 | call to method Source : B | extensions.cs:145:13:145:14 | access to local variable b1 : B | provenance | | +| extensions.cs:146:13:146:14 | access to local variable b2 : B | extensions.cs:147:14:147:15 | access to local variable b2 | provenance | | +| extensions.cs:146:13:146:14 | access to local variable b2 : B | extensions.cs:147:14:147:15 | access to local variable b2 | provenance | | +| extensions.cs:146:18:146:19 | access to local variable b1 : B | extensions.cs:76:17:76:17 | b : B | provenance | | +| extensions.cs:146:18:146:19 | access to local variable b1 : B | extensions.cs:76:17:76:17 | b : B | provenance | | +| extensions.cs:146:18:146:19 | access to local variable b1 : B | extensions.cs:146:18:146:24 | call to method B1 : B | provenance | | +| extensions.cs:146:18:146:19 | access to local variable b1 : B | extensions.cs:146:18:146:24 | call to method B1 : B | provenance | | +| extensions.cs:146:18:146:24 | call to method B1 : B | extensions.cs:146:13:146:14 | access to local variable b2 : B | provenance | | +| extensions.cs:146:18:146:24 | call to method B1 : B | extensions.cs:146:13:146:14 | access to local variable b2 : B | provenance | | +| extensions.cs:149:13:149:14 | access to local variable b3 : B | extensions.cs:150:14:150:15 | access to local variable b3 | provenance | | +| extensions.cs:149:13:149:14 | access to local variable b3 : B | extensions.cs:150:14:150:15 | access to local variable b3 | provenance | | +| extensions.cs:149:18:149:36 | call to method B1 : B | extensions.cs:149:13:149:14 | access to local variable b3 : B | provenance | | +| extensions.cs:149:18:149:36 | call to method B1 : B | extensions.cs:149:13:149:14 | access to local variable b3 : B | provenance | | +| extensions.cs:149:34:149:35 | access to local variable b1 : B | extensions.cs:76:17:76:17 | b : B | provenance | | +| extensions.cs:149:34:149:35 | access to local variable b1 : B | extensions.cs:76:17:76:17 | b : B | provenance | | +| extensions.cs:149:34:149:35 | access to local variable b1 : B | extensions.cs:149:18:149:36 | call to method B1 : B | provenance | | +| extensions.cs:149:34:149:35 | access to local variable b1 : B | extensions.cs:149:18:149:36 | call to method B1 : B | provenance | | +| extensions.cs:155:13:155:14 | access to local variable b1 : B | extensions.cs:156:18:156:19 | access to local variable b1 : B | provenance | | +| extensions.cs:155:13:155:14 | access to local variable b1 : B | extensions.cs:156:18:156:19 | access to local variable b1 : B | provenance | | +| extensions.cs:155:18:155:29 | call to method Source : B | extensions.cs:155:13:155:14 | access to local variable b1 : B | provenance | | +| extensions.cs:155:18:155:29 | call to method Source : B | extensions.cs:155:13:155:14 | access to local variable b1 : B | provenance | | +| extensions.cs:156:18:156:19 | access to local variable b1 : B | extensions.cs:5:22:5:24 | obj : B | provenance | | +| extensions.cs:156:18:156:19 | access to local variable b1 : B | extensions.cs:5:22:5:24 | obj : B | provenance | | +| extensions.cs:158:13:158:14 | access to local variable b3 : B | extensions.cs:159:41:159:42 | access to local variable b3 : B | provenance | | +| extensions.cs:158:13:158:14 | access to local variable b3 : B | extensions.cs:159:41:159:42 | access to local variable b3 : B | provenance | | +| extensions.cs:158:18:158:31 | call to method Source : B | extensions.cs:158:13:158:14 | access to local variable b3 : B | provenance | | +| extensions.cs:158:18:158:31 | call to method Source : B | extensions.cs:158:13:158:14 | access to local variable b3 : B | provenance | | +| extensions.cs:159:41:159:42 | access to local variable b3 : B | extensions.cs:5:22:5:24 | obj : B | provenance | | +| extensions.cs:159:41:159:42 | access to local variable b3 : B | extensions.cs:5:22:5:24 | obj : B | provenance | | +| extensions.cs:164:13:164:14 | access to local variable b1 : B | extensions.cs:165:9:165:10 | access to local variable b1 : B | provenance | | +| extensions.cs:164:13:164:14 | access to local variable b1 : B | extensions.cs:165:9:165:10 | access to local variable b1 : B | provenance | | +| extensions.cs:164:18:164:29 | call to method Source : B | extensions.cs:164:13:164:14 | access to local variable b1 : B | provenance | | +| extensions.cs:164:18:164:29 | call to method Source : B | extensions.cs:164:13:164:14 | access to local variable b1 : B | provenance | | +| extensions.cs:165:9:165:10 | access to local variable b1 : B | extensions.cs:5:22:5:24 | obj : B | provenance | | +| extensions.cs:165:9:165:10 | access to local variable b1 : B | extensions.cs:5:22:5:24 | obj : B | provenance | | +| extensions.cs:167:13:167:14 | access to local variable b2 : B | extensions.cs:168:32:168:33 | access to local variable b2 : B | provenance | | +| extensions.cs:167:13:167:14 | access to local variable b2 : B | extensions.cs:168:32:168:33 | access to local variable b2 : B | provenance | | +| extensions.cs:167:18:167:31 | call to method Source : B | extensions.cs:167:13:167:14 | access to local variable b2 : B | provenance | | +| extensions.cs:167:18:167:31 | call to method Source : B | extensions.cs:167:13:167:14 | access to local variable b2 : B | provenance | | +| extensions.cs:168:32:168:33 | access to local variable b2 : B | extensions.cs:5:22:5:24 | obj : B | provenance | | +| extensions.cs:168:32:168:33 | access to local variable b2 : B | extensions.cs:5:22:5:24 | obj : B | provenance | | +| extensions.cs:173:13:173:14 | access to local variable b1 : B | extensions.cs:175:18:175:19 | access to local variable b1 : B | provenance | | +| extensions.cs:173:13:173:14 | access to local variable b1 : B | extensions.cs:175:18:175:19 | access to local variable b1 : B | provenance | | +| extensions.cs:173:18:173:29 | call to method Source : B | extensions.cs:173:13:173:14 | access to local variable b1 : B | provenance | | +| extensions.cs:173:18:173:29 | call to method Source : B | extensions.cs:173:13:173:14 | access to local variable b1 : B | provenance | | +| extensions.cs:175:18:175:19 | access to local variable b1 : B | extensions.cs:59:48:59:48 | a : B | provenance | | +| extensions.cs:175:18:175:19 | access to local variable b1 : B | extensions.cs:59:48:59:48 | a : B | provenance | | +| extensions.cs:177:13:177:14 | access to local variable b4 : B | extensions.cs:178:43:178:44 | access to local variable b4 : B | provenance | | +| extensions.cs:177:13:177:14 | access to local variable b4 : B | extensions.cs:178:43:178:44 | access to local variable b4 : B | provenance | | +| extensions.cs:177:18:177:31 | call to method Source : B | extensions.cs:177:13:177:14 | access to local variable b4 : B | provenance | | +| extensions.cs:177:18:177:31 | call to method Source : B | extensions.cs:177:13:177:14 | access to local variable b4 : B | provenance | | +| extensions.cs:178:43:178:44 | access to local variable b4 : B | extensions.cs:59:48:59:48 | a : B | provenance | | +| extensions.cs:178:43:178:44 | access to local variable b4 : B | extensions.cs:59:48:59:48 | a : B | provenance | | +| extensions.cs:185:13:185:14 | access to local variable b3 : B | extensions.cs:186:14:186:15 | access to local variable b3 | provenance | | +| extensions.cs:185:13:185:14 | access to local variable b3 : B | extensions.cs:186:14:186:15 | access to local variable b3 | provenance | | +| extensions.cs:185:18:185:24 | call to operator - : B | extensions.cs:185:13:185:14 | access to local variable b3 : B | provenance | | +| extensions.cs:185:18:185:24 | call to operator - : B | extensions.cs:185:13:185:14 | access to local variable b3 : B | provenance | | +| extensions.cs:188:13:188:14 | access to local variable b4 : B | extensions.cs:189:14:189:15 | access to local variable b4 | provenance | | +| extensions.cs:188:13:188:14 | access to local variable b4 : B | extensions.cs:189:14:189:15 | access to local variable b4 | provenance | | +| extensions.cs:188:18:188:52 | call to operator - : B | extensions.cs:188:13:188:14 | access to local variable b4 : B | provenance | | +| extensions.cs:188:18:188:52 | call to operator - : B | extensions.cs:188:13:188:14 | access to local variable b4 : B | provenance | | +| extensions.cs:194:13:194:14 | access to local variable b1 : B | extensions.cs:195:14:195:15 | access to local variable b1 | provenance | | +| extensions.cs:194:13:194:14 | access to local variable b1 : B | extensions.cs:195:14:195:15 | access to local variable b1 | provenance | | +| extensions.cs:194:18:194:35 | access to property StaticProp1 : B | extensions.cs:194:13:194:14 | access to local variable b1 : B | provenance | | +| extensions.cs:194:18:194:35 | access to property StaticProp1 : B | extensions.cs:194:13:194:14 | access to local variable b1 : B | provenance | | +| extensions.cs:197:13:197:14 | access to local variable b2 : B | extensions.cs:198:14:198:15 | access to local variable b2 | provenance | | +| extensions.cs:197:13:197:14 | access to local variable b2 : B | extensions.cs:198:14:198:15 | access to local variable b2 | provenance | | +| extensions.cs:197:18:197:47 | call to extension accessor get_StaticProp1 : B | extensions.cs:197:13:197:14 | access to local variable b2 : B | provenance | | +| extensions.cs:197:18:197:47 | call to extension accessor get_StaticProp1 : B | extensions.cs:197:13:197:14 | access to local variable b2 : B | provenance | | +| extensions.cs:203:13:203:14 | access to local variable b1 : B | extensions.cs:204:30:204:31 | access to local variable b1 : B | provenance | | +| extensions.cs:203:13:203:14 | access to local variable b1 : B | extensions.cs:204:30:204:31 | access to local variable b1 : B | provenance | | +| extensions.cs:203:18:203:30 | call to method Source : B | extensions.cs:203:13:203:14 | access to local variable b1 : B | provenance | | +| extensions.cs:203:18:203:30 | call to method Source : B | extensions.cs:203:13:203:14 | access to local variable b1 : B | provenance | | +| extensions.cs:204:30:204:31 | access to local variable b1 : B | extensions.cs:38:13:38:15 | value : B | provenance | | +| extensions.cs:204:30:204:31 | access to local variable b1 : B | extensions.cs:38:13:38:15 | value : B | provenance | | +| extensions.cs:206:13:206:14 | access to local variable b2 : B | extensions.cs:207:38:207:39 | access to local variable b2 : B | provenance | | +| extensions.cs:206:13:206:14 | access to local variable b2 : B | extensions.cs:207:38:207:39 | access to local variable b2 : B | provenance | | +| extensions.cs:206:18:206:31 | call to method Source : B | extensions.cs:206:13:206:14 | access to local variable b2 : B | provenance | | +| extensions.cs:206:18:206:31 | call to method Source : B | extensions.cs:206:13:206:14 | access to local variable b2 : B | provenance | | +| extensions.cs:207:38:207:39 | access to local variable b2 : B | extensions.cs:38:13:38:15 | value : B | provenance | | +| extensions.cs:207:38:207:39 | access to local variable b2 : B | extensions.cs:38:13:38:15 | value : B | provenance | | +| extensions.cs:212:13:212:14 | access to local variable b1 : B | extensions.cs:213:9:213:10 | access to local variable b1 : B | provenance | | +| extensions.cs:212:13:212:14 | access to local variable b1 : B | extensions.cs:213:9:213:10 | access to local variable b1 : B | provenance | | +| extensions.cs:212:18:212:30 | call to method Source : B | extensions.cs:212:13:212:14 | access to local variable b1 : B | provenance | | +| extensions.cs:212:18:212:30 | call to method Source : B | extensions.cs:212:13:212:14 | access to local variable b1 : B | provenance | | +| extensions.cs:213:9:213:10 | access to local variable b1 : B | extensions.cs:76:17:76:17 | b : B | provenance | | +| extensions.cs:213:9:213:10 | access to local variable b1 : B | extensions.cs:76:17:76:17 | b : B | provenance | | +| extensions.cs:215:13:215:14 | access to local variable b2 : B | extensions.cs:216:25:216:26 | access to local variable b2 : B | provenance | | +| extensions.cs:215:13:215:14 | access to local variable b2 : B | extensions.cs:216:25:216:26 | access to local variable b2 : B | provenance | | +| extensions.cs:215:18:215:31 | call to method Source : B | extensions.cs:215:13:215:14 | access to local variable b2 : B | provenance | | +| extensions.cs:215:18:215:31 | call to method Source : B | extensions.cs:215:13:215:14 | access to local variable b2 : B | provenance | | +| extensions.cs:216:25:216:26 | access to local variable b2 : B | extensions.cs:76:17:76:17 | b : B | provenance | | +| extensions.cs:216:25:216:26 | access to local variable b2 : B | extensions.cs:76:17:76:17 | b : B | provenance | | +| extensions.cs:221:13:221:14 | access to local variable b1 : B | extensions.cs:222:9:222:10 | access to local variable b1 : B | provenance | | +| extensions.cs:221:13:221:14 | access to local variable b1 : B | extensions.cs:222:9:222:10 | access to local variable b1 : B | provenance | | +| extensions.cs:221:18:221:30 | call to method Source : B | extensions.cs:221:13:221:14 | access to local variable b1 : B | provenance | | +| extensions.cs:221:18:221:30 | call to method Source : B | extensions.cs:221:13:221:14 | access to local variable b1 : B | provenance | | +| extensions.cs:222:9:222:10 | access to local variable b1 : B | extensions.cs:89:20:89:20 | t : B | provenance | | +| extensions.cs:222:9:222:10 | access to local variable b1 : B | extensions.cs:89:20:89:20 | t : B | provenance | | +| extensions.cs:224:13:224:14 | access to local variable b2 : B | extensions.cs:225:32:225:33 | access to local variable b2 : B | provenance | | +| extensions.cs:224:13:224:14 | access to local variable b2 : B | extensions.cs:225:32:225:33 | access to local variable b2 : B | provenance | | +| extensions.cs:224:18:224:31 | call to method Source : B | extensions.cs:224:13:224:14 | access to local variable b2 : B | provenance | | +| extensions.cs:224:18:224:31 | call to method Source : B | extensions.cs:224:13:224:14 | access to local variable b2 : B | provenance | | +| extensions.cs:225:32:225:33 | access to local variable b2 : B | extensions.cs:89:20:89:20 | t : B | provenance | | +| extensions.cs:225:32:225:33 | access to local variable b2 : B | extensions.cs:89:20:89:20 | t : B | provenance | | +| extensions.cs:231:13:231:14 | access to local variable b1 : B | extensions.cs:232:32:232:33 | access to local variable b1 : B | provenance | | +| extensions.cs:231:13:231:14 | access to local variable b1 : B | extensions.cs:232:32:232:33 | access to local variable b1 : B | provenance | | +| extensions.cs:231:13:231:14 | access to local variable b1 : B | extensions.cs:235:46:235:47 | access to local variable b1 : B | provenance | | +| extensions.cs:231:13:231:14 | access to local variable b1 : B | extensions.cs:235:46:235:47 | access to local variable b1 : B | provenance | | +| extensions.cs:231:18:231:30 | call to method Source : B | extensions.cs:231:13:231:14 | access to local variable b1 : B | provenance | | +| extensions.cs:231:18:231:30 | call to method Source : B | extensions.cs:231:13:231:14 | access to local variable b1 : B | provenance | | +| extensions.cs:232:13:232:14 | access to local variable b2 : B | extensions.cs:233:14:233:15 | access to local variable b2 | provenance | | +| extensions.cs:232:13:232:14 | access to local variable b2 : B | extensions.cs:233:14:233:15 | access to local variable b2 | provenance | | +| extensions.cs:232:18:232:34 | call to method GenericM2 : B | extensions.cs:232:13:232:14 | access to local variable b2 : B | provenance | | +| extensions.cs:232:18:232:34 | call to method GenericM2 : B | extensions.cs:232:13:232:14 | access to local variable b2 : B | provenance | | +| extensions.cs:232:32:232:33 | access to local variable b1 : B | extensions.cs:96:33:96:37 | other : B | provenance | | +| extensions.cs:232:32:232:33 | access to local variable b1 : B | extensions.cs:96:33:96:37 | other : B | provenance | | +| extensions.cs:232:32:232:33 | access to local variable b1 : B | extensions.cs:232:18:232:34 | call to method GenericM2 : B | provenance | | +| extensions.cs:232:32:232:33 | access to local variable b1 : B | extensions.cs:232:18:232:34 | call to method GenericM2 : B | provenance | | +| extensions.cs:235:13:235:14 | access to local variable b3 : B | extensions.cs:236:14:236:15 | access to local variable b3 | provenance | | +| extensions.cs:235:13:235:14 | access to local variable b3 : B | extensions.cs:236:14:236:15 | access to local variable b3 | provenance | | +| extensions.cs:235:18:235:48 | call to method GenericM2 : B | extensions.cs:235:13:235:14 | access to local variable b3 : B | provenance | | +| extensions.cs:235:18:235:48 | call to method GenericM2 : B | extensions.cs:235:13:235:14 | access to local variable b3 : B | provenance | | +| extensions.cs:235:46:235:47 | access to local variable b1 : B | extensions.cs:96:33:96:37 | other : B | provenance | | +| extensions.cs:235:46:235:47 | access to local variable b1 : B | extensions.cs:96:33:96:37 | other : B | provenance | | +| extensions.cs:235:46:235:47 | access to local variable b1 : B | extensions.cs:235:18:235:48 | call to method GenericM2 : B | provenance | | +| extensions.cs:235:46:235:47 | access to local variable b1 : B | extensions.cs:235:18:235:48 | call to method GenericM2 : B | provenance | | +nodes +| extensions.cs:5:22:5:24 | obj : B | semmle.label | obj : B | +| extensions.cs:5:22:5:24 | obj : B | semmle.label | obj : B | +| extensions.cs:5:22:5:24 | obj : B | semmle.label | obj : B | +| extensions.cs:5:22:5:24 | obj : B | semmle.label | obj : B | +| extensions.cs:5:22:5:24 | obj : B | semmle.label | obj : B | +| extensions.cs:5:22:5:24 | obj : B | semmle.label | obj : B | +| extensions.cs:11:24:11:37 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:11:24:11:37 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:13:13:13:15 | value : B | semmle.label | value : B | +| extensions.cs:13:13:13:15 | value : B | semmle.label | value : B | +| extensions.cs:15:24:15:28 | access to parameter value | semmle.label | access to parameter value | +| extensions.cs:15:24:15:28 | access to parameter value | semmle.label | access to parameter value | +| extensions.cs:23:24:23:26 | access to synthetic parameter obj | semmle.label | access to synthetic parameter obj | +| extensions.cs:23:24:23:26 | access to synthetic parameter obj | semmle.label | access to synthetic parameter obj | +| extensions.cs:28:24:28:26 | access to synthetic parameter obj | semmle.label | access to synthetic parameter obj | +| extensions.cs:28:24:28:26 | access to synthetic parameter obj | semmle.label | access to synthetic parameter obj | +| extensions.cs:36:24:36:38 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:36:24:36:38 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:38:13:38:15 | value : B | semmle.label | value : B | +| extensions.cs:38:13:38:15 | value : B | semmle.label | value : B | +| extensions.cs:40:24:40:28 | access to parameter value | semmle.label | access to parameter value | +| extensions.cs:40:24:40:28 | access to parameter value | semmle.label | access to parameter value | +| extensions.cs:46:20:46:33 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:46:20:46:33 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:51:20:51:22 | access to synthetic parameter obj | semmle.label | access to synthetic parameter obj | +| extensions.cs:51:20:51:22 | access to synthetic parameter obj | semmle.label | access to synthetic parameter obj | +| extensions.cs:59:48:59:48 | a : B | semmle.label | a : B | +| extensions.cs:59:48:59:48 | a : B | semmle.label | a : B | +| extensions.cs:61:20:61:20 | access to parameter a | semmle.label | access to parameter a | +| extensions.cs:61:20:61:20 | access to parameter a | semmle.label | access to parameter a | +| extensions.cs:67:20:67:33 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:67:20:67:33 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:76:17:76:17 | b : B | semmle.label | b : B | +| extensions.cs:76:17:76:17 | b : B | semmle.label | b : B | +| extensions.cs:76:17:76:17 | b : B | semmle.label | b : B | +| extensions.cs:76:17:76:17 | b : B | semmle.label | b : B | +| extensions.cs:80:20:80:20 | access to synthetic parameter b : B | semmle.label | access to synthetic parameter b : B | +| extensions.cs:80:20:80:20 | access to synthetic parameter b : B | semmle.label | access to synthetic parameter b : B | +| extensions.cs:85:20:85:20 | access to synthetic parameter b | semmle.label | access to synthetic parameter b | +| extensions.cs:85:20:85:20 | access to synthetic parameter b | semmle.label | access to synthetic parameter b | +| extensions.cs:89:20:89:20 | t : B | semmle.label | t : B | +| extensions.cs:89:20:89:20 | t : B | semmle.label | t : B | +| extensions.cs:93:20:93:20 | access to synthetic parameter t | semmle.label | access to synthetic parameter t | +| extensions.cs:93:20:93:20 | access to synthetic parameter t | semmle.label | access to synthetic parameter t | +| extensions.cs:96:33:96:37 | other : B | semmle.label | other : B | +| extensions.cs:96:33:96:37 | other : B | semmle.label | other : B | +| extensions.cs:98:20:98:24 | access to parameter other : B | semmle.label | access to parameter other : B | +| extensions.cs:98:20:98:24 | access to parameter other : B | semmle.label | access to parameter other : B | +| extensions.cs:108:13:108:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:108:13:108:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:108:18:108:26 | access to property Prop1 : B | semmle.label | access to property Prop1 : B | +| extensions.cs:108:18:108:26 | access to property Prop1 : B | semmle.label | access to property Prop1 : B | +| extensions.cs:109:14:109:15 | access to local variable b1 | semmle.label | access to local variable b1 | +| extensions.cs:109:14:109:15 | access to local variable b1 | semmle.label | access to local variable b1 | +| extensions.cs:111:13:111:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:111:13:111:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:111:18:111:44 | call to extension accessor get_Prop1 : B | semmle.label | call to extension accessor get_Prop1 : B | +| extensions.cs:111:18:111:44 | call to extension accessor get_Prop1 : B | semmle.label | call to extension accessor get_Prop1 : B | +| extensions.cs:112:14:112:15 | access to local variable b2 | semmle.label | access to local variable b2 | +| extensions.cs:112:14:112:15 | access to local variable b2 | semmle.label | access to local variable b2 | +| extensions.cs:118:21:118:32 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:118:21:118:32 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:120:13:120:13 | access to local variable b : B | semmle.label | access to local variable b : B | +| extensions.cs:120:13:120:13 | access to local variable b : B | semmle.label | access to local variable b : B | +| extensions.cs:120:17:120:30 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:120:17:120:30 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:121:37:121:37 | access to local variable b : B | semmle.label | access to local variable b : B | +| extensions.cs:121:37:121:37 | access to local variable b : B | semmle.label | access to local variable b : B | +| extensions.cs:127:13:127:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:127:13:127:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:127:18:127:25 | call to method M1 : B | semmle.label | call to method M1 : B | +| extensions.cs:127:18:127:25 | call to method M1 : B | semmle.label | call to method M1 : B | +| extensions.cs:128:14:128:15 | access to local variable b1 | semmle.label | access to local variable b1 | +| extensions.cs:128:14:128:15 | access to local variable b1 | semmle.label | access to local variable b1 | +| extensions.cs:130:13:130:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:130:13:130:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:130:18:130:37 | call to method M1 : B | semmle.label | call to method M1 : B | +| extensions.cs:130:18:130:37 | call to method M1 : B | semmle.label | call to method M1 : B | +| extensions.cs:131:14:131:15 | access to local variable b2 | semmle.label | access to local variable b2 | +| extensions.cs:131:14:131:15 | access to local variable b2 | semmle.label | access to local variable b2 | +| extensions.cs:136:13:136:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:136:13:136:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:136:18:136:29 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:136:18:136:29 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:137:9:137:10 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:137:9:137:10 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:139:13:139:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:139:13:139:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:139:18:139:31 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:139:18:139:31 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:140:25:140:26 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:140:25:140:26 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:145:13:145:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:145:13:145:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:145:18:145:29 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:145:18:145:29 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:146:13:146:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:146:13:146:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:146:18:146:19 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:146:18:146:19 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:146:18:146:24 | call to method B1 : B | semmle.label | call to method B1 : B | +| extensions.cs:146:18:146:24 | call to method B1 : B | semmle.label | call to method B1 : B | +| extensions.cs:147:14:147:15 | access to local variable b2 | semmle.label | access to local variable b2 | +| extensions.cs:147:14:147:15 | access to local variable b2 | semmle.label | access to local variable b2 | +| extensions.cs:149:13:149:14 | access to local variable b3 : B | semmle.label | access to local variable b3 : B | +| extensions.cs:149:13:149:14 | access to local variable b3 : B | semmle.label | access to local variable b3 : B | +| extensions.cs:149:18:149:36 | call to method B1 : B | semmle.label | call to method B1 : B | +| extensions.cs:149:18:149:36 | call to method B1 : B | semmle.label | call to method B1 : B | +| extensions.cs:149:34:149:35 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:149:34:149:35 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:150:14:150:15 | access to local variable b3 | semmle.label | access to local variable b3 | +| extensions.cs:150:14:150:15 | access to local variable b3 | semmle.label | access to local variable b3 | +| extensions.cs:155:13:155:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:155:13:155:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:155:18:155:29 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:155:18:155:29 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:156:18:156:19 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:156:18:156:19 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:158:13:158:14 | access to local variable b3 : B | semmle.label | access to local variable b3 : B | +| extensions.cs:158:13:158:14 | access to local variable b3 : B | semmle.label | access to local variable b3 : B | +| extensions.cs:158:18:158:31 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:158:18:158:31 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:159:41:159:42 | access to local variable b3 : B | semmle.label | access to local variable b3 : B | +| extensions.cs:159:41:159:42 | access to local variable b3 : B | semmle.label | access to local variable b3 : B | +| extensions.cs:164:13:164:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:164:13:164:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:164:18:164:29 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:164:18:164:29 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:165:9:165:10 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:165:9:165:10 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:167:13:167:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:167:13:167:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:167:18:167:31 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:167:18:167:31 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:168:32:168:33 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:168:32:168:33 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:173:13:173:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:173:13:173:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:173:18:173:29 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:173:18:173:29 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:175:18:175:19 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:175:18:175:19 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:177:13:177:14 | access to local variable b4 : B | semmle.label | access to local variable b4 : B | +| extensions.cs:177:13:177:14 | access to local variable b4 : B | semmle.label | access to local variable b4 : B | +| extensions.cs:177:18:177:31 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:177:18:177:31 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:178:43:178:44 | access to local variable b4 : B | semmle.label | access to local variable b4 : B | +| extensions.cs:178:43:178:44 | access to local variable b4 : B | semmle.label | access to local variable b4 : B | +| extensions.cs:185:13:185:14 | access to local variable b3 : B | semmle.label | access to local variable b3 : B | +| extensions.cs:185:13:185:14 | access to local variable b3 : B | semmle.label | access to local variable b3 : B | +| extensions.cs:185:18:185:24 | call to operator - : B | semmle.label | call to operator - : B | +| extensions.cs:185:18:185:24 | call to operator - : B | semmle.label | call to operator - : B | +| extensions.cs:186:14:186:15 | access to local variable b3 | semmle.label | access to local variable b3 | +| extensions.cs:186:14:186:15 | access to local variable b3 | semmle.label | access to local variable b3 | +| extensions.cs:188:13:188:14 | access to local variable b4 : B | semmle.label | access to local variable b4 : B | +| extensions.cs:188:13:188:14 | access to local variable b4 : B | semmle.label | access to local variable b4 : B | +| extensions.cs:188:18:188:52 | call to operator - : B | semmle.label | call to operator - : B | +| extensions.cs:188:18:188:52 | call to operator - : B | semmle.label | call to operator - : B | +| extensions.cs:189:14:189:15 | access to local variable b4 | semmle.label | access to local variable b4 | +| extensions.cs:189:14:189:15 | access to local variable b4 | semmle.label | access to local variable b4 | +| extensions.cs:194:13:194:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:194:13:194:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:194:18:194:35 | access to property StaticProp1 : B | semmle.label | access to property StaticProp1 : B | +| extensions.cs:194:18:194:35 | access to property StaticProp1 : B | semmle.label | access to property StaticProp1 : B | +| extensions.cs:195:14:195:15 | access to local variable b1 | semmle.label | access to local variable b1 | +| extensions.cs:195:14:195:15 | access to local variable b1 | semmle.label | access to local variable b1 | +| extensions.cs:197:13:197:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:197:13:197:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:197:18:197:47 | call to extension accessor get_StaticProp1 : B | semmle.label | call to extension accessor get_StaticProp1 : B | +| extensions.cs:197:18:197:47 | call to extension accessor get_StaticProp1 : B | semmle.label | call to extension accessor get_StaticProp1 : B | +| extensions.cs:198:14:198:15 | access to local variable b2 | semmle.label | access to local variable b2 | +| extensions.cs:198:14:198:15 | access to local variable b2 | semmle.label | access to local variable b2 | +| extensions.cs:203:13:203:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:203:13:203:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:203:18:203:30 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:203:18:203:30 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:204:30:204:31 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:204:30:204:31 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:206:13:206:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:206:13:206:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:206:18:206:31 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:206:18:206:31 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:207:38:207:39 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:207:38:207:39 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:212:13:212:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:212:13:212:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:212:18:212:30 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:212:18:212:30 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:213:9:213:10 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:213:9:213:10 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:215:13:215:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:215:13:215:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:215:18:215:31 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:215:18:215:31 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:216:25:216:26 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:216:25:216:26 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:221:13:221:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:221:13:221:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:221:18:221:30 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:221:18:221:30 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:222:9:222:10 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:222:9:222:10 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:224:13:224:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:224:13:224:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:224:18:224:31 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:224:18:224:31 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:225:32:225:33 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:225:32:225:33 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:231:13:231:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:231:13:231:14 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:231:18:231:30 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:231:18:231:30 | call to method Source : B | semmle.label | call to method Source : B | +| extensions.cs:232:13:232:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:232:13:232:14 | access to local variable b2 : B | semmle.label | access to local variable b2 : B | +| extensions.cs:232:18:232:34 | call to method GenericM2 : B | semmle.label | call to method GenericM2 : B | +| extensions.cs:232:18:232:34 | call to method GenericM2 : B | semmle.label | call to method GenericM2 : B | +| extensions.cs:232:32:232:33 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:232:32:232:33 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:233:14:233:15 | access to local variable b2 | semmle.label | access to local variable b2 | +| extensions.cs:233:14:233:15 | access to local variable b2 | semmle.label | access to local variable b2 | +| extensions.cs:235:13:235:14 | access to local variable b3 : B | semmle.label | access to local variable b3 : B | +| extensions.cs:235:13:235:14 | access to local variable b3 : B | semmle.label | access to local variable b3 : B | +| extensions.cs:235:18:235:48 | call to method GenericM2 : B | semmle.label | call to method GenericM2 : B | +| extensions.cs:235:18:235:48 | call to method GenericM2 : B | semmle.label | call to method GenericM2 : B | +| extensions.cs:235:46:235:47 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:235:46:235:47 | access to local variable b1 : B | semmle.label | access to local variable b1 : B | +| extensions.cs:236:14:236:15 | access to local variable b3 | semmle.label | access to local variable b3 | +| extensions.cs:236:14:236:15 | access to local variable b3 | semmle.label | access to local variable b3 | +subpaths +| extensions.cs:146:18:146:19 | access to local variable b1 : B | extensions.cs:76:17:76:17 | b : B | extensions.cs:80:20:80:20 | access to synthetic parameter b : B | extensions.cs:146:18:146:24 | call to method B1 : B | +| extensions.cs:146:18:146:19 | access to local variable b1 : B | extensions.cs:76:17:76:17 | b : B | extensions.cs:80:20:80:20 | access to synthetic parameter b : B | extensions.cs:146:18:146:24 | call to method B1 : B | +| extensions.cs:149:34:149:35 | access to local variable b1 : B | extensions.cs:76:17:76:17 | b : B | extensions.cs:80:20:80:20 | access to synthetic parameter b : B | extensions.cs:149:18:149:36 | call to method B1 : B | +| extensions.cs:149:34:149:35 | access to local variable b1 : B | extensions.cs:76:17:76:17 | b : B | extensions.cs:80:20:80:20 | access to synthetic parameter b : B | extensions.cs:149:18:149:36 | call to method B1 : B | +| extensions.cs:232:32:232:33 | access to local variable b1 : B | extensions.cs:96:33:96:37 | other : B | extensions.cs:98:20:98:24 | access to parameter other : B | extensions.cs:232:18:232:34 | call to method GenericM2 : B | +| extensions.cs:232:32:232:33 | access to local variable b1 : B | extensions.cs:96:33:96:37 | other : B | extensions.cs:98:20:98:24 | access to parameter other : B | extensions.cs:232:18:232:34 | call to method GenericM2 : B | +| extensions.cs:235:46:235:47 | access to local variable b1 : B | extensions.cs:96:33:96:37 | other : B | extensions.cs:98:20:98:24 | access to parameter other : B | extensions.cs:235:18:235:48 | call to method GenericM2 : B | +| extensions.cs:235:46:235:47 | access to local variable b1 : B | extensions.cs:96:33:96:37 | other : B | extensions.cs:98:20:98:24 | access to parameter other : B | extensions.cs:235:18:235:48 | call to method GenericM2 : B | +testFailures +#select +| extensions.cs:15:24:15:28 | access to parameter value | extensions.cs:118:21:118:32 | call to method Source : B | extensions.cs:15:24:15:28 | access to parameter value | $@ | extensions.cs:118:21:118:32 | call to method Source : B | call to method Source : B | +| extensions.cs:15:24:15:28 | access to parameter value | extensions.cs:118:21:118:32 | call to method Source : B | extensions.cs:15:24:15:28 | access to parameter value | $@ | extensions.cs:118:21:118:32 | call to method Source : B | call to method Source : B | +| extensions.cs:15:24:15:28 | access to parameter value | extensions.cs:120:17:120:30 | call to method Source : B | extensions.cs:15:24:15:28 | access to parameter value | $@ | extensions.cs:120:17:120:30 | call to method Source : B | call to method Source : B | +| extensions.cs:15:24:15:28 | access to parameter value | extensions.cs:120:17:120:30 | call to method Source : B | extensions.cs:15:24:15:28 | access to parameter value | $@ | extensions.cs:120:17:120:30 | call to method Source : B | call to method Source : B | +| extensions.cs:23:24:23:26 | access to synthetic parameter obj | extensions.cs:155:18:155:29 | call to method Source : B | extensions.cs:23:24:23:26 | access to synthetic parameter obj | $@ | extensions.cs:155:18:155:29 | call to method Source : B | call to method Source : B | +| extensions.cs:23:24:23:26 | access to synthetic parameter obj | extensions.cs:155:18:155:29 | call to method Source : B | extensions.cs:23:24:23:26 | access to synthetic parameter obj | $@ | extensions.cs:155:18:155:29 | call to method Source : B | call to method Source : B | +| extensions.cs:23:24:23:26 | access to synthetic parameter obj | extensions.cs:158:18:158:31 | call to method Source : B | extensions.cs:23:24:23:26 | access to synthetic parameter obj | $@ | extensions.cs:158:18:158:31 | call to method Source : B | call to method Source : B | +| extensions.cs:23:24:23:26 | access to synthetic parameter obj | extensions.cs:158:18:158:31 | call to method Source : B | extensions.cs:23:24:23:26 | access to synthetic parameter obj | $@ | extensions.cs:158:18:158:31 | call to method Source : B | call to method Source : B | +| extensions.cs:28:24:28:26 | access to synthetic parameter obj | extensions.cs:164:18:164:29 | call to method Source : B | extensions.cs:28:24:28:26 | access to synthetic parameter obj | $@ | extensions.cs:164:18:164:29 | call to method Source : B | call to method Source : B | +| extensions.cs:28:24:28:26 | access to synthetic parameter obj | extensions.cs:164:18:164:29 | call to method Source : B | extensions.cs:28:24:28:26 | access to synthetic parameter obj | $@ | extensions.cs:164:18:164:29 | call to method Source : B | call to method Source : B | +| extensions.cs:28:24:28:26 | access to synthetic parameter obj | extensions.cs:167:18:167:31 | call to method Source : B | extensions.cs:28:24:28:26 | access to synthetic parameter obj | $@ | extensions.cs:167:18:167:31 | call to method Source : B | call to method Source : B | +| extensions.cs:28:24:28:26 | access to synthetic parameter obj | extensions.cs:167:18:167:31 | call to method Source : B | extensions.cs:28:24:28:26 | access to synthetic parameter obj | $@ | extensions.cs:167:18:167:31 | call to method Source : B | call to method Source : B | +| extensions.cs:40:24:40:28 | access to parameter value | extensions.cs:203:18:203:30 | call to method Source : B | extensions.cs:40:24:40:28 | access to parameter value | $@ | extensions.cs:203:18:203:30 | call to method Source : B | call to method Source : B | +| extensions.cs:40:24:40:28 | access to parameter value | extensions.cs:203:18:203:30 | call to method Source : B | extensions.cs:40:24:40:28 | access to parameter value | $@ | extensions.cs:203:18:203:30 | call to method Source : B | call to method Source : B | +| extensions.cs:40:24:40:28 | access to parameter value | extensions.cs:206:18:206:31 | call to method Source : B | extensions.cs:40:24:40:28 | access to parameter value | $@ | extensions.cs:206:18:206:31 | call to method Source : B | call to method Source : B | +| extensions.cs:40:24:40:28 | access to parameter value | extensions.cs:206:18:206:31 | call to method Source : B | extensions.cs:40:24:40:28 | access to parameter value | $@ | extensions.cs:206:18:206:31 | call to method Source : B | call to method Source : B | +| extensions.cs:51:20:51:22 | access to synthetic parameter obj | extensions.cs:136:18:136:29 | call to method Source : B | extensions.cs:51:20:51:22 | access to synthetic parameter obj | $@ | extensions.cs:136:18:136:29 | call to method Source : B | call to method Source : B | +| extensions.cs:51:20:51:22 | access to synthetic parameter obj | extensions.cs:136:18:136:29 | call to method Source : B | extensions.cs:51:20:51:22 | access to synthetic parameter obj | $@ | extensions.cs:136:18:136:29 | call to method Source : B | call to method Source : B | +| extensions.cs:51:20:51:22 | access to synthetic parameter obj | extensions.cs:139:18:139:31 | call to method Source : B | extensions.cs:51:20:51:22 | access to synthetic parameter obj | $@ | extensions.cs:139:18:139:31 | call to method Source : B | call to method Source : B | +| extensions.cs:51:20:51:22 | access to synthetic parameter obj | extensions.cs:139:18:139:31 | call to method Source : B | extensions.cs:51:20:51:22 | access to synthetic parameter obj | $@ | extensions.cs:139:18:139:31 | call to method Source : B | call to method Source : B | +| extensions.cs:61:20:61:20 | access to parameter a | extensions.cs:173:18:173:29 | call to method Source : B | extensions.cs:61:20:61:20 | access to parameter a | $@ | extensions.cs:173:18:173:29 | call to method Source : B | call to method Source : B | +| extensions.cs:61:20:61:20 | access to parameter a | extensions.cs:173:18:173:29 | call to method Source : B | extensions.cs:61:20:61:20 | access to parameter a | $@ | extensions.cs:173:18:173:29 | call to method Source : B | call to method Source : B | +| extensions.cs:61:20:61:20 | access to parameter a | extensions.cs:177:18:177:31 | call to method Source : B | extensions.cs:61:20:61:20 | access to parameter a | $@ | extensions.cs:177:18:177:31 | call to method Source : B | call to method Source : B | +| extensions.cs:61:20:61:20 | access to parameter a | extensions.cs:177:18:177:31 | call to method Source : B | extensions.cs:61:20:61:20 | access to parameter a | $@ | extensions.cs:177:18:177:31 | call to method Source : B | call to method Source : B | +| extensions.cs:85:20:85:20 | access to synthetic parameter b | extensions.cs:212:18:212:30 | call to method Source : B | extensions.cs:85:20:85:20 | access to synthetic parameter b | $@ | extensions.cs:212:18:212:30 | call to method Source : B | call to method Source : B | +| extensions.cs:85:20:85:20 | access to synthetic parameter b | extensions.cs:212:18:212:30 | call to method Source : B | extensions.cs:85:20:85:20 | access to synthetic parameter b | $@ | extensions.cs:212:18:212:30 | call to method Source : B | call to method Source : B | +| extensions.cs:85:20:85:20 | access to synthetic parameter b | extensions.cs:215:18:215:31 | call to method Source : B | extensions.cs:85:20:85:20 | access to synthetic parameter b | $@ | extensions.cs:215:18:215:31 | call to method Source : B | call to method Source : B | +| extensions.cs:85:20:85:20 | access to synthetic parameter b | extensions.cs:215:18:215:31 | call to method Source : B | extensions.cs:85:20:85:20 | access to synthetic parameter b | $@ | extensions.cs:215:18:215:31 | call to method Source : B | call to method Source : B | +| extensions.cs:93:20:93:20 | access to synthetic parameter t | extensions.cs:221:18:221:30 | call to method Source : B | extensions.cs:93:20:93:20 | access to synthetic parameter t | $@ | extensions.cs:221:18:221:30 | call to method Source : B | call to method Source : B | +| extensions.cs:93:20:93:20 | access to synthetic parameter t | extensions.cs:221:18:221:30 | call to method Source : B | extensions.cs:93:20:93:20 | access to synthetic parameter t | $@ | extensions.cs:221:18:221:30 | call to method Source : B | call to method Source : B | +| extensions.cs:93:20:93:20 | access to synthetic parameter t | extensions.cs:224:18:224:31 | call to method Source : B | extensions.cs:93:20:93:20 | access to synthetic parameter t | $@ | extensions.cs:224:18:224:31 | call to method Source : B | call to method Source : B | +| extensions.cs:93:20:93:20 | access to synthetic parameter t | extensions.cs:224:18:224:31 | call to method Source : B | extensions.cs:93:20:93:20 | access to synthetic parameter t | $@ | extensions.cs:224:18:224:31 | call to method Source : B | call to method Source : B | +| extensions.cs:109:14:109:15 | access to local variable b1 | extensions.cs:11:24:11:37 | call to method Source : B | extensions.cs:109:14:109:15 | access to local variable b1 | $@ | extensions.cs:11:24:11:37 | call to method Source : B | call to method Source : B | +| extensions.cs:109:14:109:15 | access to local variable b1 | extensions.cs:11:24:11:37 | call to method Source : B | extensions.cs:109:14:109:15 | access to local variable b1 | $@ | extensions.cs:11:24:11:37 | call to method Source : B | call to method Source : B | +| extensions.cs:112:14:112:15 | access to local variable b2 | extensions.cs:11:24:11:37 | call to method Source : B | extensions.cs:112:14:112:15 | access to local variable b2 | $@ | extensions.cs:11:24:11:37 | call to method Source : B | call to method Source : B | +| extensions.cs:112:14:112:15 | access to local variable b2 | extensions.cs:11:24:11:37 | call to method Source : B | extensions.cs:112:14:112:15 | access to local variable b2 | $@ | extensions.cs:11:24:11:37 | call to method Source : B | call to method Source : B | +| extensions.cs:128:14:128:15 | access to local variable b1 | extensions.cs:46:20:46:33 | call to method Source : B | extensions.cs:128:14:128:15 | access to local variable b1 | $@ | extensions.cs:46:20:46:33 | call to method Source : B | call to method Source : B | +| extensions.cs:128:14:128:15 | access to local variable b1 | extensions.cs:46:20:46:33 | call to method Source : B | extensions.cs:128:14:128:15 | access to local variable b1 | $@ | extensions.cs:46:20:46:33 | call to method Source : B | call to method Source : B | +| extensions.cs:131:14:131:15 | access to local variable b2 | extensions.cs:46:20:46:33 | call to method Source : B | extensions.cs:131:14:131:15 | access to local variable b2 | $@ | extensions.cs:46:20:46:33 | call to method Source : B | call to method Source : B | +| extensions.cs:131:14:131:15 | access to local variable b2 | extensions.cs:46:20:46:33 | call to method Source : B | extensions.cs:131:14:131:15 | access to local variable b2 | $@ | extensions.cs:46:20:46:33 | call to method Source : B | call to method Source : B | +| extensions.cs:147:14:147:15 | access to local variable b2 | extensions.cs:145:18:145:29 | call to method Source : B | extensions.cs:147:14:147:15 | access to local variable b2 | $@ | extensions.cs:145:18:145:29 | call to method Source : B | call to method Source : B | +| extensions.cs:147:14:147:15 | access to local variable b2 | extensions.cs:145:18:145:29 | call to method Source : B | extensions.cs:147:14:147:15 | access to local variable b2 | $@ | extensions.cs:145:18:145:29 | call to method Source : B | call to method Source : B | +| extensions.cs:150:14:150:15 | access to local variable b3 | extensions.cs:145:18:145:29 | call to method Source : B | extensions.cs:150:14:150:15 | access to local variable b3 | $@ | extensions.cs:145:18:145:29 | call to method Source : B | call to method Source : B | +| extensions.cs:150:14:150:15 | access to local variable b3 | extensions.cs:145:18:145:29 | call to method Source : B | extensions.cs:150:14:150:15 | access to local variable b3 | $@ | extensions.cs:145:18:145:29 | call to method Source : B | call to method Source : B | +| extensions.cs:186:14:186:15 | access to local variable b3 | extensions.cs:67:20:67:33 | call to method Source : B | extensions.cs:186:14:186:15 | access to local variable b3 | $@ | extensions.cs:67:20:67:33 | call to method Source : B | call to method Source : B | +| extensions.cs:186:14:186:15 | access to local variable b3 | extensions.cs:67:20:67:33 | call to method Source : B | extensions.cs:186:14:186:15 | access to local variable b3 | $@ | extensions.cs:67:20:67:33 | call to method Source : B | call to method Source : B | +| extensions.cs:189:14:189:15 | access to local variable b4 | extensions.cs:67:20:67:33 | call to method Source : B | extensions.cs:189:14:189:15 | access to local variable b4 | $@ | extensions.cs:67:20:67:33 | call to method Source : B | call to method Source : B | +| extensions.cs:189:14:189:15 | access to local variable b4 | extensions.cs:67:20:67:33 | call to method Source : B | extensions.cs:189:14:189:15 | access to local variable b4 | $@ | extensions.cs:67:20:67:33 | call to method Source : B | call to method Source : B | +| extensions.cs:195:14:195:15 | access to local variable b1 | extensions.cs:36:24:36:38 | call to method Source : B | extensions.cs:195:14:195:15 | access to local variable b1 | $@ | extensions.cs:36:24:36:38 | call to method Source : B | call to method Source : B | +| extensions.cs:195:14:195:15 | access to local variable b1 | extensions.cs:36:24:36:38 | call to method Source : B | extensions.cs:195:14:195:15 | access to local variable b1 | $@ | extensions.cs:36:24:36:38 | call to method Source : B | call to method Source : B | +| extensions.cs:198:14:198:15 | access to local variable b2 | extensions.cs:36:24:36:38 | call to method Source : B | extensions.cs:198:14:198:15 | access to local variable b2 | $@ | extensions.cs:36:24:36:38 | call to method Source : B | call to method Source : B | +| extensions.cs:198:14:198:15 | access to local variable b2 | extensions.cs:36:24:36:38 | call to method Source : B | extensions.cs:198:14:198:15 | access to local variable b2 | $@ | extensions.cs:36:24:36:38 | call to method Source : B | call to method Source : B | +| extensions.cs:233:14:233:15 | access to local variable b2 | extensions.cs:231:18:231:30 | call to method Source : B | extensions.cs:233:14:233:15 | access to local variable b2 | $@ | extensions.cs:231:18:231:30 | call to method Source : B | call to method Source : B | +| extensions.cs:233:14:233:15 | access to local variable b2 | extensions.cs:231:18:231:30 | call to method Source : B | extensions.cs:233:14:233:15 | access to local variable b2 | $@ | extensions.cs:231:18:231:30 | call to method Source : B | call to method Source : B | +| extensions.cs:236:14:236:15 | access to local variable b3 | extensions.cs:231:18:231:30 | call to method Source : B | extensions.cs:236:14:236:15 | access to local variable b3 | $@ | extensions.cs:231:18:231:30 | call to method Source : B | call to method Source : B | +| extensions.cs:236:14:236:15 | access to local variable b3 | extensions.cs:231:18:231:30 | call to method Source : B | extensions.cs:236:14:236:15 | access to local variable b3 | $@ | extensions.cs:231:18:231:30 | call to method Source : B | call to method Source : B | diff --git a/csharp/ql/test/library-tests/dataflow/extensions/ExtensionFlow.ql b/csharp/ql/test/library-tests/dataflow/extensions/ExtensionFlow.ql new file mode 100644 index 000000000000..9ab95f59caf3 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/extensions/ExtensionFlow.ql @@ -0,0 +1,12 @@ +/** + * @kind path-problem + */ + +import csharp +import utils.test.InlineFlowTest +import DefaultFlowTest +import PathGraph + +from PathNode source, PathNode sink +where flowPath(source, sink) +select sink, source, sink, "$@", source, source.toString() diff --git a/csharp/ql/test/library-tests/dataflow/extensions/extensions.cs b/csharp/ql/test/library-tests/dataflow/extensions/extensions.cs new file mode 100644 index 000000000000..0e1c2226683d --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/extensions/extensions.cs @@ -0,0 +1,243 @@ +using System; + +public static class MyExtensions +{ + extension(object obj) + { + public B Prop1 + { + get + { + return A.Source(1); + } + set + { + A.Sink(value); // $ hasValueFlow=2 hasValueFlow=102 + } + } + + public B Prop2 + { + get + { + A.Sink(obj); // $ hasValueFlow=6 hasValueFlow=106 + return new B(); + } + set + { + A.Sink(obj); // $ hasValueFlow=7 hasValueFlow=107 + } + } + + public static B StaticProp1 + { + get + { + return A.Source(10); + } + set + { + A.Sink(value); // $ hasValueFlow=11 hasValueFlow=111 + } + } + + public B M1() + { + return A.Source(3); + } + + public void M2() + { + A.Sink(obj); // $ hasValueFlow=4 hasValueFlow=104 + } + + public static B M3(B b) + { + return b; + } + + public static object operator +(object a, object b) + { + A.Sink(a); // $ hasValueFlow=8 hasValueFlow=108 + return new object(); + } + + public static object operator -(object a, object b) + { + return A.Source(9); + } + + public T GenericMethod(T t) + { + return t; + } + } + + extension(B b) + { + public B B1() + { + return b; + } + + public void B2() + { + A.Sink(b); // $ hasValueFlow=12 hasValueFlow=112 + } + } + + extension(T t) where T : class + { + public void GenericM1() + { + A.Sink(t); // $ hasValueFlow=13 hasValueFlow=113 + } + + public S GenericM2(S other) + { + return other; + } + } +} + +public class A +{ + public void Test1() + { + var obj = new object(); + var b1 = obj.Prop1; + Sink(b1); // $ hasValueFlow=1 + + var b2 = MyExtensions.get_Prop1(obj); + Sink(b2); // $ hasValueFlow=1 + } + + public void Test2() + { + var obj = new object(); + obj.Prop1 = Source(2); + + var b = Source(102); + MyExtensions.set_Prop1(obj, b); + } + + public void Test3() + { + var obj = new object(); + var b1 = obj.M1(); + Sink(b1); // $ hasValueFlow=3 + + var b2 = MyExtensions.M1(obj); + Sink(b2); // $ hasValueFlow=3 + } + + public void Test4() + { + var b1 = Source(4); + b1.M2(); + + var b2 = Source(104); + MyExtensions.M2(b2); + } + + public void Test5() + { + var b1 = Source(5); + var b2 = b1.B1(); + Sink(b2); // $ hasValueFlow=5 + + var b3 = MyExtensions.B1(b1); + Sink(b3); // $ hasValueFlow=5 + } + + public void Test6() + { + var b1 = Source(6); + var b2 = b1.Prop2; + + var b3 = Source(106); + var b4 = MyExtensions.get_Prop2(b3); + } + + public void Test7() + { + var b1 = Source(7); + b1.Prop2 = new B(); + + var b2 = Source(107); + MyExtensions.set_Prop2(b2, new B()); + } + + public void Test8() + { + var b1 = Source(8); + var b2 = Source(1); + var b3 = b1 + b2; + + var b4 = Source(108); + var b5 = MyExtensions.op_Addition(b4, b2); + } + + public void Test9() + { + var b1 = Source(0); + var b2 = Source(1); + var b3 = b1 - b2; + Sink(b3); // $ hasValueFlow=9 + + var b4 = MyExtensions.op_Subtraction(b1, b2); + Sink(b4); // $ hasValueFlow=9 + } + + public void Test10() + { + var b1 = object.StaticProp1; + Sink(b1); // $ hasValueFlow=10 + + var b2 = MyExtensions.get_StaticProp1(); + Sink(b2); // $ hasValueFlow=10 + } + + public void Test11() + { + var b1 = Source(11); + object.StaticProp1 = b1; + + var b2 = Source(111); + MyExtensions.set_StaticProp1(b2); + } + + public void Test12() + { + var b1 = Source(12); + b1.B2(); + + var b2 = Source(112); + MyExtensions.B2(b2); + } + + public void Test13() + { + var b1 = Source(13); + b1.GenericM1(); + + var b2 = Source(113); + MyExtensions.GenericM1(b2); + } + + public void Test14() + { + var obj = new object(); + var b1 = Source(14); + var b2 = obj.GenericM2(b1); + Sink(b2); // $ hasValueFlow=14 + + var b3 = MyExtensions.GenericM2(obj, b1); + Sink(b3); // $ hasValueFlow=14 + } + + public static T Source(object source) => throw null; + public static void Sink(object o) { } +} + +public class B { } diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs index e28b8fdfcc92..1fa43ba456e5 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs @@ -348,4 +348,98 @@ public void M1() static void Sink(object o) { } } + // Test extensions + public static class TestExtensions + { + extension(object o) + { + public object Method1() => throw null; + public static object StaticMethod1(object s) => throw null; + public object Property1 { get { throw null; } set { throw null; } } + } + + extension(T t) where T : class + { + public T GenericMethod1() => throw null; + public static T GenericStaticMethod1(T t0) => throw null; + public T GenericProperty1 { get { throw null; } set { throw null; } } + } + } + + public class M + { + public void M1() + { + var obj = new object(); + var o1 = obj.Method1(); + Sink(o1); + + var o2 = TestExtensions.Method1(obj); + Sink(o2); + } + + public void M2() + { + var obj = new object(); + var o1 = object.StaticMethod1(obj); + Sink(o1); + + var o2 = TestExtensions.StaticMethod1(obj); + Sink(o2); + } + + public void M3(object o) + { + var obj = new object(); + o.Property1 = obj; + var o1 = o.Property1; + Sink(o1); + } + + public void M4(object o) + { + var obj = new object(); + TestExtensions.set_Property1(o, obj); + var o1 = TestExtensions.get_Property1(o); + Sink(o1); + } + + public void M5() + { + var obj = new object(); + var o1 = obj.GenericMethod1(); + Sink(o1); + + var o2 = TestExtensions.GenericMethod1(obj); + Sink(o2); + } + + public void M6() + { + var obj = new object(); + var o1 = object.GenericStaticMethod1(obj); + Sink(o1); + + var o2 = TestExtensions.GenericStaticMethod1(obj); + Sink(o2); + } + + public void M7(object o) + { + var obj = new object(); + o.GenericProperty1 = obj; + var o1 = o.GenericProperty1; + Sink(o1); + } + + public void M8(object o) + { + var obj = new object(); + TestExtensions.set_GenericProperty1(o, obj); + var o1 = TestExtensions.get_GenericProperty1(o); + Sink(o1); + } + + static void Sink(object o) { } + } } diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected index 3099a3fec7e6..b5c0dd3b59c9 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected @@ -32,6 +32,14 @@ models | 31 | Summary: My.Qltest; Library; false; GetValue; (); ; Argument[this].SyntheticField[X]; ReturnValue; value; dfc-generated | | 32 | Summary: My.Qltest; Library; false; MixedFlowArgs; (System.Object,System.Object); ; Argument[1]; ReturnValue; value; manual | | 33 | Summary: My.Qltest; Library; false; SetValue; (System.Object); ; Argument[0]; Argument[this].SyntheticField[X]; value; dfc-generated | +| 34 | Summary: My.Qltest; TestExtensions+extension(Object); false; Method1; (System.Object); ; Argument[0]; ReturnValue; value; manual | +| 35 | Summary: My.Qltest; TestExtensions+extension(Object); false; StaticMethod1; (System.Object); ; Argument[0]; ReturnValue; value; manual | +| 36 | Summary: My.Qltest; TestExtensions+extension(Object); false; get_Property1; (System.Object); ; Argument[0].SyntheticField[TestExtensions.Property1]; ReturnValue; value; manual | +| 37 | Summary: My.Qltest; TestExtensions+extension(Object); false; set_Property1; (System.Object,System.Object); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.Property1]; value; manual | +| 38 | Summary: My.Qltest; TestExtensions+extension(T); false; GenericMethod1; (T); ; Argument[0]; ReturnValue; value; manual | +| 39 | Summary: My.Qltest; TestExtensions+extension(T); false; GenericStaticMethod1; (T); ; Argument[0]; ReturnValue; value; manual | +| 40 | Summary: My.Qltest; TestExtensions+extension(T); false; get_GenericProperty1; (T); ; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; ReturnValue; value; manual | +| 41 | Summary: My.Qltest; TestExtensions+extension(T); false; set_GenericProperty1; (T,T); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; value; manual | edges | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | ExternalFlow.cs:10:29:10:32 | access to local variable arg1 : Object | provenance | | | ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | provenance | | @@ -150,6 +158,73 @@ edges | ExternalFlow.cs:344:13:344:13 | [post] access to local variable l : Library [synthetic X] : Object | ExternalFlow.cs:345:18:345:18 | access to local variable l : Library [synthetic X] : Object | provenance | | | ExternalFlow.cs:344:24:344:24 | access to local variable o : Object | ExternalFlow.cs:344:13:344:13 | [post] access to local variable l : Library [synthetic X] : Object | provenance | MaD:33 | | ExternalFlow.cs:345:18:345:18 | access to local variable l : Library [synthetic X] : Object | ExternalFlow.cs:345:18:345:29 | call to method GetValue | provenance | MaD:31 | +| ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | ExternalFlow.cs:374:22:374:24 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:373:23:373:34 | object creation of type Object : Object | ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | ExternalFlow.cs:375:18:375:19 | access to local variable o1 | provenance | | +| ExternalFlow.cs:374:22:374:24 | access to local variable obj : Object | ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | provenance | MaD:34 | +| ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | provenance | | +| ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | ExternalFlow.cs:378:18:378:19 | access to local variable o2 | provenance | | +| ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | provenance | | +| ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | provenance | MaD:34 | +| ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:383:23:383:34 | object creation of type Object : Object | ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | ExternalFlow.cs:385:18:385:19 | access to local variable o1 | provenance | | +| ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | provenance | | +| ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | provenance | MaD:35 | +| ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | ExternalFlow.cs:388:18:388:19 | access to local variable o2 | provenance | | +| ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | provenance | | +| ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | provenance | MaD:35 | +| ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:393:23:393:34 | object creation of type Object : Object | ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | | +| ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:37 | +| ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | ExternalFlow.cs:396:18:396:19 | access to local variable o1 | provenance | | +| ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | provenance | MaD:36 | +| ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | provenance | | +| ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:401:23:401:34 | object creation of type Object : Object | ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | | +| ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:37 | +| ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | ExternalFlow.cs:404:18:404:19 | access to local variable o1 | provenance | | +| ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | provenance | | +| ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | provenance | MaD:36 | +| ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:409:23:409:34 | object creation of type Object : Object | ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | ExternalFlow.cs:411:18:411:19 | access to local variable o1 | provenance | | +| ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | provenance | MaD:38 | +| ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | provenance | | +| ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | ExternalFlow.cs:414:18:414:19 | access to local variable o2 | provenance | | +| ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | provenance | | +| ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | provenance | MaD:38 | +| ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | ExternalFlow.cs:421:18:421:19 | access to local variable o1 | provenance | | +| ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | provenance | | +| ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | provenance | MaD:39 | +| ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | provenance | | +| ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | provenance | | +| ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | provenance | MaD:39 | +| ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | provenance | | +| ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | | +| ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | provenance | | +| ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:41 | +| ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | provenance | | +| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | | +| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | MaD:40 | +| ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | provenance | | +| ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | provenance | | +| ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | | +| ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:41 | +| ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | provenance | | +| ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | provenance | | +| ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | provenance | MaD:40 | nodes | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | semmle.label | access to local variable arg1 : Object | | ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | @@ -294,6 +369,80 @@ nodes | ExternalFlow.cs:344:24:344:24 | access to local variable o : Object | semmle.label | access to local variable o : Object | | ExternalFlow.cs:345:18:345:18 | access to local variable l : Library [synthetic X] : Object | semmle.label | access to local variable l : Library [synthetic X] : Object | | ExternalFlow.cs:345:18:345:29 | call to method GetValue | semmle.label | call to method GetValue | +| ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:373:23:373:34 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | +| ExternalFlow.cs:374:22:374:24 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | semmle.label | call to method Method1 : Object | +| ExternalFlow.cs:375:18:375:19 | access to local variable o1 | semmle.label | access to local variable o1 | +| ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | +| ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | semmle.label | call to method Method1 : Object | +| ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:378:18:378:19 | access to local variable o2 | semmle.label | access to local variable o2 | +| ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:383:23:383:34 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | +| ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | semmle.label | call to method StaticMethod1 : Object | +| ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:385:18:385:19 | access to local variable o1 | semmle.label | access to local variable o1 | +| ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | +| ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | semmle.label | call to method StaticMethod1 : Object | +| ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:388:18:388:19 | access to local variable o2 | semmle.label | access to local variable o2 | +| ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:393:23:393:34 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | semmle.label | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | +| ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | +| ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | semmle.label | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | +| ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | semmle.label | access to property Property1 : Object | +| ExternalFlow.cs:396:18:396:19 | access to local variable o1 | semmle.label | access to local variable o1 | +| ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:401:23:401:34 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | semmle.label | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | +| ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | +| ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | semmle.label | call to extension accessor get_Property1 : Object | +| ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | semmle.label | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | +| ExternalFlow.cs:404:18:404:19 | access to local variable o1 | semmle.label | access to local variable o1 | +| ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:409:23:409:34 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | +| ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | semmle.label | call to method GenericMethod1 : Object | +| ExternalFlow.cs:411:18:411:19 | access to local variable o1 | semmle.label | access to local variable o1 | +| ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | +| ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | semmle.label | call to method GenericMethod1 : Object | +| ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:414:18:414:19 | access to local variable o2 | semmle.label | access to local variable o2 | +| ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | +| ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | semmle.label | call to method GenericStaticMethod1 : Object | +| ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:421:18:421:19 | access to local variable o1 | semmle.label | access to local variable o1 | +| ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | +| ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | semmle.label | call to method GenericStaticMethod1 : Object | +| ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:424:18:424:19 | access to local variable o2 | semmle.label | access to local variable o2 | +| ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | semmle.label | [post] access to parameter o : Object [property GenericProperty1] : Object | +| ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | semmle.label | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | +| ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | +| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | semmle.label | access to parameter o : Object [property GenericProperty1] : Object | +| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | semmle.label | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | +| ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | semmle.label | access to property GenericProperty1 : Object | +| ExternalFlow.cs:432:18:432:19 | access to local variable o1 | semmle.label | access to local variable o1 | +| ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | semmle.label | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | +| ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | semmle.label | access to local variable obj : Object | +| ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | +| ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | semmle.label | call to extension accessor get_GenericProperty1 : Object | +| ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | semmle.label | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | +| ExternalFlow.cs:440:18:440:19 | access to local variable o1 | semmle.label | access to local variable o1 | subpaths | ExternalFlow.cs:84:29:84:32 | access to local variable objs : null [element] : Object | ExternalFlow.cs:84:35:84:35 | o : Object | ExternalFlow.cs:84:40:84:40 | access to parameter o : Object | ExternalFlow.cs:84:25:84:41 | call to method Map : T[] [element] : Object | invalidModelRow @@ -328,3 +477,15 @@ invalidModelRow | ExternalFlow.cs:324:18:324:44 | call to method GetMyNestedSyntheticField | ExternalFlow.cs:322:21:322:32 | object creation of type Object : Object | ExternalFlow.cs:324:18:324:44 | call to method GetMyNestedSyntheticField | $@ | ExternalFlow.cs:322:21:322:32 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:331:18:331:45 | call to method GetMyFieldOnSyntheticField | ExternalFlow.cs:329:21:329:32 | object creation of type Object : Object | ExternalFlow.cs:331:18:331:45 | call to method GetMyFieldOnSyntheticField | $@ | ExternalFlow.cs:329:21:329:32 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:345:18:345:29 | call to method GetValue | ExternalFlow.cs:343:21:343:32 | object creation of type Object : Object | ExternalFlow.cs:345:18:345:29 | call to method GetValue | $@ | ExternalFlow.cs:343:21:343:32 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:375:18:375:19 | access to local variable o1 | ExternalFlow.cs:373:23:373:34 | object creation of type Object : Object | ExternalFlow.cs:375:18:375:19 | access to local variable o1 | $@ | ExternalFlow.cs:373:23:373:34 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:378:18:378:19 | access to local variable o2 | ExternalFlow.cs:373:23:373:34 | object creation of type Object : Object | ExternalFlow.cs:378:18:378:19 | access to local variable o2 | $@ | ExternalFlow.cs:373:23:373:34 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:385:18:385:19 | access to local variable o1 | ExternalFlow.cs:383:23:383:34 | object creation of type Object : Object | ExternalFlow.cs:385:18:385:19 | access to local variable o1 | $@ | ExternalFlow.cs:383:23:383:34 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:388:18:388:19 | access to local variable o2 | ExternalFlow.cs:383:23:383:34 | object creation of type Object : Object | ExternalFlow.cs:388:18:388:19 | access to local variable o2 | $@ | ExternalFlow.cs:383:23:383:34 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:396:18:396:19 | access to local variable o1 | ExternalFlow.cs:393:23:393:34 | object creation of type Object : Object | ExternalFlow.cs:396:18:396:19 | access to local variable o1 | $@ | ExternalFlow.cs:393:23:393:34 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:404:18:404:19 | access to local variable o1 | ExternalFlow.cs:401:23:401:34 | object creation of type Object : Object | ExternalFlow.cs:404:18:404:19 | access to local variable o1 | $@ | ExternalFlow.cs:401:23:401:34 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:411:18:411:19 | access to local variable o1 | ExternalFlow.cs:409:23:409:34 | object creation of type Object : Object | ExternalFlow.cs:411:18:411:19 | access to local variable o1 | $@ | ExternalFlow.cs:409:23:409:34 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:414:18:414:19 | access to local variable o2 | ExternalFlow.cs:409:23:409:34 | object creation of type Object : Object | ExternalFlow.cs:414:18:414:19 | access to local variable o2 | $@ | ExternalFlow.cs:409:23:409:34 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:421:18:421:19 | access to local variable o1 | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:421:18:421:19 | access to local variable o1 | $@ | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:424:18:424:19 | access to local variable o2 | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | $@ | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:432:18:432:19 | access to local variable o1 | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | $@ | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:440:18:440:19 | access to local variable o1 | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | $@ | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | object creation of type Object : Object | diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml index a582a581cf12..3a4d5bcd91b8 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml +++ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml @@ -45,6 +45,14 @@ extensions: - ["My.Qltest", "K", false, "GetMyFieldOnSyntheticField", "()", "", "Argument[this].SyntheticField[My.Qltest.K.MySyntheticField2].Field[My.Qltest.K.MyField]", "ReturnValue", "value", "manual"] - ["My.Qltest", "Library", false, "SetValue", "(System.Object)", "", "Argument[0]", "Argument[this].SyntheticField[X]", "value", "dfc-generated"] - ["My.Qltest", "Library", false, "GetValue", "()", "", "Argument[this].SyntheticField[X]", "ReturnValue", "value", "dfc-generated"] + - ["My.Qltest", "TestExtensions+extension(Object)", false, "Method1", "(System.Object)", "", "Argument[0]", "ReturnValue", "value", "manual"] + - ["My.Qltest", "TestExtensions+extension(Object)", false, "StaticMethod1", "(System.Object)", "", "Argument[0]", "ReturnValue", "value", "manual"] + - ["My.Qltest", "TestExtensions+extension(Object)", false, "get_Property1", "(System.Object)", "", "Argument[0].SyntheticField[TestExtensions.Property1]", "ReturnValue", "value", "manual"] + - ["My.Qltest", "TestExtensions+extension(Object)", false, "set_Property1", "(System.Object,System.Object)", "", "Argument[1]", "Argument[0].SyntheticField[TestExtensions.Property1]", "value", "manual"] + - ["My.Qltest", "TestExtensions+extension(T)", false, "GenericMethod1", "(T)", "", "Argument[0]", "ReturnValue", "value", "manual"] + - ["My.Qltest", "TestExtensions+extension(T)", false, "GenericStaticMethod1", "(T)", "", "Argument[0]", "ReturnValue", "value", "manual"] + - ["My.Qltest", "TestExtensions+extension(T)", false, "get_GenericProperty1", "(T)", "", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "ReturnValue", "value", "manual"] + - ["My.Qltest", "TestExtensions+extension(T)", false, "set_GenericProperty1", "(T,T)", "", "Argument[1]", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "value", "manual"] - addsTo: pack: codeql/csharp-all diff --git a/csharp/ql/test/library-tests/extension/PrintAst.expected b/csharp/ql/test/library-tests/extension/PrintAst.expected new file mode 100644 index 000000000000..962c7c9b1583 --- /dev/null +++ b/csharp/ql/test/library-tests/extension/PrintAst.expected @@ -0,0 +1,404 @@ +extensions.cs: +# 4| [Class] MyExtensions +# 6| 4: [ExtensionType] extension(String) +#-----| 2: (Parameters) +# 6| 0: [Parameter] s +# 6| -1: [TypeMention] string +# 8| 4: [Property] Prop1 +# 8| -1: [TypeMention] bool +# 8| 3: [ExtensionCallable,Getter] get_Prop1 +#-----| 2: (Parameters) +# 6| 0: [Parameter] s +# 6| -1: [TypeMention] string +# 8| 4: [GTExpr] ... > ... +# 8| 0: [PropertyCall] access to property Length +# 8| -1: [SyntheticParameterAccess] access to synthetic parameter s +# 8| 1: [IntLiteral] 0 +# 9| 5: [Property] Prop2 +# 9| -1: [TypeMention] bool +# 9| 3: [ExtensionCallable,Getter] get_Prop2 +#-----| 2: (Parameters) +# 6| 0: [Parameter] s +# 6| -1: [TypeMention] string +# 9| 4: [BlockStmt] {...} +# 9| 0: [ReturnStmt] return ...; +# 9| 0: [BoolLiteral] true +# 9| 4: [ExtensionCallable,Setter] set_Prop2 +#-----| 2: (Parameters) +# 6| 0: [Parameter] s +# 6| -1: [TypeMention] string +# 9| 1: [Parameter] value +# 9| 4: [BlockStmt] {...} +# 10| 6: [Property] StaticProp1 +# 10| -1: [TypeMention] bool +# 10| 3: [ExtensionCallable,Getter] get_StaticProp1 +# 10| 4: [BlockStmt] {...} +# 10| 0: [ReturnStmt] return ...; +# 10| 0: [BoolLiteral] false +# 11| 7: [ExtensionMethod] M1 +# 11| -1: [TypeMention] bool +#-----| 2: (Parameters) +# 6| 0: [Parameter] s +# 6| -1: [TypeMention] string +# 11| 4: [IsExpr] ... is ... +# 11| 0: [SyntheticParameterAccess] access to synthetic parameter s +# 11| 1: [NotPatternExpr] not ... +# 11| 0: [ConstantPatternExpr,NullLiteral] null +# 12| 8: [ExtensionMethod] M2 +# 12| -1: [TypeMention] string +#-----| 2: (Parameters) +# 6| 0: [Parameter] s +# 6| -1: [TypeMention] string +# 12| 1: [Parameter] other +# 12| -1: [TypeMention] string +# 12| 4: [BlockStmt] {...} +# 12| 0: [ReturnStmt] return ...; +# 12| 0: [AddExpr] ... + ... +# 12| 0: [SyntheticParameterAccess] access to synthetic parameter s +# 12| 1: [ParameterAccess] access to parameter other +# 13| 9: [ExtensionMethod] StaticM1 +# 13| -1: [TypeMention] int +# 13| 4: [BlockStmt] {...} +# 13| 0: [ReturnStmt] return ...; +# 13| 0: [IntLiteral] 0 +# 14| 10: [ExtensionMethod] StaticM2 +# 14| -1: [TypeMention] int +#-----| 2: (Parameters) +# 14| 0: [Parameter] x +# 14| -1: [TypeMention] string +# 14| 4: [BlockStmt] {...} +# 14| 0: [ReturnStmt] return ...; +# 14| 0: [PropertyCall] access to property Length +# 14| -1: [ParameterAccess] access to parameter x +# 15| 11: [ExtensionCallable,MulOperator] * +# 15| -1: [TypeMention] string +#-----| 2: (Parameters) +# 15| 0: [Parameter] a +# 15| -1: [TypeMention] int +# 15| 1: [Parameter] b +# 15| -1: [TypeMention] string +# 15| 4: [BlockStmt] {...} +# 15| 0: [ReturnStmt] return ...; +# 15| 0: [StringLiteralUtf16] "" +# 16| 14: [ExtensionMethod] StringGenericM1`1 +# 16| -1: [TypeMention] T +#-----| 1: (Type parameters) +# 16| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 6| 0: [Parameter] s +# 6| -1: [TypeMention] string +# 16| 1: [Parameter] t +# 16| -1: [TypeMention] T +# 16| 2: [Parameter] o +# 16| -1: [TypeMention] object +# 16| 4: [BlockStmt] {...} +# 16| 0: [ReturnStmt] return ...; +# 16| 0: [ParameterAccess] access to parameter t +# 19| 5: [ExtensionType] extension(Object) +# 21| 4: [ExtensionMethod] StaticObjectM1 +# 21| -1: [TypeMention] int +# 21| 4: [BlockStmt] {...} +# 21| 0: [ReturnStmt] return ...; +# 21| 0: [IntLiteral] 0 +# 22| 5: [ExtensionMethod] StaticObjectM2 +# 22| -1: [TypeMention] int +#-----| 2: (Parameters) +# 22| 0: [Parameter] s +# 22| -1: [TypeMention] string +# 22| 4: [BlockStmt] {...} +# 22| 0: [ReturnStmt] return ...; +# 22| 0: [PropertyCall] access to property Length +# 22| -1: [ParameterAccess] access to parameter s +# 23| 6: [Property] StaticProp +# 23| -1: [TypeMention] bool +# 23| 3: [ExtensionCallable,Getter] get_StaticProp +# 23| 4: [BoolLiteral] true +# 26| 8: [ExtensionType] extension(T)`1 +#-----| 1: (Type parameters) +# 26| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 26| 0: [Parameter] t +# 26| -1: [TypeMention] T +# 28| 4: [Property] GenericProp1 +# 28| -1: [TypeMention] bool +# 28| 3: [ExtensionCallable,Getter] get_GenericProp1 +#-----| 2: (Parameters) +# 26| 0: [Parameter] t +# 26| -1: [TypeMention] T +# 28| 4: [IsExpr] ... is ... +# 28| 0: [SyntheticParameterAccess] access to synthetic parameter t +# 28| 1: [NotPatternExpr] not ... +# 28| 0: [ConstantPatternExpr,NullLiteral] null +# 29| 5: [Property] GenericProp2 +# 29| -1: [TypeMention] bool +# 29| 3: [ExtensionCallable,Getter] get_GenericProp2 +#-----| 2: (Parameters) +# 26| 0: [Parameter] t +# 26| -1: [TypeMention] T +# 29| 4: [BlockStmt] {...} +# 29| 0: [ReturnStmt] return ...; +# 29| 0: [BoolLiteral] true +# 29| 4: [ExtensionCallable,Setter] set_GenericProp2 +#-----| 2: (Parameters) +# 26| 0: [Parameter] t +# 26| -1: [TypeMention] T +# 29| 1: [Parameter] value +# 29| 4: [BlockStmt] {...} +# 30| 6: [ExtensionMethod] GenericM1 +# 30| -1: [TypeMention] bool +#-----| 2: (Parameters) +# 26| 0: [Parameter] t +# 26| -1: [TypeMention] T +# 30| 4: [IsExpr] ... is ... +# 30| 0: [SyntheticParameterAccess] access to synthetic parameter t +# 30| 1: [NotPatternExpr] not ... +# 30| 0: [ConstantPatternExpr,NullLiteral] null +# 31| 7: [ExtensionMethod] GenericM2`1 +# 31| -1: [TypeMention] Void +#-----| 1: (Type parameters) +# 31| 0: [TypeParameter] S +#-----| 2: (Parameters) +# 26| 0: [Parameter] t +# 26| -1: [TypeMention] T +# 31| 1: [Parameter] other +# 31| -1: [TypeMention] S +# 31| 4: [BlockStmt] {...} +# 32| 8: [ExtensionMethod] GenericStaticM1 +# 32| -1: [TypeMention] Void +#-----| 2: (Parameters) +# 26| 0: [Parameter] t +# 26| -1: [TypeMention] T +# 32| 4: [BlockStmt] {...} +# 33| 9: [ExtensionMethod] GenericStaticM2`1 +# 33| -1: [TypeMention] Void +#-----| 1: (Type parameters) +# 33| 0: [TypeParameter] S +#-----| 2: (Parameters) +# 33| 0: [Parameter] other +# 33| -1: [TypeMention] S +# 33| 4: [BlockStmt] {...} +# 34| 10: [AddOperator,ExtensionCallable] + +# 34| -1: [TypeMention] T +#-----| 2: (Parameters) +# 34| 0: [Parameter] a +# 34| -1: [TypeMention] T +# 34| 1: [Parameter] b +# 34| -1: [TypeMention] T +# 34| 4: [BlockStmt] {...} +# 34| 0: [ReturnStmt] return ...; +# 34| 0: [NullLiteral] null +# 38| [Class] ClassicExtensions +# 40| 4: [ExtensionMethod] M3 +# 40| -1: [TypeMention] bool +#-----| 2: (Parameters) +# 40| 0: [Parameter] s +# 40| -1: [TypeMention] string +# 40| 4: [IsExpr] ... is ... +# 40| 0: [ParameterAccess] access to parameter s +# 40| 1: [NotPatternExpr] not ... +# 40| 0: [ConstantPatternExpr,NullLiteral] null +# 43| [Class] C +# 45| 6: [Method] CallingExtensions +# 45| -1: [TypeMention] Void +# 46| 4: [BlockStmt] {...} +# 47| 0: [LocalVariableDeclStmt] ... ...; +# 47| 0: [LocalVariableDeclAndInitExpr] String s = ... +# 47| -1: [TypeMention] string +# 47| 0: [LocalVariableAccess] access to local variable s +# 47| 1: [StringLiteralUtf16] "Hello World." +# 50| 1: [LocalVariableDeclStmt] ... ...; +# 50| 0: [LocalVariableDeclAndInitExpr] Boolean x11 = ... +# 50| -1: [TypeMention] bool +# 50| 0: [LocalVariableAccess] access to local variable x11 +# 50| 1: [ExtensionPropertyCall] access to property Prop1 +# 50| -1: [LocalVariableAccess] access to local variable s +# 51| 2: [LocalVariableDeclStmt] ... ...; +# 51| 0: [LocalVariableDeclAndInitExpr] Boolean x12 = ... +# 51| -1: [TypeMention] bool +# 51| 0: [LocalVariableAccess] access to local variable x12 +# 51| 1: [ExtensionPropertyCall] access to property Prop2 +# 51| -1: [LocalVariableAccess] access to local variable s +# 52| 3: [ExprStmt] ...; +# 52| 0: [AssignExpr] ... = ... +# 52| 0: [ExtensionPropertyCall] access to property Prop2 +# 52| -1: [LocalVariableAccess] access to local variable s +# 52| 1: [BoolLiteral] true +# 53| 4: [LocalVariableDeclStmt] ... ...; +# 53| 0: [LocalVariableDeclAndInitExpr] Boolean x13 = ... +# 53| -1: [TypeMention] bool +# 53| 0: [LocalVariableAccess] access to local variable x13 +# 53| 1: [ExtensionPropertyCall] access to property StaticProp1 +# 53| -1: [TypeAccess] access to type String +# 53| 0: [TypeMention] string +# 54| 5: [LocalVariableDeclStmt] ... ...; +# 54| 0: [LocalVariableDeclAndInitExpr] Boolean x14 = ... +# 54| -1: [TypeMention] bool +# 54| 0: [LocalVariableAccess] access to local variable x14 +# 54| 1: [ExtensionPropertyCall] access to property StaticProp +# 54| -1: [TypeAccess] access to type Object +# 54| 0: [TypeMention] object +# 57| 6: [LocalVariableDeclStmt] ... ...; +# 57| 0: [LocalVariableDeclAndInitExpr] Boolean x21 = ... +# 57| -1: [TypeMention] bool +# 57| 0: [LocalVariableAccess] access to local variable x21 +# 57| 1: [MethodCall] call to method M1 +# 57| -1: [LocalVariableAccess] access to local variable s +# 58| 7: [LocalVariableDeclStmt] ... ...; +# 58| 0: [LocalVariableDeclAndInitExpr] String x22 = ... +# 58| -1: [TypeMention] string +# 58| 0: [LocalVariableAccess] access to local variable x22 +# 58| 1: [MethodCall] call to method M2 +# 58| -1: [LocalVariableAccess] access to local variable s +# 58| 0: [StringLiteralUtf16] "!!!" +# 59| 8: [LocalVariableDeclStmt] ... ...; +# 59| 0: [LocalVariableDeclAndInitExpr] Int32 x23 = ... +# 59| -1: [TypeMention] int +# 59| 0: [LocalVariableAccess] access to local variable x23 +# 59| 1: [MethodCall] call to method StaticM1 +# 59| -1: [TypeAccess] access to type String +# 59| 0: [TypeMention] string +# 60| 9: [LocalVariableDeclStmt] ... ...; +# 60| 0: [LocalVariableDeclAndInitExpr] Int32 x24 = ... +# 60| -1: [TypeMention] int +# 60| 0: [LocalVariableAccess] access to local variable x24 +# 60| 1: [MethodCall] call to method StaticM2 +# 60| -1: [TypeAccess] access to type String +# 60| 0: [TypeMention] string +# 60| 0: [LocalVariableAccess] access to local variable s +# 61| 10: [LocalVariableDeclStmt] ... ...; +# 61| 0: [LocalVariableDeclAndInitExpr] Int32 x25 = ... +# 61| -1: [TypeMention] int +# 61| 0: [LocalVariableAccess] access to local variable x25 +# 61| 1: [MethodCall] call to method StaticObjectM1 +# 61| -1: [TypeAccess] access to type Object +# 61| 0: [TypeMention] object +# 62| 11: [LocalVariableDeclStmt] ... ...; +# 62| 0: [LocalVariableDeclAndInitExpr] Int32 x26 = ... +# 62| -1: [TypeMention] int +# 62| 0: [LocalVariableAccess] access to local variable x26 +# 62| 1: [MethodCall] call to method StaticObjectM2 +# 62| -1: [TypeAccess] access to type Object +# 62| 0: [TypeMention] object +# 62| 0: [LocalVariableAccess] access to local variable s +# 65| 12: [LocalVariableDeclStmt] ... ...; +# 65| 0: [LocalVariableDeclAndInitExpr] String x30 = ... +# 65| -1: [TypeMention] string +# 65| 0: [LocalVariableAccess] access to local variable x30 +# 65| 1: [ExtensionOperatorCall] call to operator * +# 65| 0: [IntLiteral] 3 +# 65| 1: [LocalVariableAccess] access to local variable s +# 68| 13: [LocalVariableDeclStmt] ... ...; +# 68| 0: [LocalVariableDeclAndInitExpr] Boolean y = ... +# 68| -1: [TypeMention] bool +# 68| 0: [LocalVariableAccess] access to local variable y +# 68| 1: [MethodCall] call to method M3 +# 68| -1: [LocalVariableAccess] access to local variable s +# 71| 14: [ExprStmt] ...; +# 71| 0: [MethodCall] call to method M1 +# 71| -1: [TypeAccess] access to type MyExtensions +# 71| 0: [TypeMention] MyExtensions +# 71| 0: [LocalVariableAccess] access to local variable s +# 72| 15: [ExprStmt] ...; +# 72| 0: [MethodCall] call to method M2 +# 72| -1: [TypeAccess] access to type MyExtensions +# 72| 0: [TypeMention] MyExtensions +# 72| 0: [LocalVariableAccess] access to local variable s +# 72| 1: [StringLiteralUtf16] "!!!" +# 73| 16: [ExprStmt] ...; +# 73| 0: [MethodCall] call to method StaticM1 +# 73| -1: [TypeAccess] access to type MyExtensions +# 73| 0: [TypeMention] MyExtensions +# 74| 17: [ExprStmt] ...; +# 74| 0: [MethodCall] call to method StaticM2 +# 74| -1: [TypeAccess] access to type MyExtensions +# 74| 0: [TypeMention] MyExtensions +# 74| 0: [LocalVariableAccess] access to local variable s +# 75| 18: [ExprStmt] ...; +# 75| 0: [MethodCall] call to method StaticObjectM1 +# 75| -1: [TypeAccess] access to type MyExtensions +# 75| 0: [TypeMention] MyExtensions +# 76| 19: [ExprStmt] ...; +# 76| 0: [MethodCall] call to method StaticObjectM2 +# 76| -1: [TypeAccess] access to type MyExtensions +# 76| 0: [TypeMention] MyExtensions +# 76| 0: [LocalVariableAccess] access to local variable s +# 79| 20: [ExprStmt] ...; +# 79| 0: [ExtensionOperatorCall] call to operator * +# 79| -1: [TypeAccess] access to type MyExtensions +# 79| 0: [TypeMention] MyExtensions +# 79| 0: [IntLiteral] 3 +# 79| 1: [LocalVariableAccess] access to local variable s +# 82| 21: [ExprStmt] ...; +# 82| 0: [MethodCall] call to extension accessor get_Prop1 +# 82| -1: [TypeAccess] access to type MyExtensions +# 82| 0: [TypeMention] MyExtensions +# 82| 0: [LocalVariableAccess] access to local variable s +# 83| 22: [ExprStmt] ...; +# 83| 0: [MethodCall] call to extension accessor get_Prop2 +# 83| -1: [TypeAccess] access to type MyExtensions +# 83| 0: [TypeMention] MyExtensions +# 83| 0: [LocalVariableAccess] access to local variable s +# 84| 23: [ExprStmt] ...; +# 84| 0: [MethodCall] call to extension accessor set_Prop2 +# 84| -1: [TypeAccess] access to type MyExtensions +# 84| 0: [TypeMention] MyExtensions +# 84| 0: [LocalVariableAccess] access to local variable s +# 84| 1: [BoolLiteral] false +# 85| 24: [ExprStmt] ...; +# 85| 0: [MethodCall] call to extension accessor get_StaticProp +# 85| -1: [TypeAccess] access to type MyExtensions +# 85| 0: [TypeMention] MyExtensions +# 88| 7: [Method] CallingGenericExtensions +# 88| -1: [TypeMention] Void +# 89| 4: [BlockStmt] {...} +# 90| 0: [LocalVariableDeclStmt] ... ...; +# 90| 0: [LocalVariableDeclAndInitExpr] String s = ... +# 90| -1: [TypeMention] string +# 90| 0: [LocalVariableAccess] access to local variable s +# 90| 1: [StringLiteralUtf16] "Hello Generic World." +# 91| 1: [LocalVariableDeclStmt] ... ...; +# 91| 0: [LocalVariableDeclAndInitExpr] Object o = ... +# 91| -1: [TypeMention] object +# 91| 0: [LocalVariableAccess] access to local variable o +# 91| 1: [ObjectCreation] object creation of type Object +# 91| 0: [TypeMention] object +# 94| 2: [ExprStmt] ...; +# 94| 0: [MethodCall] call to method GenericM1 +# 94| -1: [LocalVariableAccess] access to local variable o +# 95| 3: [ExprStmt] ...; +# 95| 0: [MethodCall] call to method GenericM1 +# 95| -1: [LocalVariableAccess] access to local variable s +# 98| 4: [ExprStmt] ...; +# 98| 0: [MethodCall] call to method GenericM1 +# 98| -1: [TypeAccess] access to type MyExtensions +# 98| 0: [TypeMention] MyExtensions +# 98| 0: [LocalVariableAccess] access to local variable o +# 99| 5: [ExprStmt] ...; +# 99| 0: [MethodCall] call to method GenericM1 +# 99| -1: [TypeAccess] access to type MyExtensions +# 99| 0: [TypeMention] MyExtensions +# 99| 0: [LocalVariableAccess] access to local variable s +# 101| 6: [ExprStmt] ...; +# 101| 0: [MethodCall] call to method GenericM2 +# 101| -1: [LocalVariableAccess] access to local variable o +# 101| 0: [IntLiteral] 42 +# 102| 7: [ExprStmt] ...; +# 102| 0: [MethodCall] call to method GenericM2 +# 102| -1: [TypeAccess] access to type MyExtensions +# 102| 0: [TypeMention] MyExtensions +# 102| 0: [LocalVariableAccess] access to local variable o +# 102| 1: [IntLiteral] 42 +# 104| 8: [ExprStmt] ...; +# 104| 0: [MethodCall] call to method StringGenericM1 +# 104| -1: [LocalVariableAccess] access to local variable s +# 104| 0: [IntLiteral] 7 +# 104| 1: [ObjectCreation] object creation of type Object +# 104| 0: [TypeMention] object +# 105| 9: [ExprStmt] ...; +# 105| 0: [MethodCall] call to method StringGenericM1 +# 105| -1: [TypeAccess] access to type MyExtensions +# 105| 0: [TypeMention] MyExtensions +# 105| 0: [LocalVariableAccess] access to local variable s +# 105| 1: [StringLiteralUtf16] "test" +# 105| 2: [ObjectCreation] object creation of type Object +# 105| 0: [TypeMention] object diff --git a/csharp/ql/test/library-tests/extension/PrintAst.qlref b/csharp/ql/test/library-tests/extension/PrintAst.qlref new file mode 100644 index 000000000000..f867dd01f9f8 --- /dev/null +++ b/csharp/ql/test/library-tests/extension/PrintAst.qlref @@ -0,0 +1 @@ +shared/PrintAst.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/extension/extensionType.expected b/csharp/ql/test/library-tests/extension/extensionType.expected new file mode 100644 index 000000000000..b622c2f4c263 --- /dev/null +++ b/csharp/ql/test/library-tests/extension/extensionType.expected @@ -0,0 +1,11 @@ +extensionTypeReceiverParameter +| extensions.cs:6:5:17:5 | extension(String) | extensions.cs:6:22:6:22 | s | +| extensions.cs:26:5:35:5 | extension(Object) | extensions.cs:26:20:26:20 | t | +| extensions.cs:26:5:35:5 | extension(String) | extensions.cs:26:20:26:20 | t | +| extensions.cs:26:5:35:5 | extension(T)`1 | extensions.cs:26:20:26:20 | t | +extensionTypeExtendedType +| extensions.cs:6:5:17:5 | extension(String) | string | +| extensions.cs:19:5:24:5 | extension(Object) | object | +| extensions.cs:26:5:35:5 | extension(Object) | object | +| extensions.cs:26:5:35:5 | extension(String) | string | +| extensions.cs:26:5:35:5 | extension(T)`1 | T | diff --git a/csharp/ql/test/library-tests/extension/extensionType.ql b/csharp/ql/test/library-tests/extension/extensionType.ql new file mode 100644 index 000000000000..c584252c4bd3 --- /dev/null +++ b/csharp/ql/test/library-tests/extension/extensionType.ql @@ -0,0 +1,11 @@ +import csharp + +query predicate extensionTypeReceiverParameter(ExtensionType et, Parameter p) { + et.getFile().getBaseName() = "extensions.cs" and + p = et.getReceiverParameter() +} + +query predicate extensionTypeExtendedType(ExtensionType et, string t) { + et.getFile().getBaseName() = "extensions.cs" and + t = et.getExtendedType().toStringWithTypes() +} diff --git a/csharp/ql/test/library-tests/extension/extensions.cs b/csharp/ql/test/library-tests/extension/extensions.cs new file mode 100644 index 000000000000..1117a98f8a07 --- /dev/null +++ b/csharp/ql/test/library-tests/extension/extensions.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; + +public static class MyExtensions +{ + extension(string s) + { + public bool Prop1 => s.Length > 0; + public bool Prop2 { get { return true; } set { } } + public static bool StaticProp1 { get { return false; } } + public bool M1() => s is not null; + public string M2(string other) { return s + other; } + public static int StaticM1() { return 0; } + public static int StaticM2(string x) { return x.Length; } + public static string operator *(int a, string b) { return ""; } + public T StringGenericM1(T t, object o) { return t; } + } + + extension(object) + { + public static int StaticObjectM1() { return 0; } + public static int StaticObjectM2(string s) { return s.Length; } + public static bool StaticProp => true; + } + + extension(T t) where T : class + { + public bool GenericProp1 => t is not null; + public bool GenericProp2 { get { return true; } set { } } + public bool GenericM1() => t is not null; + public void GenericM2(S other) { } + public void GenericStaticM1() { } + public static void GenericStaticM2(S other) { } + public static T operator +(T a, T b) { return null; } + } +} + +public static class ClassicExtensions +{ + public static bool M3(this string s) => s is not null; +} + +public class C +{ + public static void CallingExtensions() + { + var s = "Hello World."; + + // Calling the extensions properties + var x11 = s.Prop1; + var x12 = s.Prop2; + s.Prop2 = true; + var x13 = string.StaticProp1; + var x14 = object.StaticProp; + + // Calling the extensions methods. + var x21 = s.M1(); + var x22 = s.M2("!!!"); + var x23 = string.StaticM1(); + var x24 = string.StaticM2(s); + var x25 = object.StaticObjectM1(); + var x26 = object.StaticObjectM2(s); + + // Calling the extension operator. + var x30 = 3 * s; + + // Calling the classic extension method. + var y = s.M3(); + + // Calling the compiler generated static extension methods. + MyExtensions.M1(s); + MyExtensions.M2(s, "!!!"); + MyExtensions.StaticM1(); + MyExtensions.StaticM2(s); + MyExtensions.StaticObjectM1(); + MyExtensions.StaticObjectM2(s); + + // Calling the compiler generated operator method. + MyExtensions.op_Multiply(3, s); + + // Calling the compiler generated methods used by the extension property accessors. + MyExtensions.get_Prop1(s); + MyExtensions.get_Prop2(s); + MyExtensions.set_Prop2(s, false); + MyExtensions.get_StaticProp(); + } + + public static void CallingGenericExtensions() + { + var s = "Hello Generic World."; + var o = new object(); + + // Calling generic extension method + o.GenericM1(); + s.GenericM1(); + + // Calling the compiler generated static extension methods. + MyExtensions.GenericM1(o); + MyExtensions.GenericM1(s); + + o.GenericM2(42); + MyExtensions.GenericM2(o, 42); + + s.StringGenericM1(7, new object()); + MyExtensions.StringGenericM1(s, "test", new object()); + } +} diff --git a/csharp/ql/test/library-tests/extension/extensions.expected b/csharp/ql/test/library-tests/extension/extensions.expected new file mode 100644 index 000000000000..c892ff08947b --- /dev/null +++ b/csharp/ql/test/library-tests/extension/extensions.expected @@ -0,0 +1,111 @@ +extensionMethodCallArgument +| extensions.cs:57:19:57:24 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:57:19:57:19 | access to local variable s | +| extensions.cs:58:19:58:29 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:58:19:58:19 | access to local variable s | +| extensions.cs:58:19:58:29 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:12:33:12:37 | other | 1 | extensions.cs:58:24:58:28 | "!!!" | +| extensions.cs:60:19:60:36 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:14:43:14:43 | x | 0 | extensions.cs:60:35:60:35 | access to local variable s | +| extensions.cs:62:19:62:42 | call to method StaticObjectM2 | extensions.cs:22:27:22:40 | StaticObjectM2 | extensions.cs:22:49:22:49 | s | 0 | extensions.cs:62:41:62:41 | access to local variable s | +| extensions.cs:68:17:68:22 | call to method M3 | extensions.cs:40:24:40:25 | M3 | extensions.cs:40:39:40:39 | s | 0 | extensions.cs:68:17:68:17 | access to local variable s | +| extensions.cs:71:9:71:26 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:71:25:71:25 | access to local variable s | +| extensions.cs:72:9:72:33 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:72:25:72:25 | access to local variable s | +| extensions.cs:72:9:72:33 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:12:33:12:37 | other | 1 | extensions.cs:72:28:72:32 | "!!!" | +| extensions.cs:74:9:74:32 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:14:43:14:43 | x | 0 | extensions.cs:74:31:74:31 | access to local variable s | +| extensions.cs:76:9:76:38 | call to method StaticObjectM2 | extensions.cs:22:27:22:40 | StaticObjectM2 | extensions.cs:22:49:22:49 | s | 0 | extensions.cs:76:37:76:37 | access to local variable s | +| extensions.cs:94:9:94:21 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:20:26:20 | t | 0 | extensions.cs:94:9:94:9 | access to local variable o | +| extensions.cs:95:9:95:21 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:20:26:20 | t | 0 | extensions.cs:95:9:95:9 | access to local variable s | +| extensions.cs:98:9:98:33 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:20:26:20 | t | 0 | extensions.cs:98:32:98:32 | access to local variable o | +| extensions.cs:99:9:99:33 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:20:26:20 | t | 0 | extensions.cs:99:32:99:32 | access to local variable s | +| extensions.cs:101:9:101:23 | call to method GenericM2 | extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:26:20:26:20 | t | 0 | extensions.cs:101:9:101:9 | access to local variable o | +| extensions.cs:101:9:101:23 | call to method GenericM2 | extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:31:36:31:40 | other | 1 | extensions.cs:101:21:101:22 | 42 | +| extensions.cs:102:9:102:37 | call to method GenericM2 | extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:26:20:26:20 | t | 0 | extensions.cs:102:32:102:32 | access to local variable o | +| extensions.cs:102:9:102:37 | call to method GenericM2 | extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:31:36:31:40 | other | 1 | extensions.cs:102:35:102:36 | 42 | +| extensions.cs:104:9:104:47 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:104:9:104:9 | access to local variable s | +| extensions.cs:104:9:104:47 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:39:16:39 | t | 1 | extensions.cs:104:32:104:32 | 7 | +| extensions.cs:104:9:104:47 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:49:16:49 | o | 2 | extensions.cs:104:35:104:46 | object creation of type Object | +| extensions.cs:105:9:105:69 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:105:46:105:46 | access to local variable s | +| extensions.cs:105:9:105:69 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:39:16:39 | t | 1 | extensions.cs:105:49:105:54 | "test" | +| extensions.cs:105:9:105:69 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:49:16:49 | o | 2 | extensions.cs:105:57:105:68 | object creation of type Object | +extensionMethodCalls +| extensions.cs:57:19:57:24 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).M1 | +| extensions.cs:58:19:58:29 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).M2 | +| extensions.cs:59:19:59:35 | call to method StaticM1 | extensions.cs:13:27:13:34 | StaticM1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).StaticM1 | +| extensions.cs:60:19:60:36 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).StaticM2 | +| extensions.cs:61:19:61:41 | call to method StaticObjectM1 | extensions.cs:21:27:21:40 | StaticObjectM1 | extensions.cs:19:5:24:5 | extension(Object) | MyExtensions+extension(Object).StaticObjectM1 | +| extensions.cs:62:19:62:42 | call to method StaticObjectM2 | extensions.cs:22:27:22:40 | StaticObjectM2 | extensions.cs:19:5:24:5 | extension(Object) | MyExtensions+extension(Object).StaticObjectM2 | +| extensions.cs:68:17:68:22 | call to method M3 | extensions.cs:40:24:40:25 | M3 | extensions.cs:38:21:38:37 | ClassicExtensions | ClassicExtensions.M3 | +| extensions.cs:71:9:71:26 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).M1 | +| extensions.cs:72:9:72:33 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).M2 | +| extensions.cs:73:9:73:31 | call to method StaticM1 | extensions.cs:13:27:13:34 | StaticM1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).StaticM1 | +| extensions.cs:74:9:74:32 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).StaticM2 | +| extensions.cs:75:9:75:37 | call to method StaticObjectM1 | extensions.cs:21:27:21:40 | StaticObjectM1 | extensions.cs:19:5:24:5 | extension(Object) | MyExtensions+extension(Object).StaticObjectM1 | +| extensions.cs:76:9:76:38 | call to method StaticObjectM2 | extensions.cs:22:27:22:40 | StaticObjectM2 | extensions.cs:19:5:24:5 | extension(Object) | MyExtensions+extension(Object).StaticObjectM2 | +| extensions.cs:94:9:94:21 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:5:35:5 | extension(Object) | MyExtensions+extension(Object).GenericM1 | +| extensions.cs:95:9:95:21 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:5:35:5 | extension(String) | MyExtensions+extension(String).GenericM1 | +| extensions.cs:98:9:98:33 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:5:35:5 | extension(Object) | MyExtensions+extension(Object).GenericM1 | +| extensions.cs:99:9:99:33 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:5:35:5 | extension(String) | MyExtensions+extension(String).GenericM1 | +| extensions.cs:101:9:101:23 | call to method GenericM2 | extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:26:5:35:5 | extension(Object) | MyExtensions+extension(Object).GenericM2 | +| extensions.cs:102:9:102:37 | call to method GenericM2 | extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:26:5:35:5 | extension(Object) | MyExtensions+extension(Object).GenericM2 | +| extensions.cs:104:9:104:47 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).StringGenericM1 | +| extensions.cs:105:9:105:69 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).StringGenericM1 | +extensionParameter +| extensions.cs:11:21:11:22 | M1 | extensions.cs:6:22:6:22 | s | 0 | string | extensions.cs:6:22:6:22 | s | +| extensions.cs:12:23:12:24 | M2 | extensions.cs:6:22:6:22 | s | 0 | string | extensions.cs:6:22:6:22 | s | +| extensions.cs:12:23:12:24 | M2 | extensions.cs:12:33:12:37 | other | 1 | string | extensions.cs:12:33:12:37 | other | +| extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:14:43:14:43 | x | 0 | string | extensions.cs:14:43:14:43 | x | +| extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:6:22:6:22 | s | 0 | string | extensions.cs:6:22:6:22 | s | +| extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:39:16:39 | t | 1 | int | extensions.cs:16:39:16:39 | t | +| extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:49:16:49 | o | 2 | object | extensions.cs:16:49:16:49 | o | +| extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:6:22:6:22 | s | 0 | string | extensions.cs:6:22:6:22 | s | +| extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:39:16:39 | t | 1 | string | extensions.cs:16:39:16:39 | t | +| extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:49:16:49 | o | 2 | object | extensions.cs:16:49:16:49 | o | +| extensions.cs:16:18:16:35 | StringGenericM1`1 | extensions.cs:6:22:6:22 | s | 0 | string | extensions.cs:6:22:6:22 | s | +| extensions.cs:16:18:16:35 | StringGenericM1`1 | extensions.cs:16:39:16:39 | t | 1 | T | extensions.cs:16:39:16:39 | t | +| extensions.cs:16:18:16:35 | StringGenericM1`1 | extensions.cs:16:49:16:49 | o | 2 | object | extensions.cs:16:49:16:49 | o | +| extensions.cs:22:27:22:40 | StaticObjectM2 | extensions.cs:22:49:22:49 | s | 0 | string | extensions.cs:22:49:22:49 | s | +| extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:20:26:20 | t | 0 | T | extensions.cs:26:20:26:20 | t | +| extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:20:26:20 | t | 0 | object | extensions.cs:26:20:26:20 | t | +| extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:20:26:20 | t | 0 | string | extensions.cs:26:20:26:20 | t | +| extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:26:20:26:20 | t | 0 | object | extensions.cs:26:20:26:20 | t | +| extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:31:36:31:40 | other | 1 | int | extensions.cs:31:36:31:40 | other | +| extensions.cs:31:21:31:32 | GenericM2`1 | extensions.cs:26:20:26:20 | t | 0 | T | extensions.cs:26:20:26:20 | t | +| extensions.cs:31:21:31:32 | GenericM2`1 | extensions.cs:26:20:26:20 | t | 0 | object | extensions.cs:26:20:26:20 | t | +| extensions.cs:31:21:31:32 | GenericM2`1 | extensions.cs:26:20:26:20 | t | 0 | string | extensions.cs:26:20:26:20 | t | +| extensions.cs:31:21:31:32 | GenericM2`1 | extensions.cs:31:36:31:40 | other | 1 | S | extensions.cs:31:36:31:40 | other | +| extensions.cs:31:21:31:32 | GenericM2`1 | extensions.cs:31:36:31:40 | other | 1 | S | extensions.cs:31:36:31:40 | other | +| extensions.cs:31:21:31:32 | GenericM2`1 | extensions.cs:31:36:31:40 | other | 1 | S | extensions.cs:31:36:31:40 | other | +| extensions.cs:32:21:32:35 | GenericStaticM1 | extensions.cs:26:20:26:20 | t | 0 | T | extensions.cs:26:20:26:20 | t | +| extensions.cs:32:21:32:35 | GenericStaticM1 | extensions.cs:26:20:26:20 | t | 0 | object | extensions.cs:26:20:26:20 | t | +| extensions.cs:32:21:32:35 | GenericStaticM1 | extensions.cs:26:20:26:20 | t | 0 | string | extensions.cs:26:20:26:20 | t | +| extensions.cs:33:28:33:45 | GenericStaticM2`1 | extensions.cs:33:49:33:53 | other | 0 | S | extensions.cs:33:49:33:53 | other | +| extensions.cs:33:28:33:45 | GenericStaticM2`1 | extensions.cs:33:49:33:53 | other | 0 | S | extensions.cs:33:49:33:53 | other | +| extensions.cs:33:28:33:45 | GenericStaticM2`1 | extensions.cs:33:49:33:53 | other | 0 | S | extensions.cs:33:49:33:53 | other | +| extensions.cs:40:24:40:25 | M3 | extensions.cs:40:39:40:39 | s | 0 | string | extensions.cs:40:39:40:39 | s | +extensionOperatorCallArgument +| extensions.cs:15:39:15:39 | * | extensions.cs:65:19:65:23 | call to operator * | extensions.cs:15:45:15:45 | a | 0 | extensions.cs:65:19:65:19 | 3 | +| extensions.cs:15:39:15:39 | * | extensions.cs:65:19:65:23 | call to operator * | extensions.cs:15:55:15:55 | b | 1 | extensions.cs:65:23:65:23 | access to local variable s | +| extensions.cs:15:39:15:39 | * | extensions.cs:79:9:79:38 | call to operator * | extensions.cs:15:45:15:45 | a | 0 | extensions.cs:79:34:79:34 | 3 | +| extensions.cs:15:39:15:39 | * | extensions.cs:79:9:79:38 | call to operator * | extensions.cs:15:55:15:55 | b | 1 | extensions.cs:79:37:79:37 | access to local variable s | +extensionOperatorCalls +| extensions.cs:65:19:65:23 | call to operator * | extensions.cs:15:39:15:39 | * | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).op_Multiply | +| extensions.cs:79:9:79:38 | call to operator * | extensions.cs:15:39:15:39 | * | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).op_Multiply | +extensionProperty +| extensions.cs:8:21:8:25 | Prop1 | extensions.cs:6:5:17:5 | extension(String) | +| extensions.cs:9:21:9:25 | Prop2 | extensions.cs:6:5:17:5 | extension(String) | +| extensions.cs:10:28:10:38 | StaticProp1 | extensions.cs:6:5:17:5 | extension(String) | +| extensions.cs:23:28:23:37 | StaticProp | extensions.cs:19:5:24:5 | extension(Object) | +| extensions.cs:28:21:28:32 | GenericProp1 | extensions.cs:26:5:35:5 | extension(Object) | +| extensions.cs:28:21:28:32 | GenericProp1 | extensions.cs:26:5:35:5 | extension(String) | +| extensions.cs:28:21:28:32 | GenericProp1 | extensions.cs:26:5:35:5 | extension(T)`1 | +| extensions.cs:29:21:29:32 | GenericProp2 | extensions.cs:26:5:35:5 | extension(Object) | +| extensions.cs:29:21:29:32 | GenericProp2 | extensions.cs:26:5:35:5 | extension(String) | +| extensions.cs:29:21:29:32 | GenericProp2 | extensions.cs:26:5:35:5 | extension(T)`1 | +extensionPropertyCall +| extensions.cs:50:19:50:25 | access to property Prop1 | extensions.cs:8:21:8:25 | Prop1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).Prop1 | +| extensions.cs:51:19:51:25 | access to property Prop2 | extensions.cs:9:21:9:25 | Prop2 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).Prop2 | +| extensions.cs:52:9:52:15 | access to property Prop2 | extensions.cs:9:21:9:25 | Prop2 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).Prop2 | +| extensions.cs:53:19:53:36 | access to property StaticProp1 | extensions.cs:10:28:10:38 | StaticProp1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(String).StaticProp1 | +| extensions.cs:54:19:54:35 | access to property StaticProp | extensions.cs:23:28:23:37 | StaticProp | extensions.cs:19:5:24:5 | extension(Object) | MyExtensions+extension(Object).StaticProp | +extensionAccessorCall +| extensions.cs:82:9:82:33 | call to extension accessor get_Prop1 | extensions.cs:8:30:8:41 | get_Prop1 | extensions.cs:8:21:8:25 | Prop1 | MyExtensions+extension(String).get_Prop1 | +| extensions.cs:83:9:83:33 | call to extension accessor get_Prop2 | extensions.cs:9:29:9:31 | get_Prop2 | extensions.cs:9:21:9:25 | Prop2 | MyExtensions+extension(String).get_Prop2 | +| extensions.cs:84:9:84:40 | call to extension accessor set_Prop2 | extensions.cs:9:50:9:52 | set_Prop2 | extensions.cs:9:21:9:25 | Prop2 | MyExtensions+extension(String).set_Prop2 | +| extensions.cs:85:9:85:37 | call to extension accessor get_StaticProp | extensions.cs:23:42:23:45 | get_StaticProp | extensions.cs:23:28:23:37 | StaticProp | MyExtensions+extension(Object).get_StaticProp | diff --git a/csharp/ql/test/library-tests/extension/extensions.ql b/csharp/ql/test/library-tests/extension/extensions.ql new file mode 100644 index 000000000000..03830c5851d0 --- /dev/null +++ b/csharp/ql/test/library-tests/extension/extensions.ql @@ -0,0 +1,69 @@ +import csharp + +query predicate extensionMethodCallArgument( + ExtensionMethodCall emc, ExtensionMethod em, Parameter p, int i, Expr e +) { + em.getFile().getBaseName() = "extensions.cs" and + emc.getTarget() = em and + em.getParameter(i) = p and + emc.getArgument(i) = e +} + +query predicate extensionMethodCalls( + ExtensionMethodCall emc, ExtensionMethod em, Type t, string type +) { + em.getFile().getBaseName() = "extensions.cs" and + emc.getTarget() = em and + em.getDeclaringType() = t and + em.getFullyQualifiedNameDebug() = type +} + +query predicate extensionParameter( + ExtensionMethod em, Parameter p, int i, string type, Parameter unbound +) { + em.getFile().getBaseName() = "extensions.cs" and + p = em.getParameter(i) and + type = p.getType().toStringWithTypes() and + unbound = p.getUnboundDeclaration() +} + +query predicate extensionOperatorCallArgument( + ExtensionOperator op, ExtensionOperatorCall opc, Parameter p, int pos, Expr e +) { + opc.getTarget() = op and + op.getFile().getBaseName() = "extensions.cs" and + p = op.getParameter(pos) and + e = opc.getArgument(pos) +} + +query predicate extensionOperatorCalls( + ExtensionOperatorCall opc, ExtensionOperator op, Type t, string type +) { + op.getFile().getBaseName() = "extensions.cs" and + opc.getTarget() = op and + op.getDeclaringType() = t and + op.getFullyQualifiedNameDebug() = type +} + +query predicate extensionProperty(ExtensionProperty p, Type t) { + p.getFile().getBaseName() = "extensions.cs" and + p.getDeclaringType() = t +} + +query predicate extensionPropertyCall( + ExtensionPropertyCall pc, ExtensionProperty p, Type t, string type +) { + p.getFile().getBaseName() = "extensions.cs" and + pc.getProperty() = p and + p.getDeclaringType() = t and + p.getFullyQualifiedNameDebug() = type +} + +query predicate extensionAccessorCall( + MethodCall m, ExtensionAccessor a, ExtensionProperty p, string type +) { + p.getFile().getBaseName() = "extensions.cs" and + (a.(Getter).getDeclaration() = p or a.(Setter).getDeclaration() = p) and + m.getTargetAccessor() = a and + a.getFullyQualifiedNameDebug() = type +} diff --git a/csharp/ql/test/library-tests/extension/options b/csharp/ql/test/library-tests/extension/options new file mode 100644 index 000000000000..77b22963f5c8 --- /dev/null +++ b/csharp/ql/test/library-tests/extension/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj