Add support for primary constructors in LoggerMessageGenerator - #101660

Merged
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors
May 28, 2024
Merged

Add support for primary constructors in LoggerMessageGenerator#101660
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors

Conversation

@kimsey0

Copy link
Copy Markdown
Contributor

Fixes#91121.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 28, 2024
@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 thanks for submitting the PR. I converted it to draft till it is ready for actual review.

@kimsey0

Copy link
Copy Markdown
ContributorAuthor

@tarekgh, with the helpful suggestion from Cyrus, I now think this is ready for review. Should I mark it as such or wait for more feedback, perhaps from @eiriktsarpalis? (I don't know when he's back from vacation.)

.Where(ic => ic.DeclaringSyntaxReferences
.Any(ds => ds.GetSyntax() is ClassDeclarationSyntax));

foreach (IMethodSymbol primaryConstructor in primaryConstructors)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So, this in itself is a great example of why I said you're not going to get lookup right if you do it by yourself. Consider this example; I've created a protected field in the base type with a wider type than the logger parameter in the derived type, and that protected member shadows the primary constructor parameter. Another similar example is this, where I've shadowed the primary constructor parameter with a field directly in the type itself. I'm not opposed to the idea of adding a new LookupSymbols API here to allow SG authors to say "I need to know what names are available when I implement the body of this type", but it's also important to note that available names are by nature impacted by the usings in the file. Let me talk with @AlekseyTs and see if we can come up with any ideas that avoid you having to try and get this correct.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You should also test scenarios like this:

classTest(ILoggerlogger){privatereadonlyILogger_logger=logger;}

and ensure that you're using the right logger for that scenario.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

private readonly ILogger _logger = logger;

good test as we don't support private fields.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Sure, that would be possible. Talking with Aleksey, that's likely the approach you want to take in general. However, I'm going to strongly recommend that you explicitly consider these cases and lay out, in comments and documentation, the exact rules you follow. IE, what happens when a primary constructor parameter is shadowed? What happens when a base type has a protected member that is named differently than the parameter (ie, has an _)? This will make it easier to verify the behavior is what you're expecting, and to handle bugs as by-design or not.

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

You only need the check that kimsey0 put in already. It's important to note that you can only detect primary constructors from source, you cannot detect them from metadata.

good test as we don't support private fields.

Wait, what? I'll reiterate that I think you need spell out exactly what the rules are, in comments above the code, so that you can verify the code follows them. I thought I might understand the rules, but clearly I do not.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. If both the behavior described above as well as the code implementing it is acceptable to all parties, I think this is ready for review again.

@tarekghtarekghMay 24, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'll try to review it when I get a chance. PR is not a draft anymore. Thanks for all the help you have provided here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. Thanks a lot!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I forgot to commit and push the info diagnostic, but just did that. I don't know if there are any guidelines for how exactly these diagnostic messages should be written or how the translation flow goes? (We can also just revert this. I think it's useful, but not necessary.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You don't have to worry about the translation of the added messages. I am seeing the added diagnostic is useful to catch the concerned case.

@tarekgh

tarekgh commented May 23, 2024

Copy link
Copy Markdown
Member

@geeknoid@joperezr to be aware about this change if need to update the extensions logging source gen too.

@joperezr

Copy link
Copy Markdown
Member

Thanks for flagging this @tarekgh! It does seem like it is something we'll want to do in extensions. Logged dotnet/extensions#5178 to track

@tarekgh

Copy link
Copy Markdown
Member
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.


Refers to: src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs:1115 in 6cf2b2f. [](commit_id = 6cf2b2f, deletion_comment = False)

@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 I added a few minor comments. I think we should be good to go after addressing these. Thanks!

@kimsey0

Copy link
Copy Markdown
ContributorAuthor
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.

I added assertions that the new diagnostic is reported to the existing test cases with shadowed primary constructor parameters. Would you like any additional tests of this?

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @kimsey0 providing the fix!

@tarekgh
tarekgh merged commit 9daa4b4 into dotnet:mainMay 28, 2024
@kimsey0
kimsey0 deleted the logger-message-generator-primary-constructors branch May 28, 2024 17:06
@kimsey0

Copy link
Copy Markdown
ContributorAuthor

Thanks a lot for the help, @tarekgh!

Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
…t#101660)
* Add support for primary constructors in LoggerMessageGenerator
* Get the primary constructor parameters types from the constructor symbol instead of from the semantic model
* Prioritize fields over primary constructor parameters and ignore shadowed parameters when finding a logger
* Make checking for primary constructors non-conditional on Roslyn version and simplify project setup
* Reintroduce Roslyn 4.8 test project
* Add info-level diagnostic for logger primary constructor parameters that are shadowed by field
* Update list of diagnostics with new logging message generator diagnostic
* Only add non-logger field names to set of shadowed names
* Add comment explaining the use of the set of shadowed names with an example
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Loggingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LoggerMessage source generator does not work with logger from primary constructor.

6 participants

@kimsey0@tarekgh@joperezr@333fred@CyrusNajmabadi@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Add support for primary constructors in LoggerMessageGenerator - #101660

Merged
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors
May 28, 2024
Merged

Add support for primary constructors in LoggerMessageGenerator#101660
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors

Conversation

@kimsey0

Copy link
Copy Markdown
Contributor

Fixes#91121.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 28, 2024
@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 thanks for submitting the PR. I converted it to draft till it is ready for actual review.

@kimsey0

Copy link
Copy Markdown
ContributorAuthor

@tarekgh, with the helpful suggestion from Cyrus, I now think this is ready for review. Should I mark it as such or wait for more feedback, perhaps from @eiriktsarpalis? (I don't know when he's back from vacation.)

.Where(ic => ic.DeclaringSyntaxReferences
.Any(ds => ds.GetSyntax() is ClassDeclarationSyntax));

foreach (IMethodSymbol primaryConstructor in primaryConstructors)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So, this in itself is a great example of why I said you're not going to get lookup right if you do it by yourself. Consider this example; I've created a protected field in the base type with a wider type than the logger parameter in the derived type, and that protected member shadows the primary constructor parameter. Another similar example is this, where I've shadowed the primary constructor parameter with a field directly in the type itself. I'm not opposed to the idea of adding a new LookupSymbols API here to allow SG authors to say "I need to know what names are available when I implement the body of this type", but it's also important to note that available names are by nature impacted by the usings in the file. Let me talk with @AlekseyTs and see if we can come up with any ideas that avoid you having to try and get this correct.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You should also test scenarios like this:

classTest(ILoggerlogger){privatereadonlyILogger_logger=logger;}

and ensure that you're using the right logger for that scenario.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

private readonly ILogger _logger = logger;

good test as we don't support private fields.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Sure, that would be possible. Talking with Aleksey, that's likely the approach you want to take in general. However, I'm going to strongly recommend that you explicitly consider these cases and lay out, in comments and documentation, the exact rules you follow. IE, what happens when a primary constructor parameter is shadowed? What happens when a base type has a protected member that is named differently than the parameter (ie, has an _)? This will make it easier to verify the behavior is what you're expecting, and to handle bugs as by-design or not.

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

You only need the check that kimsey0 put in already. It's important to note that you can only detect primary constructors from source, you cannot detect them from metadata.

good test as we don't support private fields.

Wait, what? I'll reiterate that I think you need spell out exactly what the rules are, in comments above the code, so that you can verify the code follows them. I thought I might understand the rules, but clearly I do not.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. If both the behavior described above as well as the code implementing it is acceptable to all parties, I think this is ready for review again.

@tarekghtarekghMay 24, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'll try to review it when I get a chance. PR is not a draft anymore. Thanks for all the help you have provided here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. Thanks a lot!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I forgot to commit and push the info diagnostic, but just did that. I don't know if there are any guidelines for how exactly these diagnostic messages should be written or how the translation flow goes? (We can also just revert this. I think it's useful, but not necessary.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You don't have to worry about the translation of the added messages. I am seeing the added diagnostic is useful to catch the concerned case.

@tarekgh

tarekgh commented May 23, 2024

Copy link
Copy Markdown
Member

@geeknoid@joperezr to be aware about this change if need to update the extensions logging source gen too.

@joperezr

Copy link
Copy Markdown
Member

Thanks for flagging this @tarekgh! It does seem like it is something we'll want to do in extensions. Logged dotnet/extensions#5178 to track

@tarekgh

Copy link
Copy Markdown
Member
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.


Refers to: src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs:1115 in 6cf2b2f. [](commit_id = 6cf2b2f, deletion_comment = False)

@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 I added a few minor comments. I think we should be good to go after addressing these. Thanks!

@kimsey0

Copy link
Copy Markdown
ContributorAuthor
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.

I added assertions that the new diagnostic is reported to the existing test cases with shadowed primary constructor parameters. Would you like any additional tests of this?

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @kimsey0 providing the fix!

@tarekgh
tarekgh merged commit 9daa4b4 into dotnet:mainMay 28, 2024
@kimsey0
kimsey0 deleted the logger-message-generator-primary-constructors branch May 28, 2024 17:06
@kimsey0

Copy link
Copy Markdown
ContributorAuthor

Thanks a lot for the help, @tarekgh!

Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
…t#101660)
* Add support for primary constructors in LoggerMessageGenerator
* Get the primary constructor parameters types from the constructor symbol instead of from the semantic model
* Prioritize fields over primary constructor parameters and ignore shadowed parameters when finding a logger
* Make checking for primary constructors non-conditional on Roslyn version and simplify project setup
* Reintroduce Roslyn 4.8 test project
* Add info-level diagnostic for logger primary constructor parameters that are shadowed by field
* Update list of diagnostics with new logging message generator diagnostic
* Only add non-logger field names to set of shadowed names
* Add comment explaining the use of the set of shadowed names with an example
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Loggingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LoggerMessage source generator does not work with logger from primary constructor.

6 participants

@kimsey0@tarekgh@joperezr@333fred@CyrusNajmabadi@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add support for primary constructors in LoggerMessageGenerator - #101660

Merged
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors
May 28, 2024
Merged

Add support for primary constructors in LoggerMessageGenerator#101660
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors

Conversation

@kimsey0

Copy link
Copy Markdown
Contributor

Fixes#91121.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 28, 2024
@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 thanks for submitting the PR. I converted it to draft till it is ready for actual review.

@kimsey0

Copy link
Copy Markdown
ContributorAuthor

@tarekgh, with the helpful suggestion from Cyrus, I now think this is ready for review. Should I mark it as such or wait for more feedback, perhaps from @eiriktsarpalis? (I don't know when he's back from vacation.)

.Where(ic => ic.DeclaringSyntaxReferences
.Any(ds => ds.GetSyntax() is ClassDeclarationSyntax));

foreach (IMethodSymbol primaryConstructor in primaryConstructors)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So, this in itself is a great example of why I said you're not going to get lookup right if you do it by yourself. Consider this example; I've created a protected field in the base type with a wider type than the logger parameter in the derived type, and that protected member shadows the primary constructor parameter. Another similar example is this, where I've shadowed the primary constructor parameter with a field directly in the type itself. I'm not opposed to the idea of adding a new LookupSymbols API here to allow SG authors to say "I need to know what names are available when I implement the body of this type", but it's also important to note that available names are by nature impacted by the usings in the file. Let me talk with @AlekseyTs and see if we can come up with any ideas that avoid you having to try and get this correct.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You should also test scenarios like this:

classTest(ILoggerlogger){privatereadonlyILogger_logger=logger;}

and ensure that you're using the right logger for that scenario.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

private readonly ILogger _logger = logger;

good test as we don't support private fields.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Sure, that would be possible. Talking with Aleksey, that's likely the approach you want to take in general. However, I'm going to strongly recommend that you explicitly consider these cases and lay out, in comments and documentation, the exact rules you follow. IE, what happens when a primary constructor parameter is shadowed? What happens when a base type has a protected member that is named differently than the parameter (ie, has an _)? This will make it easier to verify the behavior is what you're expecting, and to handle bugs as by-design or not.

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

You only need the check that kimsey0 put in already. It's important to note that you can only detect primary constructors from source, you cannot detect them from metadata.

good test as we don't support private fields.

Wait, what? I'll reiterate that I think you need spell out exactly what the rules are, in comments above the code, so that you can verify the code follows them. I thought I might understand the rules, but clearly I do not.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. If both the behavior described above as well as the code implementing it is acceptable to all parties, I think this is ready for review again.

@tarekghtarekghMay 24, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'll try to review it when I get a chance. PR is not a draft anymore. Thanks for all the help you have provided here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. Thanks a lot!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I forgot to commit and push the info diagnostic, but just did that. I don't know if there are any guidelines for how exactly these diagnostic messages should be written or how the translation flow goes? (We can also just revert this. I think it's useful, but not necessary.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You don't have to worry about the translation of the added messages. I am seeing the added diagnostic is useful to catch the concerned case.

@tarekgh

tarekgh commented May 23, 2024

Copy link
Copy Markdown
Member

@geeknoid@joperezr to be aware about this change if need to update the extensions logging source gen too.

@joperezr

Copy link
Copy Markdown
Member

Thanks for flagging this @tarekgh! It does seem like it is something we'll want to do in extensions. Logged dotnet/extensions#5178 to track

@tarekgh

Copy link
Copy Markdown
Member
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.


Refers to: src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs:1115 in 6cf2b2f. [](commit_id = 6cf2b2f, deletion_comment = False)

@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 I added a few minor comments. I think we should be good to go after addressing these. Thanks!

@kimsey0

Copy link
Copy Markdown
ContributorAuthor
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.

I added assertions that the new diagnostic is reported to the existing test cases with shadowed primary constructor parameters. Would you like any additional tests of this?

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @kimsey0 providing the fix!

@tarekgh
tarekgh merged commit 9daa4b4 into dotnet:mainMay 28, 2024
@kimsey0
kimsey0 deleted the logger-message-generator-primary-constructors branch May 28, 2024 17:06
@kimsey0

Copy link
Copy Markdown
ContributorAuthor

Thanks a lot for the help, @tarekgh!

Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
…t#101660)
* Add support for primary constructors in LoggerMessageGenerator
* Get the primary constructor parameters types from the constructor symbol instead of from the semantic model
* Prioritize fields over primary constructor parameters and ignore shadowed parameters when finding a logger
* Make checking for primary constructors non-conditional on Roslyn version and simplify project setup
* Reintroduce Roslyn 4.8 test project
* Add info-level diagnostic for logger primary constructor parameters that are shadowed by field
* Update list of diagnostics with new logging message generator diagnostic
* Only add non-logger field names to set of shadowed names
* Add comment explaining the use of the set of shadowed names with an example
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Loggingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LoggerMessage source generator does not work with logger from primary constructor.

6 participants

@kimsey0@tarekgh@joperezr@333fred@CyrusNajmabadi@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add support for primary constructors in LoggerMessageGenerator - #101660

Merged
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors
May 28, 2024
Merged

Add support for primary constructors in LoggerMessageGenerator#101660
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors

Conversation

@kimsey0

Copy link
Copy Markdown
Contributor

Fixes#91121.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 28, 2024
@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 thanks for submitting the PR. I converted it to draft till it is ready for actual review.

@kimsey0

Copy link
Copy Markdown
ContributorAuthor

@tarekgh, with the helpful suggestion from Cyrus, I now think this is ready for review. Should I mark it as such or wait for more feedback, perhaps from @eiriktsarpalis? (I don't know when he's back from vacation.)

.Where(ic => ic.DeclaringSyntaxReferences
.Any(ds => ds.GetSyntax() is ClassDeclarationSyntax));

foreach (IMethodSymbol primaryConstructor in primaryConstructors)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So, this in itself is a great example of why I said you're not going to get lookup right if you do it by yourself. Consider this example; I've created a protected field in the base type with a wider type than the logger parameter in the derived type, and that protected member shadows the primary constructor parameter. Another similar example is this, where I've shadowed the primary constructor parameter with a field directly in the type itself. I'm not opposed to the idea of adding a new LookupSymbols API here to allow SG authors to say "I need to know what names are available when I implement the body of this type", but it's also important to note that available names are by nature impacted by the usings in the file. Let me talk with @AlekseyTs and see if we can come up with any ideas that avoid you having to try and get this correct.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You should also test scenarios like this:

classTest(ILoggerlogger){privatereadonlyILogger_logger=logger;}

and ensure that you're using the right logger for that scenario.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

private readonly ILogger _logger = logger;

good test as we don't support private fields.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Sure, that would be possible. Talking with Aleksey, that's likely the approach you want to take in general. However, I'm going to strongly recommend that you explicitly consider these cases and lay out, in comments and documentation, the exact rules you follow. IE, what happens when a primary constructor parameter is shadowed? What happens when a base type has a protected member that is named differently than the parameter (ie, has an _)? This will make it easier to verify the behavior is what you're expecting, and to handle bugs as by-design or not.

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

You only need the check that kimsey0 put in already. It's important to note that you can only detect primary constructors from source, you cannot detect them from metadata.

good test as we don't support private fields.

Wait, what? I'll reiterate that I think you need spell out exactly what the rules are, in comments above the code, so that you can verify the code follows them. I thought I might understand the rules, but clearly I do not.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. If both the behavior described above as well as the code implementing it is acceptable to all parties, I think this is ready for review again.

@tarekghtarekghMay 24, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'll try to review it when I get a chance. PR is not a draft anymore. Thanks for all the help you have provided here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. Thanks a lot!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I forgot to commit and push the info diagnostic, but just did that. I don't know if there are any guidelines for how exactly these diagnostic messages should be written or how the translation flow goes? (We can also just revert this. I think it's useful, but not necessary.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You don't have to worry about the translation of the added messages. I am seeing the added diagnostic is useful to catch the concerned case.

@tarekgh

tarekgh commented May 23, 2024

Copy link
Copy Markdown
Member

@geeknoid@joperezr to be aware about this change if need to update the extensions logging source gen too.

@joperezr

Copy link
Copy Markdown
Member

Thanks for flagging this @tarekgh! It does seem like it is something we'll want to do in extensions. Logged dotnet/extensions#5178 to track

@tarekgh

Copy link
Copy Markdown
Member
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.


Refers to: src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs:1115 in 6cf2b2f. [](commit_id = 6cf2b2f, deletion_comment = False)

@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 I added a few minor comments. I think we should be good to go after addressing these. Thanks!

@kimsey0

Copy link
Copy Markdown
ContributorAuthor
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.

I added assertions that the new diagnostic is reported to the existing test cases with shadowed primary constructor parameters. Would you like any additional tests of this?

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @kimsey0 providing the fix!

@tarekgh
tarekgh merged commit 9daa4b4 into dotnet:mainMay 28, 2024
@kimsey0
kimsey0 deleted the logger-message-generator-primary-constructors branch May 28, 2024 17:06
@kimsey0

Copy link
Copy Markdown
ContributorAuthor

Thanks a lot for the help, @tarekgh!

Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
…t#101660)
* Add support for primary constructors in LoggerMessageGenerator
* Get the primary constructor parameters types from the constructor symbol instead of from the semantic model
* Prioritize fields over primary constructor parameters and ignore shadowed parameters when finding a logger
* Make checking for primary constructors non-conditional on Roslyn version and simplify project setup
* Reintroduce Roslyn 4.8 test project
* Add info-level diagnostic for logger primary constructor parameters that are shadowed by field
* Update list of diagnostics with new logging message generator diagnostic
* Only add non-logger field names to set of shadowed names
* Add comment explaining the use of the set of shadowed names with an example
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Loggingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LoggerMessage source generator does not work with logger from primary constructor.

6 participants

@kimsey0@tarekgh@joperezr@333fred@CyrusNajmabadi@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Add support for primary constructors in LoggerMessageGenerator - #101660

Merged
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors
May 28, 2024
Merged

Add support for primary constructors in LoggerMessageGenerator#101660
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors

Conversation

@kimsey0

Copy link
Copy Markdown
Contributor

Fixes#91121.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 28, 2024
@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 thanks for submitting the PR. I converted it to draft till it is ready for actual review.

@kimsey0

Copy link
Copy Markdown
ContributorAuthor

@tarekgh, with the helpful suggestion from Cyrus, I now think this is ready for review. Should I mark it as such or wait for more feedback, perhaps from @eiriktsarpalis? (I don't know when he's back from vacation.)

.Where(ic => ic.DeclaringSyntaxReferences
.Any(ds => ds.GetSyntax() is ClassDeclarationSyntax));

foreach (IMethodSymbol primaryConstructor in primaryConstructors)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So, this in itself is a great example of why I said you're not going to get lookup right if you do it by yourself. Consider this example; I've created a protected field in the base type with a wider type than the logger parameter in the derived type, and that protected member shadows the primary constructor parameter. Another similar example is this, where I've shadowed the primary constructor parameter with a field directly in the type itself. I'm not opposed to the idea of adding a new LookupSymbols API here to allow SG authors to say "I need to know what names are available when I implement the body of this type", but it's also important to note that available names are by nature impacted by the usings in the file. Let me talk with @AlekseyTs and see if we can come up with any ideas that avoid you having to try and get this correct.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You should also test scenarios like this:

classTest(ILoggerlogger){privatereadonlyILogger_logger=logger;}

and ensure that you're using the right logger for that scenario.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

private readonly ILogger _logger = logger;

good test as we don't support private fields.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Sure, that would be possible. Talking with Aleksey, that's likely the approach you want to take in general. However, I'm going to strongly recommend that you explicitly consider these cases and lay out, in comments and documentation, the exact rules you follow. IE, what happens when a primary constructor parameter is shadowed? What happens when a base type has a protected member that is named differently than the parameter (ie, has an _)? This will make it easier to verify the behavior is what you're expecting, and to handle bugs as by-design or not.

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

You only need the check that kimsey0 put in already. It's important to note that you can only detect primary constructors from source, you cannot detect them from metadata.

good test as we don't support private fields.

Wait, what? I'll reiterate that I think you need spell out exactly what the rules are, in comments above the code, so that you can verify the code follows them. I thought I might understand the rules, but clearly I do not.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. If both the behavior described above as well as the code implementing it is acceptable to all parties, I think this is ready for review again.

@tarekghtarekghMay 24, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'll try to review it when I get a chance. PR is not a draft anymore. Thanks for all the help you have provided here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. Thanks a lot!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I forgot to commit and push the info diagnostic, but just did that. I don't know if there are any guidelines for how exactly these diagnostic messages should be written or how the translation flow goes? (We can also just revert this. I think it's useful, but not necessary.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You don't have to worry about the translation of the added messages. I am seeing the added diagnostic is useful to catch the concerned case.

@tarekgh

tarekgh commented May 23, 2024

Copy link
Copy Markdown
Member

@geeknoid@joperezr to be aware about this change if need to update the extensions logging source gen too.

@joperezr

Copy link
Copy Markdown
Member

Thanks for flagging this @tarekgh! It does seem like it is something we'll want to do in extensions. Logged dotnet/extensions#5178 to track

@tarekgh

Copy link
Copy Markdown
Member
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.


Refers to: src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs:1115 in 6cf2b2f. [](commit_id = 6cf2b2f, deletion_comment = False)

@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 I added a few minor comments. I think we should be good to go after addressing these. Thanks!

@kimsey0

Copy link
Copy Markdown
ContributorAuthor
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.

I added assertions that the new diagnostic is reported to the existing test cases with shadowed primary constructor parameters. Would you like any additional tests of this?

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @kimsey0 providing the fix!

@tarekgh
tarekgh merged commit 9daa4b4 into dotnet:mainMay 28, 2024
@kimsey0
kimsey0 deleted the logger-message-generator-primary-constructors branch May 28, 2024 17:06
@kimsey0

Copy link
Copy Markdown
ContributorAuthor

Thanks a lot for the help, @tarekgh!

Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
…t#101660)
* Add support for primary constructors in LoggerMessageGenerator
* Get the primary constructor parameters types from the constructor symbol instead of from the semantic model
* Prioritize fields over primary constructor parameters and ignore shadowed parameters when finding a logger
* Make checking for primary constructors non-conditional on Roslyn version and simplify project setup
* Reintroduce Roslyn 4.8 test project
* Add info-level diagnostic for logger primary constructor parameters that are shadowed by field
* Update list of diagnostics with new logging message generator diagnostic
* Only add non-logger field names to set of shadowed names
* Add comment explaining the use of the set of shadowed names with an example
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Loggingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LoggerMessage source generator does not work with logger from primary constructor.

6 participants

@kimsey0@tarekgh@joperezr@333fred@CyrusNajmabadi@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add support for primary constructors in LoggerMessageGenerator - #101660

Merged
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors
May 28, 2024
Merged

Add support for primary constructors in LoggerMessageGenerator#101660
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors

Conversation

@kimsey0

Copy link
Copy Markdown
Contributor

Fixes#91121.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 28, 2024
@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 thanks for submitting the PR. I converted it to draft till it is ready for actual review.

@kimsey0

Copy link
Copy Markdown
ContributorAuthor

@tarekgh, with the helpful suggestion from Cyrus, I now think this is ready for review. Should I mark it as such or wait for more feedback, perhaps from @eiriktsarpalis? (I don't know when he's back from vacation.)

.Where(ic => ic.DeclaringSyntaxReferences
.Any(ds => ds.GetSyntax() is ClassDeclarationSyntax));

foreach (IMethodSymbol primaryConstructor in primaryConstructors)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So, this in itself is a great example of why I said you're not going to get lookup right if you do it by yourself. Consider this example; I've created a protected field in the base type with a wider type than the logger parameter in the derived type, and that protected member shadows the primary constructor parameter. Another similar example is this, where I've shadowed the primary constructor parameter with a field directly in the type itself. I'm not opposed to the idea of adding a new LookupSymbols API here to allow SG authors to say "I need to know what names are available when I implement the body of this type", but it's also important to note that available names are by nature impacted by the usings in the file. Let me talk with @AlekseyTs and see if we can come up with any ideas that avoid you having to try and get this correct.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You should also test scenarios like this:

classTest(ILoggerlogger){privatereadonlyILogger_logger=logger;}

and ensure that you're using the right logger for that scenario.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

private readonly ILogger _logger = logger;

good test as we don't support private fields.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Sure, that would be possible. Talking with Aleksey, that's likely the approach you want to take in general. However, I'm going to strongly recommend that you explicitly consider these cases and lay out, in comments and documentation, the exact rules you follow. IE, what happens when a primary constructor parameter is shadowed? What happens when a base type has a protected member that is named differently than the parameter (ie, has an _)? This will make it easier to verify the behavior is what you're expecting, and to handle bugs as by-design or not.

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

You only need the check that kimsey0 put in already. It's important to note that you can only detect primary constructors from source, you cannot detect them from metadata.

good test as we don't support private fields.

Wait, what? I'll reiterate that I think you need spell out exactly what the rules are, in comments above the code, so that you can verify the code follows them. I thought I might understand the rules, but clearly I do not.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. If both the behavior described above as well as the code implementing it is acceptable to all parties, I think this is ready for review again.

@tarekghtarekghMay 24, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'll try to review it when I get a chance. PR is not a draft anymore. Thanks for all the help you have provided here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. Thanks a lot!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I forgot to commit and push the info diagnostic, but just did that. I don't know if there are any guidelines for how exactly these diagnostic messages should be written or how the translation flow goes? (We can also just revert this. I think it's useful, but not necessary.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You don't have to worry about the translation of the added messages. I am seeing the added diagnostic is useful to catch the concerned case.

@tarekgh

tarekgh commented May 23, 2024

Copy link
Copy Markdown
Member

@geeknoid@joperezr to be aware about this change if need to update the extensions logging source gen too.

@joperezr

Copy link
Copy Markdown
Member

Thanks for flagging this @tarekgh! It does seem like it is something we'll want to do in extensions. Logged dotnet/extensions#5178 to track

@tarekgh

Copy link
Copy Markdown
Member
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.


Refers to: src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs:1115 in 6cf2b2f. [](commit_id = 6cf2b2f, deletion_comment = False)

@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 I added a few minor comments. I think we should be good to go after addressing these. Thanks!

@kimsey0

Copy link
Copy Markdown
ContributorAuthor
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.

I added assertions that the new diagnostic is reported to the existing test cases with shadowed primary constructor parameters. Would you like any additional tests of this?

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @kimsey0 providing the fix!

@tarekgh
tarekgh merged commit 9daa4b4 into dotnet:mainMay 28, 2024
@kimsey0
kimsey0 deleted the logger-message-generator-primary-constructors branch May 28, 2024 17:06
@kimsey0

Copy link
Copy Markdown
ContributorAuthor

Thanks a lot for the help, @tarekgh!

Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
…t#101660)
* Add support for primary constructors in LoggerMessageGenerator
* Get the primary constructor parameters types from the constructor symbol instead of from the semantic model
* Prioritize fields over primary constructor parameters and ignore shadowed parameters when finding a logger
* Make checking for primary constructors non-conditional on Roslyn version and simplify project setup
* Reintroduce Roslyn 4.8 test project
* Add info-level diagnostic for logger primary constructor parameters that are shadowed by field
* Update list of diagnostics with new logging message generator diagnostic
* Only add non-logger field names to set of shadowed names
* Add comment explaining the use of the set of shadowed names with an example
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Loggingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LoggerMessage source generator does not work with logger from primary constructor.

6 participants

@kimsey0@tarekgh@joperezr@333fred@CyrusNajmabadi@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add support for primary constructors in LoggerMessageGenerator - #101660

Merged
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors
May 28, 2024
Merged

Add support for primary constructors in LoggerMessageGenerator#101660
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors

Conversation

@kimsey0

Copy link
Copy Markdown
Contributor

Fixes#91121.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 28, 2024
@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 thanks for submitting the PR. I converted it to draft till it is ready for actual review.

@kimsey0

Copy link
Copy Markdown
ContributorAuthor

@tarekgh, with the helpful suggestion from Cyrus, I now think this is ready for review. Should I mark it as such or wait for more feedback, perhaps from @eiriktsarpalis? (I don't know when he's back from vacation.)

.Where(ic => ic.DeclaringSyntaxReferences
.Any(ds => ds.GetSyntax() is ClassDeclarationSyntax));

foreach (IMethodSymbol primaryConstructor in primaryConstructors)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So, this in itself is a great example of why I said you're not going to get lookup right if you do it by yourself. Consider this example; I've created a protected field in the base type with a wider type than the logger parameter in the derived type, and that protected member shadows the primary constructor parameter. Another similar example is this, where I've shadowed the primary constructor parameter with a field directly in the type itself. I'm not opposed to the idea of adding a new LookupSymbols API here to allow SG authors to say "I need to know what names are available when I implement the body of this type", but it's also important to note that available names are by nature impacted by the usings in the file. Let me talk with @AlekseyTs and see if we can come up with any ideas that avoid you having to try and get this correct.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You should also test scenarios like this:

classTest(ILoggerlogger){privatereadonlyILogger_logger=logger;}

and ensure that you're using the right logger for that scenario.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

private readonly ILogger _logger = logger;

good test as we don't support private fields.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Sure, that would be possible. Talking with Aleksey, that's likely the approach you want to take in general. However, I'm going to strongly recommend that you explicitly consider these cases and lay out, in comments and documentation, the exact rules you follow. IE, what happens when a primary constructor parameter is shadowed? What happens when a base type has a protected member that is named differently than the parameter (ie, has an _)? This will make it easier to verify the behavior is what you're expecting, and to handle bugs as by-design or not.

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

You only need the check that kimsey0 put in already. It's important to note that you can only detect primary constructors from source, you cannot detect them from metadata.

good test as we don't support private fields.

Wait, what? I'll reiterate that I think you need spell out exactly what the rules are, in comments above the code, so that you can verify the code follows them. I thought I might understand the rules, but clearly I do not.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. If both the behavior described above as well as the code implementing it is acceptable to all parties, I think this is ready for review again.

@tarekghtarekghMay 24, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'll try to review it when I get a chance. PR is not a draft anymore. Thanks for all the help you have provided here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. Thanks a lot!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I forgot to commit and push the info diagnostic, but just did that. I don't know if there are any guidelines for how exactly these diagnostic messages should be written or how the translation flow goes? (We can also just revert this. I think it's useful, but not necessary.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You don't have to worry about the translation of the added messages. I am seeing the added diagnostic is useful to catch the concerned case.

@tarekgh

tarekgh commented May 23, 2024

Copy link
Copy Markdown
Member

@geeknoid@joperezr to be aware about this change if need to update the extensions logging source gen too.

@joperezr

Copy link
Copy Markdown
Member

Thanks for flagging this @tarekgh! It does seem like it is something we'll want to do in extensions. Logged dotnet/extensions#5178 to track

@tarekgh

Copy link
Copy Markdown
Member
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.


Refers to: src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs:1115 in 6cf2b2f. [](commit_id = 6cf2b2f, deletion_comment = False)

@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 I added a few minor comments. I think we should be good to go after addressing these. Thanks!

@kimsey0

Copy link
Copy Markdown
ContributorAuthor
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.

I added assertions that the new diagnostic is reported to the existing test cases with shadowed primary constructor parameters. Would you like any additional tests of this?

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @kimsey0 providing the fix!

@tarekgh
tarekgh merged commit 9daa4b4 into dotnet:mainMay 28, 2024
@kimsey0
kimsey0 deleted the logger-message-generator-primary-constructors branch May 28, 2024 17:06
@kimsey0

Copy link
Copy Markdown
ContributorAuthor

Thanks a lot for the help, @tarekgh!

Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
…t#101660)
* Add support for primary constructors in LoggerMessageGenerator
* Get the primary constructor parameters types from the constructor symbol instead of from the semantic model
* Prioritize fields over primary constructor parameters and ignore shadowed parameters when finding a logger
* Make checking for primary constructors non-conditional on Roslyn version and simplify project setup
* Reintroduce Roslyn 4.8 test project
* Add info-level diagnostic for logger primary constructor parameters that are shadowed by field
* Update list of diagnostics with new logging message generator diagnostic
* Only add non-logger field names to set of shadowed names
* Add comment explaining the use of the set of shadowed names with an example
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Loggingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LoggerMessage source generator does not work with logger from primary constructor.

6 participants

@kimsey0@tarekgh@joperezr@333fred@CyrusNajmabadi@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Add support for primary constructors in LoggerMessageGenerator - #101660

Merged
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors
May 28, 2024
Merged

Add support for primary constructors in LoggerMessageGenerator#101660
tarekgh merged 9 commits into
dotnet:mainfrom
kimsey0:logger-message-generator-primary-constructors

Conversation

@kimsey0

Copy link
Copy Markdown
Contributor

Fixes#91121.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 28, 2024
@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 thanks for submitting the PR. I converted it to draft till it is ready for actual review.

@kimsey0

Copy link
Copy Markdown
ContributorAuthor

@tarekgh, with the helpful suggestion from Cyrus, I now think this is ready for review. Should I mark it as such or wait for more feedback, perhaps from @eiriktsarpalis? (I don't know when he's back from vacation.)

.Where(ic => ic.DeclaringSyntaxReferences
.Any(ds => ds.GetSyntax() is ClassDeclarationSyntax));

foreach (IMethodSymbol primaryConstructor in primaryConstructors)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So, this in itself is a great example of why I said you're not going to get lookup right if you do it by yourself. Consider this example; I've created a protected field in the base type with a wider type than the logger parameter in the derived type, and that protected member shadows the primary constructor parameter. Another similar example is this, where I've shadowed the primary constructor parameter with a field directly in the type itself. I'm not opposed to the idea of adding a new LookupSymbols API here to allow SG authors to say "I need to know what names are available when I implement the body of this type", but it's also important to note that available names are by nature impacted by the usings in the file. Let me talk with @AlekseyTs and see if we can come up with any ideas that avoid you having to try and get this correct.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You should also test scenarios like this:

classTest(ILoggerlogger){privatereadonlyILogger_logger=logger;}

and ensure that you're using the right logger for that scenario.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

private readonly ILogger _logger = logger;

good test as we don't support private fields.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred is it possible to lookup the fields first and then if didn't find any try to look up the primary constructors?

Sure, that would be possible. Talking with Aleksey, that's likely the approach you want to take in general. However, I'm going to strongly recommend that you explicitly consider these cases and lay out, in comments and documentation, the exact rules you follow. IE, what happens when a primary constructor parameter is shadowed? What happens when a base type has a protected member that is named differently than the parameter (ie, has an _)? This will make it easier to verify the behavior is what you're expecting, and to handle bugs as by-design or not.

Also, for detecting the primary constructor, should check constructor.Body == null && constructor.ExpressionBody == null?

You only need the check that kimsey0 put in already. It's important to note that you can only detect primary constructors from source, you cannot detect them from metadata.

good test as we don't support private fields.

Wait, what? I'll reiterate that I think you need spell out exactly what the rules are, in comments above the code, so that you can verify the code follows them. I thought I might understand the rules, but clearly I do not.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. If both the behavior described above as well as the code implementing it is acceptable to all parties, I think this is ready for review again.

@tarekghtarekghMay 24, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'll try to review it when I get a chance. PR is not a draft anymore. Thanks for all the help you have provided here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sounds good. Thanks a lot!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I forgot to commit and push the info diagnostic, but just did that. I don't know if there are any guidelines for how exactly these diagnostic messages should be written or how the translation flow goes? (We can also just revert this. I think it's useful, but not necessary.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You don't have to worry about the translation of the added messages. I am seeing the added diagnostic is useful to catch the concerned case.

@tarekgh

tarekgh commented May 23, 2024

Copy link
Copy Markdown
Member

@geeknoid@joperezr to be aware about this change if need to update the extensions logging source gen too.

@joperezr

Copy link
Copy Markdown
Member

Thanks for flagging this @tarekgh! It does seem like it is something we'll want to do in extensions. Logged dotnet/extensions#5178 to track

@tarekgh

Copy link
Copy Markdown
Member
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.


Refers to: src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs:1115 in 6cf2b2f. [](commit_id = 6cf2b2f, deletion_comment = False)

@tarekgh

Copy link
Copy Markdown
Member

@kimsey0 I added a few minor comments. I think we should be good to go after addressing these. Thanks!

@kimsey0

Copy link
Copy Markdown
ContributorAuthor
 Assert.Equal("SYSLIB1026", diagnostics[0].Id);

Please add similar test for the new diagnostic we added.

I added assertions that the new diagnostic is reported to the existing test cases with shadowed primary constructor parameters. Would you like any additional tests of this?

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @kimsey0 providing the fix!

@tarekgh
tarekgh merged commit 9daa4b4 into dotnet:mainMay 28, 2024
@kimsey0
kimsey0 deleted the logger-message-generator-primary-constructors branch May 28, 2024 17:06
@kimsey0

Copy link
Copy Markdown
ContributorAuthor

Thanks a lot for the help, @tarekgh!

Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
…t#101660)
* Add support for primary constructors in LoggerMessageGenerator
* Get the primary constructor parameters types from the constructor symbol instead of from the semantic model
* Prioritize fields over primary constructor parameters and ignore shadowed parameters when finding a logger
* Make checking for primary constructors non-conditional on Roslyn version and simplify project setup
* Reintroduce Roslyn 4.8 test project
* Add info-level diagnostic for logger primary constructor parameters that are shadowed by field
* Update list of diagnostics with new logging message generator diagnostic
* Only add non-logger field names to set of shadowed names
* Add comment explaining the use of the set of shadowed names with an example
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Loggingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LoggerMessage source generator does not work with logger from primary constructor.

6 participants

@kimsey0@tarekgh@joperezr@333fred@CyrusNajmabadi@ericstj