-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Add potential exceptions when generating doc comment #54894
Conversation
|
||
if (expression is ObjectCreationExpressionSyntax { Type: TypeSyntax type }) | ||
{ | ||
yield return type.ToString(); |
There was a problem hiding this comment.
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.
@@ -13,7 +14,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.DocumentationComments | |||
{ | |||
internal static class OmniSharpDocumentationCommentsSnippetService |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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!).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice, thanks!
There was a problem hiding this 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.
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); |
There was a problem hiding this comment.
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"); |
There was a problem hiding this comment.
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"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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); |
There was a problem hiding this comment.
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)); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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.
Could you also apply this when generating documentation for interface member with single implementation? |
There was a problem hiding this 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); |
There was a problem hiding this comment.
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;' |
There was a problem hiding this comment.
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)) |
There was a problem hiding this comment.
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.
@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! |
Fixes #54245