Skip to content

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Oct 14, 2025

Summary

Fixes #13456

The documentation for ISymbol.Locations and ISymbol.DeclaringSyntaxReferences was unclear about the behavior for partial members. The documentation mentioned that "partial classes" may be defined in more than one location, which led developers to expect the same behavior for partial methods, properties, and events. However, partial members only return one location in these properties.

Changes

Documentation Updates

Updated the XML documentation for both properties in ISymbol.cs to:

  1. Clarify partial types: Changed "partial classes" to "partial types such as classes, structs, and interfaces" to be more inclusive and explicit
  2. Document partial members behavior: Added explicit notes that partial members (methods, properties, events) return only one location, not multiple
  3. Provide guidance: Direct developers to use the PartialDefinitionPart and PartialImplementationPart properties on IMethodSymbol, IPropertySymbol, or IEventSymbol to get all locations for partial members

Test Coverage

Added PartialMethodsLocationsAndSyntaxReferences test that documents and verifies:

  • Partial methods have only 1 location in both Locations and DeclaringSyntaxReferences arrays
  • The returned location is for the definition part
  • All locations can be retrieved by accessing the PartialImplementationPart property

Example

Before this change, developers had to discover through trial and error that they needed code like this to get all locations:

var methodSymbols = 
    Enumerable.Repeat(method, 1) 
    .Union(Enumerable.Repeat(method.PartialDefinitionPart, 1))  
    .Union(Enumerable.Repeat(method.PartialImplementationPart, 1))  
    .Where(methodSymbol => methodSymbol != null)  
    .Distinct(); 

Now the documentation clearly explains this behavior and points developers to the correct properties.

Original prompt

This section details on the original issue you should resolve

<issue_title>Provide better API and documentation for SyntaxReferences of partial methods </issue_title>
<issue_description>Version Used:
v2.3.2
Steps to Reproduce:
Get an ISymbol for a partial method.
e.g. Console App with Microsoft.CodeAnalysis Nuget package

        static void Main(string[] args)
        {
            var ws = new AdhocWorkspace();
            var project = ws.AddProject("Ass1", LanguageNames.CSharp);
            ws.AddDocument(project.Id, "DefinitionPart.cs", SourceText.From(
@"
namespace N1
{
    partial class C1
    {
        partial void PartialM();
    }
}
"));
            ws.AddDocument(project.Id, "ImplementationPart.cs", SourceText.From(
@"
namespace N1
{
    partial class C1
    {
        partial void PartialM() { }
    }
}
"));
            var compilation = ws.CurrentSolution.Projects.First().GetCompilationAsync().GetAwaiter().GetResult();
            var methodSymbols = compilation.GetSymbolsWithName(s => s == "PartialM");
            var method = methodSymbols.First() as IMethodSymbol;
            Console.WriteLine($"Number of symbols                   : { methodSymbols.Count() }");
            Console.WriteLine($"DeclaringSyntaxReferences           : { method.DeclaringSyntaxReferences.Count() }");
            Console.WriteLine($"DeclaringSyntaxReference.Location   : { method.DeclaringSyntaxReferences.First().SyntaxTree.FilePath }");
            Console.WriteLine($"Locations                           : { method.Locations.Count() }");
            Console.WriteLine($"Location                            : { method.Locations.First().SourceTree.FilePath }");
            Console.WriteLine($"Has PartialDefinitionPart           : { method.PartialDefinitionPart != null }");
            Console.WriteLine($"Has PartialImplementationPart       : { method.PartialImplementationPart != null }");
            Console.WriteLine($"PartialImplementationPart.Location  : { method.PartialImplementationPart.Locations.First().SourceTree.FilePath }");
            Console.ReadLine();
        }

Expected Behavior:

method.DeclaringSyntaxReferences and method.Locations contain references to both files (as does the ISymbol for class C1).

Actual Behavior:

Number of symbols                   : 1
DeclaringSyntaxReferences           : 1
DeclaringSyntaxReference.Location   : DefinitionPart.cs
Locations                           : 1
Location                            : DefinitionPart.cs
Has PartialDefinitionPart           : False
Has PartialImplementationPart       : True
PartialImplementationPart.Location  : ImplementationPart.cs

From the documentation comment of DeclaringSyntaxReferences and Locations

.. Some Symbols (for example, partial classes) may be defined in more than one location. ..

I would expect that for partial methods the implementation and definition part would be included in the DeclaringSyntaxReferences and/or Locations collections.
It requires a cast to IMethodSymbol to get both locations and to be sure to get all locations you have to something along the lines:

var methodSymbols = 
    Enumerable.Repeat(method, 1) 
    .Union(Enumerable.Repeat(method.PartialDefinitionPart, 1)  
    .Union(Enumerable.Repeat(method.PartialImplementationPart, 1)))  
    .Where(methodSymbol => methodSymbol != null)  
    .Distinct(); 

This is hard to discover and get right as an API consumer.

It would be nice to

  1. Extend the documentation for DeclaringSyntaxReferences and Locations to mention the Partial...Part properties of IMethodSymbol.
  2. Provide an extension method to get all source code locations relevant to an ISymbol.</issue_description>

<agent_instructions>Copilot, can you update the documentation for DeclaringSyntaxReferences and Locations. It should clarify that you can get multiple results for partial types, but not for partial members. </agent_instructions>

Comments on the Issue (you are @copilot in this section)

Fixes #22598


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Copilot AI and others added 2 commits October 14, 2025 14:26
@Copilot Copilot AI changed the title [WIP] Provide better API and documentation for SyntaxReferences Update documentation for DeclaringSyntaxReferences and Locations to clarify partial members behavior Oct 14, 2025
@Copilot Copilot AI requested a review from CyrusNajmabadi October 14, 2025 14:33
Copilot finished work on behalf of CyrusNajmabadi October 14, 2025 14:33
@CyrusNajmabadi CyrusNajmabadi marked this pull request as ready for review October 14, 2025 14:40
@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner October 14, 2025 14:40
@CyrusNajmabadi
Copy link
Member

@dotnet/roslyn-compiler ptal.

@jcouv
Copy link
Member

jcouv commented Oct 14, 2025

I don't understand why this PR didn't automatically get labelled with "Compiler" given that it touches a compiler file. Is there a bot problem?
The way to get compiler reviews is to add this label.

@CyrusNajmabadi
Copy link
Member

@dotnet/roslyn-compiler ptal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provide better API and documentation for SyntaxReferences of partial methods Incorrectly identifying unnecessary imports

3 participants