dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
19.1k stars 4.04k forks source link

IDE0065 messes up if/endifs around namespaces #40001

Open stephentoub opened 5 years ago

stephentoub commented 5 years ago

Version Used: 3.5.0-beta2-19570-07+4bd316035f64c9776d5420af71df8ba38e8e23e4

Steps to Reproduce: Create a project with this code:

using System;

namespace MyNamespace
{
#if !FOO
    using System.Runtime.CompilerServices;
#endif

    class Program
    {
        static void Main() { }
    }
}

Then apply IDE0065 when it fires on the using System.Runtime.CompilerServices; directive.

Expected Behavior: Refactors to:

using System;
#if !FOO
using System.Runtime.CompilerServices;
#endif

namespace MyNamespace
{
    class Program
    {
        static void Main() { }
    }
}

or doesn't offer the refactoring.

Actual Behavior: Refactors to:

using System;
#if !FOO
using System.Runtime.CompilerServices;

namespace MyNamespace
{
#endif

    class Program
    {
        static void Main() { }
    }
}

which is broken and won't compile if that compilation constant is set.

worthy7 commented 3 years ago

Bump, just happened to me

stephentoub commented 2 years ago

I just went to file this issue after getting hit by it, and discovered I already did over two years ago :)

Evangelink commented 2 years ago

There is another related scenario.

Steps to reproduce:

#if NET6_0

namespace ConsoleApp
{
    using System;

    internal class Class1
    {
        public void M()
        {
            Console.WriteLine("");
        }
    }
}

#endif

Actual Behavior:

Applying the fix gives

using System;

#if NET6_0

namespace ConsoleApp
{
    internal class Class1
    {
        public void M()
        {
            Console.WriteLine("");
        }
    }
}

#endif

It's less severe because the code still compiles but we end up with warnings about unused using when compiling in different target framework (which can cause build break because of TreatWarningsAsErrors).

Expected Behavior:

Applying the fix gives


#if NET6_0

using System;

namespace ConsoleApp
{
    internal class Class1
    {
        public void M()
        {
            Console.WriteLine("");
        }
    }
}

#endif
belav commented 1 year ago

Related we ran into this on a project that multitargets net48 and net7.0

namespace MyNamespace;

using System;
#if NET6_0_OR_GREATER
using System.Linq;
#endif

public class MyClass { }

// results in

using System;
#if NET6_0_OR_GREATER
using System.Linq;

namespace MyNamespace;
#endif

public class MyClass { }

And it sometimes duplicates the namespace.