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
18.95k stars 4.02k forks source link

Transitive references are not considered by Roslyns Semantic model? #3249

Open Inspyro opened 9 years ago

Inspyro commented 9 years ago

Assume the following project layout: ProjectA declares a custom attribute ProjectB references ProjectA and uses the custom attribute on ClassA ProjectC references ProjectB and uses ClassA in ClassB

Now we want get the AttributeData (compiled version of the custom attribute) by using the semantic model of ProjectC, however we only get an ErrorType as long as ProjectC does not reference ProjectA (the one that contains the custom attribute).

Is this a Roslyn bug? Or is there a way to retrieve the AttributeData without adding a reference to ProjectA.

Here is the source code to reproduce the issue

private static void Main ()
    {
      using (var workspace = new AdhocWorkspace())
      {
        var libraryUsedByA = AddProject (workspace.CurrentSolution, "LibraryUsedByA")
            .AddDocument (
                "SomeAttribute.cs",
                "[System.AttributeUsage(System.AttributeTargets.Class)] public class SomeAttribute : System.Attribute { }").Project;

        var projectA = AddProject (libraryUsedByA.Solution, "ProjectA")
            .AddProjectReference (new ProjectReference (libraryUsedByA.Id))
            .AddDocument ("SomeClass.cs", "[SomeAttribute] public class SomeClass { }").Project;

        var someComposedClass = AddProject (projectA.Solution, "ProjectB")
            .AddProjectReference (new ProjectReference (projectA.Id))
            //.AddProjectReference(new ProjectReference(libraryUsedByA.Id)) //Why is this needed?
            .AddDocument ("SomeComposedClass.cs", "public class SomeComposedClass { SomeClass _someClass; }");

        var semanticModelOfProjectB = someComposedClass.GetSemanticModelAsync().Result;
        var someClassField = semanticModelOfProjectB.SyntaxTree.GetRoot().DescendantNodes().OfType<FieldDeclarationSyntax>().Single();

        var fieldSymbol = semanticModelOfProjectB.GetSymbolInfo (someClassField.Declaration.Type).Symbol;
        var someAttribute = fieldSymbol.GetAttributes().Single();

        Trace.Assert (someAttribute.AttributeConstructor != null);
      }
    }

    private static Project AddProject (Solution solution, string projectName)
    {
      return solution.AddProject (projectName, projectName, LanguageNames.CSharp)
          .AddMetadataReference (MetadataReference.CreateFromAssembly (typeof (string).Assembly))
          .WithCompilationOptions (
              new CSharpCompilationOptions (OutputKind.DynamicallyLinkedLibrary, assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default));
    }
Inspyro commented 9 years ago

The above example throws in the trace assert, as it cannot find the AttributeConstructor (it only finds an ErrorType for someAttribute)

matkoch commented 9 years ago

+1 I'm facing the same problem.

fschmied commented 9 years ago

@gafter, @Pilchie Seems like a bug to me, shouldn't this have the "Bug" label rather than the "Questions" label?

gafter commented 9 years ago

shouldn't this have the "Bug" label rather than the "Questions" label?

@fschmied That is the question. I believe the answer is "no", but it requires investigation.

j3parker commented 6 years ago

Any recent thoughts on this?

CyrusNajmabadi commented 5 years ago

@j3parker It's safe to assume that if there hasn't been any further discussion or links here then nothing really had changed. IMO, this is not a bug. It's an intrinsic way the Compilation/SemanticModel apis work. Barring any major shifts in thinking here, the right way to deal with this would be to add the appropriate references to the compilation, then ask semantic model questions. Thanks!