About Jolt.NET Libraries

Inspired by the Boost C++ libraries, Jolt.NET aims to complement the .NET Base Class Library (BCL) with algorithms, data structures, and general productivity tools. It is the hope of the authors that the features of Jolt.NET will one day be part of, or represented in the BCL and the .NET Framework.

Limitations to XML Doc Comment Parsing

Hello everyone!

I've been working on improving the support for XML doc comment queries with metadata types, but came across some limitations in the reflection API that have hindered my progress.  Specifically, I've been trying to add support for retrieving doc comments for methods containing a function pointer as a parameter, and methods containing a parameter that has been decorated with an optional or required custom modifier.  Unfortunately, given the current state of the reflection API (for which I will elaborate upon below), I don't believe that I can implement these features and achieve a general solution that works for all inputs.

The goal of this feature is to be able to retrieve the XML comments as given in the following code example.

public ref class T
/// <summary/>
/// <param name="param">A function pointer of managed types</param>
void FnPtrMethod(String^ (*param)(TimeSpan, DateTime, array<int>^)) { }

Since a function pointer is a native C++ entity, it is not recognized by the CLR and consequently I don't believe it to be possible to adequately represent it with a metadata object.  Given the method FnPtrMethod above, the managed type of its sole parameter param is rendered by the reflection API as System.IntPtr.  This is understandable sense since the function pointer is really a raw native pointer to the address of executable code.  It makes no difference that its arguments are managed types, since the type that encompasses them is not managed. If all we have to work with is an IntPtr instance, then it is impossible to infer that the IntPtr is really a function pointer and fetch its managed arguments for processing.

I'm fairly confident that my analysis is correct, but in the hope of being wrong I've started a discussion on StackOverflow just to be sure.  If you know the trick to get this to work, please respond to this blog entry or to the discussion on StackOverflow.

The goal of this feature is to be able to retrieve the XML comments as given in the following code example.

public ref class T
/// <summary/>
/// <param name="x">modopt</param>
/// <param name="y">modreq</param>
void modifiers(const int x, volatile int y) { }

This feature may be implemented, but only for a small number of variations in the types of method parameters.  The problem lies in the placement of the ParameterInfo.GetOptionalCustomModifiers() and ParameterInfo.GetRequiredCustomModifiers() methods.  These methods are specific to a parameter, and I believe that they should be generalized and applied to any instance of System.Type.  For instance, consider the following method.

public ref class C
/// <summary/>
/// <param name="param">Generic action containing modreq/modopt generic argument.</param>
generic <typename T>
void f(Action<const volatile T>^ param) { }

The sole parameter param of function f does not have a custom modifier, however the generic method argument T that participates in the definition of the parameter type does.  In this case, it doesn't make sense to call param.GetOptionalCustomModifiers() since the modifiers apply to T.  To get the metadata for T, we need to call GetGenericArguments() resulting in a System.Type array.  But, System.Type does not provide a means to get its custom modifiers!  A similar problem also exists with array and pointer types as custom modifiers are applied to the element type of these entities.  We need to call GetElementType() on the array/pointer type, but are again presented with a System.Type instance and with no way to get its custom modifiers.

Regarding this issue, I've opened a bug report with Microsoft in hopes that the API flaw will be addressed in a future version of the .NET Framework.

However, all is not lost.  We can still use the ParameterInfo.GetOptionalCustomModifiers() and ParameterInfo.GetRequiredCustomModifiers() methods to get custom modifiers for a parameter that is not an array, pointer, or decorated with the by-ref/out attributes (all of these types require us to call GetElementType() to get the type to which the modifier is applied).  Also, the parameter can not be dependent on a generic method or type parameter having a custom modifier applied to it.  This will at least expose the feature to a small number of methods, but it clearly won't work in the general case.  Consequently, I've decided to postpone implementing this feature until I get clearer direction from the community.  If you would like to see this feature implement in Jolt.NET, please vote it up on the Jolt.NET CodePlex web site.

Recent Jolt.NET Revisions and Xml Doc Comment Parsing

I try to make a habit of posting to the development blog each time a significant feature or piece of code gets committed to the source repository.  Consequently, I would like to use this post to summarize what has been committed in the past month as several updates have been made.  Also, I'll describe some of the work I've been doing on matching XML doc comment elements with their corresponding metadata type from the System.Reflection namespace.

Commit Summary

Maintenance and refactoring is the main aspect of the Jolt.NET 0.4 release.  Prior to this release, I've intentionally delayed many code clean-up tasks as well as performing upgrades of 3rd party dependencies so that I could work on more important features.  Now that all those features are complete, I have spent some time to restore the code to its "pristine" state.  Here is a summary of the recent updates related to maintenance.

  • Updated QuickGraph dependency to QuickGraph 3.3.40824
    • Removed FSM->MSAGL conversion code as MSAGL is no longer supported by QuickGraph (superseded by GLEE)
    • Removed explicit implementation of equality semantics for Transition class as it is now supported natively by QuickGraph's EquatableEdge type
  • Updated RhinoMocks dependency to RhinoMocks 3.6
    • Modified relevant unit tests to utilize Act-Arrange-Assert syntax
  • Update NUnit dependency to NUnit 2.5.2
    • Adopted the use of new constraints to simplify and/or strengthen existing unit tests
    • Added additional unit tests to verify presence of attributes on types and their members, a task facilitated by the new constraints in NUnit 2.5
  • Unit test maintenance
    • Fixed many issues that prevented unit tests from being run in an NUnit project (aggregating many test fixtures)
    • Moved much of the reflection code for accessing types and members by strings into separate classes, improving the readability of some unit tests

The following commits introduced new features that were previously planned to be included with the Jolt.NET 0.4 release.

  • The Jolt.Convert class will now correctly generate the XML doc comments representation of an explicit or implicit operator
    • Predefined .NET operators were already supported
    • Consequently, you can now process XML doc comments with a System.Reflection.MethodInfo type referring to an operator
  • Created the Jolt.Testing.Assertions.VisualStudio.XmlAssert class to integrate the Jolt XML assertions to the Visual Studio test framework

XML Doc Comment Processing

"Processing the XML File (C# Programming Guide)" describes the supported XML doc comment markup for various types, methods, parameters, and fields.  For a given metadata type instance, Jolt.Convert will produce the correct markup, with the exception of the following constructs.

  • Function pointer parameter (ELEMENT_TYPE_FNPTR)
  • Optional understanding modifier (ELEMENT_TYPE_CMOD_OPT)
  • Required understanding modifier (ELEMENT_TYPE_CMOD_REQ)
  • Pinned field (ELEMENT_TYPE_PINNED)
  • Dimensionless and rank-less array (ELEMENT_TYPE_GENERICARRAY)

In order to verify that my implementation is correct, I compare the output of a .NET compiler with the output of the Jolt.Convert class.  Since the C# language does not currently support these constructs directly, other means are required for testing the implementation of the Jolt.Convert class, which are demonstrated below.

To produce XML doc comments with ELEMENT_TYPE_FNPTR, ELEMENT_TYPE_CMOD_OPT, and ELEMENT_TYPE_CMOD_REQ markup, we may use the the C++/CLI compiler to compile the following class.

public ref class XmlDocCommentTest
typedef int (*function_ptr)(char, int, double);

void fnptr(function_ptr f); // ELEMENT_TYPE_FNPTR
void mod_opt(const int n); // ELEMENT_TYPE_CMOD_OPT
void mod_req(volatile int n); // ELEMENT_TYPE_CMOD_REQ

Function pointers are a common construct for C/C++ developers, but understanding why const and volatile translate to optional and required modifiers requires some explanation.  Paul DiLascia covers this topic in his article "C++ At Work: Rationales, Highlights, and a Farewell".

ELEMENT_TYPE_PINNED is a bit more tricky since the general C++ literature on pinned pointers states that their usage is restricted to non-static local stack variables, which can not be decorated with XML doc comments.  However, the System.Runtime.CompilerServices namespace gives some hints on how discover that a field is pinned.  Unfortunately I do not know of a way to verify this behavior using a .NET compiler or other tool.

Finally, ELEMENT_TYPE_GENERICARRAY appears to be deprecated as I can not locate any reference to it in modern .NET documentation (apart from the aforementioned document).

In the mean time, I plan to implement support for all ELEMENT_TYPE_FNPTR, ELEMENT_TYPE_CMOD_OPT, and ELEMENT_TYPE_CMOD_REQ in Jolt.NET 0.4.  For ELEMENT_TYPE_PINNED, I will wait until the feature is highly requested or until I stumble upon a tool that will produce the desired output.