diff --git a/PublicApiAnalyzer/PublicApiAnalyzer/ApiDesign/DeclarePublicAPIAnalyzer.Impl.cs b/PublicApiAnalyzer/PublicApiAnalyzer/ApiDesign/DeclarePublicAPIAnalyzer.Impl.cs index 6de1cdd..f8866c6 100644 --- a/PublicApiAnalyzer/PublicApiAnalyzer/ApiDesign/DeclarePublicAPIAnalyzer.Impl.cs +++ b/PublicApiAnalyzer/PublicApiAnalyzer/ApiDesign/DeclarePublicAPIAnalyzer.Impl.cs @@ -102,6 +102,25 @@ internal void OnSymbolAction(SymbolAnalysisContext symbolContext) this.OnSymbolActionCore(symbolContext.Symbol, symbolContext.ReportDiagnostic); } + internal void OnPropertyAction(SymbolAnalysisContext symbolContext) + { + // If a property is non-implicit, but it's accessors *are* implicit, + // then we will not get called back for the accessor methods. Add + // those methods explicitly in this case. This happens, for example, + // in VB with properties like: + // + // public readonly property A as Integer + // + // In this case, the getter/setters are both implicit, and will not + // trigger the callback to analyze them. So we manually do it ourselves. + var property = (IPropertySymbol)symbolContext.Symbol; + if (!property.IsImplicitlyDeclared) + { + this.CheckPropertyAccessor(symbolContext, property.GetMethod); + this.CheckPropertyAccessor(symbolContext, property.SetMethod); + } + } + internal void OnCompilationEnd(CompilationAnalysisContext context) { this.ProcessTypeForwardedAttributes(context.Compilation, context.ReportDiagnostic, context.CancellationToken); @@ -169,6 +188,28 @@ private static bool ContainsPublicApiName(string apiLineText, string publicApiNa return index == 0 || (index > 0 && apiLineText[index - 1] == ' '); } + private void CheckPropertyAccessor(SymbolAnalysisContext symbolContext, IMethodSymbol accessor) + { + if (accessor == null) + { + return; + } + + // Only process implicit accessors. We won't get callbacks for them + // normally with RegisterSymbolAction. + if (!accessor.IsImplicitlyDeclared) + { + return; + } + + if (!this.IsPublicAPI(accessor)) + { + return; + } + + this.OnSymbolActionCore(accessor, symbolContext.ReportDiagnostic, isImplicitlyDeclaredConstructor: false); + } + /// Analyzes a symbol. /// The symbol to analyze. Will also analyze implicit constructors too. /// Action called to actually report a diagnostic. diff --git a/PublicApiAnalyzer/PublicApiAnalyzer/ApiDesign/DeclarePublicAPIAnalyzer.cs b/PublicApiAnalyzer/PublicApiAnalyzer/ApiDesign/DeclarePublicAPIAnalyzer.cs index 7320969..b72ae2c 100644 --- a/PublicApiAnalyzer/PublicApiAnalyzer/ApiDesign/DeclarePublicAPIAnalyzer.cs +++ b/PublicApiAnalyzer/PublicApiAnalyzer/ApiDesign/DeclarePublicAPIAnalyzer.cs @@ -259,6 +259,9 @@ private void OnCompilationStart(CompilationStartAnalysisContext compilationConte SymbolKind.Event, SymbolKind.Field, SymbolKind.Method); + compilationContext.RegisterSymbolAction( + impl.OnPropertyAction, + SymbolKind.Property); compilationContext.RegisterCompilationEndAction(impl.OnCompilationEnd); }