fix: do not inspect compiler extensions without a public parameterless constructor#17
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request fixes several issues with compiler extension inspection in the Roslyn component, specifically addressing exceptions that occurred when inspecting abstract classes, non-public types, or types without public parameterless constructors. It also corrects the behavior where inherited attributes were incorrectly detected.
Changes:
- Added validation to skip abstract classes and types without public parameterless constructors before instantiation
- Changed from
GetExportedTypes()toGetTypes()to inspect internal and private compiler extensions - Modified
GetCustomAttributecalls to useinherit: falseto prevent false detection of inherited attributes - Added comprehensive demo classes and tests to verify edge cases
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| source/lib/FlashOWare.CodeAnalysis.Inspection.Core/Components/RoslynComponent.cs | Core logic changes: added IsNotConstructible validation, switched to GetTypes(), fixed attribute inheritance |
| source/lib/FlashOWare.CodeAnalysis.Inspection.Core/FlashOWare.CodeAnalysis.Inspection.Core.csproj | Updated package references to include CSharp and VisualBasic packages |
| source/tests/FlashOWare.CodeAnalysis.Inspection.Core.Tests/Components/RoslynComponentTests.cs | Updated test expectations to include internal and private compiler extensions |
| source/tests/FlashOWare.CodeAnalysis.Inspection.Core.Tests/Assertions/CompilerExtensionAssertions.cs | Added new AssertExtension method to validate extensions by type name |
| source/tests/FlashOWare.CodeAnalysis.Inspection.Core.Tests/Assertions/ClassInfoAssertions.cs | Added overload to compare TypeName with ClassInfo |
| source/demo/FlashOWare.CodeAnalysis.Demo/Generators/CommonIncrementalGeneratorDemos.cs | Added demo classes for edge case testing (abstract, internal, private, missing constructors, etc.) |
| source/demo/FlashOWare.CodeAnalysis.Demo/Generators/CommonSourceGeneratorDemos.cs | Added demo classes for edge case testing |
| source/demo/FlashOWare.CodeAnalysis.Demo/Diagnostics/CommonDiagnosticAnalyzerDemos.cs | Added demo classes for edge case testing |
| source/demo/FlashOWare.CodeAnalysis.Demo/Diagnostics/CommonDiagnosticSuppressorDemos.cs | Added demo classes for edge case testing |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Type type = extension.GetType(); | ||
| Assert.IsFalse(type.IsAbstract); | ||
| Assert.IsTrue(type.IsSealed); | ||
|
|
There was a problem hiding this comment.
The assertions at lines 34-35 check properties of the CompilerExtension wrapper type (GeneratorInfo, AnalyzerInfo, SuppressorInfo) rather than the inspected compiler extension type. Since all wrapper types are sealed by design, these assertions will always pass and don't provide meaningful validation of the inspected types. Consider removing these assertions or changing them to validate properties of extension.Class (the inspected type) if that's the intent.
| Type type = extension.GetType(); | |
| Assert.IsFalse(type.IsAbstract); | |
| Assert.IsTrue(type.IsSealed); |
| private static ImmutableArray<CompilerExtension> Inspect(Assembly component) | ||
| { | ||
| Type[] types = component.GetExportedTypes(); | ||
| Type[] types = component.GetTypes(); |
There was a problem hiding this comment.
The change from GetExportedTypes() to GetTypes() could throw ReflectionTypeLoadException if some types in the assembly cannot be loaded. Consider wrapping this call in a try-catch block or using GetTypes() with exception handling to gracefully handle assemblies with types that fail to load. Alternatively, use Assembly.GetTypes() with a try-catch that accesses the LoaderExceptions property to log or handle specific failures.
There was a problem hiding this comment.
Will fix in a follow-up.
Summary
abstractclasspublicconstructor[Attribute]is only inheritedRemarks