mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
115 lines
4.2 KiB
C#
115 lines
4.2 KiB
C#
using System.IO;
|
|
using System.Linq;
|
|
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
using Semmle.Extraction.CSharp.Util;
|
|
|
|
namespace Semmle.Extraction.CSharp.Entities
|
|
{
|
|
internal class UserOperator : Method
|
|
{
|
|
protected UserOperator(Context cx, IMethodSymbol init)
|
|
: base(cx, init) { }
|
|
|
|
protected override MethodKind ExplicitlyImplementsKind => MethodKind.UserDefinedOperator;
|
|
|
|
public override void Populate(TextWriter trapFile)
|
|
{
|
|
PopulateMethod(trapFile);
|
|
PopulateModifiers(trapFile);
|
|
|
|
var returnType = Type.Create(Context, Symbol.ReturnType);
|
|
trapFile.operators(this,
|
|
Symbol.Name,
|
|
OperatorSymbol(Context, Symbol),
|
|
ContainingType,
|
|
returnType.TypeRef,
|
|
(UserOperator)OriginalDefinition);
|
|
|
|
ContainingType.PopulateGenerics();
|
|
Overrides(trapFile);
|
|
|
|
if (Context.OnlyScaffold)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Context.ExtractLocation(Symbol))
|
|
{
|
|
WriteLocationsToTrap(trapFile.operator_location, this, Locations);
|
|
}
|
|
|
|
if (IsSourceDeclaration)
|
|
{
|
|
var declSyntaxReferences = Symbol.DeclaringSyntaxReferences.Select(s => s.GetSyntax()).ToArray();
|
|
foreach (var declaration in declSyntaxReferences.OfType<OperatorDeclarationSyntax>())
|
|
TypeMention.Create(Context, declaration.ReturnType, this, returnType);
|
|
foreach (var declaration in declSyntaxReferences.OfType<ConversionOperatorDeclarationSyntax>())
|
|
TypeMention.Create(Context, declaration.Type, this, returnType);
|
|
}
|
|
}
|
|
|
|
public override bool NeedsPopulation => Context.Defines(Symbol) || IsImplicitOperator(out _);
|
|
|
|
public override Type ContainingType
|
|
{
|
|
get
|
|
{
|
|
IsImplicitOperator(out var containingType);
|
|
return Type.Create(Context, containingType);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// For some reason, some operators are missing from the Roslyn database of mscorlib.
|
|
/// This method returns <code>true</code> for such operators.
|
|
/// </summary>
|
|
/// <param name="containingType">The type containing this operator.</param>
|
|
/// <returns></returns>
|
|
private bool IsImplicitOperator(out ITypeSymbol containingType)
|
|
{
|
|
containingType = Symbol.ContainingType;
|
|
if (containingType is not null)
|
|
{
|
|
return containingType is not INamedTypeSymbol containingNamedType ||
|
|
!containingNamedType.GetMembers(Symbol.Name).Contains(Symbol);
|
|
}
|
|
|
|
var pointerType = Symbol.Parameters.Select(p => p.Type).OfType<IPointerTypeSymbol>().FirstOrDefault();
|
|
if (pointerType is not null)
|
|
{
|
|
containingType = pointerType;
|
|
return true;
|
|
}
|
|
|
|
Context.ModelError(Symbol, "Unexpected implicit operator");
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Converts a method name into a symbolic name.
|
|
/// Logs an error if the name is not found.
|
|
/// </summary>
|
|
/// <param name="cx">Extractor context.</param>
|
|
/// <param name="method">The method symbol.</param>
|
|
/// <returns>The converted name.</returns>
|
|
private static string OperatorSymbol(Context cx, IMethodSymbol method)
|
|
{
|
|
if (!method.TryGetOperatorSymbol(out var result))
|
|
cx.ModelError(method, $"Unhandled operator name in OperatorSymbol(): '{method.Name}'");
|
|
return result;
|
|
}
|
|
|
|
public static new UserOperator Create(Context cx, IMethodSymbol symbol) => UserOperatorFactory.Instance.CreateEntityFromSymbol(cx, symbol);
|
|
|
|
private class UserOperatorFactory : CachedEntityFactory<IMethodSymbol, UserOperator>
|
|
{
|
|
public static UserOperatorFactory Instance { get; } = new UserOperatorFactory();
|
|
|
|
public override UserOperator Create(Context cx, IMethodSymbol init) => new UserOperator(cx, init);
|
|
}
|
|
}
|
|
}
|