Skip to content

External Type Tracking for C# - #65

Closed
sergitorres-codere wants to merge 1 commit into
bartolli:mainfrom
sergitorres-codere:feature/csharp-external-type-tracking
Closed

External Type Tracking for C##65
sergitorres-codere wants to merge 1 commit into
bartolli:mainfrom
sergitorres-codere:feature/csharp-external-type-tracking

Conversation

@sergitorres-codere

Copy link
Copy Markdown
Contributor

When working with C# codebases, users frequently search for types that are defined in external assemblies (DLLs, NuGet packages) rather than in source code. Currently, Codanna returns "No symbols found" for these types, which is confusing because:

  1. The types ARE used extensively in the codebase
  2. Users can see them in their IDE and code
  3. The error message doesn't explain WHY they're not found

Example

public class EventProcessor {
    DataTransferObject _cachedDataA;  // DataTransferObject is from external assembly
    DataTransferObject _cachedDataB;
}

Before this PR:

codanna retrieve symbol DataTransferObject
→ symbol not found

After this PR:

codanna retrieve symbol DataTransferObject
→ DataTransferObject (ExternalType) at EventProcessor.cs:21
   Signature: external type: DataTransferObject

   Note: This type is not defined in your source code.
   It's from an external assembly/library.
   Use 'search_symbols' to find all usages of this type in your codebase.

Solution

Add external type tracking specifically for C#, with a design that can be extended to other compiled languages (Java, etc.).

Key Features

  1. Distinguish local vs. external types

    • Track all types defined in source code (classes, interfaces, structs, enums, records)
    • Detect when a type reference is NOT locally defined
  2. Smart filtering

    • Skip primitive types (int, string, bool, etc.)
    • Skip well-known framework types (String, Int32, Object, etc.)
    • Only track user-defined external types
  3. Clear communication

    • New SymbolKind::ExternalType makes it explicit
    • Helpful MCP tool messages guide users
    • Signature includes "external type:" prefix

Implementation Details

1. New Symbol Kind (src/types/mod.rs)

pub enum SymbolKind {
    // ... existing variants ...
    /// External type reference (not defined in source code)
    /// Used primarily for tracking references to types from external assemblies/libraries
    /// in compiled languages like C# and Java
    ExternalType,
}

2. C# Parser Changes (src/parsing/csharp/parser.rs)

Added tracking infrastructure:

pub struct CSharpParser {
    // ... existing fields ...
    local_types: HashSet<String>,
    external_type_refs: HashMap<String, Option<String>>,
}

Modified type processing methods:

  • process_class, process_interface, process_struct, process_enum, process_record
    • All now call record_local_type() to track definitions

Added external type detection:

  • process_field_declaration now extracts type references
  • Checks if type is local, primitive, or external
  • Creates ExternalType symbol for genuine external references

3. MCP Tool Enhancement (src/mcp/mod.rs)

if symbol.kind == crate::SymbolKind::ExternalType {
    result.push_str("\nNote: This type is not defined in your source code. ");
    result.push_str("It's from an external assembly/library.\n");
    result.push_str("Use 'search_symbols' to find all usages of this type in your codebase.\n");
}

Testing

Test Case: External NuGet Package Type

Code:

using Company.Product.DataMapper.Model;

public class EventProcessor : IEventProcessor
{
    DataTransferObject _cachedDataA;
    DataTransferObject _cachedDataB;

    public DataTransferObject ProcessedData { get; set; }
}

Result:

$ codanna retrieve symbol DataTransferObject
DataTransferObject (ExternalType) at EventProcessor.cs:21 [symbol_id:80]
Module: Company.Product.ServiceLayer...
Signature: external type: DataTransferObject
Visibility: Public

Note: This type is not defined in your source code.
It's from an external assembly/library.
Use 'search_symbols' to find all usages of this type in your codebase.

Impact

  • ✅ Fixes confusion about missing symbols
  • ✅ Improves C# developer experience significantly
  • ✅ Provides actionable guidance (use search_symbols)
  • ✅ Foundation for Java and other compiled language support

Documentation Updates

  • Updated docs/architecture/language-support.md to document external type tracking
  • Updated docs/user-guide/mcp-tools.md with ExternalType kind information
  • Updated docs/integrations/agent-guidance.md with guidance for AI agents on handling external types

This change addresses a usability issue where types from external assemblies
(DLLs, NuGet packages) were not tracked, leading to "symbol not found" errors
when searching for commonly-used external types.

**Changes:**

1. **Add ExternalType symbol kind** (`src/types/mod.rs`)
   - New `SymbolKind::ExternalType` variant for tracking external type references
   - Updated `FromStr` implementation and tests

2. **C# parser enhancements** (`src/parsing/csharp/parser.rs`)
   - Track locally-defined types (classes, interfaces, structs, enums, records)
   - Detect external type references in field declarations
   - Skip primitive and framework types (int, string, etc.)
   - Create ExternalType symbols for unresolved types

3. **MCP tool improvements** (`src/mcp/mod.rs`)
   - Add helpful note when ExternalType is found
   - Guide users to use `search_symbols` for finding usages

4. **Vector embedding support** (`src/vector/embedding.rs`)
   - Handle ExternalType in symbol text generation

**Testing:**
- Verified with C# codebase containing external assembly references
- `MapperResult` from `Codere.SBGOnline.EventsMapper.Model` now correctly
  identified as ExternalType instead of "not found"

**Impact:**
- Improves user experience for C# developers (and future Java support)
- Reduces confusion about missing symbols
- Provides clear distinction between "not found" and "external type"

**Future work:**
- Extend to other compiled languages (Java, etc.)
- Parse XML documentation for external types
- Track namespace/assembly metadata

Closes issue with external type references in C# projects.
@bartolli

bartolli commented Nov 8, 2025

Copy link
Copy Markdown
Owner

Hi @sergitorres-codere ,

I checked the changes you proposed. Here’s what I think.

We already have import tracking and external detection in place. Adding a new symbol kind for external types might not be the best solution. Instead, the retrieve_symbol function could check imports when no symbols are found. That would solve the confusing UX when an external symbol isn’t located.

How about this simple adjustment. We enhance the find_symbol MCP tool to check imports when a symbol isn’t found:

if symbols.is_empty() {
    // Check if name exists in imports
    let all_imports = indexer.get_all_imports();
    let matching_imports: Vec<_> = all_imports
        .iter()
        .filter(|imp| {
            imp.path.ends_with(&name) ||
            imp.alias.as_ref() == Some(&name)
        })
        .collect();

    if !matching_imports.is_empty() {
        return format!(
            "'{name}' is an external type (not defined in source code).
              Found in imports:
              {list_imports}
              
              Use 'search_symbols query:\"{name}\"' to find usages."
        );
    }
}

The benefit is that it uses the existing import storage.. no new symbol kind is needed, no index bloat, and it will work for all import types by leveraging the ImportOrigin determination. What do you think? I could go ahead and make those changes.

@sergitorres-codere

Copy link
Copy Markdown
Contributor Author

hi @bartolli ,

makes sense, did not notice that... no worries i will take care of it, i am also about to create a new PR to support the rest of missing features in the C# parser so i can include this change on it

i believe is better to close this PR and ignore it at this point

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants