From 99ab98c884b377fbc0a0f62861ec13e01897562d Mon Sep 17 00:00:00 2001 From: triton Date: Fri, 3 May 2013 14:54:36 +0100 Subject: [PATCH] Added a new pass that checks for ambiguous function/method overloads. --- src/Generator/AST/Utils.cs | 21 +++ src/Generator/Diagnostics.cs | 3 +- src/Generator/Driver.cs | 1 + .../Passes/CheckAmbiguousOverloads.cs | 140 ++++++++++++++++++ 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 src/Generator/AST/Utils.cs create mode 100644 src/Generator/Passes/CheckAmbiguousOverloads.cs diff --git a/src/Generator/AST/Utils.cs b/src/Generator/AST/Utils.cs new file mode 100644 index 00000000..f563d7ab --- /dev/null +++ b/src/Generator/AST/Utils.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace Cxxi.AST +{ + public static class Utils + { + public static IList GetFunctionOverloads(Function function, + Class @class = null) + { + var overloads = new List(); + + if (@class == null) + { + var @namespace = function.Namespace; + return @namespace.GetFunctionOverloads(function); + } + + return @class.GetFunctionOverloads(function); + } + } +} diff --git a/src/Generator/Diagnostics.cs b/src/Generator/Diagnostics.cs index 47d4dbbb..6a5aba57 100644 --- a/src/Generator/Diagnostics.cs +++ b/src/Generator/Diagnostics.cs @@ -4,7 +4,8 @@ namespace Cxxi { public enum DiagnosticId { - InvalidOperatorOverload + AmbiguousOverload, + InvalidOperatorOverload, SymbolNotFound } diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index ee21891f..148c6d02 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -141,6 +141,7 @@ namespace Cxxi passes.ResolveIncompleteDecls(TypeDatabase); passes.CheckTypeReferences(); passes.CheckFlagEnums(); + passes.CheckAmbiguousOverloads(); if (Options.GeneratorKind == LanguageGeneratorKind.CSharp) passes.CheckAbiParameters(Options); diff --git a/src/Generator/Passes/CheckAmbiguousOverloads.cs b/src/Generator/Passes/CheckAmbiguousOverloads.cs new file mode 100644 index 00000000..98082128 --- /dev/null +++ b/src/Generator/Passes/CheckAmbiguousOverloads.cs @@ -0,0 +1,140 @@ +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); + } + } +}