| | | 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 | | } |