Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add potential exceptions when generating doc comment #54894

Merged
merged 10 commits into from
Jul 28, 2021

Conversation

Youssef1313
Copy link
Member

@Youssef1313 Youssef1313 commented Jul 17, 2021

Fixes #54245

@Youssef1313 Youssef1313 requested a review from a team as a code owner July 17, 2021 11:21

if (expression is ObjectCreationExpressionSyntax { Type: TypeSyntax type })
{
yield return type.ToString();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likely won't work with generics. But that's likely so niche as to not be relevant.

Is also like it if we filtered it exceptions in an inner scope that are caught before escaping.

@Youssef1313 Youssef1313 requested a review from a team as a code owner July 17, 2021 21:06
@@ -13,7 +14,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.DocumentationComments
{
internal static class OmniSharpDocumentationCommentsSnippetService
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@333fred Can you take a look at the breaking changes for OmniSharp here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be fine, these are already used in an async method. @JoeRobich and @filipw, fyi for the next time we upgrade Roslyn we'll need to make a small change here (and yay, the EA assembly is working as expected!).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, thanks!

Copy link
Member Author

@Youssef1313 Youssef1313 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CyrusNajmabadi This is lacking tests and few TODOs. But should be good to re-review.

I'll continue the work on it tomorrow (it's almost midnight here).

Edit: C# work is done.

@Youssef1313 Youssef1313 requested review from CyrusNajmabadi and removed request for a team July 17, 2021 21:11
@jinujoseph jinujoseph added the Community The pull request was submitted by a contributor who is not a Microsoft employee. label Jul 19, 2021
private static DocumentationCommentSnippet? InsertOnCharacterTyped(IDocumentationCommentSnippetService service, SyntaxTree syntaxTree, SourceText text, int position, DocumentOptionSet options, CancellationToken cancellationToken)
=> service.GetDocumentationCommentSnippetOnCharacterTyped(syntaxTree, text, position, options, cancellationToken);
private static DocumentationCommentSnippet? InsertOnCharacterTyped(IDocumentationCommentSnippetService service, SyntaxTree syntaxTree, SourceText text, int position, DocumentOptionSet options, SemanticModel model, CancellationToken cancellationToken)
=> service.GetDocumentationCommentSnippetOnCharacterTyped(syntaxTree, text, position, options, model, cancellationToken);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to pass a semantic model and a syntax tree. thel atter comes with the former.

{
var throwExpressionsAndStatements = member.DescendantNodes().Where(n => n.IsKind(SyntaxKind.ThrowExpression, SyntaxKind.ThrowStatement));
var namespacesInScope = model.GetUsingNamespacesInScope(member);
var hasUsingSystem = namespacesInScope.Contains(n => n.ContainingNamespace.IsGlobalNamespace && n.Name == "System");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs doc as to why you're doing this.

{
var throwExpressionsAndStatements = member.DescendantNodes().Where(n => n.IsKind(SyntaxKind.ThrowExpression, SyntaxKind.ThrowStatement));
var namespacesInScope = model.GetUsingNamespacesInScope(member);
var hasUsingSystem = namespacesInScope.Contains(n => n.ContainingNamespace.IsGlobalNamespace && n.Name == "System");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var hasUsingSystem = namespacesInScope.Contains(n => n.ContainingNamespace.IsGlobalNamespace && n.Name == "System");
var hasUsingSystem = namespacesInScope.Contains(n => n.ContainingNamespace.IsGlobalNamespace && n.Name == nameof(System));


private static bool IsExceptionCaughtAndNotRethrown(SyntaxNode throwExpressionOrStatement, ITypeSymbol exceptionType, SemanticModel model, CancellationToken cancellationToken)
{
var tryStatement = throwExpressionOrStatement.FirstAncestorOrSelfUntil<TryStatementSyntax>(n => n is CatchClauseSyntax or LocalFunctionStatementSyntax or MemberDeclarationSyntax);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think you'd need to walk up all containing try statements, not jsut the immediate one.

}

return list;
}

private static IEnumerable<string> GetExceptions(SyntaxNode member, SemanticModel model, OptionSet options, CancellationToken cancellationToken)
{
var throwExpressionsAndStatements = member.DescendantNodes().Where(n => n.IsKind(SyntaxKind.ThrowExpression, SyntaxKind.ThrowStatement));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will find in nested lambdas/localfunctions

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finding in nested local functions (possible lambdas too) is okay since they're expected to be called within the method. However, a try catch wrapping the local function call seems tricky to handle. Is this an important scenario?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i could see the argument about nested local functions (and even the it's iffy). not lambdas though. I would personally not handle either unless you can actually see the local function being called (as opposed to passed as a delegate).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and i do think we should basically be doing this analysis as finding the locations in the method where exceptions can be thrown, but then filtering those out if they are contained ina try/catch that would catch that particular exception.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment still applies.

@@ -92,8 +92,9 @@ private static void ApplySnippet(DocumentationCommentSnippet snippet, ITextBuffe
var syntaxTree = document.GetRequiredSyntaxTreeSynchronously(cancellationToken);
var text = syntaxTree.GetText(cancellationToken);
var documentOptions = document.GetOptionsAsync(cancellationToken).WaitAndGetResult(cancellationToken);
var semanticModel = document.GetRequiredSemanticModelAsync(cancellationToken).AsTask().WaitAndGetResult(cancellationToken);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getting the semantic model may be expensive. to mitigate this we should get a document with frozen-partial-semantics.

@maxkoshevoi
Copy link

Could you also apply this when generating documentation for interface member with single implementation?

Copy link
Member

@333fred 333fred left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O# EA layer changes LGTM.

var documentOptions = document.GetOptionsAsync(cancellationToken).WaitAndGetResult(cancellationToken);

var snippet = getSnippetAction(service, syntaxTree, text, caretPosition, documentOptions, cancellationToken);
var semanticModel = document.GetPartialSemanticModelAsync(cancellationToken).WaitAndGetResult(cancellationToken);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tbh, this is just incredibly concerning. semantic models (and the work therin) is not cheap, and this is a sync codepath. do we need semantics? can't we look for throws purely syntactically?

var throwExpressionsAndStatements = member.DescendantNodes().Where(n => n.IsKind(SyntaxKind.ThrowExpression, SyntaxKind.ThrowStatement));
var namespacesInScope = model.GetUsingNamespacesInScope(member);
// We generate <exception cref="System.NullReferenceException"> if there is no 'using System;', and generate
// <exception cref="NullReferenceException"> if there is a 'using System;'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this feels unnecessary. we can just look at how the throw looked. if teh user says throw NullReferenceException then we generate the same. if they say throw System.NullReferenceException likewise.


if (model.GetOperation(catchClause, cancellationToken) is ICatchClauseOperation catchClauseOperation)
{
if (exceptionType.InheritsFromOrEquals(catchClauseOperation.ExceptionType))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i see. you use semantics for this. i'm ok with this doing a simple thing and just comparing the last portion of the name for equality. it will be more than good enough and will avoid semantics.

@CyrusNajmabadi
Copy link
Member

@Youssef1313 i can make thsee changes if you'd like.

@Youssef1313
Copy link
Member Author

@Youssef1313 i can make thsee changes if you'd like.

That would be awesome and much appreciated! I didn't get enough time for this. Thanks!

@CyrusNajmabadi CyrusNajmabadi merged commit ac28a69 into dotnet:main Jul 28, 2021
@ghost ghost added this to the Next milestone Jul 28, 2021
@Youssef1313 Youssef1313 deleted the exceptions-doc-comments branch July 29, 2021 05:22
@dibarbet dibarbet modified the milestones: Next, 17.0.P4 Aug 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-IDE Community The pull request was submitted by a contributor who is not a Microsoft employee. Feature Request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature request] When generating summary add <exception> for every exception thrown in a method
7 participants