diff --git a/InterfaceStubGenerator/Diagnostics.cs b/InterfaceStubGenerator/Diagnostics.cs new file mode 100644 index 000000000..54eb5a3ec --- /dev/null +++ b/InterfaceStubGenerator/Diagnostics.cs @@ -0,0 +1,99 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; + +namespace Refit.Generator +{ + public class Diagnostic + { + public string Type { get; private set; } + public string Code { get; private set; } + public string File { get; protected set; } + public int? Line { get; protected set; } + public int? Character { get; protected set; } + public string Message { get; protected set; } + + public Diagnostic(string type, string code) + { + Type = type; + Code = code; + } + + protected void setLocation(Location location) + { + var line = location.GetMappedLineSpan().StartLinePosition; + + File = location.FilePath; + Line = line.Line + 1; + Character = line.Character + 1; + } + + public override string ToString() + { + var builder = new StringBuilder(); + + if (!string.IsNullOrWhiteSpace(File)) { + builder.Append(File); + if (Line.HasValue) { + builder.AppendFormat("({0}", Line); + if (Character.HasValue) + builder.AppendFormat(",{0}", Character); + builder.Append(")"); + } + builder.Append(": "); + } + builder.AppendFormat("{0} {1}", Type, Code); + if (!string.IsNullOrWhiteSpace(Message)) + builder.AppendFormat(": {0}", Message); + + return builder.ToString(); + } + } + + public class Warning : Diagnostic + { + public Warning(string code) : base("warning", code) { } + } + + public class MissingRefitAttributeWarning : Warning + { + public string InterfaceName { get; private set; } + public string MethodName { get; private set; } + + public MissingRefitAttributeWarning(InterfaceDeclarationSyntax @interface, MethodDeclarationSyntax method) + : base("RF001") + { + setLocation(method.GetLocation()); + + InterfaceName = @interface.Identifier.Text; + MethodName = method.Identifier.Text; + + Message = string.Format( + "Method {0}.{1} either has no Refit HTTP method attribute or you've used something other than a string literal for the 'path' argument.", + InterfaceName, MethodName); + } + } + + public class MultipleRefitMethodSameNameWarning : Warning + { + public string InterfaceName { get; private set; } + public string MethodName { get; private set; } + + public MultipleRefitMethodSameNameWarning(InterfaceDeclarationSyntax @interface, MethodDeclarationSyntax method) + : base("RF002") + { + setLocation(method.GetLocation()); + + InterfaceName = @interface.Identifier.Text; + MethodName = method.Identifier.Text; + + Message = string.Format( + "Method {0}.{1} has been declared multiple times. Refit doesn't support overloading.", + InterfaceName, MethodName); + } + } +} diff --git a/InterfaceStubGenerator/InterfaceStubGenerator.cs b/InterfaceStubGenerator/InterfaceStubGenerator.cs index 935289602..543981933 100644 --- a/InterfaceStubGenerator/InterfaceStubGenerator.cs +++ b/InterfaceStubGenerator/InterfaceStubGenerator.cs @@ -34,6 +34,8 @@ public string GenerateInterfaceStubs(string[] paths) var templateInfo = GenerateTemplateInfoForInterfaceList(interfacesToGenerate); + GenerateWarnings(interfacesToGenerate); + Encoders.HtmlEncode = (s) => s; var text = Render.StringToString(ExtractTemplateSource(), templateInfo); return text; @@ -126,6 +128,27 @@ public ClassTemplateInfo GenerateClassInfoForInterface(InterfaceDeclarationSynta return ret; } + public void GenerateWarnings(List interfacesToGenerate) + { + var missingAttributeWarnings = interfacesToGenerate + .SelectMany(i => i.Members.OfType().Select(m => new {Interface = i, Method = m})) + .Where(x => !HasRefitHttpMethodAttribute(x.Method)) + .Select(x => new MissingRefitAttributeWarning(x.Interface, x.Method)); + + var overloadWarnings = interfacesToGenerate + .SelectMany(i => i.Members.OfType().Select(m => new {Interface = i, Method = m})) + .Where(x => HasRefitHttpMethodAttribute(x.Method)) + .GroupBy(x => new {Interface = x.Interface, MethodName = x.Method.Identifier.Text}) + .Where(g => g.Count() > 1) + .SelectMany(g => g.Select(x => new MultipleRefitMethodSameNameWarning(x.Interface, x.Method))); + + var diagnostics = missingAttributeWarnings.Concat(overloadWarnings); + + foreach (var diagnostic in diagnostics) { + Console.Error.WriteLine(diagnostic); + } + } + public static string ExtractTemplateSource() { var ourPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); diff --git a/InterfaceStubGenerator/InterfaceStubGenerator.csproj b/InterfaceStubGenerator/InterfaceStubGenerator.csproj index 13e655fec..a0ec4bbb7 100644 --- a/InterfaceStubGenerator/InterfaceStubGenerator.csproj +++ b/InterfaceStubGenerator/InterfaceStubGenerator.csproj @@ -75,6 +75,7 @@ + @@ -95,4 +96,4 @@ --> - + \ No newline at end of file diff --git a/Refit-Tests/MethodOverloads.cs b/Refit-Tests/MethodOverloads.cs new file mode 100644 index 000000000..fe207ae06 --- /dev/null +++ b/Refit-Tests/MethodOverloads.cs @@ -0,0 +1,16 @@ +using System; +using System.Threading.Tasks; +using Refit; + +namespace Refit.Tests +{ + public interface IUseOverloadedMethods + { + [Get("/")] + Task Get(); + + [Get("/{id}")] + Task Get(int id); + } +} + diff --git a/Refit-Tests/Refit-Tests-Android.csproj b/Refit-Tests/Refit-Tests-Android.csproj index 8296b7f9d..bb82631ee 100644 --- a/Refit-Tests/Refit-Tests-Android.csproj +++ b/Refit-Tests/Refit-Tests-Android.csproj @@ -72,6 +72,7 @@ + diff --git a/Refit-Tests/Refit-Tests-Net45.csproj b/Refit-Tests/Refit-Tests-Net45.csproj index 20f25eeb7..741f37694 100644 --- a/Refit-Tests/Refit-Tests-Net45.csproj +++ b/Refit-Tests/Refit-Tests-Net45.csproj @@ -112,6 +112,7 @@ + diff --git a/Refit-Tests/Refit-Tests-iOS.csproj b/Refit-Tests/Refit-Tests-iOS.csproj index ca881a6ed..9c5041553 100644 --- a/Refit-Tests/Refit-Tests-iOS.csproj +++ b/Refit-Tests/Refit-Tests-iOS.csproj @@ -129,6 +129,7 @@ +