Fully qualify references to generated interfaces#1
Conversation
8e7605b to
640a9bb
Compare
This addresses an issue where, when a class references a generated interface, those references are not fully qualified, resulting in an interface that doesn't compile. The change is to precalculate the list of interface names that will be generated, and, during symbol string generation, replace unrecognised symbols with generated names _where a single unambiguous match can be made between the symbol and the list of interfaces being generated_.
- Change approach to use `ToDisplayParts`, which removes the need for regex parsing of generated code - Fix bug in `ReplaceWithInferredInterfaceName` where dots weren't being escaped - Add tests to ensure partially qualified references will be resolved correctly
…class; refactor This centralises the rendering logic plus simplifies the implementation to use `ITypeSymbol.WithNullableAnnotation` and hands the rendering off to the default `ToDisplayString` implementation
640a9bb to
44b679e
Compare
|
Resolved - I've done the split as I suggested below. Previous body:
|
| { | ||
| /// <inheritdoc cref="AutomaticInterfaceExample.DemoClass.TryStartTransaction(int?, int, string, Func{int, int})" /> | ||
| bool TryStartTransaction(int? param, int param2 = 0, string? data = null, Func<int, int>? func = null); | ||
| bool TryStartTransaction(int? param, int param2 = 0, string? data = null, Func<int, int> func = null); |
There was a problem hiding this comment.
Better null management now it's centralised - the func really wasn't nullable in the original definition.
| { | ||
| /// <inheritdoc cref="AutomaticInterfaceExample.DemoClass.CMethod{T, T1, T2, T3, T4, T5}(string, string)" /> | ||
| string CMethod<T, T1, T2, T3, T4, T5>(string x, string y) where T : class where T1 : struct where T3 : global::AutomaticInterfaceExample.DemoClass where T4 : IDemoClass where T5 : new(); | ||
| string CMethod<T, T1, T2, T3, T4, T5>(string x, string y) where T : class where T1 : struct where T3 : global::AutomaticInterfaceExample.DemoClass where T4 : global::AutomaticInterfaceExample.IDemoClass where T5 : new(); |
There was a problem hiding this comment.
The result of the new interface name resolution - correct qualification and no ambiguity in generated interfaces that reference generated interfaces.
| var sourceErrors = sourceDiagnostics | ||
| .Where(d => d.Severity == DiagnosticSeverity.Error) | ||
| .Where(x => x.Id != "CS0246") // missing references are ok | ||
| .Where(x => x.Id != "CS0246" && x.Id != "CS0234") // missing references are ok |
There was a problem hiding this comment.
Needed now we're referencing interfaces that don't yet exist.
| // The first syntax tree is the input code, the second two are the two generated attribute classes, and the rest is the generated code. | ||
| return string.Join( | ||
| Environment.NewLine + Environment.NewLine, | ||
| outputCompilation.SyntaxTrees.Skip(3) | ||
| ); |
There was a problem hiding this comment.
Don't just export the first syntax tree, export them all. We now have tests that generate two interfaces and we need them both in the output.
| ### 6.0.2 | ||
|
|
||
| - Added feature to allow generated interfaces to reference other generated interfaces |
There was a problem hiding this comment.
Possibly should be 7.0.0 - I'll leave the versioning to you @ChristianSauer 🙂
|
Hi @ChristianSauer , I've resolved the issue around how to work with RoslynExtensions and have split out the customisations into a new class, This PR is now ready for review. I hope all is going well with you, and if there are ways I can help with this project, I'd be happy to contribute |
6418e24 to
3248feb
Compare
…cements/extensions into a new project-specific class, `RoslynExtensionsAutomaticInterface`
This is a copy of codecentric#89, reopening after the sunsetting of that project.
This addresses an issue where, when a class references a generated interface, those references are not fully qualified, resulting in an interface that doesn't compile. See codecentric#87.
The change is to precalculate the list of interface names that will be generated, and, during symbol string generation, replace unrecognised symbols with generated names where a single unambiguous match can be made between the symbol and the list of interfaces being generated.
For the example provided in codecentric#87, the code will now generate this output: