using System.Collections.Generic; using System.Linq; using Cxxi.Generators; namespace Cxxi.Passes { struct OverloadSignature { public string Return; public List Parameters; public Function Function; public OverloadSignature(Function function) { Function = function; var typePrinter = Type.TypePrinter; Return = function.ReturnType.Visit(typePrinter); Parameters = new List(); foreach (var param in function.Parameters) { var paramType = param.Type.Visit(typePrinter); Parameters.Add(paramType); } } public static bool IsAmbiguous(OverloadSignature overload1, OverloadSignature overload2, Class @class) { if (overload1.Function == overload2.Function) return false; if (TextTemplate.CheckIgnoreFunction(@class, overload1.Function)) return false; if (TextTemplate.CheckIgnoreFunction(@class, overload2.Function)) return false; // TODO: Default parameters? if (overload1.Parameters.Count != overload2.Parameters.Count) return false; if (overload1.Parameters.Count == 0) return true; for (var i = 0; i < overload1.Parameters.Count; i++) { if (overload1.Parameters[i] != overload2.Parameters[i]) return false; } return true; } }; public class CheckAmbiguousOverloads : TranslationUnitPass { private Class currentClass; private readonly ISet visited; public CheckAmbiguousOverloads() { visited = new HashSet(); Options.VisitNamespaceEnums = false; Options.VisitNamespaceTemplates = false; Options.VisitNamespaceTypedefs = false; Options.VisitClassBases = false; Options.VisitClassFields = false; Options.VisitClassProperties = false; Options.VisitClassEvents = false; Options.VisitClassVariables = false; } public override bool VisitClassDecl(Class @class) { visited.Clear(); currentClass = @class; return base.VisitClassDecl(@class); } public override bool VisitMethodDecl(Method method) { CheckOverloads(method); return false; } public override bool VisitFunctionDecl(Function function) { CheckOverloads(function); return false; } private bool CheckOverloads(Function function) { if (visited.Contains(function)) return false; var overloads = AST.Utils.GetFunctionOverloads(function, currentClass); var signatures = overloads.Select(fn => new OverloadSignature(fn)).ToList(); foreach (var sig1 in signatures) { visited.Add(sig1.Function); foreach (var sig2 in signatures) { if (!OverloadSignature.IsAmbiguous(sig1, sig2, currentClass)) continue; Driver.Diagnostics.EmitWarning(DiagnosticId.AmbiguousOverload, "Overload {0}::{1} is ambiguous, renaming automatically", currentClass.OriginalName, sig1.Function.QualifiedOriginalName); RenameOverload(sig1.Function); return false; } } return true; } public void RenameOverload(Function function) { function.Name = function.Name + "0"; } } public static class CheckAmbiguousOverloadsExtensions { public static void CheckAmbiguousOverloads(this PassBuilder builder) { var pass = new CheckAmbiguousOverloads(); builder.AddPass(pass); } } }