ICSharpCode.NRefactory

NRefactory supports analysis of C# source code: it includes a parser, abstract syntax tree, type system, semantic analysis (resolver), code completion, and several refactorings. Depends on Roslyn 1.0.0-rc2 packages.


Keywords
Analysis, C#, Parser, Semantic, SharpDevelop
Install
Install-Package ICSharpCode.NRefactory -Version 6.0.0-beta1

Documentation

Note: There is currently no maintainer for NRefactory.

If you need a C# parser / compiler frontend, use Microsoft.CodeAnalysis (Roslyn)
instead.

The refactorings in NRefactory have been ported to Roslyn:
    https://github.com/icsharpcode/RefactoringEssentials/

------------------------------------------------------------------------------

Overview of the NRefactory library:

Introductory documentation:
	 http://www.codeproject.com/Articles/408663/Using-NRefactory-for-analyzing-Csharp-code

How to download:
	- Binaries are provided as a NuGet package (http://nuget.org/packages/ICSharpCode.NRefactory)
	- Sourcecode is available on GitHub (https://github.com/icsharpcode/NRefactory)

How to compile:
	1. Get Mono.Cecil 0.9.6
		Get Cecil from https://github.com/jbevain/cecil ('git clone git://github.com/jbevain/cecil.git')
		or download Cecil from https://github.com/jbevain/cecil/ and unzip it into a directory named "cecil"
		next to the directory containing NRefactory.
	2. If you need the IKVM binding get it from https://github.com/mono/ikvm-fork and put it next to the NRefactory directory
		like Mono.Cecil - name it "ikvm".
	3. Open NRefactory.sln in your favorite .NET IDE and compile.

Features:
	- C# Parser
	- Abstract Syntax Tree with pattern-matching support
	- Semantic Analysis for C# (supports C# 5.0)
	- Code Completion for C#
	- Pretty Printer for C#
	- Lots of C# refactorings
	
Non-Features:
    - C# 6 is not supported.
	- VB support is not implemented.
	- NRefactory cannot generate IL code -- it's a compiler frontend, not a full compiler

Dependencies:
	.NET 4.0
	Mono.Cecil 0.9.6
	NRefactory contains a modified copy of mcs (Mono's C# compiler) for the C# parser.


Namespace overview:

ICSharpCode.NRefactory assembly
	ICSharpCode.NRefactory.Editor:
		Interfaces that abstract from the text editor control used.
		Maybe future AvalonEdit versions will directly implement these interfaces, but you could also write adapters for other editors.
	
	ICSharpCode.NRefactory.TypeSystem:
		Contains a language-independent representation of the .NET type system.
		The type system is divided into two portions: unresolved and resolved type systems.
	
	ICSharpCode.NRefactory.TypeSystem.Implementation:
		Contains default implementations for the type system interfaces.
	
	ICSharpCode.NRefactory.Semantics:
		Contains classes (ResolveResults) used to represent the semantics of a language element.
		ResolveResults can have child results, thus forming semantic trees.
	
	ICSharpCode.NRefactory.Documentation:
		Classes for working with .xml documentation files.
		See "doc/XML Documentation.html" for details.
	
	ICSharpCode.NRefactory.PatternMatching:
		Provides classes for pattern matching over the C# and VB ASTs.
		See "doc/Pattern Matching.html" for details.
	
	ICSharpCode.NRefactory.Util:
		Various helper classes.


ICSharpCode.NRefactory.CSharp assembly
	ICSharpCode.NRefactory.CSharp:
		Abstract Syntax Tree for C#
	
	ICSharpCode.NRefactory.CSharp.Completion:
		Code completion (IntelliSense) for C#
	
	ICSharpCode.NRefactory.CSharp.Resolver:
		Semantic analysis for C# (resolving the meaning of expressions)
	
	ICSharpCode.NRefactory.CSharp.Analysis:
		Semantic analysis for C# (additional analysis functionality)
	
	ICSharpCode.NRefactory.CSharp.TypeSystem:
		Contains type system implementations specific to C#.
	
	ICSharpCode.NRefactory.CSharp.Refactoring:
		Infrastructure for refactorings; and several built-in refactorings.

ICSharpCode.NRefactory.VB assembly
	ICSharpCode.NRefactory.VB:
		Abstract Syntax Tree for VB

ICSharpCode.NRefactory.Xml assembly
	ICSharpCode.NRefactory.Xml:
		Error-tolerant XML parser. Supports incremental parsing.
		When tags don't match correctly, the parser uses a heuristic to guess the parse tree.
		The heuristic tries to minimize the edit distance from the erroneous document to
		the fixed document, and it also considers the indentation.



Null-Object pattern:
	The NRefactory library makes extensive use of the null object pattern.
	As a result, NullReferenceExceptions should be very rare when working with this library.
	In the type system, both ITypeReference and IType use SpecialType.UnknownType to represent
	unknown types.
	Unless the XML documentation says otherwise, no method or property returning a ITypeReference
	or IType will return null.
	
	Note that the null object pattern is not used for ITypeDefinition:
	IProjectContent.GetClass() returns null when a type is not found. Take care to abort your
	operation or substitute UnknownType instead of passing the null to code expecting an IType.
	
	The pattern also extends to the C# resolver, which always produces a ResolveResult, even in
	error cases. Use ResolveResult.IsError to detect resolver errors.
	Also note that many resolver errors still have a meaningful type attached, this allows code
	completion to work in the presence of minor semantic errors.
	
	The C# AST makes use of special null nodes when accessing the getter of an AST property and no
	child node with that role exists. Check the IsNull property to test whether a node is a null node.
	Null nodes are not considered to be part of the AST (e.g. they don't have a parent).

FAQ:
Q:  What is the difference between NRefactory and Roslyn?
	- NRefactory is ready and stable, Roslyn is only a CTP at this point of time.
	- NRefactory does not have VB support.
	- NRefactory cannot compile code to IL; it's not a full compiler, just a frontend.
	- NRefactory C# AST is mutable and supports pattern matching; Roslyn is immutable and does not have built-in pattern matching.

Q:	What is the difference between types and type definitions?

A:	Basically, a type (IType) is any type in the .NET type system:
		- an array (ArrayType)
		- a pointer (PointerType)
		- a managed reference (ByReferenceType)
		- a parameterized type (ParameterizedType, e.g. List<int>)
		- a type parameter (ITypeParameter, e.g. T)
		- or a type definition (ITypeDefiniton)
	
	Type definitions are only classes, structs, enums and delegates.
	Every type definition is a type, but not every type is a type definition.
	NRefactory's ITypeDefinition derives from IType, so you can directly use any type definition
	as a type.
	In the other direction, you could try to cast a type to ITypeDefinition, or you can call the
	GetDefinition() method. The GetDefinition() method will also return the underlying
	ITypeDefinition if given a parameterized type, so "List<int>".GetDefinition() is "List<T>".


Q:	What is the difference between types and type references?
	I've seen lots of duplicated classes (ArrayType vs. ArrayTypeReference, etc.)
	
A:	If you've previously used the .NET Reflection API, the concept of type references will be new
	to you.
	
	NRefactory has the concept of the "unresolved type system": every assembly/project is stored
	in unresolved form.
	It is possible to load some source code into a project which contains the type reference
	"int[]" without having to load mscorlib into NRefactory.
	So inside the entities stored for the project, the array type is only referenced using an
	ITypeReference.
	This interface has a single method:
	    interface ITypeReference {
	       IType Resolve(ITypeResolutionContext context);
	    }
	By calling the Resolve()-method, you will get back the actual ArrayType.
	
	Not only type references are split up this way; pretty much every class in the type system
	comes in unresolved and resolved forms.


Q:  What is a compilation (ICompilation)?

A:	A compilation serves as the root object of the resolved type system.
	It consists of a main assembly and multiple referenced assemblies,
	and may also contain additional information like compiler options.


Q:  What's in an ITypeResolveContext?

A:  An ITypeResolveContext is an environment for looking up namespaces and types.
	It consists of the current compilation, the current type definition,
	and language-specific implementations may add additional information (e.g. the list of usings).
	
	Generally, you cannot resolve a type reference without knowing what kind of context is expected.


Q:	How do I get the IType or ITypeReference for a primitive type such as string or int?
	
A:	To get an IType for a primitive type, use:
		compilation.FindType(KnownTypeCode.Int32)
	
	To get an ITypeReference, use:
		KnownTypeReference.Int32
	
	It is also possible to use a System.Type for retrieving a type:
	   compilation.FindType(typeof(int))
	or
	   typeof(int).ToTypeReference().


Q:	Is it thread-safe?

A:	This question is a bit difficult to answer.
	NRefactory was designed to be usable in a multi-threaded IDE.
	But of course, this does not mean that everything is thread-safe.
	
	First off, there's no hidden static state, so any two operations working on independent data
	can be executed concurrently.
	[Actually, sometimes static state is used for caches, but those uses are thread-safe.]
	TODO: what about the C# parser? gmcs is full of static state...
		-> this is being worked on; for the time being, NRefactory uses a global lock during parsing;
		   so it's thread-safe but slow.
	
	Some instance methods may use hidden instance state, so it is not safe to e.g. use an instance
	of the CSharp.Resolver.TypeInference class concurrently.
	Instead, you need to create an instance on every thread.
	
	The type system itself is thread-safe. Both the unresolved and the resolved type systems are
	immutable.
	
	When you add to an IProjectContent, the existing project content isn't modified,
	but a new project content is created instead. All implementations of the type system interfaces
	are either immutable or freezable.
	
	And on the resolved type system side, ICompilation is immutable as well.
	Internally, the resolved type system will resolve elements only on demand, but this is done
	in a thread-safe manner.


Q:	What format do the .ToString() methods use?

A:	They don't use any particular format. They're merely intended as a debugging aid.
	Currently .ToString() usually matches .ReflectionName, but that may change in the future.