private bool AnalyzeMemberWithinContext(ITypeSymbol type, ISymbol?symbol, SyntaxNodeAnalysisContext context, Location?focusDiagnosticOn = null) { if (type is null) { throw new ArgumentNullException(nameof(type)); } bool requiresUIThread = (type.TypeKind == TypeKind.Interface || type.TypeKind == TypeKind.Class || type.TypeKind == TypeKind.Struct) && this.MembersRequiringMainThread.Contains(type, symbol); if (requiresUIThread) { ThreadingContext threadingContext = ThreadingContext.Unknown; SyntaxNode? methodDeclaration = context.Node.FirstAncestorOrSelf <SyntaxNode>(n => CSharpCommonInterest.MethodSyntaxKinds.Contains(n.Kind())); if (methodDeclaration is object) { threadingContext = this.methodDeclarationNodes.GetValueOrDefault(methodDeclaration); } if (threadingContext != ThreadingContext.MainThread) { CSharpUtils.ContainingFunctionData function = CSharpUtils.GetContainingFunction((CSharpSyntaxNode)context.Node); Location location = focusDiagnosticOn ?? context.Node.GetLocation(); DiagnosticDescriptor?descriptor = function.IsAsync ? DescriptorAsync : DescriptorSync; var formattingArgs = function.IsAsync ? new object[] { type.Name } : new object[] { type.Name, this.MainThreadAssertingMethods.FirstOrDefault() }; context.ReportDiagnostic(Diagnostic.Create(descriptor, location, this.DiagnosticProperties, formattingArgs)); return(true); } } return(false); }
private static void CheckArgument( ISymbol targetSymbol, IObjectCreationOperation creation, IParameterSymbol parameter, string stringArgument, OperationAnalysisContext context) { bool matchesParameter = MatchesParameter(targetSymbol, creation, stringArgument); DiagnosticDescriptor?rule = null; if (IsMessage(parameter) && matchesParameter) { rule = RuleIncorrectMessage; } else if (IsParameterName(parameter) && !matchesParameter) { // Allow argument exceptions in accessors to use the associated property symbol name. if (MatchesAssociatedSymbol(targetSymbol, stringArgument)) { return; } rule = RuleIncorrectParameterName; } if (rule != null) { context.ReportDiagnostic(context.Operation.Syntax.CreateDiagnostic(rule, targetSymbol.Name, stringArgument, parameter.Name, creation.Type.Name)); } }
public bool Equals(DiagnosticDescriptor?x, DiagnosticDescriptor?y) { if (ReferenceEquals(x, y)) { return(true); } if (x is null || y is null) { return(false); } // The properties are guaranteed to be non-null by DiagnosticDescriptor invariants. Debug.Assert(x.Description != null && x.Title != null && x.CustomTags != null); Debug.Assert(y.Description != null && y.Title != null && y.CustomTags != null); return(x.Category == y.Category && x.DefaultSeverity == y.DefaultSeverity && x.Description !.Equals(y.Description) && x.HelpLinkUri == y.HelpLinkUri && x.Id == y.Id && x.IsEnabledByDefault == y.IsEnabledByDefault && x.Title !.Equals(y.Title) && x.CustomTags.SequenceEqual(y.CustomTags)); }
/// <inheritdoc/> protected override bool ValidateTargetType( GeneratorExecutionContext context, AttributeData attributeData, ClassDeclarationSyntax classDeclaration, INamedTypeSymbol classDeclarationSymbol, [NotNullWhen(false)] out DiagnosticDescriptor?descriptor) { INamedTypeSymbol iNotifyPropertyChangedSymbol = context.Compilation.GetTypeByMetadataName("System.ComponentModel.INotifyPropertyChanged") !, iNotifyPropertyChangingSymbol = context.Compilation.GetTypeByMetadataName("System.ComponentModel.INotifyPropertyChanging") !; // Check if the type already implements INotifyPropertyChanged... if (classDeclarationSymbol.AllInterfaces.Any(i => SymbolEqualityComparer.Default.Equals(i, iNotifyPropertyChangedSymbol))) { descriptor = DuplicateINotifyPropertyChangedInterfaceForObservableObjectAttributeError; return(false); } // ...or INotifyPropertyChanging if (classDeclarationSymbol.AllInterfaces.Any(i => SymbolEqualityComparer.Default.Equals(i, iNotifyPropertyChangingSymbol))) { descriptor = DuplicateINotifyPropertyChangingInterfaceForObservableObjectAttributeError; return(false); } descriptor = null; return(true); }
/// <summary> /// Processes the markup syntax for this <see cref="SolutionState"/> according to the current /// <see cref="MarkupHandling"/>, and returns a new <see cref="SolutionState"/> with the /// <see cref="ProjectState.Sources"/>, <see cref="ProjectState.GeneratedSources"/>, /// <see cref="ProjectState.AdditionalFiles"/>, <see cref="ProjectState.AnalyzerConfigFiles"/>, and /// <see cref="ExpectedDiagnostics"/> updated accordingly. /// </summary> /// <param name="markupOptions">Additional options to apply during markup processing.</param> /// <param name="defaultDiagnostic">The diagnostic descriptor to use for markup spans without an explicit name, /// or <see langword="null"/> if no such default exists.</param> /// <param name="supportedDiagnostics">The diagnostics supported by analyzers used by the test.</param> /// <param name="fixableDiagnostics">The set of diagnostic IDs to treat as fixable. This value is only used when /// <see cref="MarkupHandling"/> is <see cref="MarkupMode.IgnoreFixable"/>.</param> /// <param name="defaultPath">The default file path for diagnostics reported in source code.</param> /// <returns>A new <see cref="SolutionState"/> with all markup processing completed according to the current /// <see cref="MarkupHandling"/>. The <see cref="MarkupHandling"/> of the returned instance is /// <see cref="MarkupMode.None"/>.</returns> /// <exception cref="InvalidOperationException">If <see cref="InheritanceMode"/> is not /// <see cref="StateInheritanceMode.Explicit"/>.</exception> public SolutionState WithProcessedMarkup(MarkupOptions markupOptions, DiagnosticDescriptor?defaultDiagnostic, ImmutableArray <DiagnosticDescriptor> supportedDiagnostics, ImmutableArray <string> fixableDiagnostics, string defaultPath) { if (InheritanceMode != StateInheritanceMode.Explicit) { throw new InvalidOperationException("Inheritance processing must complete before markup processing."); } var markupLocations = ImmutableDictionary <string, FileLinePositionSpan> .Empty; (var expected, var testSources) = ProcessMarkupSources(Sources, ExpectedDiagnostics, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath); var(additionalExpected2, testGeneratedSources) = ProcessMarkupSources(GeneratedSources, expected, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath); var(additionalExpected1, additionalFiles) = ProcessMarkupSources(AdditionalFiles.Concat(AdditionalFilesFactories.SelectMany(factory => factory())), additionalExpected2, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath); var(additionalExpected, analyzerConfigFiles) = ProcessMarkupSources(AnalyzerConfigFiles, additionalExpected1, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath); var result = new SolutionState(Name, Language, DefaultPrefix, DefaultExtension); result.MarkupHandling = MarkupMode.None; result.InheritanceMode = StateInheritanceMode.Explicit; result.ReferenceAssemblies = ReferenceAssemblies; result.OutputKind = OutputKind; result.DocumentationMode = DocumentationMode; result.Sources.AddRange(testSources); result.GeneratedSources.AddRange(testGeneratedSources); result.AdditionalFiles.AddRange(additionalFiles); result.AnalyzerConfigFiles.AddRange(analyzerConfigFiles); foreach (var(projectName, projectState) in AdditionalProjects) { var(correctedIntermediateDiagnostics, additionalProjectSources) = ProcessMarkupSources(projectState.Sources, additionalExpected, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath); var(correctedDiagnostics2, additionalProjectGeneratedSources) = ProcessMarkupSources(projectState.GeneratedSources, correctedIntermediateDiagnostics, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath); var(correctedDiagnostics1, additionalProjectAdditionalFiles) = ProcessMarkupSources(projectState.AdditionalFiles.Concat(projectState.AdditionalFilesFactories.SelectMany(factory => factory())), correctedDiagnostics2, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath); var(correctedDiagnostics, additionalProjectAnalyzerConfigFiles) = ProcessMarkupSources(projectState.AnalyzerConfigFiles, correctedDiagnostics1, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath); var processedProjectState = new ProjectState(projectState); processedProjectState.Sources.Clear(); processedProjectState.Sources.AddRange(additionalProjectSources); processedProjectState.GeneratedSources.Clear(); processedProjectState.GeneratedSources.AddRange(additionalProjectGeneratedSources); processedProjectState.AdditionalFiles.Clear(); processedProjectState.AdditionalFilesFactories.Clear(); processedProjectState.AdditionalFiles.AddRange(additionalProjectAdditionalFiles); processedProjectState.AnalyzerConfigFiles.Clear(); processedProjectState.AnalyzerConfigFiles.AddRange(additionalProjectAnalyzerConfigFiles); result.AdditionalProjects.Add(projectName, processedProjectState); additionalExpected = correctedDiagnostics; } for (var i = 0; i < additionalExpected.Length; i++) { additionalExpected[i] = additionalExpected[i].WithAppliedMarkupLocations(markupLocations); } result.AdditionalProjectReferences.AddRange(AdditionalProjectReferences); result.AdditionalReferences.AddRange(AdditionalReferences); result.ExpectedDiagnostics.AddRange(additionalExpected); return(result); }
public int Compare(DiagnosticDescriptor?x, DiagnosticDescriptor?y) { // Sort null as less than non-null. if (x is null) { return(y is null ? 0 : -1); } if (y is null) { return(1); } return(GetOrderIndexFromDescriptor(x) - GetOrderIndexFromDescriptor(y)); }
protected AbstractCodeStyleDiagnosticAnalyzer( string descriptorId, LocalizableString title, LocalizableString?messageFormat = null, bool configurable = true) { DescriptorId = descriptorId; _localizableTitle = title; _localizableMessageFormat = messageFormat ?? title; Descriptor = CreateDescriptorWithId(DescriptorId, _localizableTitle, _localizableMessageFormat, isConfigurable: configurable); UnnecessaryWithSuggestionDescriptor = CreateUnnecessaryDescriptor(DescriptorId, configurable); UnnecessaryWithoutSuggestionDescriptor = CreateUnnecessaryDescriptor(descriptorId + "WithoutSuggestion", configurable); SupportedDiagnostics = ImmutableArray.Create( Descriptor, UnnecessaryWithoutSuggestionDescriptor, UnnecessaryWithSuggestionDescriptor); }
/// <summary> /// Helper method to format a Diagnostic into an easily readable string /// </summary> /// <param name="analyzer">The analyzer that this verifier tests</param> /// <param name="diagnostics">The Diagnostics to be formatted</param> /// <returns>The Diagnostics formatted as a string</returns> private static string FormatDiagnostics(DiagnosticAnalyzer analyzer, params Diagnostic[] diagnostics) { StringBuilder builder = new(); foreach (Diagnostic diagnostic in diagnostics) { builder = builder.Append("// ") .AppendLine(diagnostic.ToString()); Type analyzerType = analyzer.GetType(); ImmutableArray <DiagnosticDescriptor> rules = analyzer.SupportedDiagnostics; DiagnosticDescriptor?rule = rules.FirstOrDefault(rule => rule.Id == diagnostic.Id); if (rule == null) { continue; } Location location = diagnostic.Location; if (location == Location.None) { builder = builder.Append(provider: CultureInfo.InvariantCulture, $"GetGlobalResult({analyzerType.Name}.{rule.Id})"); } else { Assert.True(condition: location.IsInSource, $"Test base does not currently handle diagnostics in metadata locations. Diagnostic in metadata: {diagnostic}\r\n"); string resultMethodName = GetResultMethodName(diagnostic); LinePosition linePosition = diagnostic.Location.GetLineSpan() .StartLinePosition; builder = builder.Append(provider: CultureInfo.InvariantCulture, $"{resultMethodName}({linePosition.Line + 1}, {linePosition.Character + 1}, {analyzerType.Name}.{rule.Id})"); } builder = builder.Append(value: ',') .AppendLine(); } return(builder.ToString() .TrimEnd() .TrimEnd(',') + Environment.NewLine); }
/// <nodoc /> protected DiagnosticAnalyzerBase( bool supportFading, params DiagnosticDescriptor[] diagnostics) { Contract.Requires(diagnostics.Length != 0); Descriptor = diagnostics[0]; DescriptorId = Descriptor.Id; var supportedDiagnostics = diagnostics.ToImmutableArray(); if (supportFading) { UnnecessaryWithSuggestionDescriptor = CreateUnnecessaryDescriptor(); UnnecessaryWithoutSuggestionDescriptor = CreateUnnecessaryDescriptor(DescriptorId + "WithoutSuggestion"); supportedDiagnostics = supportedDiagnostics.Add(UnnecessaryWithoutSuggestionDescriptor).Add(UnnecessaryWithSuggestionDescriptor); } SupportedDiagnostics = supportedDiagnostics; }
public bool Equals(DiagnosticDescriptor?x, DiagnosticDescriptor?y) { if (ReferenceEquals(x, y)) { return(true); } if (x is null || y is null) { return(false); } return(x.Category == y.Category && x.DefaultSeverity == y.DefaultSeverity && x.Description.Equals(y.Description) && x.HelpLinkUri == y.HelpLinkUri && x.Id == y.Id && x.IsEnabledByDefault == y.IsEnabledByDefault && x.Title.Equals(y.Title) && x.ImmutableCustomTags.SequenceEqual(y.ImmutableCustomTags)); }
/// <inheritdoc/> protected override bool ValidateTargetType( GeneratorExecutionContext context, AttributeData attributeData, ClassDeclarationSyntax classDeclaration, INamedTypeSymbol classDeclarationSymbol, [NotNullWhen(false)] out DiagnosticDescriptor?descriptor) { INamedTypeSymbol observableRecipientSymbol = context.Compilation.GetTypeByMetadataName("Microsoft.Toolkit.Mvvm.ComponentModel.ObservableRecipient") !, observableObjectSymbol = context.Compilation.GetTypeByMetadataName("Microsoft.Toolkit.Mvvm.ComponentModel.ObservableObject") !, observableObjectAttributeSymbol = context.Compilation.GetTypeByMetadataName("Microsoft.Toolkit.Mvvm.ComponentModel.ObservableObjectAttribute") !, iNotifyPropertyChangedSymbol = context.Compilation.GetTypeByMetadataName("System.ComponentModel.INotifyPropertyChanged") !; // Check if the type already inherits from ObservableRecipient if (classDeclarationSymbol.InheritsFrom(observableRecipientSymbol)) { descriptor = DuplicateObservableRecipientError; return(false); } // In order to use [ObservableRecipient], the target type needs to inherit from ObservableObject, // or be annotated with [ObservableObject] or [INotifyPropertyChanged] (with additional helpers). if (!classDeclarationSymbol.InheritsFrom(observableObjectSymbol) && !classDeclarationSymbol.GetAttributes().Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, observableObjectAttributeSymbol)) && !classDeclarationSymbol.GetAttributes().Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, iNotifyPropertyChangedSymbol) && !a.HasNamedArgument("IncludeAdditionalHelperMethods", false))) { descriptor = MissingBaseObservableObjectFunctionalityError; return(false); } descriptor = null; return(true); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { INamedTypeSymbol?expectedExceptionType = compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingExpectedExceptionAttribute); INamedTypeSymbol?nunitAssertType = compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.NUnitFrameworkAssert); INamedTypeSymbol?xunitAssertType = compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.XunitAssert); INamedTypeSymbol?linqEnumerableType = compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemLinqEnumerable); compilationContext.RegisterOperationBlockStartAction(osContext => { if (osContext.OwningSymbol is not IMethodSymbol method) { return; } osContext.RegisterOperationAction(opContext => { IOperation expression = ((IExpressionStatementOperation)opContext.Operation).Operation; var userDefinedMethods = compilationContext.Options.GetAdditionalUseResultsMethodsOption(UserDefinedMethodRule, expression.Syntax.SyntaxTree, compilationContext.Compilation, compilationContext.CancellationToken); DiagnosticDescriptor?rule = null; string targetMethodName = ""; switch (expression.Kind) { case OperationKind.ObjectCreation: IMethodSymbol ctor = ((IObjectCreationOperation)expression).Constructor; if (ctor != null) { rule = ObjectCreationRule; targetMethodName = ctor.ContainingType.Name; } break; case OperationKind.Invocation: IInvocationOperation invocationExpression = (IInvocationOperation)expression; IMethodSymbol targetMethod = invocationExpression.TargetMethod; if (targetMethod.ReturnsVoid) { break; } if (IsStringCreatingMethod(targetMethod)) { rule = StringCreationRule; } else if (IsTryParseMethod(targetMethod)) { rule = TryParseRule; } else if (IsHResultOrErrorCodeReturningMethod(targetMethod)) { rule = HResultOrErrorCodeRule; } else if (IsPureMethod(targetMethod, opContext.Compilation)) { rule = PureMethodRule; } else if (targetMethod.ContainingType.Equals(linqEnumerableType)) { rule = LinqMethodRule; } else if (userDefinedMethods.Contains(targetMethod.OriginalDefinition)) { rule = UserDefinedMethodRule; } targetMethodName = targetMethod.Name; break; } if (rule != null) { if (ShouldSkipAnalyzing(opContext, expectedExceptionType, xunitAssertType, nunitAssertType)) { return; } Diagnostic diagnostic = expression.CreateDiagnostic(rule, method.Name, targetMethodName); opContext.ReportDiagnostic(diagnostic); } }, OperationKind.ExpressionStatement); }); }); }
/// <inheritdoc /> public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze); context.RegisterCompilationStartAction(compilationStartContext => { var mainThreadAssertingMethods = CommonInterest.ReadMethods(compilationStartContext.Options, CommonInterest.FileNamePatternForMethodsThatAssertMainThread, compilationStartContext.CancellationToken).ToImmutableArray(); var mainThreadSwitchingMethods = CommonInterest.ReadMethods(compilationStartContext.Options, CommonInterest.FileNamePatternForMethodsThatSwitchToMainThread, compilationStartContext.CancellationToken).ToImmutableArray(); var membersRequiringMainThread = CommonInterest.ReadTypesAndMembers(compilationStartContext.Options, CommonInterest.FileNamePatternForMembersRequiringMainThread, compilationStartContext.CancellationToken).ToImmutableArray(); ImmutableDictionary <string, string>?diagnosticProperties = ImmutableDictionary <string, string> .Empty .Add(CommonInterest.FileNamePatternForMethodsThatAssertMainThread.ToString(), string.Join("\n", mainThreadAssertingMethods)) .Add(CommonInterest.FileNamePatternForMethodsThatSwitchToMainThread.ToString(), string.Join("\n", mainThreadSwitchingMethods)); var methodsDeclaringUIThreadRequirement = new HashSet <IMethodSymbol>(); var methodsAssertingUIThreadRequirement = new HashSet <IMethodSymbol>(); var callerToCalleeMap = new Dictionary <IMethodSymbol, List <CallInfo> >(); compilationStartContext.RegisterCodeBlockStartAction <SyntaxKind>(codeBlockStartContext => { var methodAnalyzer = new MethodAnalyzer( mainThreadAssertingMethods: mainThreadAssertingMethods, mainThreadSwitchingMethods: mainThreadSwitchingMethods, membersRequiringMainThread: membersRequiringMainThread, methodsDeclaringUIThreadRequirement: methodsDeclaringUIThreadRequirement, methodsAssertingUIThreadRequirement: methodsAssertingUIThreadRequirement, diagnosticProperties: diagnosticProperties); codeBlockStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzeInvocation), SyntaxKind.InvocationExpression); codeBlockStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzeMemberAccess), SyntaxKind.SimpleMemberAccessExpression); codeBlockStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzeCast), SyntaxKind.CastExpression); codeBlockStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzeAs), SyntaxKind.AsExpression); codeBlockStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzeAs), SyntaxKind.IsExpression); codeBlockStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzeIsPattern), SyntaxKind.IsPatternExpression); }); compilationStartContext.RegisterOperationAction(Utils.DebuggableWrapper(c => this.AddToCallerCalleeMap(c, callerToCalleeMap)), OperationKind.Invocation); compilationStartContext.RegisterOperationAction(Utils.DebuggableWrapper(c => this.AddToCallerCalleeMap(c, callerToCalleeMap)), OperationKind.PropertyReference); compilationStartContext.RegisterCompilationEndAction(compilationEndContext => { Dictionary <IMethodSymbol, List <CallInfo> >?calleeToCallerMap = CreateCalleeToCallerMap(callerToCalleeMap); HashSet <IMethodSymbol>?transitiveClosureOfMainThreadRequiringMethods = GetTransitiveClosureOfMainThreadRequiringMethods(methodsAssertingUIThreadRequirement, calleeToCallerMap); foreach (IMethodSymbol?implicitUserMethod in transitiveClosureOfMainThreadRequiringMethods.Except(methodsDeclaringUIThreadRequirement)) { var reportSites = from info in callerToCalleeMap[implicitUserMethod] where transitiveClosureOfMainThreadRequiringMethods.Contains(info.MethodSymbol) group info by info.MethodSymbol into bySymbol select new { Location = bySymbol.First().InvocationSyntax.GetLocation(), CalleeMethod = bySymbol.Key }; foreach (var site in reportSites) { bool isAsync = Utils.IsAsyncReady(implicitUserMethod); DiagnosticDescriptor?descriptor = isAsync ? DescriptorAsync : DescriptorSync; string calleeName = Utils.GetFullName(site.CalleeMethod); var formattingArgs = isAsync ? new object[] { calleeName } : new object[] { calleeName, mainThreadAssertingMethods.FirstOrDefault() }; Diagnostic diagnostic = Diagnostic.Create( descriptor, site.Location, diagnosticProperties, formattingArgs); compilationEndContext.ReportDiagnostic(diagnostic); } } }); }); }
public sealed override void Initialize(AnalysisContext context) { ImmutableHashSet <string> cachedDeserializationMethodNames = this.DeserializationMethodNames; Debug.Assert(!cachedDeserializationMethodNames.IsEmpty); context.EnableConcurrentExecution(); // Security analyzer - analyze and report diagnostics on generated code. context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationStartAnalysisContext) => { WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate( compilationStartAnalysisContext.Compilation); INamedTypeSymbol?deserializerTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(this.DeserializerTypeMetadataName); if (deserializerTypeSymbol == null) { return; } compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IInvocationOperation invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (invocationOperation.Instance?.Type?.DerivesFrom(deserializerTypeSymbol) == true && cachedDeserializationMethodNames.Contains(invocationOperation.TargetMethod.MetadataName)) { DiagnosticDescriptor?chosenDiagnostic = this.ChooseDiagnosticDescriptor(operationAnalysisContext, wellKnownTypeProvider); if (chosenDiagnostic != null) { operationAnalysisContext.ReportDiagnostic( invocationOperation.CreateDiagnostic( chosenDiagnostic, invocationOperation.TargetMethod.ToDisplayString( SymbolDisplayFormat.MinimallyQualifiedFormat))); } } }, OperationKind.Invocation); compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IMethodReferenceOperation methodReferenceOperation = (IMethodReferenceOperation)operationAnalysisContext.Operation; if (methodReferenceOperation.Instance?.Type?.DerivesFrom(deserializerTypeSymbol) == true && cachedDeserializationMethodNames.Contains(methodReferenceOperation.Method.MetadataName)) { DiagnosticDescriptor?chosenDiagnostic = this.ChooseDiagnosticDescriptor(operationAnalysisContext, wellKnownTypeProvider); if (chosenDiagnostic != null) { operationAnalysisContext.ReportDiagnostic( methodReferenceOperation.CreateDiagnostic( chosenDiagnostic, methodReferenceOperation.Method.ToDisplayString( SymbolDisplayFormat.MinimallyQualifiedFormat))); } } }, OperationKind.MethodReference); }); }
private static void AnalyzeMethodSignature(AutoLayoutTypeCache autoLayoutCache, Action <Diagnostic> reportDiagnostic, IMethodSymbol method, ImmutableArray <Location> locationsOverride = default, DiagnosticDescriptor?descriptorOverride = null) { AnalyzeSignatureType(locationsOverride.IsDefaultOrEmpty ? method.Locations : locationsOverride, method.ReturnType); foreach (var param in method.Parameters) { var paramLocation = locationsOverride.IsDefaultOrEmpty ? param.Locations : locationsOverride; if (param.RefKind != RefKind.None) { reportDiagnostic(paramLocation.CreateDiagnostic(descriptorOverride ?? FeatureUnsupportedWhenRuntimeMarshallingDisabledByRefParameters)); } AnalyzeSignatureType(paramLocation, param.Type); } void AnalyzeSignatureType(ImmutableArray <Location> locations, ITypeSymbol type) { if (type.SpecialType == SpecialType.System_Void) { return; } if (type.Language == LanguageNames.CSharp) { if (!type.IsUnmanagedType) { reportDiagnostic(locations.CreateDiagnostic(descriptorOverride ?? FeatureUnsupportedWhenRuntimeMarshallingDisabledManagedParameterOrReturnTypes)); } } // For non-C# languages, we'll do a quick check to catch simple cases // since IsUnmanagedType only works in languages that support unmanaged types // and non-C# languages that might not support is (such as VB) aren't a big focus of the attribute // this analyzer validates. else if (type.IsReferenceType || type.GetMembers().Any(m => m is IFieldSymbol { IsStatic: false, Type.IsReferenceType: true })) { reportDiagnostic(locations.CreateDiagnostic(descriptorOverride ?? FeatureUnsupportedWhenRuntimeMarshallingDisabledManagedParameterOrReturnTypes)); } if (type.IsValueType && autoLayoutCache.TypeIsAutoLayoutOrContainsAutoLayout(type)) { reportDiagnostic(locations.CreateDiagnostic(descriptorOverride ?? FeatureUnsupportedWhenRuntimeMarshallingDisabledAutoLayoutTypes)); } }