This project is read-only.
1
Vote

Incorrect PDB info emitted for reference with multiple extern aliases

description

Compile b.cs:

csc /target:library b.cs
namespace N { public class D { } }
namespace M { public class E { } }
Compile a.cs:

csc /target:library /r:A=b.dll /r:B=b.dll /debug:full a.cs
extern alias A;
extern alias B;
 
using A::N;
using B::M;
using X = A::N;
using Y = B::N;
 
public class C
{
    public static void Main()
    {
        System.Console.WriteLine(new D());
        System.Console.WriteLine(new E());
        System.Console.WriteLine(new X.D());
        System.Console.WriteLine(new Y.D());
    }
}
Compare PDB generated by VS 2013 vs Roslyn:

VS 2013:
  <scope startOffset="0x0" endOffset="0x23">
    <extern alias="A" />
    <extern alias="B" />
    <namespace qualifier=__"A"__ name="N" />
    <namespace qualifier="B" name="M" />
    <alias name="X" qualifier=__"A"__ target="N" kind="namespace" />
    <alias name="Y" qualifier="B" target="N" kind="namespace" />
    <externinfo alias="A" assembly="b, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" />
    <externinfo alias="B" assembly="b, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </scope>
Roslyn:
  <scope startOffset="0x0" endOffset="0x18">
    <extern alias="A" />
    <extern alias="B" />
    <namespace qualifier=__"B"__ name="N" />
    <namespace qualifier="B" name="M" />
    <alias name="X" qualifier=__"B"__ target="N" kind="namespace" />
    <alias name="Y" qualifier="B" target="N" kind="namespace" />
    <externinfo alias="A" assembly="b, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" />
    <externinfo alias="B" assembly="b, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </scope>

comments

acasey wrote Nov 10, 2014 at 9:46 PM

In commit f790dbff943a, I updated the behavior in a way that should prevent us from emitting incorrect Custom Debug Info, but fails to completely resolve the issue.

The desired behavior is to preserve the extern alias used in source. Unfortunately, this is difficult because the :: syntax for extern aliases is optional - a dot may be used instead. Consequently, "A.B" may refer to either "A::B" or "global::A.B" and we can't distinguish without binding. Rather than solving this problem, I opted for the simpler solution of filtering out extern aliases that are not in scope at the location of the using. The result is that the custom debug info may still not match what was in source, but it should bind equivalently (i.e. even if we choose the "wrong" extern alias, it should still be an extern alias of the same assembly).

TL;DR: our behavior is no longer incorrect, but it could still be improved.