Skip to content

Commit

Permalink
Add support for detecting and tracking internal APIs
Browse files Browse the repository at this point in the history
Closes #6156. I took the approach of refactoring the analyzer implementation to understand both public and internal, which are tracked in separate files (the new one is InternalAPI.(Un)Shipped.txt). I've also refactored the tests to run on both public and internal, with a few marginal baseline changes to account for some subtle differences between public and internal. Separated out into two commits to ensure that the test modification is correctly detected as a rename and modify, not a new file.
  • Loading branch information
333fred committed Sep 13, 2022
1 parent c76a28b commit 9e45ad4
Show file tree
Hide file tree
Showing 33 changed files with 4,444 additions and 2,276 deletions.
Empty file modified restore.sh
100644 → 100755
Empty file.
Original file line number Diff line number Diff line change
@@ -1 +1,17 @@
; Please do not edit this file manually, it should only be updated through code fix application.

### New Rules

Rule ID | Category | Severity | Notes
--------|----------|----------|-------
RS0051 | ApiDesign | Disabled | DeclarePublicApiAnalyzer, [Documentation](https://github.com/dotnet/roslyn-analyzers/blob/main/src/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)
RS0052 | ApiDesign | Disabled | DeclarePublicApiAnalyzer, [Documentation](https://github.com/dotnet/roslyn-analyzers/blob/main/src/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)
RS0053 | ApiDesign | Disabled | DeclarePublicApiAnalyzer, [Documentation](https://github.com/dotnet/roslyn-analyzers/blob/main/src/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)
RS0054 | ApiDesign | Disabled | DeclarePublicApiAnalyzer, [Documentation](https://github.com/dotnet/roslyn-analyzers/blob/main/src/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)
RS0055 | ApiDesign | Disabled | DeclarePublicApiAnalyzer, [Documentation](https://github.com/dotnet/roslyn-analyzers/blob/main/src/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)
RS0056 | ApiDesign | Disabled | DeclarePublicApiAnalyzer, [Documentation](https://github.com/dotnet/roslyn-analyzers/blob/main/src/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)
RS0057 | ApiDesign | Disabled | DeclarePublicApiAnalyzer, [Documentation](https://github.com/dotnet/roslyn-analyzers/blob/main/src/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)
RS0058 | ApiDesign | Disabled | DeclarePublicApiAnalyzer, [Documentation](https://github.com/dotnet/roslyn-analyzers/blob/main/src/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)
RS0059 | ApiDesign | Disabled | DeclarePublicApiAnalyzer, [Documentation](https://github.com/dotnet/roslyn/blob/main/docs/Adding%20Optional%20Parameters%20in%20Public%20API.md)
RS0060 | ApiDesign | Disabled | DeclarePublicApiAnalyzer, [Documentation](https://github.com/dotnet/roslyn/blob/main/docs/Adding%20Optional%20Parameters%20in%20Public%20API.md)
RS0061 | ApiDesign | Disabled | DeclarePublicApiAnalyzer, [Documentation](https://github.com/dotnet/roslyn-analyzers/blob/main/src/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)
197 changes: 114 additions & 83 deletions src/PublicApiAnalyzers/Core/Analyzers/DeclarePublicApiAnalyzer.Impl.cs

Large diffs are not rendered by default.

229 changes: 60 additions & 169 deletions src/PublicApiAnalyzers/Core/Analyzers/DeclarePublicApiAnalyzer.cs

Large diffs are not rendered by default.

Large diffs are not rendered by default.

130 changes: 100 additions & 30 deletions src/PublicApiAnalyzers/Core/Analyzers/PublicApiAnalyzerResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
<value>Add public types and members to the declared API</value>
</data>
<data name="DeclarePublicApiMessage" xml:space="preserve">
<value>Symbol '{0}' is not part of the declared API</value>
<value>Symbol '{0}' is not part of the declared public API</value>
</data>
<data name="DeclarePublicApiDescription" xml:space="preserve">
<value>All public types and members should be declared in PublicAPI.txt. This draws attention to API changes in the code reviews and source control history, and helps prevent breaking changes.</value>
Expand All @@ -135,13 +135,13 @@
<data name="AnnotatePublicApiDescription" xml:space="preserve">
<value>All public types and members should be declared with nullability annotations in PublicAPI.txt. This draws attention to API nullability changes in the code reviews and source control history, and helps prevent breaking changes.</value>
</data>
<data name="ShouldAnnotateApiFilesTitle" xml:space="preserve">
<data name="ShouldAnnotatePublicApiFilesTitle" xml:space="preserve">
<value>Enable tracking of nullability of reference types in the declared API</value>
</data>
<data name="ShouldAnnotateApiFilesMessage" xml:space="preserve">
<data name="ShouldAnnotatePublicApiFilesMessage" xml:space="preserve">
<value>PublicAPI.txt is missing '#nullable enable', so the nullability annotations of API isn't recorded. It is recommended to enable this tracking.</value>
</data>
<data name="ShouldAnnotateApiFilesDescription" xml:space="preserve">
<data name="ShouldAnnotatePublicApiFilesDescription" xml:space="preserve">
<value>PublicAPI.txt files should have `#nullable enable` to track nullability information, or this diagnostic should be suppressed. With nullability enabled, PublicAPI.txt records which types are nullable (suffix `?` on type) or non-nullable (suffix `!`). It also tracks any API that is still using an oblivious reference type (prefix `~` on line).</value>
</data>
<data name="ObliviousPublicApiTitle" xml:space="preserve">
Expand All @@ -153,13 +153,13 @@
<data name="ObliviousPublicApiDescription" xml:space="preserve">
<value>All public members should use either nullable or non-nullable reference types, but no oblivious reference types.</value>
</data>
<data name="RemoveDeletedApiTitle" xml:space="preserve">
<data name="RemoveDeletedPublicApiTitle" xml:space="preserve">
<value>Remove deleted types and members from the declared API</value>
</data>
<data name="RemoveDeletedApiMessage" xml:space="preserve">
<data name="RemoveDeletedPublicApiMessage" xml:space="preserve">
<value>Symbol '{0}' is part of the declared API, but is either not public or could not be found</value>
</data>
<data name="RemoveDeletedApiDescription" xml:space="preserve">
<data name="RemoveDeletedPublicApiDescription" xml:space="preserve">
<value>When removing a public type or member, put that entry in PublicAPI.Unshipped.txt with '*REMOVED*' prefix. This draws attention to API changes in the code reviews and source control history, and helps prevent breaking changes.</value>
<comment>{Locked="*REMOVED*"}</comment>
</data>
Expand Down Expand Up @@ -187,7 +187,7 @@
<data name="DuplicateSymbolsInPublicApiFilesMessage" xml:space="preserve">
<value>The symbol '{0}' appears more than once in the public API files</value>
</data>
<data name="PublicImplicitConstructorErrorMessageName" xml:space="preserve">
<data name="ImplicitConstructorErrorMessageName" xml:space="preserve">
<value>implicit constructor for '{0}'</value>
</data>
<data name="AvoidMultipleOverloadsWithOptionalParametersTitle" xml:space="preserve">
Expand All @@ -197,15 +197,15 @@
<value>Symbol '{0}' violates the backcompat requirement: 'Do not add multiple overloads with optional parameters'. See '{1}' for details.</value>
</data>
<data name="OverloadWithOptionalParametersShouldHaveMostParametersTitle" xml:space="preserve">
<value>Public API with optional parameter(s) should have the most parameters amongst its public overloads</value>
<value>API with optional parameter(s) should have the most parameters amongst its public overloads</value>
</data>
<data name="OverloadWithOptionalParametersShouldHaveMostParametersMessage" xml:space="preserve">
<value>Symbol '{0}' violates the backcompat requirement: 'Public API with optional parameter(s) should have the most parameters amongst its public overloads'. See '{1}' for details.</value>
<value>'{0}' violates the backcompat requirement: 'API with optional parameter(s) should have the most parameters amongst its public overloads'. See '{1}' for details.</value>
</data>
<data name="PublicImplicitGetAccessor" xml:space="preserve">
<data name="ImplicitGetAccessor" xml:space="preserve">
<value>implicit get-accessor for '{0}'</value>
</data>
<data name="PublicImplicitSetAccessor" xml:space="preserve">
<data name="ImplicitSetAccessor" xml:space="preserve">
<value>implicit set-accessor for '{0}'</value>
</data>
<data name="PublicApiFilesMissingTitle" xml:space="preserve">
Expand All @@ -214,34 +214,104 @@
<data name="PublicApiFilesMissingMessage" xml:space="preserve">
<value>The solution must contain two files with the type "AdditionalFiles": PublicAPI.Unshipped.txt and PublicAPI.Shipped.txt. At least one of these files is missing or has the wrong type.</value>
</data>
<data name="AddAllItemsInDocumentToThePublicApiTitle" xml:space="preserve">
<value>Add all items in document '{0}' to the public API</value>
<data name="AddAllItemsInDocumentToTheApiTitle" xml:space="preserve">
<value>Add all items in document '{0}' to the API</value>
</data>
<data name="AddAllItemsInProjectToThePublicApiTitle" xml:space="preserve">
<value>Add all items in project '{0}' to the public API</value>
<data name="AddAllItemsInProjectToTheApiTitle" xml:space="preserve">
<value>Add all items in project '{0}' to the API</value>
</data>
<data name="AddAllItemsInTheSolutionToThePublicApiTitle" xml:space="preserve">
<value>Add all items in the solution to the public API</value>
<data name="AddAllItemsInTheSolutionToTheApiTitle" xml:space="preserve">
<value>Add all items in the solution to the API</value>
</data>
<data name="AnnotateAllItemsInDocumentToThePublicApiTitle" xml:space="preserve">
<value>Annotate all items in document '{0}' in the public API</value>
<data name="AnnotateAllItemsInDocumentToTheApiTitle" xml:space="preserve">
<value>Annotate all items in document '{0}' in the API</value>
</data>
<data name="AnnotateAllItemsInProjectToThePublicApiTitle" xml:space="preserve">
<value>Annotate all items in project '{0}' in the public API</value>
<data name="AnnotateAllItemsInProjectToTheApiTitle" xml:space="preserve">
<value>Annotate all items in project '{0}' in the API</value>
</data>
<data name="AnnotateAllItemsInTheSolutionToThePublicApiTitle" xml:space="preserve">
<value>Annotate all items in the solution in the public API</value>
<data name="AnnotateAllItemsInTheSolutionToTheApiTitle" xml:space="preserve">
<value>Annotate all items in the solution in the API</value>
</data>
<data name="EnableNullableInProjectToThePublicApiTitle" xml:space="preserve">
<value>Enable nullability annotations in the public API for project '{0}'</value>
<data name="EnableNullableInProjectToTheApiTitle" xml:space="preserve">
<value>Enable nullability annotations in the API for project '{0}'</value>
</data>
<data name="EnableNullableInTheSolutionToThePublicApiTitle" xml:space="preserve">
<value>Enable nullability annotations in the public API for the solution</value>
<data name="EnableNullableInTheSolutionToTheApiTitle" xml:space="preserve">
<value>Enable nullability annotations in the API for the solution</value>
</data>
<data name="RemovedApiIsNotActuallyRemovedMessage" xml:space="preserve">
<value>Symbol '{0}' is marked as removed but it isn't deleted in source code</value>
</data>
<data name="RemovedApiIsNotActuallyRemovedTitle" xml:space="preserve">
<value>Public API is marked as removed but it exists in source code</value>
<value>API is marked as removed but it exists in source code</value>
</data>
<data name="DeclareInternalApiTitle" xml:space="preserve">
<value>Add internal types and members to the declared API</value>
</data>
<data name="DeclareInternalApiMessage" xml:space="preserve">
<value>Symbol '{0}' is not part of the declared API</value>
</data>
<data name="DeclareInternalApiDescription" xml:space="preserve">
<value>All internal types and members should be declared in InternalAPI.txt. This draws attention to API changes in the code reviews and source control history, and helps prevent breaking changes.</value>
</data>
<data name="AnnotateInternalApiTitle" xml:space="preserve">
<value>Annotate nullability of internal types and members in the declared API</value>
</data>
<data name="AnnotateInternalApiMessage" xml:space="preserve">
<value>Symbol '{0}' is missing nullability annotations in the declared API</value>
</data>
<data name="AnnotateInternalApiDescription" xml:space="preserve">
<value>All internal types and members should be declared with nullability annotations in InternalAPI.txt. This draws attention to API nullability changes in the code reviews and source control history, and helps prevent breaking changes.</value>
</data>
<data name="ShouldAnnotateInternalApiFilesTitle" xml:space="preserve">
<value>Enable tracking of nullability of reference types in the declared API</value>
</data>
<data name="ShouldAnnotateInternalApiFilesMessage" xml:space="preserve">
<value>InternalAPI.txt is missing '#nullable enable', so the nullability annotations of API isn't recorded. It is recommended to enable this tracking.</value>
</data>
<data name="ShouldAnnotateInternalApiFilesDescription" xml:space="preserve">
<value>InternalAPI.txt files should have `#nullable enable` to track nullability information, or this diagnostic should be suppressed. With nullability enabled, InternalAPI.txt records which types are nullable (suffix `?` on type) or non-nullable (suffix `!`). It also tracks any API that is still using an oblivious reference type (prefix `~` on line).</value>
</data>
<data name="ObliviousInternalApiTitle" xml:space="preserve">
<value>Internal members should not use oblivious types</value>
</data>
<data name="ObliviousInternalApiMessage" xml:space="preserve">
<value>Symbol '{0}' uses some oblivious reference types</value>
</data>
<data name="ObliviousInternalApiDescription" xml:space="preserve">
<value>All internal members should use either nullable or non-nullable reference types, but no oblivious reference types.</value>
</data>
<data name="RemoveDeletedInternalApiTitle" xml:space="preserve">
<value>Remove deleted types and members from the declared internal API</value>
</data>
<data name="RemoveDeletedInternalApiMessage" xml:space="preserve">
<value>Symbol '{0}' is part of the declared internal API, but is either not internal or could not be found</value>
</data>
<data name="RemoveDeletedInternalApiDescription" xml:space="preserve">
<value>When removing a internal type or member, put that entry in InternalAPI.Unshipped.txt with '*REMOVED*' prefix. This draws attention to API changes in the code reviews and source control history, and helps prevent breaking changes.</value>
<comment>{Locked="*REMOVED*"}</comment>
</data>
<data name="InternalApiFilesInvalidTitle" xml:space="preserve">
<value>The contents of the internal API files are invalid</value>
</data>
<data name="InternalApiFilesInvalidMessage" xml:space="preserve">
<value>The contents of the internal API files are invalid: {0}</value>
</data>
<data name="InternalApiFileMissingTitle" xml:space="preserve">
<value>Missing shipped or unshipped internal API file</value>
</data>
<data name="InternalApiFileMissingMessage" xml:space="preserve">
<value>Internal API file '{0}' is missing or not marked as an additional analyzer file</value>
</data>
<data name="DuplicateSymbolsInInternalApiFilesTitle" xml:space="preserve">
<value>Do not duplicate symbols in internal API files</value>
</data>
<data name="DuplicateSymbolsInInternalApiFilesMessage" xml:space="preserve">
<value>The symbol '{0}' appears more than once in the internal API files</value>
</data>
<data name="InternalApiFilesMissingTitle" xml:space="preserve">
<value>One or both of the internal API files are missing</value>
</data>
<data name="InternalApiFilesMissingMessage" xml:space="preserve">
<value>The solution must contain two files with the type "AdditionalFiles": InternalAPI.Unshipped.txt and internalAPI.Shipped.txt. At least one of these files is missing or has the wrong type.</value>
</data>
</root>
</root>
6 changes: 3 additions & 3 deletions src/PublicApiAnalyzers/Core/Analyzers/PublicApiFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ namespace Microsoft.CodeAnalysis.PublicApiAnalyzers
{
public readonly struct PublicApiFile
{
public PublicApiFile(string path)
public PublicApiFile(string path, bool isPublic)
{
var fileName = Path.GetFileName(path);

IsShipping = IsFile(fileName, DeclarePublicApiAnalyzer.ShippedFileNamePrefix);
var isUnshippedFile = IsFile(fileName, DeclarePublicApiAnalyzer.UnshippedFileNamePrefix);
IsShipping = IsFile(fileName, isPublic ? DeclarePublicApiAnalyzer.PublicShippedFileNamePrefix : DeclarePublicApiAnalyzer.InternalShippedFileNamePrefix);
var isUnshippedFile = IsFile(fileName, isPublic ? DeclarePublicApiAnalyzer.PublicUnshippedFileNamePrefix : DeclarePublicApiAnalyzer.InternalUnshippedFileNamePrefix);

IsApiFile = IsShipping || isUnshippedFile;
}
Expand Down
Loading

0 comments on commit 9e45ad4

Please sign in to comment.