| | | 1 | | using Microsoft.CodeAnalysis; |
| | | 2 | | |
| | | 3 | | namespace NexusLabs.Needlr.Generators; |
| | | 4 | | |
| | | 5 | | /// <summary> |
| | | 6 | | /// Contains diagnostic descriptors for the Needlr source generator. |
| | | 7 | | /// </summary> |
| | | 8 | | internal static class DiagnosticDescriptors |
| | | 9 | | { |
| | | 10 | | private const string Category = "NexusLabs.Needlr.Generators"; |
| | | 11 | | private const string HelpLinkBase = "https://github.com/nexus-labs/needlr/blob/main/docs/analyzers/"; |
| | | 12 | | |
| | | 13 | | /// <summary> |
| | | 14 | | /// NDLRGEN001: Internal type in referenced assembly cannot be registered. |
| | | 15 | | /// </summary> |
| | | 16 | | /// <remarks> |
| | | 17 | | /// This error is emitted when a type in a referenced assembly: |
| | | 18 | | /// - Matches the namespace filter |
| | | 19 | | /// - Would be registerable (injectable or plugin) if it were accessible |
| | | 20 | | /// - Is internal (not public) and thus inaccessible from the generated code |
| | | 21 | | /// |
| | | 22 | | /// To fix this error, add [GenerateTypeRegistry] to the referenced assembly |
| | | 23 | | /// so that it generates its own type registry that can access its internal types. |
| | | 24 | | /// </remarks> |
| | 1 | 25 | | public static readonly DiagnosticDescriptor InaccessibleInternalType = new( |
| | 1 | 26 | | id: "NDLRGEN001", |
| | 1 | 27 | | title: "Internal type in referenced assembly cannot be registered", |
| | 1 | 28 | | messageFormat: "Type '{0}' in assembly '{1}' is internal and cannot be registered. Add [GenerateTypeRegistry] at |
| | 1 | 29 | | category: Category, |
| | 1 | 30 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 31 | | isEnabledByDefault: true, |
| | 1 | 32 | | description: "Internal types in referenced assemblies cannot be accessed by the generated code. To include inter |
| | 1 | 33 | | helpLinkUri: HelpLinkBase + "NDLRGEN001.md"); |
| | | 34 | | |
| | | 35 | | /// <summary> |
| | | 36 | | /// NDLRGEN002: Referenced assembly has internal plugin types but no [GenerateTypeRegistry] attribute. |
| | | 37 | | /// </summary> |
| | | 38 | | /// <remarks> |
| | | 39 | | /// This error is emitted when a referenced assembly: |
| | | 40 | | /// - Contains internal types that implement plugin interfaces (e.g., IServiceCollectionPlugin) |
| | | 41 | | /// - Does not have a [GenerateTypeRegistry] attribute |
| | | 42 | | /// |
| | | 43 | | /// Without the attribute, the internal plugin types will not be registered and will |
| | | 44 | | /// silently fail to load at runtime. |
| | | 45 | | /// </remarks> |
| | 1 | 46 | | public static readonly DiagnosticDescriptor MissingGenerateTypeRegistryAttribute = new( |
| | 1 | 47 | | id: "NDLRGEN002", |
| | 1 | 48 | | title: "Referenced assembly has internal plugin types but no type registry", |
| | 1 | 49 | | messageFormat: "Assembly '{0}' contains internal plugin type '{1}' but has no [GenerateTypeRegistry] attribute. |
| | 1 | 50 | | category: Category, |
| | 1 | 51 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 52 | | isEnabledByDefault: true, |
| | 1 | 53 | | description: "Referenced assemblies with internal plugin types must have a [GenerateTypeRegistry] attribute to g |
| | 1 | 54 | | helpLinkUri: HelpLinkBase + "NDLRGEN002.md"); |
| | | 55 | | |
| | | 56 | | /// <summary> |
| | | 57 | | /// NDLRGEN003: [GenerateFactory] on type with all injectable parameters is unnecessary. |
| | | 58 | | /// </summary> |
| | 1 | 59 | | public static readonly DiagnosticDescriptor FactoryAllParamsInjectable = new( |
| | 1 | 60 | | id: "NDLRGEN003", |
| | 1 | 61 | | title: "[GenerateFactory] unnecessary - all parameters are injectable", |
| | 1 | 62 | | messageFormat: "Type '{0}' has [GenerateFactory] but all constructor parameters are injectable. Consider removin |
| | 1 | 63 | | category: Category, |
| | 1 | 64 | | defaultSeverity: DiagnosticSeverity.Warning, |
| | 1 | 65 | | isEnabledByDefault: true, |
| | 1 | 66 | | description: "The [GenerateFactory] attribute generates a factory for types with mixed injectable and runtime pa |
| | 1 | 67 | | helpLinkUri: HelpLinkBase + "NDLRGEN003.md"); |
| | | 68 | | |
| | | 69 | | /// <summary> |
| | | 70 | | /// NDLRGEN004: [GenerateFactory] on type with no injectable parameters provides low value. |
| | | 71 | | /// </summary> |
| | 1 | 72 | | public static readonly DiagnosticDescriptor FactoryNoInjectableParams = new( |
| | 1 | 73 | | id: "NDLRGEN004", |
| | 1 | 74 | | title: "[GenerateFactory] has low value - no injectable parameters", |
| | 1 | 75 | | messageFormat: "Type '{0}' has [GenerateFactory] but no constructor parameters are injectable. The factory provi |
| | 1 | 76 | | category: Category, |
| | 1 | 77 | | defaultSeverity: DiagnosticSeverity.Warning, |
| | 1 | 78 | | isEnabledByDefault: true, |
| | 1 | 79 | | description: "The [GenerateFactory] attribute is most useful when a type has a mix of injectable and runtime par |
| | 1 | 80 | | helpLinkUri: HelpLinkBase + "NDLRGEN004.md"); |
| | | 81 | | |
| | | 82 | | /// <summary> |
| | | 83 | | /// NDLRGEN005: [GenerateFactory<T>] type argument must be an interface implemented by the class. |
| | | 84 | | /// </summary> |
| | 1 | 85 | | public static readonly DiagnosticDescriptor FactoryTypeArgNotImplemented = new( |
| | 1 | 86 | | id: "NDLRGEN005", |
| | 1 | 87 | | title: "[GenerateFactory<T>] type argument not implemented", |
| | 1 | 88 | | messageFormat: "Type '{0}' has [GenerateFactory<{1}>] but does not implement '{1}'. The type argument must be an |
| | 1 | 89 | | category: Category, |
| | 1 | 90 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 91 | | isEnabledByDefault: true, |
| | 1 | 92 | | description: "When using [GenerateFactory<T>], T must be an interface that the decorated class implements. The f |
| | 1 | 93 | | helpLinkUri: HelpLinkBase + "NDLRGEN005.md"); |
| | | 94 | | |
| | | 95 | | /// <summary> |
| | | 96 | | /// NDLRGEN006: [OpenDecoratorFor] type argument must be an open generic interface. |
| | | 97 | | /// </summary> |
| | 1 | 98 | | public static readonly DiagnosticDescriptor OpenDecoratorTypeNotOpenGeneric = new( |
| | 1 | 99 | | id: "NDLRGEN006", |
| | 1 | 100 | | title: "[OpenDecoratorFor] type must be an open generic interface", |
| | 1 | 101 | | messageFormat: "Type argument '{0}' in [OpenDecoratorFor] is not an open generic interface: {1}", |
| | 1 | 102 | | category: Category, |
| | 1 | 103 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 104 | | isEnabledByDefault: true, |
| | 1 | 105 | | description: "The [OpenDecoratorFor] attribute requires an open generic interface type. Use typeof(IInterface<>) |
| | 1 | 106 | | helpLinkUri: HelpLinkBase + "NDLRGEN006.md"); |
| | | 107 | | |
| | | 108 | | /// <summary> |
| | | 109 | | /// NDLRGEN007: [OpenDecoratorFor] decorator class must be an open generic with matching arity. |
| | | 110 | | /// </summary> |
| | 1 | 111 | | public static readonly DiagnosticDescriptor OpenDecoratorClassNotOpenGeneric = new( |
| | 1 | 112 | | id: "NDLRGEN007", |
| | 1 | 113 | | title: "[OpenDecoratorFor] decorator must be an open generic class", |
| | 1 | 114 | | messageFormat: "Class '{0}' with [OpenDecoratorFor({1})] must be an open generic class with {2} type parameter(s |
| | 1 | 115 | | category: Category, |
| | 1 | 116 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 117 | | isEnabledByDefault: true, |
| | 1 | 118 | | description: "When using [OpenDecoratorFor(typeof(IInterface<>))], the decorated class must also be an open gene |
| | 1 | 119 | | helpLinkUri: HelpLinkBase + "NDLRGEN007.md"); |
| | | 120 | | |
| | | 121 | | /// <summary> |
| | | 122 | | /// NDLRGEN008: [OpenDecoratorFor] decorator class must implement the open generic interface. |
| | | 123 | | /// </summary> |
| | 1 | 124 | | public static readonly DiagnosticDescriptor OpenDecoratorNotImplementingInterface = new( |
| | 1 | 125 | | id: "NDLRGEN008", |
| | 1 | 126 | | title: "[OpenDecoratorFor] decorator must implement the interface", |
| | 1 | 127 | | messageFormat: "Class '{0}' has [OpenDecoratorFor({1})] but does not implement '{1}'. The decorator must impleme |
| | 1 | 128 | | category: Category, |
| | 1 | 129 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 130 | | isEnabledByDefault: true, |
| | 1 | 131 | | description: "A decorator must implement the same interface as the services it wraps. Ensure the class implement |
| | 1 | 132 | | helpLinkUri: HelpLinkBase + "NDLRGEN008.md"); |
| | | 133 | | |
| | | 134 | | // ============================================================================ |
| | | 135 | | // Options Validation Analyzers (NDLRGEN014-021) |
| | | 136 | | // ============================================================================ |
| | | 137 | | |
| | | 138 | | /// <summary> |
| | | 139 | | /// NDLRGEN014: Validator type must implement IOptionsValidator<T> or have a valid Validate method. |
| | | 140 | | /// </summary> |
| | 1 | 141 | | public static readonly DiagnosticDescriptor ValidatorTypeMissingInterface = new( |
| | 1 | 142 | | id: "NDLRGEN014", |
| | 1 | 143 | | title: "Validator type has no validation method", |
| | 1 | 144 | | messageFormat: "Validator type '{0}' must have a Validate method. Implement IOptionsValidator<{1}> or add a 'Val |
| | 1 | 145 | | category: Category, |
| | 1 | 146 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 147 | | isEnabledByDefault: true, |
| | 1 | 148 | | description: "When using Validator property on [Options], the specified type must have a valid validation method |
| | 1 | 149 | | helpLinkUri: HelpLinkBase + "NDLRGEN014.md"); |
| | | 150 | | |
| | | 151 | | /// <summary> |
| | | 152 | | /// NDLRGEN015: Validator's generic type parameter doesn't match the options type. |
| | | 153 | | /// </summary> |
| | 1 | 154 | | public static readonly DiagnosticDescriptor ValidatorTypeMismatch = new( |
| | 1 | 155 | | id: "NDLRGEN015", |
| | 1 | 156 | | title: "Validator type mismatch", |
| | 1 | 157 | | messageFormat: "Validator '{0}' validates '{1}' but is applied to options type '{2}'. The validator must be for |
| | 1 | 158 | | category: Category, |
| | 1 | 159 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 160 | | isEnabledByDefault: true, |
| | 1 | 161 | | description: "The Validator specified in [Options(Validator = ...)] must validate the same type as the options c |
| | 1 | 162 | | helpLinkUri: HelpLinkBase + "NDLRGEN015.md"); |
| | | 163 | | |
| | | 164 | | /// <summary> |
| | | 165 | | /// NDLRGEN016: ValidateMethod specified but method not found on target type. |
| | | 166 | | /// </summary> |
| | 1 | 167 | | public static readonly DiagnosticDescriptor ValidateMethodNotFound = new( |
| | 1 | 168 | | id: "NDLRGEN016", |
| | 1 | 169 | | title: "Validation method not found", |
| | 1 | 170 | | messageFormat: "Method '{0}' not found on type '{1}'. Ensure the method exists and has the correct signature.", |
| | 1 | 171 | | category: Category, |
| | 1 | 172 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 173 | | isEnabledByDefault: true, |
| | 1 | 174 | | description: "The ValidateMethod specified in [Options] must exist on the options type (or Validator type if spe |
| | 1 | 175 | | helpLinkUri: HelpLinkBase + "NDLRGEN016.md"); |
| | | 176 | | |
| | | 177 | | /// <summary> |
| | | 178 | | /// NDLRGEN017: Validation method has incorrect signature. |
| | | 179 | | /// </summary> |
| | 1 | 180 | | public static readonly DiagnosticDescriptor ValidateMethodWrongSignature = new( |
| | 1 | 181 | | id: "NDLRGEN017", |
| | 1 | 182 | | title: "Validation method has wrong signature", |
| | 1 | 183 | | messageFormat: "Method '{0}' on type '{1}' has wrong signature, expected {2}", |
| | 1 | 184 | | category: Category, |
| | 1 | 185 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 186 | | isEnabledByDefault: true, |
| | 1 | 187 | | description: "Validation methods must return IEnumerable<ValidationError> or IEnumerable<string>. Instance metho |
| | 1 | 188 | | helpLinkUri: HelpLinkBase + "NDLRGEN017.md"); |
| | | 189 | | |
| | | 190 | | /// <summary> |
| | | 191 | | /// NDLRGEN018: Validator specified but ValidateOnStart is false. |
| | | 192 | | /// </summary> |
| | 1 | 193 | | public static readonly DiagnosticDescriptor ValidatorWontRun = new( |
| | 1 | 194 | | id: "NDLRGEN018", |
| | 1 | 195 | | title: "Validator won't run", |
| | 1 | 196 | | messageFormat: "Validator '{0}' will not run because ValidateOnStart is false. Set ValidateOnStart = true to ena |
| | 1 | 197 | | category: Category, |
| | 1 | 198 | | defaultSeverity: DiagnosticSeverity.Warning, |
| | 1 | 199 | | isEnabledByDefault: true, |
| | 1 | 200 | | description: "When Validator is specified but ValidateOnStart is not enabled, the validator will never be invoke |
| | 1 | 201 | | helpLinkUri: HelpLinkBase + "NDLRGEN018.md"); |
| | | 202 | | |
| | | 203 | | /// <summary> |
| | | 204 | | /// NDLRGEN019: ValidateMethod specified but ValidateOnStart is false. |
| | | 205 | | /// </summary> |
| | 1 | 206 | | public static readonly DiagnosticDescriptor ValidateMethodWontRun = new( |
| | 1 | 207 | | id: "NDLRGEN019", |
| | 1 | 208 | | title: "Validation method won't run", |
| | 1 | 209 | | messageFormat: "ValidateMethod '{0}' will not run because ValidateOnStart is false. Set ValidateOnStart = true t |
| | 1 | 210 | | category: Category, |
| | 1 | 211 | | defaultSeverity: DiagnosticSeverity.Warning, |
| | 1 | 212 | | isEnabledByDefault: true, |
| | 1 | 213 | | description: "When ValidateMethod is specified but ValidateOnStart is not enabled, the validation method will ne |
| | 1 | 214 | | helpLinkUri: HelpLinkBase + "NDLRGEN019.md"); |
| | | 215 | | |
| | | 216 | | // ============================================================================ |
| | | 217 | | // AOT Compatibility Analyzers (NDLRGEN020+) |
| | | 218 | | // ============================================================================ |
| | | 219 | | |
| | | 220 | | /// <summary> |
| | | 221 | | /// NDLRGEN020: [Options] attribute is not compatible with AOT/trimming. |
| | | 222 | | /// </summary> |
| | | 223 | | /// <remarks> |
| | | 224 | | /// The [Options] feature generates calls to Configure<T>() and BindConfiguration() |
| | | 225 | | /// which use reflection for configuration binding. These APIs are not AOT-compatible. |
| | | 226 | | /// </remarks> |
| | 1 | 227 | | public static readonly DiagnosticDescriptor OptionsNotAotCompatible = new( |
| | 1 | 228 | | id: "NDLRGEN020", |
| | 1 | 229 | | title: "[Options] is not compatible with AOT", |
| | 1 | 230 | | messageFormat: "Type '{0}' has [Options] attribute but is in an AOT-enabled project. The [Options] feature uses |
| | 1 | 231 | | category: Category, |
| | 1 | 232 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 233 | | isEnabledByDefault: true, |
| | 1 | 234 | | description: "The [Options] attribute generates code that calls Configure<T>() and BindConfiguration() which use |
| | 1 | 235 | | helpLinkUri: HelpLinkBase + "NDLRGEN020.md"); |
| | | 236 | | |
| | | 237 | | /// <summary> |
| | | 238 | | /// NDLRGEN021: Positional record with [Options] must be declared partial. |
| | | 239 | | /// </summary> |
| | | 240 | | /// <remarks> |
| | | 241 | | /// Positional records lack parameterless constructors, which are required for |
| | | 242 | | /// configuration binding. When the record is partial, the generator can emit |
| | | 243 | | /// a parameterless constructor. Non-partial records cannot be extended. |
| | | 244 | | /// </remarks> |
| | 1 | 245 | | public static readonly DiagnosticDescriptor PositionalRecordMustBePartial = new( |
| | 1 | 246 | | id: "NDLRGEN021", |
| | 1 | 247 | | title: "Positional record must be partial for [Options]", |
| | 1 | 248 | | messageFormat: "Positional record '{0}' has [Options] but is not declared partial. Add the 'partial' modifier to |
| | 1 | 249 | | category: Category, |
| | 1 | 250 | | defaultSeverity: DiagnosticSeverity.Warning, |
| | 1 | 251 | | isEnabledByDefault: true, |
| | 1 | 252 | | description: "Positional records (records with primary constructor parameters) lack parameterless constructors, |
| | 1 | 253 | | helpLinkUri: HelpLinkBase + "NDLRGEN021.md"); |
| | | 254 | | |
| | | 255 | | /// <summary> |
| | | 256 | | /// NDLRGEN022: Disposable service may be captured by a longer-lived service. |
| | | 257 | | /// </summary> |
| | | 258 | | /// <remarks> |
| | | 259 | | /// This error is emitted when a longer-lived service (e.g., Singleton) has a constructor |
| | | 260 | | /// dependency on a shorter-lived service (e.g., Scoped, Transient) that implements |
| | | 261 | | /// IDisposable or IAsyncDisposable. This is a "captive dependency" anti-pattern where |
| | | 262 | | /// the disposable may be disposed while the consuming service still holds a reference. |
| | | 263 | | /// |
| | | 264 | | /// Unlike NDLRCOR012 which only detects explicit lifetime attributes, this diagnostic |
| | | 265 | | /// uses inferred lifetimes from Needlr's convention-based discovery, catching more issues. |
| | | 266 | | /// </remarks> |
| | 1 | 267 | | public static readonly DiagnosticDescriptor DisposableCaptiveDependency = new( |
| | 1 | 268 | | id: "NDLRGEN022", |
| | 1 | 269 | | title: "Disposable captive dependency detected", |
| | 1 | 270 | | messageFormat: "'{0}' ({1}) depends on '{2}' ({3}) which implements IDisposable. The disposable may be disposed |
| | 1 | 271 | | category: Category, |
| | 1 | 272 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 273 | | isEnabledByDefault: true, |
| | 1 | 274 | | description: "A longer-lived service captures a shorter-lived disposable dependency. When the shorter-lived scop |
| | 1 | 275 | | helpLinkUri: HelpLinkBase + "NDLRGEN022.md"); |
| | | 276 | | |
| | | 277 | | /// <summary> |
| | | 278 | | /// NDLRGEN030: DataAnnotation attribute cannot be source-generated. |
| | | 279 | | /// </summary> |
| | 1 | 280 | | public static readonly DiagnosticDescriptor UnsupportedDataAnnotation = new( |
| | 1 | 281 | | id: "NDLRGEN030", |
| | 1 | 282 | | title: "DataAnnotation attribute cannot be source-generated", |
| | 1 | 283 | | messageFormat: "DataAnnotation '{0}' on '{1}.{2}' cannot be source-generated. In AOT mode, this validation will |
| | 1 | 284 | | category: Category, |
| | 1 | 285 | | defaultSeverity: DiagnosticSeverity.Warning, |
| | 1 | 286 | | isEnabledByDefault: true, |
| | 1 | 287 | | description: "This DataAnnotation validation attribute cannot be source-generated because it requires runtime re |
| | 1 | 288 | | helpLinkUri: HelpLinkBase + "NDLRGEN030.md"); |
| | | 289 | | |
| | | 290 | | // ============================================================================ |
| | | 291 | | // Provider Analyzers (NDLRGEN031-034) |
| | | 292 | | // ============================================================================ |
| | | 293 | | |
| | | 294 | | /// <summary> |
| | | 295 | | /// NDLRGEN031: [Provider] on class requires `partial` modifier. |
| | | 296 | | /// </summary> |
| | 1 | 297 | | public static readonly DiagnosticDescriptor ProviderClassNotPartial = new( |
| | 1 | 298 | | id: "NDLRGEN031", |
| | 1 | 299 | | title: "[Provider] on class requires partial modifier", |
| | 1 | 300 | | messageFormat: "Class '{0}' has [Provider] attribute but is not declared partial. Add the 'partial' modifier to |
| | 1 | 301 | | category: Category, |
| | 1 | 302 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 303 | | isEnabledByDefault: true, |
| | 1 | 304 | | description: "When applying [Provider] to a class (shorthand mode), the class must be declared partial so the ge |
| | 1 | 305 | | helpLinkUri: HelpLinkBase + "NDLRGEN031.md"); |
| | | 306 | | |
| | | 307 | | /// <summary> |
| | | 308 | | /// NDLRGEN032: [Provider] interface must only contain get-only properties. |
| | | 309 | | /// </summary> |
| | 1 | 310 | | public static readonly DiagnosticDescriptor ProviderInterfaceInvalidMember = new( |
| | 1 | 311 | | id: "NDLRGEN032", |
| | 1 | 312 | | title: "[Provider] interface has invalid member", |
| | 1 | 313 | | messageFormat: "Interface '{0}' has [Provider] attribute but contains {1}. Provider interfaces must only contain |
| | 1 | 314 | | category: Category, |
| | 1 | 315 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 316 | | isEnabledByDefault: true, |
| | 1 | 317 | | description: "Provider interfaces should only contain get-only properties that represent the services to be prov |
| | 1 | 318 | | helpLinkUri: HelpLinkBase + "NDLRGEN032.md"); |
| | | 319 | | |
| | | 320 | | /// <summary> |
| | | 321 | | /// NDLRGEN033: Provider property type is a concrete class, consider using an interface. |
| | | 322 | | /// </summary> |
| | 1 | 323 | | public static readonly DiagnosticDescriptor ProviderPropertyConcreteType = new( |
| | 1 | 324 | | id: "NDLRGEN033", |
| | 1 | 325 | | title: "Provider property uses concrete type", |
| | 1 | 326 | | messageFormat: "Provider property '{0}.{1}' has type '{2}' which is a concrete class. Consider using an interfac |
| | 1 | 327 | | category: Category, |
| | 1 | 328 | | defaultSeverity: DiagnosticSeverity.Warning, |
| | 1 | 329 | | isEnabledByDefault: true, |
| | 1 | 330 | | description: "Provider properties represent services resolved from the DI container. Using interface types inste |
| | 1 | 331 | | helpLinkUri: HelpLinkBase + "NDLRGEN033.md"); |
| | | 332 | | |
| | | 333 | | /// <summary> |
| | | 334 | | /// NDLRGEN034: Circular provider dependency detected. |
| | | 335 | | /// </summary> |
| | 1 | 336 | | public static readonly DiagnosticDescriptor ProviderCircularDependency = new( |
| | 1 | 337 | | id: "NDLRGEN034", |
| | 1 | 338 | | title: "Circular provider dependency detected", |
| | 1 | 339 | | messageFormat: "Provider '{0}' has a circular dependency: {1}", |
| | 1 | 340 | | category: Category, |
| | 1 | 341 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 342 | | isEnabledByDefault: true, |
| | 1 | 343 | | description: "A circular dependency was detected in the provider dependency graph. Provider A references Provide |
| | 1 | 344 | | helpLinkUri: HelpLinkBase + "NDLRGEN034.md"); |
| | | 345 | | |
| | | 346 | | // ============================================================================ |
| | | 347 | | // Composition Analyzers (NDLRGEN035-038) |
| | | 348 | | // ============================================================================ |
| | | 349 | | |
| | | 350 | | /// <summary> |
| | | 351 | | /// NDLRGEN035: [RegisterClosedOverImplementationsOf] source type must be an open generic interface. |
| | | 352 | | /// </summary> |
| | 1 | 353 | | public static readonly DiagnosticDescriptor ComposedSourceNotOpenGenericInterface = new( |
| | 1 | 354 | | id: "NDLRGEN035", |
| | 1 | 355 | | title: "[RegisterClosedOverImplementationsOf] source type must be an open generic interface", |
| | 1 | 356 | | messageFormat: "Source type argument '{0}' in [RegisterClosedOverImplementationsOf] is not an open generic inter |
| | 1 | 357 | | category: Category, |
| | 1 | 358 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 359 | | isEnabledByDefault: true, |
| | 1 | 360 | | description: "The [RegisterClosedOverImplementationsOf] attribute requires an open generic interface type whose |
| | 1 | 361 | | helpLinkUri: HelpLinkBase + "NDLRGEN035.md"); |
| | | 362 | | |
| | | 363 | | /// <summary> |
| | | 364 | | /// NDLRGEN036: [RegisterClosedOverImplementationsOf] composition class must be an open generic with matching arity. |
| | | 365 | | /// </summary> |
| | 1 | 366 | | public static readonly DiagnosticDescriptor ComposedClassNotOpenGeneric = new( |
| | 1 | 367 | | id: "NDLRGEN036", |
| | 1 | 368 | | title: "[RegisterClosedOverImplementationsOf] composition must be an open generic class", |
| | 1 | 369 | | messageFormat: "Class '{0}' with [RegisterClosedOverImplementationsOf({1})] must be an open generic class with { |
| | 1 | 370 | | category: Category, |
| | 1 | 371 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 372 | | isEnabledByDefault: true, |
| | 1 | 373 | | description: "When using [RegisterClosedOverImplementationsOf(typeof(IInterface<>))], the annotated composition |
| | 1 | 374 | | helpLinkUri: HelpLinkBase + "NDLRGEN036.md"); |
| | | 375 | | |
| | | 376 | | /// <summary> |
| | | 377 | | /// NDLRGEN037: [RegisterClosedOverImplementationsOf] composition class must implement the As service type. |
| | | 378 | | /// </summary> |
| | 1 | 379 | | public static readonly DiagnosticDescriptor ComposedClassNotImplementingAs = new( |
| | 1 | 380 | | id: "NDLRGEN037", |
| | 1 | 381 | | title: "[RegisterClosedOverImplementationsOf] composition must implement the As service type", |
| | 1 | 382 | | messageFormat: "Class '{0}' must implement the 'As' service type specified by [RegisterClosedOverImplementations |
| | 1 | 383 | | category: Category, |
| | 1 | 384 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 385 | | isEnabledByDefault: true, |
| | 1 | 386 | | description: "Each closed composition is registered as the service type named by 'As', so the annotated class mu |
| | 1 | 387 | | helpLinkUri: HelpLinkBase + "NDLRGEN037.md"); |
| | | 388 | | |
| | | 389 | | /// <summary> |
| | | 390 | | /// NDLRGEN038: A discovered type argument cannot legally close the composition type. |
| | | 391 | | /// </summary> |
| | | 392 | | /// <remarks> |
| | | 393 | | /// Emitted by the generator (not the per-attribute analyzer) because only the generator knows the |
| | | 394 | | /// full set of discovered implementations. The offending registration is skipped rather than emitting |
| | | 395 | | /// code that fails to compile, turning a would-be runtime absence into a build-time signal. |
| | | 396 | | /// </remarks> |
| | 1 | 397 | | public static readonly DiagnosticDescriptor ComposedTypeArgumentViolatesConstraints = new( |
| | 1 | 398 | | id: "NDLRGEN038", |
| | 1 | 399 | | title: "[RegisterClosedOverImplementationsOf] discovered type argument violates composition constraints", |
| | 1 | 400 | | messageFormat: "Composition '{0}' cannot be closed over type argument(s) '{1}' from an implementation of '{2}' b |
| | 1 | 401 | | category: Category, |
| | 1 | 402 | | defaultSeverity: DiagnosticSeverity.Warning, |
| | 1 | 403 | | isEnabledByDefault: true, |
| | 1 | 404 | | description: "An implementation of the designated open generic interface was discovered whose type argument(s) d |
| | 1 | 405 | | helpLinkUri: HelpLinkBase + "NDLRGEN038.md"); |
| | | 406 | | |
| | | 407 | | // ============================================================================ |
| | | 408 | | // Generated Constructor Analyzer (NDLRGEN039-056) |
| | | 409 | | // ============================================================================ |
| | | 410 | | |
| | | 411 | | /// <summary> |
| | | 412 | | /// NDLRGEN039: A type using generated-constructor generation must be declared partial. |
| | | 413 | | /// </summary> |
| | 1 | 414 | | public static readonly DiagnosticDescriptor GeneratedConstructorRequiresPartialType = new( |
| | 1 | 415 | | id: "NDLRGEN039", |
| | 1 | 416 | | title: "Generated-constructor type must be partial", |
| | 1 | 417 | | messageFormat: "Type '{0}' must be declared 'partial' because it uses [GenerateConstructor] or a field-level con |
| | 1 | 418 | | category: Category, |
| | 1 | 419 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 420 | | isEnabledByDefault: true, |
| | 1 | 421 | | description: "Roslyn source generators can only contribute new members to a type declared partial. Add the 'part |
| | 1 | 422 | | helpLinkUri: HelpLinkBase + "NDLRGEN039.md"); |
| | | 423 | | |
| | | 424 | | /// <summary> |
| | | 425 | | /// NDLRGEN040: A record type or nested type cannot use generated-constructor generation. |
| | | 426 | | /// </summary> |
| | 1 | 427 | | public static readonly DiagnosticDescriptor GeneratedConstructorUnsupportedTypeShape = new( |
| | 1 | 428 | | id: "NDLRGEN040", |
| | 1 | 429 | | title: "Generated-constructor type shape is unsupported", |
| | 1 | 430 | | messageFormat: "Type '{0}' cannot use generated-constructor generation because it is {1}", |
| | 1 | 431 | | category: Category, |
| | 1 | 432 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 433 | | isEnabledByDefault: true, |
| | 1 | 434 | | description: "Generated-constructor generation only supports top-level, non-record partial classes. Records and |
| | 1 | 435 | | helpLinkUri: HelpLinkBase + "NDLRGEN040.md"); |
| | | 436 | | |
| | | 437 | | /// <summary> |
| | | 438 | | /// NDLRGEN041: An explicit instance constructor conflicts with generated-constructor generation. |
| | | 439 | | /// </summary> |
| | 1 | 440 | | public static readonly DiagnosticDescriptor GeneratedConstructorConflictsWithExplicitConstructor = new( |
| | 1 | 441 | | id: "NDLRGEN041", |
| | 1 | 442 | | title: "Generated-constructor conflicts with an explicit constructor", |
| | 1 | 443 | | messageFormat: "Type '{0}' declares an explicit instance constructor, which conflicts with generated-constructor |
| | 1 | 444 | | category: Category, |
| | 1 | 445 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 446 | | isEnabledByDefault: true, |
| | 1 | 447 | | description: "Generated-constructor generation requires exactly one unambiguous constructor. A type with its own |
| | 1 | 448 | | helpLinkUri: HelpLinkBase + "NDLRGEN041.md"); |
| | | 449 | | |
| | | 450 | | /// <summary> |
| | | 451 | | /// NDLRGEN042: The base type must expose an accessible parameterless constructor. |
| | | 452 | | /// </summary> |
| | 1 | 453 | | public static readonly DiagnosticDescriptor GeneratedConstructorBaseTypeRequiresParameterlessConstructor = new( |
| | 1 | 454 | | id: "NDLRGEN042", |
| | 1 | 455 | | title: "Generated-constructor base type requires a parameterless constructor", |
| | 1 | 456 | | messageFormat: "Type '{0}' derives from '{1}', which has no accessible parameterless constructor; generated-cons |
| | 1 | 457 | | category: Category, |
| | 1 | 458 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 459 | | isEnabledByDefault: true, |
| | 1 | 460 | | description: "The generated constructor relies on the implicit base() call. A base type that requires constructo |
| | 1 | 461 | | helpLinkUri: HelpLinkBase + "NDLRGEN042.md"); |
| | | 462 | | |
| | | 463 | | /// <summary> |
| | | 464 | | /// NDLRGEN043: No eligible field exists for generated-constructor generation. |
| | | 465 | | /// </summary> |
| | 1 | 466 | | public static readonly DiagnosticDescriptor GeneratedConstructorNoEligibleFields = new( |
| | 1 | 467 | | id: "NDLRGEN043", |
| | 1 | 468 | | title: "No eligible field for generated-constructor generation", |
| | 1 | 469 | | messageFormat: "Type '{0}' has no private readonly instance field without an initializer, so generated-construct |
| | 1 | 470 | | category: Category, |
| | 1 | 471 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 472 | | isEnabledByDefault: true, |
| | 1 | 473 | | description: "Generated-constructor generation requires at least one eligible field: a private, instance, readon |
| | 1 | 474 | | helpLinkUri: HelpLinkBase + "NDLRGEN043.md"); |
| | | 475 | | |
| | | 476 | | /// <summary> |
| | | 477 | | /// NDLRGEN044: Normalized constructor parameter names collide. |
| | | 478 | | /// </summary> |
| | 1 | 479 | | public static readonly DiagnosticDescriptor GeneratedConstructorParameterNameCollision = new( |
| | 1 | 480 | | id: "NDLRGEN044", |
| | 1 | 481 | | title: "Generated-constructor parameter names collide", |
| | 1 | 482 | | messageFormat: "Type '{0}' has two or more eligible fields that normalize to the same constructor parameter name |
| | 1 | 483 | | category: Category, |
| | 1 | 484 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 485 | | isEnabledByDefault: true, |
| | 1 | 486 | | description: "Field names are normalized to constructor parameter names by removing a leading underscore and low |
| | 1 | 487 | | helpLinkUri: HelpLinkBase + "NDLRGEN044.md"); |
| | | 488 | | |
| | | 489 | | /// <summary> |
| | | 490 | | /// NDLRGEN045: A constructor guard exclusion attribute has no effect. |
| | | 491 | | /// </summary> |
| | 1 | 492 | | public static readonly DiagnosticDescriptor ConstructorGuardAttributeHasNoEffect = new( |
| | 1 | 493 | | id: "NDLRGEN045", |
| | 1 | 494 | | title: "Constructor guard attribute has no effect", |
| | 1 | 495 | | messageFormat: "Field '{0}' has {1}, but its containing type has no [GenerateConstructor] and no other field has |
| | 1 | 496 | | category: Category, |
| | 1 | 497 | | defaultSeverity: DiagnosticSeverity.Warning, |
| | 1 | 498 | | isEnabledByDefault: true, |
| | 1 | 499 | | description: "[ConstructorIgnore] and [ConstructorGuard(ConstructorGuardKind.None)] are exclusion-only modifiers |
| | 1 | 500 | | helpLinkUri: HelpLinkBase + "NDLRGEN045.md"); |
| | | 501 | | |
| | | 502 | | /// <summary> |
| | | 503 | | /// NDLRGEN046: A constructor guard attribute is applied to an ineligible field. |
| | | 504 | | /// </summary> |
| | 1 | 505 | | public static readonly DiagnosticDescriptor ConstructorGuardAttributeOnIneligibleField = new( |
| | 1 | 506 | | id: "NDLRGEN046", |
| | 1 | 507 | | title: "Constructor guard attribute applied to an ineligible field", |
| | 1 | 508 | | messageFormat: "Field '{0}' cannot participate in generated-constructor generation because it is {1}, so its con |
| | 1 | 509 | | category: Category, |
| | 1 | 510 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 511 | | isEnabledByDefault: true, |
| | 1 | 512 | | description: "Only a private, instance, readonly field without an initializer can become a generated-constructor |
| | 1 | 513 | | helpLinkUri: HelpLinkBase + "NDLRGEN046.md"); |
| | | 514 | | |
| | | 515 | | /// <summary> |
| | | 516 | | /// NDLRGEN047: A guard-mode enum argument is not a defined value. |
| | | 517 | | /// </summary> |
| | 1 | 518 | | public static readonly DiagnosticDescriptor InvalidConstructorGuardEnumValue = new( |
| | 1 | 519 | | id: "NDLRGEN047", |
| | 1 | 520 | | title: "Invalid constructor guard enum value", |
| | 1 | 521 | | messageFormat: "'{0}' is not a defined {1} value", |
| | 1 | 522 | | category: Category, |
| | 1 | 523 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 524 | | isEnabledByDefault: true, |
| | 1 | 525 | | description: "ConstructorGuardKind and ConstructorNullGuardMode arguments must be one of the enum's defined memb |
| | 1 | 526 | | helpLinkUri: HelpLinkBase + "NDLRGEN047.md"); |
| | | 527 | | |
| | | 528 | | /// <summary> |
| | | 529 | | /// NDLRGEN048: A built-in guard kind is incompatible with the field's type. |
| | | 530 | | /// </summary> |
| | 1 | 531 | | public static readonly DiagnosticDescriptor ConstructorGuardIncompatibleWithFieldType = new( |
| | 1 | 532 | | id: "NDLRGEN048", |
| | 1 | 533 | | title: "Constructor guard incompatible with member type", |
| | 1 | 534 | | messageFormat: "The '{0}' guard cannot be used on member '{1}' of type '{2}': {3}", |
| | 1 | 535 | | category: Category, |
| | 1 | 536 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 537 | | isEnabledByDefault: true, |
| | 1 | 538 | | description: "NotNullOrEmpty and NotNullOrWhiteSpace only apply to string-compatible fields or properties. NotNu |
| | 1 | 539 | | helpLinkUri: HelpLinkBase + "NDLRGEN048.md"); |
| | | 540 | | |
| | | 541 | | /// <summary> |
| | | 542 | | /// NDLRGEN049: A custom guard type is missing or inaccessible. |
| | | 543 | | /// </summary> |
| | 1 | 544 | | public static readonly DiagnosticDescriptor ConstructorGuardTypeInvalid = new( |
| | 1 | 545 | | id: "NDLRGEN049", |
| | 1 | 546 | | title: "Custom constructor guard type is invalid", |
| | 1 | 547 | | messageFormat: "The custom guard type for member '{0}' is invalid: {1}", |
| | 1 | 548 | | category: Category, |
| | 1 | 549 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 550 | | isEnabledByDefault: true, |
| | 1 | 551 | | description: "A custom constructor guard type must exist and be accessible from the generated constructor. Fix t |
| | 1 | 552 | | helpLinkUri: HelpLinkBase + "NDLRGEN049.md"); |
| | | 553 | | |
| | | 554 | | /// <summary> |
| | | 555 | | /// NDLRGEN050: A custom guard method name is empty or whitespace. |
| | | 556 | | /// </summary> |
| | 1 | 557 | | public static readonly DiagnosticDescriptor ConstructorGuardMethodNameInvalid = new( |
| | 1 | 558 | | id: "NDLRGEN050", |
| | 1 | 559 | | title: "Custom constructor guard method name is invalid", |
| | 1 | 560 | | messageFormat: "The custom guard method name for member '{0}' must not be empty or consist only of white space", |
| | 1 | 561 | | category: Category, |
| | 1 | 562 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 563 | | isEnabledByDefault: true, |
| | 1 | 564 | | description: "An explicit custom guard method name must be a non-empty, non-whitespace identifier, typically sup |
| | 1 | 565 | | helpLinkUri: HelpLinkBase + "NDLRGEN050.md"); |
| | | 566 | | |
| | | 567 | | /// <summary> |
| | | 568 | | /// NDLRGEN051: No compatible custom guard method was found. |
| | | 569 | | /// </summary> |
| | 1 | 570 | | public static readonly DiagnosticDescriptor ConstructorGuardMethodInvalid = new( |
| | 1 | 571 | | id: "NDLRGEN051", |
| | 1 | 572 | | title: "Custom constructor guard method is invalid", |
| | 1 | 573 | | messageFormat: "Guard method '{0}' on type '{1}' is not valid for member '{2}' of type '{3}': {4}", |
| | 1 | 574 | | category: Category, |
| | 1 | 575 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 576 | | isEnabledByDefault: true, |
| | 1 | 577 | | description: "A custom guard method must be an accessible static method returning void with exactly two paramete |
| | 1 | 578 | | helpLinkUri: HelpLinkBase + "NDLRGEN051.md"); |
| | | 579 | | |
| | | 580 | | /// <summary> |
| | | 581 | | /// NDLRGEN052: Multiple custom guard method overloads match the field. |
| | | 582 | | /// </summary> |
| | 1 | 583 | | public static readonly DiagnosticDescriptor ConstructorGuardMethodAmbiguous = new( |
| | 1 | 584 | | id: "NDLRGEN052", |
| | 1 | 585 | | title: "Custom constructor guard method is ambiguous", |
| | 1 | 586 | | messageFormat: "Multiple accessible static methods named '{0}' on type '{1}' are compatible with member '{2}' of |
| | 1 | 587 | | category: Category, |
| | 1 | 588 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 589 | | isEnabledByDefault: true, |
| | 1 | 590 | | description: "Overload resolution for a custom guard method is intentionally simple and direct rather than full |
| | 1 | 591 | | helpLinkUri: HelpLinkBase + "NDLRGEN052.md"); |
| | | 592 | | |
| | | 593 | | /// <summary> |
| | | 594 | | /// NDLRGEN053: [ConstructorGuardDefinition] is applied to an unsupported attribute type. |
| | | 595 | | /// </summary> |
| | 1 | 596 | | public static readonly DiagnosticDescriptor ConstructorGuardDefinitionTargetInvalid = new( |
| | 1 | 597 | | id: "NDLRGEN053", |
| | 1 | 598 | | title: "[ConstructorGuardDefinition] target is invalid", |
| | 1 | 599 | | messageFormat: "'{0}' cannot carry [ConstructorGuardDefinition] because it is {1}", |
| | 1 | 600 | | category: Category, |
| | 1 | 601 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 602 | | isEnabledByDefault: true, |
| | 1 | 603 | | description: "[ConstructorGuardDefinition] must decorate an Attribute-derived type whose [AttributeUsage] allows |
| | 1 | 604 | | helpLinkUri: HelpLinkBase + "NDLRGEN053.md"); |
| | | 605 | | |
| | | 606 | | /// <summary> |
| | | 607 | | /// NDLRGEN054: A [ConstructorGuardDefinition]'s own guard reference is unresolved. |
| | | 608 | | /// </summary> |
| | 1 | 609 | | public static readonly DiagnosticDescriptor ConstructorGuardDefinitionUnresolvedGuard = new( |
| | 1 | 610 | | id: "NDLRGEN054", |
| | 1 | 611 | | title: "[ConstructorGuardDefinition] guard contract is unresolved", |
| | 1 | 612 | | messageFormat: "[ConstructorGuardDefinition] on '{0}' is invalid: {1}", |
| | 1 | 613 | | category: Category, |
| | 1 | 614 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 615 | | isEnabledByDefault: true, |
| | 1 | 616 | | description: "The guard type and method referenced by [ConstructorGuardDefinition] must resolve to the same acce |
| | 1 | 617 | | helpLinkUri: HelpLinkBase + "NDLRGEN054.md"); |
| | | 618 | | |
| | | 619 | | /// <summary> |
| | | 620 | | /// NDLRGEN055: A parameterized custom guard alias usage forwards an argument shape |
| | | 621 | | /// or a named argument/property that this version does not support forwarding. |
| | | 622 | | /// </summary> |
| | 1 | 623 | | public static readonly DiagnosticDescriptor ConstructorGuardAliasUsageArgumentUnsupported = new( |
| | 1 | 624 | | id: "NDLRGEN055", |
| | 1 | 625 | | title: "Constructor guard alias usage argument is unsupported", |
| | 1 | 626 | | messageFormat: "The alias attribute usage on member '{0}' is invalid: {1}", |
| | 1 | 627 | | category: Category, |
| | 1 | 628 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 629 | | isEnabledByDefault: true, |
| | 1 | 630 | | description: "A parameterized custom guard alias forwards every positional constructor argument of its usage ont |
| | 1 | 631 | | helpLinkUri: HelpLinkBase + "NDLRGEN055.md"); |
| | | 632 | | |
| | | 633 | | /// <summary> |
| | | 634 | | /// NDLRGEN056: A custom guard method is incompatible with the arguments a |
| | | 635 | | /// parameterized alias usage forwards to it, either because the method's effective |
| | | 636 | | /// arity does not match the number of forwarded arguments, or because one of the |
| | | 637 | | /// forwarded argument types is incompatible with the corresponding parameter. |
| | | 638 | | /// </summary> |
| | 1 | 639 | | public static readonly DiagnosticDescriptor ConstructorGuardForwardedArgumentIncompatible = new( |
| | 1 | 640 | | id: "NDLRGEN056", |
| | 1 | 641 | | title: "Custom constructor guard method is incompatible with forwarded alias arguments", |
| | 1 | 642 | | messageFormat: "Guard method '{0}' on type '{1}' cannot accept the arguments forwarded for member '{2}' of type |
| | 1 | 643 | | category: Category, |
| | 1 | 644 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 645 | | isEnabledByDefault: true, |
| | 1 | 646 | | description: "A parameterized custom guard alias usage forwards its own positional constructor arguments between |
| | 1 | 647 | | helpLinkUri: HelpLinkBase + "NDLRGEN056.md"); |
| | | 648 | | |
| | | 649 | | // ============================================================================ |
| | | 650 | | // Record Constructor Overload Analyzer (NDLRGEN057-062) |
| | | 651 | | // ============================================================================ |
| | | 652 | | |
| | | 653 | | /// <summary> |
| | | 654 | | /// NDLRGEN057: A record receiving a generated constructor overload must be partial. |
| | | 655 | | /// </summary> |
| | 1 | 656 | | public static readonly DiagnosticDescriptor RecordConstructorOverloadRequiresPartialType = new( |
| | 1 | 657 | | id: "NDLRGEN057", |
| | 1 | 658 | | title: "Record constructor-overload type must be partial", |
| | 1 | 659 | | messageFormat: "Record '{0}' must be declared 'partial' because [RecordConstructorOverloadParameter] requires a |
| | 1 | 660 | | category: Category, |
| | 1 | 661 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 662 | | isEnabledByDefault: true, |
| | 1 | 663 | | description: "A generated forwarding constructor can only be contributed to a partial positional record class. A |
| | 1 | 664 | | helpLinkUri: HelpLinkBase + "NDLRGEN057.md"); |
| | | 665 | | |
| | | 666 | | /// <summary> |
| | | 667 | | /// NDLRGEN058: The marked property's containing type is not a supported record. |
| | | 668 | | /// </summary> |
| | 1 | 669 | | public static readonly DiagnosticDescriptor RecordConstructorOverloadUnsupportedTypeShape = new( |
| | 1 | 670 | | id: "NDLRGEN058", |
| | 1 | 671 | | title: "Record constructor-overload type shape is unsupported", |
| | 1 | 672 | | messageFormat: "Type '{0}' cannot use [RecordConstructorOverloadParameter] because it is {1}", |
| | 1 | 673 | | category: Category, |
| | 1 | 674 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 675 | | isEnabledByDefault: true, |
| | 1 | 676 | | description: "Record constructor-overload generation supports only top-level, non-file-local positional record c |
| | 1 | 677 | | helpLinkUri: HelpLinkBase + "NDLRGEN058.md"); |
| | | 678 | | |
| | | 679 | | /// <summary> |
| | | 680 | | /// NDLRGEN059: A marked property cannot be assigned by the generated overload. |
| | | 681 | | /// </summary> |
| | 1 | 682 | | public static readonly DiagnosticDescriptor RecordConstructorOverloadPropertyUnsupported = new( |
| | 1 | 683 | | id: "NDLRGEN059", |
| | 1 | 684 | | title: "Record constructor-overload property is unsupported", |
| | 1 | 685 | | messageFormat: "Property '{0}' cannot participate in a generated record constructor overload because it is {1}", |
| | 1 | 686 | | category: Category, |
| | 1 | 687 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 688 | | isEnabledByDefault: true, |
| | 1 | 689 | | description: "A participating property must be a non-static, non-indexer, non-required, assignable instance prop |
| | 1 | 690 | | helpLinkUri: HelpLinkBase + "NDLRGEN059.md"); |
| | | 691 | | |
| | | 692 | | /// <summary> |
| | | 693 | | /// NDLRGEN060: A property guard has no participating record-overload parameter. |
| | | 694 | | /// </summary> |
| | 1 | 695 | | public static readonly DiagnosticDescriptor ConstructorGuardOnNonparticipatingProperty = new( |
| | 1 | 696 | | id: "NDLRGEN060", |
| | 1 | 697 | | title: "Constructor guard property does not participate in an overload", |
| | 1 | 698 | | messageFormat: "Property '{0}' has a constructor guard but is not marked with [RecordConstructorOverloadParamete |
| | 1 | 699 | | category: Category, |
| | 1 | 700 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 701 | | isEnabledByDefault: true, |
| | 1 | 702 | | description: "Constructor guards on properties are valid only for properties marked with [RecordConstructorOverl |
| | 1 | 703 | | helpLinkUri: HelpLinkBase + "NDLRGEN060.md"); |
| | | 704 | | |
| | | 705 | | /// <summary> |
| | | 706 | | /// NDLRGEN061: Field-based constructor generation conflicts with the record-only feature. |
| | | 707 | | /// </summary> |
| | 1 | 708 | | public static readonly DiagnosticDescriptor RecordConstructorOverloadConflictsWithGeneratedConstructor = new( |
| | 1 | 709 | | id: "NDLRGEN061", |
| | 1 | 710 | | title: "Record constructor overload conflicts with field-based generation", |
| | 1 | 711 | | messageFormat: "Type '{0}' cannot combine [RecordConstructorOverloadParameter] with [GenerateConstructor] or a f |
| | 1 | 712 | | category: Category, |
| | 1 | 713 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 714 | | isEnabledByDefault: true, |
| | 1 | 715 | | description: "The field-based generated-constructor feature owns an ordinary class construction path and partici |
| | 1 | 716 | | helpLinkUri: HelpLinkBase + "NDLRGEN061.md"); |
| | | 717 | | |
| | | 718 | | /// <summary> |
| | | 719 | | /// NDLRGEN062: The proposed constructor signature already exists. |
| | | 720 | | /// </summary> |
| | 1 | 721 | | public static readonly DiagnosticDescriptor RecordConstructorOverloadSignatureCollision = new( |
| | 1 | 722 | | id: "NDLRGEN062", |
| | 1 | 723 | | title: "Record constructor-overload signature collides", |
| | 1 | 724 | | messageFormat: "Record '{0}' cannot receive the generated constructor overload because its C# signature would co |
| | 1 | 725 | | category: Category, |
| | 1 | 726 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 727 | | isEnabledByDefault: true, |
| | 1 | 728 | | description: "Constructor signature identity ignores parameter names, nullable annotations, optional values, and |
| | 1 | 729 | | helpLinkUri: HelpLinkBase + "NDLRGEN062.md"); |
| | | 730 | | |
| | | 731 | | // ============================================================================ |
| | | 732 | | // Generated Constructor Suggestions (NDLRGEN063) |
| | | 733 | | // ============================================================================ |
| | | 734 | | |
| | | 735 | | /// <summary> |
| | | 736 | | /// NDLRGEN063: A hand-written constructor is mechanically replaceable by |
| | | 737 | | /// Needlr's generated-constructor feature. |
| | | 738 | | /// </summary> |
| | 1 | 739 | | public static readonly DiagnosticDescriptor GenerateConstructorSuggested = new( |
| | 1 | 740 | | id: "NDLRGEN063", |
| | 1 | 741 | | title: "Constructor can be generated by Needlr", |
| | 1 | 742 | | messageFormat: "Constructor for type '{0}' can be replaced by Needlr's generated-constructor feature without cha |
| | 1 | 743 | | category: Category, |
| | 1 | 744 | | defaultSeverity: DiagnosticSeverity.Info, |
| | 1 | 745 | | isEnabledByDefault: true, |
| | 1 | 746 | | description: "The type has one public constructor whose parameters, supported guard calls, and private readonly |
| | 1 | 747 | | helpLinkUri: HelpLinkBase + "NDLRGEN063.md"); |
| | | 748 | | |
| | | 749 | | // ============================================================================ |
| | | 750 | | // HttpClient Analyzers (NDLRHTTP001-006) |
| | | 751 | | // ============================================================================ |
| | | 752 | | |
| | | 753 | | /// <summary> |
| | | 754 | | /// NDLRHTTP001: [HttpClientOptions] target must implement INamedHttpClientOptions. |
| | | 755 | | /// </summary> |
| | 1 | 756 | | public static readonly DiagnosticDescriptor HttpClientMustImplementMarker = new( |
| | 1 | 757 | | id: "NDLRHTTP001", |
| | 1 | 758 | | title: "[HttpClientOptions] target must implement INamedHttpClientOptions", |
| | 1 | 759 | | messageFormat: "Type '{0}' has [HttpClientOptions] but does not implement INamedHttpClientOptions. Implement the |
| | 1 | 760 | | category: Category, |
| | 1 | 761 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 762 | | isEnabledByDefault: true, |
| | 1 | 763 | | description: "The INamedHttpClientOptions marker is the contract that opts a type into HttpClient source generat |
| | 1 | 764 | | helpLinkUri: HelpLinkBase + "NDLRHTTP001.md"); |
| | | 765 | | |
| | | 766 | | /// <summary> |
| | | 767 | | /// NDLRHTTP002: Attribute Name argument conflicts with the ClientName property on the type. |
| | | 768 | | /// </summary> |
| | 1 | 769 | | public static readonly DiagnosticDescriptor HttpClientNameSourceConflict = new( |
| | 1 | 770 | | id: "NDLRHTTP002", |
| | 1 | 771 | | title: "HttpClient name sources conflict", |
| | 1 | 772 | | messageFormat: "Type '{0}' has [HttpClientOptions(Name = \"{1}\")] but its ClientName property resolves to \"{2} |
| | 1 | 773 | | category: Category, |
| | 1 | 774 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 775 | | isEnabledByDefault: true, |
| | 1 | 776 | | description: "The HttpClient name can come from the attribute argument, a ClientName property on the type, or ty |
| | 1 | 777 | | helpLinkUri: HelpLinkBase + "NDLRHTTP002.md"); |
| | | 778 | | |
| | | 779 | | /// <summary> |
| | | 780 | | /// NDLRHTTP003: ClientName property body is not a literal expression and no attribute Name override is supplied. |
| | | 781 | | /// </summary> |
| | 1 | 782 | | public static readonly DiagnosticDescriptor HttpClientNamePropertyNotLiteral = new( |
| | 1 | 783 | | id: "NDLRHTTP003", |
| | 1 | 784 | | title: "ClientName property body is not a literal expression", |
| | 1 | 785 | | messageFormat: "Type '{0}' has a ClientName property whose body is not a string literal. The generator resolves |
| | 1 | 786 | | category: Category, |
| | 1 | 787 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 788 | | isEnabledByDefault: true, |
| | 1 | 789 | | description: "HttpClient names must be known at compile time because the generator emits services.AddHttpClient( |
| | 1 | 790 | | helpLinkUri: HelpLinkBase + "NDLRHTTP003.md"); |
| | | 791 | | |
| | | 792 | | /// <summary> |
| | | 793 | | /// NDLRHTTP004: Resolved HttpClient name is empty or whitespace. |
| | | 794 | | /// </summary> |
| | 1 | 795 | | public static readonly DiagnosticDescriptor HttpClientNameEmpty = new( |
| | 1 | 796 | | id: "NDLRHTTP004", |
| | 1 | 797 | | title: "Resolved HttpClient name is empty", |
| | 1 | 798 | | messageFormat: "Type '{0}' has [HttpClientOptions] but no name source resolves to a non-empty value", |
| | 1 | 799 | | category: Category, |
| | 1 | 800 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 801 | | isEnabledByDefault: true, |
| | 1 | 802 | | description: "At least one of the three name sources must yield a non-empty string. This typically happens when |
| | 1 | 803 | | helpLinkUri: HelpLinkBase + "NDLRHTTP004.md"); |
| | | 804 | | |
| | | 805 | | /// <summary> |
| | | 806 | | /// NDLRHTTP005: Two [HttpClientOptions] types in the compilation resolve to the same client name. |
| | | 807 | | /// </summary> |
| | 1 | 808 | | public static readonly DiagnosticDescriptor HttpClientNameCollision = new( |
| | 1 | 809 | | id: "NDLRHTTP005", |
| | 1 | 810 | | title: "Duplicate HttpClient name", |
| | 1 | 811 | | messageFormat: "Type '{0}' resolves to HttpClient name \"{1}\" which is already used by type '{2}'. HttpClient n |
| | 1 | 812 | | category: Category, |
| | 1 | 813 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 814 | | isEnabledByDefault: true, |
| | 1 | 815 | | description: "services.AddHttpClient(\"name\", ...) registrations are keyed by name. Two options types resolving |
| | 1 | 816 | | helpLinkUri: HelpLinkBase + "NDLRHTTP005.md", |
| | 1 | 817 | | customTags: WellKnownDiagnosticTags.CompilationEnd); |
| | | 818 | | |
| | | 819 | | /// <summary> |
| | | 820 | | /// NDLRHTTP006: ClientName property must be an instance property returning string. |
| | | 821 | | /// </summary> |
| | 1 | 822 | | public static readonly DiagnosticDescriptor HttpClientNamePropertyWrongShape = new( |
| | 1 | 823 | | id: "NDLRHTTP006", |
| | 1 | 824 | | title: "ClientName property has wrong shape", |
| | 1 | 825 | | messageFormat: "Type '{0}' has a ClientName property that is not a readable instance property of type 'string'. |
| | 1 | 826 | | category: Category, |
| | 1 | 827 | | defaultSeverity: DiagnosticSeverity.Error, |
| | 1 | 828 | | isEnabledByDefault: true, |
| | 1 | 829 | | description: "The ClientName property is one of the three name sources recognized by the generator. To avoid amb |
| | 1 | 830 | | helpLinkUri: HelpLinkBase + "NDLRHTTP006.md"); |
| | | 831 | | } |