I was surprised how easy it is to build a simple code search solution based on Lucene and Roslyn. By code search solution I mean indexing C# files on disk and searching through them. Here's how it works.

After typing search term and hitting search I show the total number of hits (files found), file names and highlited terms:


Details page is for seeing the complete file with the search terms highlighted:


As expected, there are boolean and wildcard searchers. So, it is pretty simple, but here's an interesting twist. You can also search by class, function, parameter, return value and so on:

Field Purpose Example
class Find files where this class is declared and defined class:Bindings
method Where is this method defined? method:GetValueOrNull
parameter Show me methods for the given parameter name parameter:dictionary
return Locate methods returning this type return:double
base Look for the classes derived from the given class base:doubledocvalues
code Search within methods only. This can be helpful to ignore noice when too many hits are returned by general query. code:"prime*result"
comment I need to see where the given search term used as multi-line or single-line comment comment:todo

Essentially I ported to .Net this Java code where instead of Java AST parser I use Roslyn. For example, some of the indexing code looks like this:

public void Index(string contentPath)  
    var indexDirectory = new SimpleFSDirectory(new DirectoryInfo(_configuration.IndexPath));
    Log(string.Format("Begining to index {0}. Index location: {1}", contentPath, indexDirectory.Directory.FullName));
    using (var writer = new IndexWriter(indexDirectory, new CSharpAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED))
        IndexDirectory(writer, new DirectoryInfo(contentPath));
    Log(string.Format("Indexed {0:N0} files.", _fileCount));

private void IndexFile(IndexWriter writer, FileInfo file)  
    if (writer == null || file == null || Path.GetExtension(file.Name) != ".cs" 
        || !file.Exists || (file.Attributes & FileAttributes.Hidden) != 0)
    var doc = new Document();
    doc.Add(new Field(Fields.Content, file.OpenText(), Field.TermVector.WITH_OFFSETS));
    var parser = new CSharpParser();
    var syntax = parser.Parse(file.FullName);
    AddComments(doc, syntax);
    AddUsings(doc, syntax);
    AddClasses(doc, syntax);
    doc.Add(new Field(Fields.Path, Path.Combine(file.DirectoryName, file.Name), Field.Store.YES, Field.Index.NO));
    writer.AddDocument(doc); // here we can specify an analyzer

CSharpParser is a simple Roslyn wrapper. I am going to publish this code on Github soon.