dotnet / vscode-csharp

Official C# support for Visual Studio Code
MIT License
2.85k stars 666 forks source link

Renaming file or creating new file breaks omnisharp lookup #2040

Open bitinn opened 6 years ago

bitinn commented 6 years ago

Environment data

dotnet --info output:

.NET Command Line Tools (2.1.4)

Product Information:
 Version:            2.1.4
 Commit SHA-1 hash:  5e8add2190

Runtime Environment:
 OS Name:     Mac OS X
 OS Version:  10.13
 OS Platform: Darwin
 RID:         osx.10.12-x64
 Base Path:   /usr/local/share/dotnet/sdk/2.1.4/

Microsoft .NET Core Shared Framework Host

  Version  : 2.0.5
  Build    : 17373eb129b3b05aa18ece963f8795d65ef8ea54

VS Code version:

Version 1.20.1 (1.20.1)

C# Extension version:

1.14.0

Steps to reproduce

Create a file or rename a file and wait for Omnisharp to parse the file.

Expected behavior

VSCode should be able to find all existing namespace and assemblies.

Actual behavior

VSCode failed to find interfaces in the same namespace, and we can only reproduce it in current session, restarting VSCode, the issue is gone.

It seems Omnisharp somehow couldn't recognize new file or renamed file are in the same namespace.

Screenshots

Existing file:

screen shot 2018-02-15 at 14 48 51

Create a new file with simple class name change:

screen shot 2018-02-15 at 14 48 51

Problems:

screen shot 2018-02-15 at 14 49 18

Restart or reload VSCode:

screen shot 2018-02-15 at 14 55 07
rchande commented 6 years ago

Thanks for reporting this @bitinn. Looks like this issue was fixed on Windows but still happens on OS X. We'll take a look.

rchande commented 6 years ago

@bitinn I'm having trouble reproducing this on my Mac. Do you see this issue in a simple project (eg, dotnet new console and add a file), or only in your large project?

For this feature to work, your project needs to have file globbing enabled within the csproj files. Otherwise, when you add a file, omnisharp doesn't know what project to associate it with.

bitinn commented 6 years ago

@rchande Just a large Unity project it seems, I tried a separate project where I build a small plugin (dll) for Unity and the issue doesn't appear when I add a new file.

DustinCampbell commented 6 years ago

I think the problem here is that Unity projects do not support file globbing and C# for VS Code does not automatically update your project file to add/change/remove <Compile Include="your_new_file.cs" />s for new or renamed files. It looks to me like this is the same as https://github.com/OmniSharp/omnisharp-vscode/issues/1970.

bitinn commented 6 years ago

@DustinCampbell since this is a known limit, are there:

Basically, using VS Code with Unity means VS Code don't have to "build" the project. I just need it to know enough about Unity and my source code so that OmniSharp can provide basic intellisense suggestions.

DustinCampbell commented 6 years ago

You should be able to restart OmniSharp as a workaround. Run OmniSharp: Restart OmniSharp from the VS Code command palette.

You could use globbing patterns in your file. MSBuild supports them. Unfortunately, Unity does not. Unity will just stomp over your globs the next time it generates your project.

Basically, using VS Code with Unity means VS Code don't have to "build" the project. I just need it to know enough about Unity and my source code so that OmniSharp can provide basic intellisense suggestions.

Note that getting IntelliSense means performing a "build". This is design-time build that does not actually compile binaries. However, from the MSBuild perspective, it is still a build in that references need to be resolved, conditions in the project file must be evaluated, etc.

bitinn commented 6 years ago

@DustinCampbell thx for that!

But one more question: I don't fully understand why OmniSharp needs <Compile Include="your_new_file.cs" /> to see new file: for my smaller project, it appears my .csproj file only include existing files anyway, so how did OmniSharp discover a new file?

(In below example, only BLogger.cs is in the csproj file, I added a DLogger.cs and OmniSharp is able to discover it without refresh.)

EDIT: I am not sure if #1970 only concerns rename (which means .csproj points to a file that no longer exists) or does it include creating new file (which means .csproj doesn't include such a file). It might be the same either way, but then I don't understand how OmniSharp is able to discover new file for my smaller project (which was created from VS Community, but I don't see a file glob pattern?)

screen shot 2018-02-16 at 22 10 44
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BeginHQ.Plugins", "BeginHQ.Plugins\BeginHQ.Plugins.csproj", "{AA98C067-30E5-4D1B-8F2D-71BE4B36D4CE}"
EndProject
Global
    GlobalSection(SolutionConfigurationPlatforms) = preSolution
        Debug|Any CPU = Debug|Any CPU
        Release|Any CPU = Release|Any CPU
    EndGlobalSection
    GlobalSection(ProjectConfigurationPlatforms) = postSolution
        {AA98C067-30E5-4D1B-8F2D-71BE4B36D4CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {AA98C067-30E5-4D1B-8F2D-71BE4B36D4CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {AA98C067-30E5-4D1B-8F2D-71BE4B36D4CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {AA98C067-30E5-4D1B-8F2D-71BE4B36D4CE}.Release|Any CPU.Build.0 = Release|Any CPU
    EndGlobalSection
EndGlobal
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{AA98C067-30E5-4D1B-8F2D-71BE4B36D4CE}</ProjectGuid>
    <OutputType>Library</OutputType>
    <RootNamespace>BeginHQ.Plugins</RootNamespace>
    <AssemblyName>BeginHQ.Plugins</AssemblyName>
    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug</OutputPath>
    <DefineConstants>DEBUG;</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <ConsolePause>false</ConsolePause>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <Optimize>true</Optimize>
    <OutputPath>bin\Release</OutputPath>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <ConsolePause>false</ConsolePause>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="UnityEditor">
      <HintPath>..\..\..\..\..\..\Applications\Unity\Unity.app\Contents\Managed\UnityEditor.dll</HintPath>
    </Reference>
    <Reference Include="UnityEngine">
      <HintPath>..\..\..\..\..\..\Applications\Unity\Unity.app\Contents\Managed\UnityEngine.dll</HintPath>
    </Reference>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="BLogger.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
DustinCampbell commented 6 years ago

OmniSharp has a little bit of extra logic that will try to handle files that aren't included in a project if you make an edit in it. Essentially, if it can find a project that the file is likely to belong to, it will add it to OmniSharp's in-memory workspace. However, it won't change your project file.

bitinn commented 6 years ago

@DustinCampbell @rchande Thx! If I understand your explanation correctly: it looks like every time I rename a file or create a file, we are in uncharted territory where OmniSharp need to figure out whether a file belongs to the project without checking .csproj (which is now outdated).

While I fully understand that design decision. Maybe, just maybe, we can have a per-workspace setting, where we overrule .csproj and tell OmniSharp: hey, just check every .cs file in this folder.

It's quite dumb, but for Unity users, I can't think of a better solution. (It would be a pain to ask Unity to refresh .csproj file when we are working in VS Code).

SirIntruder commented 6 years ago

@DustinCampbell @bitinn Just restarting omnisharp after renaming doesn't work, you actually have to focus on unity3d to let it update .csprojs, and THEN reload Omnisharp/Vscode. Much fun πŸ˜›

After I understood the problem (and realised Omnisharp can't fix this issue in general, unity3D project system is too quirky) I took the pain to write a separate small crude extension which:

-turns on if it detects you are editing a Unity3d project -onDocumentOpen checks if the opened .cs file is not included in any .csproj project -if so, emulute Unity magic to find appropriate csproj and add missing "compile include=" line

All fine so far, The remaining issue was that omnisharp apparently doesn't listen to changes to .csproj files, so I still had to reload vscode for this to work... I forgot you can just restart omnisharp, maybe triggering that automaticaly after editing .csproj would feel smooth enough.

anyway, it would be best if o# knew how to listen to outside .csproj changes, should this in principle be similar to recent "dotnet restore" improvements?

rchande commented 6 years ago

@SirIntruder Nice work! That's very cool. Any plans to publish that extension? I bet there would be a lot of interest. For our side, I'll take a look and see if we can listen to csproj changes.

SirIntruder commented 6 years ago

thanks! I would like to, yet didn't want to publish it if it can't work without reloading vscode. But with "restart omnisharp" approach it may actually be just good enough for small-to-medium projects. Fingers crossed for listening to .csproj changes though, would fix a lot of the issues πŸ˜„

if anyone is brave enough to try this, I have uploaded .vsix here. https://github.com/SirIntruder/unitysmooth/releases I can probably steal some more time for it this week

p.s. after a bit of testing, I realised omnisharp doesn't like being restarted a lot, it gets perma stuck if it doesn't "recover" fully from previous restart. Any idea on when it should be 'safe' to restart? You can see behaviour for yourself by some simple restart command spamming.

crystalbyte commented 6 years ago

I have stumbled upon the same issue, is there any update on this?

SirIntruder commented 6 years ago

I was debugging today and I am pretty sure what is the issue. Omnisharp correctly listens to csproj. files, that was not the problem..

Issue was omnisharp's handling of .cs files which are not in any csproj, which @DustinCampbell mentioned. IIRC it finds first folders with project files and links new/renamed file to all of the found projects in that folder. In Unity case, all of its csprojs are in root folder, so new/renamed files are added everywhere.

Problem is that those transient links are not removed when projects are updated. Unity3d, (or me manually, doesn't matter) will later on put the new/renamed file to its correct csproj, but o# will keep it in all projects.

vscode bug

^Here TestClassB is added to the Assembly-CSharp.csproj, but o# still keeps it in Assembly-CSharp-firstpass.csproj as well - that's some other project, which doesn't know of TestClassA.cs.

So TestClassA.cs appears to simultaneously exist and doesn't exist.

And once you reload omnisharp/vscode, that temp link B had with Assembly-CSharp-firstpass.csproj doesn't exist anymore, and that weird error is gone with it.

vscode bug after restart

Does this make sense? I assume issue should be raised to omnisharp-roslyn

rchande commented 6 years ago

@SirIntruder Nice sleuthing! I think you're right--this is an Omnisharp bug. I'm the developer who will probably fix this in OmniSharp. I'm not very familiar with unity, so to help me reproduce this, would you mind sharing your repro steps? It'll just make it faster to validate that the fix works for your scenario. Thanks!

SirIntruder commented 6 years ago

omnisharp_bug_repro.zip

Of course! I uploaded an archive of my test project. I tried to step through omnisharp code while reproducing this, it went something like this:

gamefish commented 6 years ago

Same issue here. I have to restart vscode each time I create a new c# file. Annoying :)

Dzivo commented 6 years ago

Same issue here need to restart vs code each time i rename file with a class in it

bitinn commented 6 years ago

A quick recap on the workaround for future visitors:

  1. Goto "View -> Command Palette".
  2. Search for "OmniSharp" to find the "Restart OmniSharp" item.

It should solve 90% of your problem, the rest you need an Editor restart.

Jonatthu commented 6 years ago

@bitinn Even doing that sometimes vscode has problems restarting the solution or the project and just logs project loaded without bringing the intellisense or the assembly metadata or references

SirIntruder commented 6 years ago

You have to first focus unity, which will update project files correctly, and then restart omnisharp.

ckohnert commented 6 years ago

I'd love to see this fix. πŸ‘

Unfortunately, as a workaround, restarting omnisharp is not great. In a pretty small project, it takes me about 8-9 seconds to see the results in the file I'm working in, and this can happen over 20-30+ times a day when you're making a decent amount of changes or doing some refactoring/cleanups.

Shnagenburg commented 6 years ago

I've run into this problem as well with VSCode + Unity and would love a fix. I can only get it to consistently work by closing and restarting VSCode every time I create a new file.

ericrini commented 5 years ago

This is consistently a problem when renaming a .cs file using the right click "rename" option (F2).

What I will see is that OmniSharp will start reporting that the class in the new file is a duplicate of an existing. This can be fixed by restarting VS Code, or creating an empty file with the old file name and no content.

vlab22 commented 5 years ago

In my vscode only works if I focus Unity to it changes de csproj files then "Reload Windows" in vscode. Only restarting Omnisharp doesn't work, always need Unity "compiling" task.

akshita31 commented 5 years ago

As per https://github.com/OmniSharp/omnisharp-roslyn/pull/1159 this problem should be fixed. @SirIntruder Can you confirm if we can close this now ? Can someone here try setting "omnisharp.path": "latest" and checking if the error still persists?

bitinn commented 5 years ago

OK so here is my test result with Omnisharp version 1.32.12-beta.51.

Setup:

Test 1:

Test 2:

Conclusion:

Not sure this is by design, @SirIntruder I guess?

SirIntruder commented 5 years ago

Yup, fIxing that would require Omsnisharp to be able to "read Unity's mind". Basically, there is code in omnisharp that takes a filePath for the new file on one hand, and list of project files on the other hand, and tries to find the most likely match. If there was a way for a plugin to be inserted at this point, it would be possible to inject Unity's magic formula and have everything work out of the box. I don't know much about omnisharp's plugin architecture though, a member of omnisharp team could comment on this.

rchande commented 5 years ago

@bitinn Thanks for the analysis! @SirIntruder is correct that OmniSharp tries to figure out what project file to associate new files with. In test 1, are you adding the file in the same directory as or a child directory of the project file Unity generates?

bitinn commented 5 years ago

@rchande

In test 1, are you adding the file in the same directory as or a child directory of the project file Unity generates?

A child directory, a typical Unity repo looks something like this, and all scripts are somewhere under Assets folder (obviously can be much deeper down the hierarchy:

Screen Shot 2019-03-22 at 15 43 04 Screen Shot 2019-03-22 at 15 52 00

I should note that Test 1 doesn't reliably reproduce, I suspect it has something to do with omnisharp's extra logic that auto-detect new file or changes that wasn't in the csproj, so what's "supported" out of the box becomes a lot more muddier.

brunocapdevila commented 5 years ago

I have the same problem here on Windows 10 with version 1.32.3

Creating or renaming a new file messes Omnisharp up. Not even restarting it fixes the problem. Only solution is to restart vscode... This makes the editor almost unusable

Has there been any progress on this issue? I wouldn't want to come back to Visual Studio

Thanks

[EDIT] Problem solved: It seems that Omnisharp got confused with all dotnet versions installed in my PC.

I uninstalled all sdks, visual studio related sdks, remove path variables manually set by myself. Reinstalled vscode, dot net and omnisharp.

Everything works fine now!

martin-braun commented 5 years ago

Also I can confirm that Omnisharp fails when creating new files in a Unity Project. It stops finding any references, but I do not get errors, it's like Omnisharp is not running at all. Not even my code snippets can be found.

Only a restart of VSCode fixes it, but only, if the empty file is not there, anymore, either by deleting or adding contents to it.

I'm on Mac OS X.

Blackclaws commented 4 years ago

I have the same problem and I'm wondering why Omnisharp doesn't simply add the file to a csproj that covers any file close by, this would at least work for creating files in the same directory as existing files.

Visual Studio is able to add files to an open Unity solution just fine. What is keeping omnisharp from doing the same? Or is this something that should happen on vscode project management level?

MartinHaeusler commented 3 years ago

I have this problem as well (Windows 10). Whenever I add a new .cs file, there's no code completion inside it. I can't reference it in existing files either. I have to restart omisharp a lot*. This basically makes it next to unusable for me...

Any chance to get this fixed? Sadly, uninstalling all SDKs except for one is not an option for me...

EDIT: Just to make this point clear. I'm talking about creating a new .cs file within* VSCode. No external file system modifications taking place.

scgbear commented 3 years ago
Internal Tracking devdivcsef 412378
pgpais commented 3 years ago

Any update on this?

I'm encountering the same issue where creating a new .cs file in vscode requires me to focus Unity, wait for it to compile the new changes and then go back to vscode.

SirIntruder commented 3 years ago

I whipped out a small script that should fix this issue for Unity projects - https://gist.github.com/SirIntruder/5a8b0659df44f29b3538538a82313f66

I've tested it around a bit (Unity is at 2020.3) and it seems it works, Do tell if you encounter any problems.

Ideally, Unity should have out-of-the-box solution for this as part of vscode-editor package, I don't see a way for omnisharp to fix this properly by itself.

WalissonPires commented 1 year ago

Here the same thing happens. I'm using a web api project. It only resolves when I restart Ommisharp.

Tantol commented 1 year ago

I have the same problem on .NET MVC app. Its annoying.