Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Exception when navigating to generated code #47782

Closed
YairHalberstadt opened this issue Sep 17, 2020 · 6 comments · Fixed by #49059
Closed

Exception when navigating to generated code #47782

YairHalberstadt opened this issue Sep 17, 2020 · 6 comments · Fixed by #49059
Assignees
Milestone

Comments

@YairHalberstadt
Copy link
Contributor

YairHalberstadt commented Sep 17, 2020

Version Used: VS 16.8 preview 3

Steps to Reproduce:

  1. Clone https://github.com/YairHalberstadt/stronginject
  2. Open in VS
  3. Navigate to StrongInject.Tests.Integration.TestInstancePerDependencyHasCorrectScope.cs
  4. Add the following member to the Container class: public object x => _disposed;
  5. Try "Go to definition" on the _disposed token.

Expected Behavior:

Navigates to the generated source:

Actual Behavior:

Following error:

System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Users\yairh\AppData\Local\Temp\VisualStudioSourceGeneratedDocuments\641523fb-d396-4f48-8bc8-096813428ed9\b8cbb0e1-02f7-483c-9c43-433036febd5b_StrongInject.Generator.SourceGenerator_StrongInject.Tests.IntegrationTestInstancePerDependencyHasCorrectScopeContainer.generated.cs'.

   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)

   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)

   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)

   at System.IO.StreamWriter.CreateFile(String path, Boolean append, Boolean checkHost)

   at System.IO.StreamWriter..ctor(String path, Boolean append, Encoding encoding, Int32 bufferSize, Boolean checkHost)

   at System.IO.File.InternalWriteAllText(String path, String contents, Encoding encoding, Boolean checkHost)

   at System.IO.File.WriteAllText(String path, String contents)

   at Microsoft.VisualStudio.LanguageServices.Implementation.SourceGeneratedFileManager.NavigateToSourceGeneratedFile(Project project, ISourceGenerator generator, String generatedSourceHintName, TextSpan sourceSpan)

   at Microsoft.VisualStudio.LanguageServices.Implementation.VisualStudioSymbolNavigationService.TryNavigateToSymbol(ISymbol symbol, Project project, OptionSet options, CancellationToken cancellationToken)

   at Microsoft.CodeAnalysis.FindUsages.DefinitionItem.DefaultDefinitionItem.<>c.<TryNavigateToMetadataSymbol>b__6_0(ISymbol symbol, Project project, ISymbolNavigationService service)

   at Microsoft.CodeAnalysis.FindUsages.DefinitionItem.DefaultDefinitionItem.TryNavigateToMetadataSymbol(Workspace workspace, String symbolKey, Func`4 action)

   at Microsoft.CodeAnalysis.FindUsages.DefinitionItem.DefaultDefinitionItem.TryNavigateToMetadataSymbol(Workspace workspace, String symbolKey)

   at Microsoft.CodeAnalysis.FindUsages.DefinitionItem.DefaultDefinitionItem.TryNavigateTo(Workspace workspace, Boolean showInPreviewTab, Boolean activateTab)

   at Microsoft.CodeAnalysis.Editor.Host.IStreamingFindUsagesPresenterExtensions.<TryNavigateToOrPresentItemsAsync>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---

   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

   at Microsoft.VisualStudio.Threading.JoinableTask.CompleteOnCurrentThread()

   at Microsoft.VisualStudio.Threading.JoinableTask`1.CompleteOnCurrentThread()

   at Microsoft.VisualStudio.Threading.JoinableTaskFactory.Run[T](Func`1 asyncMethod, JoinableTaskCreationOptions creationOptions)

   at Microsoft.CodeAnalysis.Editor.GoToDefinition.GoToDefinitionHelpers.TryGoToDefinition(ISymbol symbol, Solution solution, IThreadingContext threadingContext, IStreamingFindUsagesPresenter streamingPresenter, CancellationToken cancellationToken, Boolean thirdPartyNavigationAllowed)

   at Microsoft.CodeAnalysis.Editor.GoToDefinition.AbstractGoToDefinitionService.TryGoToDefinition(Document document, Int32 position, CancellationToken cancellationToken)

   at Microsoft.CodeAnalysis.Editor.GoToDefinition.GoToDefinitionCommandHandler.TryExecuteCommand(Document document, Int32 caretPosition, IGoToDefinitionService goToDefinitionService, CommandExecutionContext context)

   at Microsoft.CodeAnalysis.Editor.GoToDefinition.GoToDefinitionCommandHandler.ExecuteCommand(GoToDefinitionCommandArgs args, CommandExecutionContext context)

   at Microsoft.VisualStudio.UI.Text.Commanding.Implementation.EditorCommandHandlerService.<>c__DisplayClass14_1`1.<ExecuteStartingAtIndex>b__0()

   at Microsoft.VisualStudio.Text.Utilities.GuardedOperations.CallExtensionPoint(Object errorSource, Action call, Predicate`1 exceptionFilter)
--- End of stack trace from previous location where exception was thrown ---

   at Microsoft.VisualStudio.Telemetry.WindowsErrorReporting.WatsonReport.GetClrWatsonExceptionInfo(Exception exceptionObject)

Note the directory C:\Users\yairh\AppData\Local\Temp\VisualStudioSourceGeneratedDocuments\641523fb-d396-4f48-8bc8-096813428ed9 is created in this process, but is empty.

@YairHalberstadt
Copy link
Contributor Author

cc @jasonmalinowski

@YairHalberstadt
Copy link
Contributor Author

I think the issue might be the character count of:

C:\Users\yairh\AppData\Local\Temp\VisualStudioSourceGeneratedDocuments\641523fb-d396-4f48-8bc8-096813428ed9\b8cbb0e1-02f7-483c-9c43-433036febd5b_StrongInject.Generator.SourceGenerator_StrongInject.Tests.IntegrationTestInstancePerDependencyHasCorrectScopeContainer.generated.cs

is 276 which is greater than the maximum of 260.

Perhaps the generated name should just be a random guid to avoid running into this issue?

@YairHalberstadt
Copy link
Contributor Author

Indeed when the generated name is shorter, this works.

@YairHalberstadt
Copy link
Contributor Author

Also, even when goto definition works, peek definition errors.

@jasonmalinowski
Copy link
Member

So what's icky is the file path has to match the name that the compiler embeds or else the debugger doesn't know they're the same. We were already tracking changing it in #47211 but length wasn't something we were worrying about yet.

FYI to @chsienki on this one.

@jasonmalinowski
Copy link
Member

Also I'll reach out to the VS platform right now to ask about long path support. 😄

@jinujoseph jinujoseph added this to the 16.9 milestone Oct 14, 2020
jasonmalinowski added a commit to jasonmalinowski/roslyn that referenced this issue Oct 29, 2020
Right now when we open a generated file, we make a temporary file on
disk to placate parts of the VS API that need a file on disk. (If we had
the ability to have our own URI or moniker that'd be fine, but for now
we don't have such an ability.) The original plan was to pack in the
necessary information we need into the path so we can figure out what
file that represents so we can re-open generated files between runs of
VS without requiring actual state.

In practice, that didn't work yet (if nothing else, because we're
packing in a project ID which is random GUID that isn't persisted across
process runs). But the bigger problem is this also runs into MAX_PATH
issues, if the generator assembly or type names are fairly long. So
for now, let's just generate a GUID for the name and store the extra
information in a little lookup table.

This, and also just renaming the parent directory we put things in,
shaves off a fair number of characters, and also means the name of the
generator assembly or type name are no longer something being added
into the overall path length. The only "controllable" parts of the
path that can vary in length is the file name (which must match the hint
name from the compiler), and the user's username.

Fixes dotnet#47782, or at least as well
as we can.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants