Annotate CommandLineParser/Arguments and File/PathUtilities#41063
Annotate CommandLineParser/Arguments and File/PathUtilities#41063jcouv merged 21 commits intodotnet:masterfrom
Conversation
| /// Gets the emit options. | ||
| /// </summary> | ||
| public EmitOptions EmitOptions { get; internal set; } | ||
| public EmitOptions EmitOptions { get; internal set; } = null!; // initialized by Parse |
There was a problem hiding this comment.
❓ Why not make this a constructor parameter (required initialization)? #Resolved
There was a problem hiding this comment.
Tried it after your suggestion, but decided against it as it breaks the regularity of the code in parser and also implies a change in VB code. Neither of these seem worth it.
The topic of field initializers will be re-discussed in LDM and at the very least we'll provide some guidance to the recommended pattern for dealing with this situation.
In reply to: 368190989 [](ancestors = 368190989)
|
|
||
| internal static ReportDiagnostic GetDiagnosticOptionsFromRulesetFile(string rulesetFileFullPath, out Dictionary<string, ReportDiagnostic> diagnosticOptions, IList<Diagnostic> diagnosticsOpt, CommonMessageProvider messageProviderOpt) | ||
| #nullable enable | ||
| internal static ReportDiagnostic GetDiagnosticOptionsFromRulesetFile(string? rulesetFileFullPath, out Dictionary<string, ReportDiagnostic> diagnosticOptions, IList<Diagnostic> diagnosticsOpt, CommonMessageProvider messageProviderOpt) |
There was a problem hiding this comment.
| internal static ReportDiagnostic GetDiagnosticOptionsFromRulesetFile(string? rulesetFileFullPath, out Dictionary<string, ReportDiagnostic> diagnosticOptions, IList<Diagnostic> diagnosticsOpt, CommonMessageProvider messageProviderOpt) | |
| internal static ReportDiagnostic GetDiagnosticOptionsFromRulesetFile(string? rulesetFileFullPath, out Dictionary<string, ReportDiagnostic> diagnosticOptions, IList<Diagnostic>? diagnosticsOpt, CommonMessageProvider? messageProviderOpt) | |
| ``` #Resolved |
| } | ||
|
|
||
| if (string.IsNullOrEmpty(filePath)) | ||
| if (RoslynString.IsNullOrWhiteSpace(filePath)) |
There was a problem hiding this comment.
📝 this change aligns with logic in ParseResourceDescription (called a few lines above). The effect is to change which error is reported (see ParseResources test, which was updated). #Resolved
| if (!string.IsNullOrEmpty(outputDirectory) && baseDirectory != outputDirectory) | ||
| if (RoslynString.IsNullOrEmpty(outputDirectory)) | ||
| { | ||
| AddDiagnostic(diagnostics, ErrorCode.ERR_NoOutputDirectory); |
There was a problem hiding this comment.
📝 this new error guards against null output directory, allowing us to declare OutputDirectory as non-nullable. #Resolved
There was a problem hiding this comment.
📝 This new error means loc change, and the cutoff for 16.5 already passed so this needs to retarget 16.6 Preview 1 #Resolved
There was a problem hiding this comment.
There was a problem hiding this comment.
You could get a null OutputDirectory, which we're not prepared to handle in code that reads that property.
I'm not sure if that emitting code (which reads the property) could be reached though.
In reply to: 377830798 [](ancestors = 377830798,370462374)
|
@dotnet/roslyn-compiler @sharwell for review. This annotates more of the public APIs. Thanks #Resolved |
1 similar comment
|
@dotnet/roslyn-compiler @sharwell for review. This annotates more of the public APIs. Thanks #Resolved |
sharwell
left a comment
There was a problem hiding this comment.
Marking request changes just for the retarget due to loc change
| } | ||
|
|
||
| var moduleFileKey = FileKey.Create(PathUtilities.CombineAbsoluteAndRelativePaths(assemblyDir, moduleName)); | ||
| var moduleFileKey = FileKey.Create(PathUtilities.CombineAbsoluteAndRelativePaths(assemblyDir!, moduleName)); |
There was a problem hiding this comment.
💡 Replacing the condition above would remove the need for this suppression:
-if (moduleBuilder.Count == 0)
+if (assemblyDir is null)If that's too confusing, an equally usable alternative is moving the initialization of assemblyDir outside that if statement:
assemblyDir ??= Path.GetDirectoryName(fileKey.FullPath);
``` #Resolved| if (references.IsDefaultOrEmpty && messageProviderOpt != null) | ||
| { | ||
| diagnosticsOpt.Add(new DiagnosticInfo(messageProviderOpt, messageProviderOpt.ERR_MetadataFileNotFound, cmdReference.Reference)); | ||
| diagnosticsOpt!.Add(new DiagnosticInfo(messageProviderOpt, messageProviderOpt.ERR_MetadataFileNotFound, cmdReference.Reference)); |
There was a problem hiding this comment.
💭 If you're going to need a suppression either way, why not keep the original check and place the suppression on messageProviderOpt?
Edit: Oh, because two suppressions. In that case, I vote for the original code but add:
RoslynDebug.AssertNotNull(messageProviderOpt);
``` #Resolved| if (!string.IsNullOrEmpty(outputDirectory) && baseDirectory != outputDirectory) | ||
| if (RoslynString.IsNullOrEmpty(outputDirectory)) | ||
| { | ||
| AddDiagnostic(diagnostics, ErrorCode.ERR_NoOutputDirectory); |
There was a problem hiding this comment.
📝 This new error means loc change, and the cutoff for 16.5 already passed so this needs to retarget 16.6 Preview 1 #Resolved
| private static IEnumerable<string> ParseUsings(string arg, string? value, IList<Diagnostic> diagnostics) | ||
| { | ||
| if (value.Length == 0) | ||
| if (value is null || value.Length == 0) |
There was a problem hiding this comment.
| if (value is null || value.Length == 0) | |
| if (RoslynString.IsNullOrEmpty(value)) | |
| ``` #Resolved |
| /// Compilation name or null if not specified. | ||
| /// </summary> | ||
| public string CompilationName { get; internal set; } | ||
| public string? CompilationName { get; internal set; } |
There was a problem hiding this comment.
I distinctly remember fixing a bug that came about specifically because the code didn't realize CompilationName could be null. Seeing this makes me happy for the time I spent fixing that bug some years ago. #Resolved
| /// Trims all '.' and whitespace from the end of the path | ||
| /// </summary> | ||
| internal static string RemoveTrailingSpacesAndDots(string path) | ||
| internal static string? RemoveTrailingSpacesAndDots(string? path) |
There was a problem hiding this comment.
Did you consider using NotNullWhenNotNull to mark the return? #Resolved
| } | ||
|
|
||
| if (responsePaths != null) | ||
| if (responsePaths != null && |
There was a problem hiding this comment.
Feels like we're hiding a bug here. Agree this change is necessary because the old code path would essentially throw in the case where GetDirectoryName returned null. At the same time though now this will just silently continue. Should we issue the diagnostic FTL_InvalidInputFileName when we can't get a directory name here? #Closed
There was a problem hiding this comment.
Makes sense.
I'll add the diagnostic. I've not been able to hit this case yet though, so it will lack coverage...
In reply to: 378077429 [](ancestors = 378077429)
| } | ||
|
|
||
| if (path.Length == 1) | ||
| if (path!.Length == 1) |
There was a problem hiding this comment.
Seems like path could be null in the case here where kind == PathKind.Empty #Resolved
There was a problem hiding this comment.
See assertion I added above. In this branch, we know that GetPathKind(path) == kind == PathKind.RelativeToCurrentDirectory
In reply to: 378078393 [](ancestors = 378078393)
|
Done with review pass (iteration 12) #Resolved |
| [Theory] | ||
| [InlineData(null, null)] | ||
| [InlineData("c:", null)] | ||
| [InlineData("c:\\", null)] |
There was a problem hiding this comment.
"c:\" [](start = 20, length = 6)
Are these tests only run on Windows? #Closed
There was a problem hiding this comment.
I thought the logic in the method didn't depend on the current platform, but it looks like it does (directory separator is \ or /). I'll make the test conditional.
In reply to: 378585981 [](ancestors = 378585981)
| [InlineData("\\first\\second", "\\first")] | ||
| [InlineData("\\first\\second\\", "\\first\\second")] | ||
| [InlineData("\\first\\second\\third", "\\first\\second")] | ||
| public void TestGetDirectoryName_Windows(string path, string expectedOutput) |
There was a problem hiding this comment.
public [](start = 8, length = 6)
Do we need to test relative paths as well? #Closed
There was a problem hiding this comment.
Doesn't hurt. I'll add.
The main point of this test is to show when we're returning null
In reply to: 378586494 [](ancestors = 378586494)
master is now targeting 16.6, so no loc constraint
| else | ||
| { | ||
| pdbPath = Path.ChangeExtension(Path.Combine(outputDirectory, outputFileName), ".pdb"); | ||
| // If outputDirectory were null, then outputFileName would be null (see ParseAndNormalizeFile) |
There was a problem hiding this comment.
These comments are better served with an assert for verification. #Resolved
333fred
left a comment
There was a problem hiding this comment.
LGTM (commit 20) with assertion changes.
Hum, this is an existing suppression, and I'm not sure it's justified... I'll add to tracking issue for null directories In reply to: 586411159 [](ancestors = 586411159) Refers to: src/Compilers/Core/Portable/AssemblyUtilities.cs:63 in 886d453. [](commit_id = 886d453, deletion_comment = False) |
It's justified. The rational is captured here #41485 (comment) |
|
@jaredpar I’ll update the comment |
|
@jaredpar I'm going to leave the comment as-is for follow-up. Reading the rationale again, I suspect that it is incorrect. If you open a file in the root directory, the I'll go ahead and merge leaving the follow-up comment. |
This found a bug (added tests and a simple fix in
CommandLineParser.EnumerateFiles).I also added a null check in
CommandLineParser(line 428) which I could not protect or rationalize otherwise.